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 2022/01/29 20:33:05 UTC

[groovy] branch GROOVY_3_0_X updated (0e7e7e7 -> 7c0c0d0)

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

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


    from 0e7e7e7  GROOVY-7033: visit AIC's field, method, and parameter annotations
     new 68fd441  GROOVY-8050: STC: no outer class method or property access from outside
     new 7c0c0d0  GROOVY-10414: STC: set non-static outer class property via setter method

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../transform/stc/StaticTypeCheckingVisitor.java   | 70 ++++++++++------------
 src/test/gls/innerClass/InnerClassTest.groovy      | 13 ++++
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 68 ++++++++++++++++++++-
 .../groovy/transform/stc/STCAssignmentTest.groovy  | 34 ++++++-----
 4 files changed, 130 insertions(+), 55 deletions(-)

[groovy] 01/02: GROOVY-8050: STC: no outer class method or property access from outside

Posted by em...@apache.org.
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 <er...@thomsonreuters.com>
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]

[groovy] 02/02: GROOVY-10414: STC: set non-static outer class property via setter method

Posted by em...@apache.org.
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 7c0c0d0bfcda3f59febbf268f9ccc132b697b074
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Dec 14 14:58:14 2021 -0600

    GROOVY-10414: STC: set non-static outer class property via setter method
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
 src/test/gls/innerClass/InnerClassTest.groovy      | 13 +++++++++
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 28 ++++++++++++++----
 .../groovy/transform/stc/STCAssignmentTest.groovy  | 34 +++++++++++++---------
 3 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index e407f95..618d9d4 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -670,6 +670,19 @@ final class InnerClassTest {
         assert err =~ /Apparent variable 'count' was found in a static scope but doesn't refer to a local variable, static field or class./
     }
 
+    @Test // GROOVY-8050
+    void testUsageOfOuterField13() {
+        assertScript '''
+            class Outer {
+                class Inner {
+                }
+                def p = 1
+            }
+            def i = new Outer.Inner(new Outer())
+            assert i.p == 1
+        '''
+    }
+
     @Test
     void testUsageOfOuterSuperField() {
         assertScript '''
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 7e9ae33..e2c57ad 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -564,8 +564,26 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-8050
+    // GROOVY-10414
     void testOuterPropertyAccess3() {
+        assertScript '''
+            class Outer {
+                class Inner {
+                    def m() {
+                        setP(2)
+                        getP()
+                    }
+                }
+                def p = 1
+            }
+            def i = new Outer.Inner(new Outer())
+            def x = i.m()
+            assert x == 2
+        '''
+    }
+
+    // GROOVY-8050
+    void testOuterPropertyAccess4() {
         shouldFailWithMessages '''
             class Outer {
                 class Inner {
@@ -579,7 +597,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-8050
-    void testOuterPropertyAccess4() {
+    void testOuterPropertyAccess5() {
         shouldFailWithMessages '''
             class Outer {
                 class Inner {
@@ -593,7 +611,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9598
-    void testOuterPropertyAccess5() {
+    void testOuterPropertyAccess6() {
         shouldFailWithMessages '''
             class Outer {
                 static class Inner {
@@ -608,7 +626,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         ''', 'The variable [p] is undeclared.'
     }
 
-    void testOuterPropertyAccess6() {
+    void testOuterPropertyAccess7() {
         shouldFailWithMessages '''
             class Outer {
                 static class Inner {
@@ -624,7 +642,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-7024
-    void testOuterPropertyAccess7() {
+    void testOuterPropertyAccess8() {
         assertScript '''
             class Outer {
                 static Map props = [bar: 10, baz: 20]
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index 1c6752a..462334c 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -573,13 +573,13 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
         ['I', 'def', 'var', 'Object'].each {
             assertScript """
                 interface I {
-                    def foo()
+                    def m()
                 }
                 class A implements I {
-                    def foo() { 'A' }
+                    def m() { 'A' }
                 }
                 class B implements I {
-                    def foo() { 'B' }
+                    def m() { 'B' }
                 }
 
                 $it x
@@ -590,34 +590,40 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
                 } else if (z) {
                     x = new B()
                 }
-                assert x.foo() == 'B'
+                assert x.m() == 'B'
             """
         }
     }
 
-    void testForLoopWithNewAssignment() {
+    void testForLoopWithAssignment() {
         shouldFailWithMessages '''
             def x = '123'
-            for (int i=0; i<5;i++) { x = new HashSet() }
+            for (int i = 0; i < -1; i += 1) {
+                x = new HashSet()
+            }
             x.toInteger()
-        ''', 'Cannot find matching method java.io.Serializable#toInteger()'
+        ''',
+        'Cannot find matching method java.io.Serializable#toInteger()'
     }
 
-    void testWhileLoopWithNewAssignment() {
+    void testWhileLoopWithAssignment() {
         shouldFailWithMessages '''
             def x = '123'
-            while (false) { x = new HashSet() }
+            while (false) {
+                x = new HashSet()
+            }
             x.toInteger()
-        ''', 'Cannot find matching method java.io.Serializable#toInteger()'
+        ''',
+        'Cannot find matching method java.io.Serializable#toInteger()'
     }
 
-    void testTernaryWithNewAssignment() {
+    void testTernaryInitWithAssignment() {
         shouldFailWithMessages '''
             def x = '123'
-            def cond = false
-            cond?(x = new HashSet()):3
+            def y = (false ? (x = new HashSet()) : 42)
             x.toInteger()
-        ''', 'Cannot find matching method java.io.Serializable#toInteger()'
+        ''',
+        'Cannot find matching method java.io.Serializable#toInteger()'
     }
 
     void testFloatSub() {