You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2020/06/24 00:25:10 UTC

[groovy] 03/03: GROOVY-9598: account for static modifier when checking for outer members

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

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

commit fc5de1cf3ce6fc703b81ecee76357ceea01091bb
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Jun 22 19:56:48 2020 -0500

    GROOVY-9598: account for static modifier when checking for outer members
    
    (cherry picked from commit a960547e9a560d5d7216912c5fe2e1ea7116d20e)
---
 .../groovy/classgen/VariableScopeVisitor.java      | 31 +++++++-------
 src/test/gls/innerClass/InnerClassTest.groovy      | 38 +++++++++++++++++
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 47 ++++++++++++++++++++++
 3 files changed, 100 insertions(+), 16 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index 12edb39..ef22321 100644
--- a/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -56,6 +56,7 @@ import java.util.LinkedList;
 import java.util.function.BiConsumer;
 
 import static java.lang.reflect.Modifier.isFinal;
+import static java.lang.reflect.Modifier.isStatic;
 import static org.apache.groovy.ast.tools.MethodNodeUtils.getPropertyName;
 
 /**
@@ -191,10 +192,12 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
             if (pn.getName().equals(name)) return pn;
         }
 
-        Variable ret = findClassMember(cn.getSuperClass(), name);
-        if (ret != null) return ret;
-        if (isAnonymous(cn)) return null;
-        return findClassMember(cn.getOuterClass(), name);
+        for (ClassNode face : cn.getInterfaces()) {
+            FieldNode fn = face.getDeclaredField(name);
+            if (fn != null) return fn;
+        }
+
+        return findClassMember(cn.getSuperClass(), name);
     }
 
     private Variable findVariableDeclaration(final String name) {
@@ -225,9 +228,13 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
                 break;
             }
 
-            ClassNode classScope = scope.getClassScope();
-            if (classScope != null) {
-                Variable member = findClassMember(classScope, name);
+            ClassNode node = scope.getClassScope();
+            if (node != null) {
+                Variable member = findClassMember(node, name);
+                while (member == null && node.getOuterClass() != null && !isAnonymous(node)) {
+                    crossingStaticContext = (crossingStaticContext || isStatic(node.getModifiers()));
+                    member = findClassMember((node = node.getOuterClass()), name);
+                }
                 if (member != null) {
                     boolean staticScope = (crossingStaticContext || inSpecialConstructorCall), staticMember = member.isInStaticContext();
                     // prevent a static context (e.g. a static method) from accessing a non-static variable (e.g. a non-static field)
@@ -236,7 +243,7 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
                     }
                 }
                 // GROOVY-5961
-                if (!isAnonymous(classScope)) break;
+                if (!isAnonymous(scope.getClassScope())) break;
             }
             scope = scope.getParent();
         }
@@ -460,14 +467,6 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
         popState();
     }
 
-    /**
-     * Sets the current class node context.
-     */
-    public void prepareVisit(ClassNode node) {
-        currentClass = node;
-        currentScope.setClassScope(node);
-    }
-
     @Override
     public void visitConstructorCallExpression(final ConstructorCallExpression expression) {
         boolean oldInSpecialCtorFlag = inSpecialConstructorCall;
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index e82496d..3f4393e 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -600,6 +600,26 @@ final class InnerClassTest {
     }
 
     @Test
+    void testUsageOfOuterField12() {
+        def err = shouldFail '''
+            class C {
+                int count
+                static def m() {
+                    new LinkedList() {
+                        def get(int i) {
+                            count += 1
+                            super.get(i)
+                        }
+                    }
+                }
+            }
+            C.m()
+        '''
+
+        assert err =~ /Apparent variable 'count' was found in a static scope but doesn't refer to a local variable, static field or class./
+    }
+
+    @Test
     void testUsageOfOuterSuperField() {
         assertScript '''
             class InnerBase {
@@ -635,6 +655,24 @@ final class InnerClassTest {
     }
 
     @Test
+    void testUsageOfOuterSuperField2() {
+        assertScript '''
+            interface I {
+                String CONST = 'value'
+            }
+            class A implements I {
+                static class B {
+                    def test() {
+                        CONST
+                    }
+                }
+            }
+            def x = new A.B().test()
+            assert x == 'value'
+        '''
+    }
+
+    @Test
     void testUsageOfOuterField_WrongCallToSuper() {
         shouldFail '''
             class Outer {
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 545cde5..3b39eff 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -387,6 +387,53 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    void testOuterPropertyAccess1() {
+        assertScript '''
+            class Outer {
+                class Inner {
+                    def m() {
+                        p
+                    }
+                }
+                def p = 1
+            }
+            def i = new Outer.Inner(new Outer())
+            def x = i.m()
+            assert x == 1
+        '''
+    }
+
+    // GROOVY-9598
+    void testOuterPropertyAccess2() {
+        shouldFailWithMessages '''
+            class Outer {
+                static class Inner {
+                    def m() {
+                        p
+                    }
+                }
+                def p = 1
+            }
+            def i = new Outer.Inner()
+            def x = i.m()
+        ''', "Apparent variable 'p' was found in a static scope but doesn't refer to a local variable, static field or class."
+    }
+
+    void testOuterPropertyAccess3() {
+        shouldFailWithMessages '''
+            class Outer {
+                static class Inner {
+                    def m() {
+                        this.p
+                    }
+                }
+                def p = 1
+            }
+            def i = new Outer.Inner()
+            def x = i.m()
+        ''', 'No such property: p for class: Outer$Inner'
+    }
+
     void testPrivateFieldAccessInClosure() {
         assertScript '''
             class A {