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 2020/06/23 00:57:10 UTC

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

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

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

commit 38d11b0e4733e49828a52e34ee017d777e860760
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
---
 .../groovy/classgen/VariableScopeVisitor.java      | 28 +++++--------
 .../stc/FieldsAndPropertiesSTCTest.groovy          | 47 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 17 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..5228987 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,7 @@ 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);
+        return findClassMember(cn.getSuperClass(), name);
     }
 
     private Variable findVariableDeclaration(final String name) {
@@ -225,9 +223,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,12 +238,12 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
                     }
                 }
                 // GROOVY-5961
-                if (!isAnonymous(classScope)) break;
+                if (!isAnonymous(scope.getClassScope())) break;
             }
             scope = scope.getParent();
         }
         if (variable == null) {
-            variable = new DynamicVariable(name, crossingStaticContext);
+            variable = new DynamicVariable(name, currentScope.isInStaticContext() || inSpecialConstructorCall);
         }
 
         boolean isClassVariable = (scope.isClassScope() && !scope.isReferencedLocalVariable(name))
@@ -460,14 +462,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/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 545cde5..5104ce9 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()
+        ''', 'The variable [p] is undeclared'
+    }
+
+    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 {