This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 68fd441e51121f763ab0124d0dd95402fb204e3f
Author: Eric Milles <[email protected]>
AuthorDate: Mon Dec 13 21:44:02 2021 -0600

    GROOVY-8050: STC: no outer class method or property access from outside
    
    Conflicts:
        
src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 70 ++++++++++------------
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 50 +++++++++++++++-
 2 files changed, 79 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 4732da9..2bf2504 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4749,13 +4749,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
@@ -4765,25 +4766,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,22 +4792,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                     pname = extractPropertyNameFromMethodName("is", name);
                 }
                 if (pname != null) {
-                    // we don't use property exists there because findMethod 
is called on super clases recursively
-                    PropertyNode property = null;
-                    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;
-                            }
-                        }
-                        curNode = curNode.getSuperClass();
-                    }
+                    PropertyNode property = findProperty(receiver, pname);
                     if (property != null) {
                         int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? 
Opcodes.ACC_STATIC : 0);
                         MethodNode node = new MethodNode(name, mods, 
property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, 
GENERATED_EMPTY_STATEMENT);
@@ -4822,13 +4804,8 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 // maybe we are looking for a setter ?
                 String pname = extractPropertyNameFromMethodName("set", name);
                 if (pname != null) {
-                    ClassNode curNode = receiver;
-                    PropertyNode property = null;
-                    while (property == null && curNode != null) {
-                        property = curNode.getProperty(pname);
-                        curNode = curNode.getSuperClass();
-                    }
-                    if (property != null) {
+                    PropertyNode property = findProperty(receiver, pname);
+                    if (property != null && 
!Modifier.isFinal(property.getModifiers())) {
                         ClassNode type = property.getOriginType();
                         if 
(implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), 
wrapTypeIfNecessary(type))) {
                             int mods = Opcodes.ACC_PUBLIC | 
(property.isStatic() ? Opcodes.ACC_STATIC : 0);
@@ -4872,6 +4849,23 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         return EMPTY_METHODNODE_LIST;
     }
 
+    private PropertyNode findProperty(final ClassNode receiver, final String 
name) {
+        for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
+            PropertyNode property = cn.getProperty(name);
+            if (property != null) return property;
+
+            if (!cn.isStaticClass() && cn.getOuterClass() != null
+                    && 
typeCheckingContext.getEnclosingClassNodes().contains(cn)) {
+                ClassNode outer = cn.getOuterClass();
+                do {
+                    property = outer.getProperty(name);
+                    if (property != null) return property;
+                } while (!outer.isStaticClass() && (outer = 
outer.getOuterClass()) != null);
+            }
+        }
+        return null;
+    }
+
     /**
      * Given a method name and a prefix, returns the name of the property that 
should be looked up,
      * following the java beans rules. For example, "getName" would return 
"name", while
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy 
b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 37df715..7e9ae33 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -548,8 +548,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 {
@@ -564,7 +608,7 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
         ''', 'The variable [p] is undeclared.'
     }
 
-    void testOuterPropertyAccess3() {
+    void testOuterPropertyAccess6() {
         shouldFailWithMessages '''
             class Outer {
                 static class Inner {
@@ -580,7 +624,7 @@ class FieldsAndPropertiesSTCTest extends 
StaticTypeCheckingTestCase {
     }
 
     // GROOVY-7024
-    void testOuterPropertyAccess4() {
+    void testOuterPropertyAccess7() {
         assertScript '''
             class Outer {
                 static Map props = [bar: 10, baz: 20]

Reply via email to