You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2021/12/14 03:44:15 UTC
[groovy] branch master updated: GROOVY-8050: STC: no outer class method or property access from outside
This is an automated email from the ASF dual-hosted git repository.
emilles pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new e71a44a GROOVY-8050: STC: no outer class method or property access from outside
e71a44a is described below
commit e71a44a04eda3a0b27de7f54b2176c1e3fdafad1
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Dec 13 21:44:02 2021 -0600
GROOVY-8050: STC: no outer class method or property access from outside
---
.../transform/stc/StaticTypeCheckingVisitor.java | 68 ++++++++++------------
.../stc/FieldsAndPropertiesSTCTest.groovy | 50 +++++++++++++++-
2 files changed, 77 insertions(+), 41 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index b93193e..04e3ee6 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4748,13 +4748,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) {
if (isPrimitiveType(receiver)) receiver = getWrapper(receiver);
+
List<MethodNode> methods;
- if (!receiver.isInterface() && "<init>".equals(name)) {
+ if ("<init>".equals(name) && !receiver.isInterface()) {
methods = addGeneratedMethods(receiver, new ArrayList<>(receiver.getDeclaredConstructors()));
if (methods.isEmpty()) {
MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT);
node.setDeclaringClass(receiver);
- methods = Collections.singletonList(node);
+ methods.add(node);
if (receiver.isArray()) {
// No need to check the arguments against an array constructor: it just needs to exist. The array is
// created through coercion or by specifying its dimension(s), anyway, and would not match an
@@ -4764,25 +4765,21 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
} else {
methods = findMethodsWithGenerated(receiver, name);
- if (receiver.isInterface()) {
- if ("call".equals(name) && isFunctionalInterface(receiver)) {
- MethodNode sam = findSAM(receiver);
+ if ("call".equals(name) && receiver.isInterface()) {
+ MethodNode sam = findSAM(receiver);
+ if (sam != null) {
MethodNode callMethod = new MethodNode("call", sam.getModifiers(), sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode());
callMethod.setDeclaringClass(sam.getDeclaringClass());
callMethod.setSourcePosition(sam);
methods.add(callMethod);
}
}
- // TODO: investigate the trait exclusion a bit further, needed otherwise
- // CallMethodOfTraitInsideClosureAndClosureParamTypeInference fails saying
- // not static method can't be called from a static context
- if (typeCheckingContext.getEnclosingClosure() == null || (receiver.getOuterClass() != null && !receiver.getName().endsWith("$Trait$Helper"))) {
- // not in a closure or within an inner class
- ClassNode parent = receiver;
- while (parent.getOuterClass() != null && !parent.isStaticClass()) {
- parent = parent.getOuterClass();
- methods.addAll(findMethodsWithGenerated(parent, name));
- }
+ if (!receiver.isStaticClass() && receiver.getOuterClass() != null
+ && !receiver.getName().endsWith("$Trait$Helper") // GROOVY-7242
+ && typeCheckingContext.getEnclosingClassNodes().contains(receiver)) {
+ ClassNode outer = receiver.getOuterClass();
+ do { methods.addAll(findMethodsWithGenerated(outer, name));
+ } while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
}
if (methods.isEmpty()) {
addArrayMethods(methods, receiver, name, args);
@@ -4795,33 +4792,28 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
}
PropertyNode property = null;
if (pname != null) {
- // we don't use property exists there because findMethod is called on super clases recursively
- ClassNode curNode = receiver;
- while (property == null && curNode != null) {
- property = curNode.getProperty(pname);
- ClassNode svCur = curNode;
- while (property == null && svCur.getOuterClass() != null && !svCur.isStaticClass()) {
- svCur = svCur.getOuterClass();
- property = svCur.getProperty(pname);
- if (property != null) {
- receiver = svCur;
- break;
- }
+ outer_upper: // can't use existsProperty because it calls findMethod
+ for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
+ property = cn.getProperty(pname);
+ if (property != null) break outer_upper;
+ if (!cn.isStaticClass() && cn.getOuterClass() != null
+ && typeCheckingContext.getEnclosingClassNodes().contains(cn)) {
+ ClassNode outer = cn.getOuterClass();
+ do {
+ property = outer.getProperty(pname);
+ if (property != null) break outer_upper;
+ } while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null);
}
- curNode = curNode.getSuperClass();
}
- } else {
- // look for a property with the getterName set since it may not match above
- ClassNode curNode = receiver;
- while (property == null && curNode != null && !curNode.isStaticClass()) {
- for (PropertyNode p : curNode.getProperties()) {
- if (name.equals(p.getGetterName())) {
- property = p;
- receiver = curNode;
- break;
+ } else { // look for property via getGetterName() for non-canonical case
+ out:
+ for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
+ for (PropertyNode pn : cn.getProperties()) {
+ if (name.equals(pn.getGetterName())) {
+ property = pn;
+ break out;
}
}
- curNode = curNode.getSuperClass();
}
}
if (property != null) {
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index a7ccf1e..393d67d 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -646,8 +646,52 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'''
}
- // GROOVY-9598
void testOuterPropertyAccess2() {
+ assertScript '''
+ class Outer {
+ class Inner {
+ def m() {
+ getP()
+ }
+ }
+ def p = 1
+ }
+ def i = new Outer.Inner(new Outer())
+ def x = i.m()
+ assert x == 1
+ '''
+ }
+
+ // GROOVY-8050
+ void testOuterPropertyAccess3() {
+ shouldFailWithMessages '''
+ class Outer {
+ class Inner {
+ }
+ def p = 1
+ }
+ def i = new Outer.Inner(new Outer())
+ def x = i.p
+ ''',
+ 'No such property: p for class: Outer$Inner'
+ }
+
+ // GROOVY-8050
+ void testOuterPropertyAccess4() {
+ shouldFailWithMessages '''
+ class Outer {
+ class Inner {
+ }
+ def p = 1
+ }
+ def i = new Outer.Inner(new Outer())
+ def x = i.getP()
+ ''',
+ 'Cannot find matching method Outer$Inner#getP()'
+ }
+
+ // GROOVY-9598
+ void testOuterPropertyAccess5() {
shouldFailWithMessages '''
class Outer {
static class Inner {
@@ -663,7 +707,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
'The variable [p] is undeclared.'
}
- void testOuterPropertyAccess3() {
+ void testOuterPropertyAccess6() {
shouldFailWithMessages '''
class Outer {
static class Inner {
@@ -680,7 +724,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
}
// GROOVY-7024
- void testOuterPropertyAccess4() {
+ void testOuterPropertyAccess7() {
assertScript '''
class Outer {
static Map props = [bar: 10, baz: 20]