This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY_2_5_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 7910206f94b07b202003e534cabd937edc2d23a5 Author: Eric Milles <[email protected]> AuthorDate: Thu Aug 25 13:19:19 2022 -0500 GROOVY-8050, GROOVY-10414: STC: non-static outer class property setter --- .../transform/stc/StaticTypeCheckingVisitor.java | 71 ++++++++++------------ .../stc/FieldsAndPropertiesSTCTest.groovy | 2 +- 2 files changed, 34 insertions(+), 39 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 220cb0e053..954d8c06ba 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -4666,13 +4666,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { protected List<MethodNode> findMethod(ClassNode receiver, final String name, final ClassNode... args) { if (isPrimitiveType(receiver)) receiver = getWrapper(receiver); + List<MethodNode> methods; - if (!receiver.isInterface() && "<init>".equals(name)) { + if ("<init>".equals(name) && !receiver.isInterface()) { methods = addGeneratedMethods(receiver, new ArrayList<MethodNode>(receiver.getDeclaredConstructors())); if (methods.isEmpty()) { MethodNode node = new ConstructorNode(Opcodes.ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT); node.setDeclaringClass(receiver); - methods = Collections.singletonList(node); + methods.add(node); if (receiver.isArray()) { // No need to check the arguments against an array constructor: it just needs to exist. The array is // created through coercion or by specifying its dimension(s), anyway, and would not match an @@ -4682,16 +4683,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } } else { methods = findMethodsWithGenerated(receiver, name); - // TODO: investigate the trait exclusion a bit further, needed otherwise - // CallMethodOfTraitInsideClosureAndClosureParamTypeInference fails saying - // not static method can't be called from a static context - if (typeCheckingContext.getEnclosingClosure() == null || (receiver instanceof InnerClassNode && !receiver.getName().endsWith("$Trait$Helper"))) { - // not in a closure or within an inner class - ClassNode parent = receiver; - while (parent instanceof InnerClassNode && !parent.isStaticClass()) { - parent = parent.getOuterClass(); - methods.addAll(findMethodsWithGenerated(parent, name)); - } + if (!receiver.isStaticClass() && receiver.getOuterClass() != null + && !receiver.getName().endsWith("$Trait$Helper") // GROOVY-7242 + && typeCheckingContext.getEnclosingClassNodes().contains(receiver)) { + ClassNode outer = receiver.getOuterClass(); + do { methods.addAll(findMethodsWithGenerated(outer, name)); + } while (!outer.isStaticClass() && (outer = outer.getOuterClass()) != null); } if (methods.isEmpty()) { addArrayMethods(methods, receiver, name, args); @@ -4703,22 +4700,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { pname = extractPropertyNameFromMethodName("is", name); } if (pname != null) { - // we don't use property exists there because findMethod is called on super clases recursively - PropertyNode property = null; - ClassNode curNode = receiver; - while (property == null && curNode != null) { - property = curNode.getProperty(pname); - ClassNode svCur = curNode; - while (property == null && svCur instanceof InnerClassNode && !svCur.isStaticClass()) { - svCur = svCur.getOuterClass(); - property = svCur.getProperty(pname); - if (property != null) { - receiver = svCur; - break; - } - } - curNode = curNode.getSuperClass(); - } + PropertyNode property = findProperty(receiver, pname); if (property != null) { int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0); MethodNode node = new MethodNode(name, mods, property.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, GENERATED_EMPTY_STATEMENT); @@ -4730,13 +4712,8 @@ 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(); - } - if (property != null) { + PropertyNode property = findProperty(receiver, pname); + if (property != null && !Modifier.isFinal(property.getModifiers())) { ClassNode type = property.getOriginType(); if (implementsInterfaceOrIsSubclassOf(wrapTypeIfNecessary(args[0]), wrapTypeIfNecessary(type))) { int mods = Opcodes.ACC_PUBLIC | (property.isStatic() ? Opcodes.ACC_STATIC : 0); @@ -4765,10 +4742,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } } - if (isClassClassNodeWrappingConcreteType(receiver)) { - chosen = findMethod(receiver.getGenericsTypes()[0].getType(), name, args); - if (!chosen.isEmpty()) return chosen; + if (isClassClassNodeWrappingConcreteType(receiver)) { // GROOVY-6802, GROOVY-6803 + List<MethodNode> result = findMethod(receiver.getGenericsTypes()[0].getType(), name, args); + if (!result.isEmpty()) return result; } + if (receiver.equals(GSTRING_TYPE)) { return findMethod(STRING_TYPE, name, args); } @@ -4779,6 +4757,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; + } + private List<MethodNode> filterMethodsByVisibility(List<MethodNode> methods) { if (!asBoolean(methods)) { return EMPTY_METHODNODE_LIST; diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy index 09c0b05b42..f0688df44e 100644 --- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy +++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy @@ -576,7 +576,7 @@ class FieldsAndPropertiesSTCTest extends StaticTypeCheckingTestCase { ''' } - @NotYetImplemented // GROOVY-10414 + // GROOVY-10414 void testOuterPropertyAccess3() { assertScript ''' class Outer {
