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 {