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() {