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 21:09:38 UTC

[groovy] branch master updated: GROOVY-10414: STC: set non-static outer class property via setter method

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 436adf2  GROOVY-10414: STC: set non-static outer class property via setter method
436adf2 is described below

commit 436adf29e24a0ea19c9168b012d7b2c728d64dcb
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
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 42 +++++++++++-----------
 src/test/gls/innerClass/InnerClassTest.groovy      | 13 +++++++
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 28 ++++++++++++---
 .../groovy/transform/stc/STCAssignmentTest.groovy  | 34 ++++++++++--------
 4 files changed, 77 insertions(+), 40 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 04e3ee6..3f0af1e 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4792,21 +4792,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
                 PropertyNode property = null;
                 if (pname != null) {
-                    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);
-                        }
-                    }
-                } else { // look for property via getGetterName() for non-canonical case
-                    out:
+                    property = findProperty(receiver, pname);
+                } else {
+                    out: // look for property via getGetterName() for non-canonical case
                     for (ClassNode cn = receiver; cn != null; cn = cn.getSuperClass()) {
                         for (PropertyNode pn : cn.getProperties()) {
                             if (name.equals(pn.getGetterName())) {
@@ -4826,12 +4814,7 @@ 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();
-                    }
+                    PropertyNode property = findProperty(receiver, pname);
                     if (property != null && !Modifier.isFinal(property.getModifiers())) {
                         ClassNode type = property.getOriginType();
                         if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) {
@@ -4876,6 +4859,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/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index b5d5d9d..9469812 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -751,6 +751,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 393d67d..3a8b66b 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -662,8 +662,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 {
@@ -677,7 +695,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-8050
-    void testOuterPropertyAccess4() {
+    void testOuterPropertyAccess5() {
         shouldFailWithMessages '''
             class Outer {
                 class Inner {
@@ -691,7 +709,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9598
-    void testOuterPropertyAccess5() {
+    void testOuterPropertyAccess6() {
         shouldFailWithMessages '''
             class Outer {
                 static class Inner {
@@ -707,7 +725,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         'The variable [p] is undeclared.'
     }
 
-    void testOuterPropertyAccess6() {
+    void testOuterPropertyAccess7() {
         shouldFailWithMessages '''
             class Outer {
                 static class Inner {
@@ -724,7 +742,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 499af6e..adc5d75 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -709,13 +709,13 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
         for (it in ['I', 'def', 'var', 'Object']) {
             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
@@ -726,34 +726,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() {