This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch GROOVY-9821 in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 78331f6b74d86fdd93fd202fcab44852eb367c5d Author: Eric Milles <[email protected]> AuthorDate: Thu Nov 19 15:29:06 2020 -0600 GROOVY-9821: STC: check "T" from "? extends T" for spread property --- .../transform/stc/StaticTypeCheckingSupport.java | 2 +- .../transform/stc/StaticTypeCheckingVisitor.java | 41 +++++++++++----------- .../groovy/transform/stc/GenericsSTCTest.groovy | 32 +++++++++++++++++ 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index 126afb0..5034dec 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -1900,7 +1900,7 @@ public abstract class StaticTypeCheckingSupport { return newBound; } - private static ClassNode getCombinedBoundType(final GenericsType genericsType) { + static ClassNode getCombinedBoundType(final GenericsType genericsType) { // TODO: this method should really return some kind of meta ClassNode // representing the combination of all bounds. The code here, just picks // something out to be able to proceed and is not actually correct 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 115988c..136f7fe 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -189,6 +189,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.constX; import static org.codehaus.groovy.ast.tools.GeneralUtils.getSetterName; import static org.codehaus.groovy.ast.tools.GeneralUtils.isOrImplements; import static org.codehaus.groovy.ast.tools.GeneralUtils.localVarX; +import static org.codehaus.groovy.ast.tools.GeneralUtils.propX; import static org.codehaus.groovy.ast.tools.GeneralUtils.thisPropX; import static org.codehaus.groovy.ast.tools.GeneralUtils.varX; import static org.codehaus.groovy.ast.tools.GenericsUtils.toGenericTypesString; @@ -246,6 +247,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findDG import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findSetters; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.findTargetVariable; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.fullyResolveType; +import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCombinedBoundType; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getCorrectedClassNode; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getGenericsWithoutArray; import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.getOperationName; @@ -899,12 +901,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } private void validateResourceInARM(final BinaryExpression expression, final ClassNode lType) { - if (expression instanceof DeclarationExpression) { - if (TryCatchStatement.isResource(expression)) { - if (!lType.implementsInterface(AUTOCLOSEABLE_TYPE)) { - addError("Resource[" + lType.getName() + "] in ARM should be of type AutoCloseable", expression); - } - } + if (expression instanceof DeclarationExpression + && TryCatchStatement.isResource(expression) + && !isOrImplements(lType, AUTOCLOSEABLE_TYPE)) { + addError("Resource[" + lType.getName() + "] in ARM should be of type AutoCloseable", expression); } } @@ -1660,19 +1660,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { } private ClassNode getTypeForSpreadExpression(final ClassNode testClass, final ClassNode objectExpressionType, final PropertyExpression pexp) { - if (!pexp.isSpreadSafe()) return null; - MethodCallExpression mce = callX(varX("_", testClass), "iterator", ArgumentListExpression.EMPTY_ARGUMENTS); - mce.setImplicitThis(false); - mce.visit(this); - ClassNode callType = getType(mce); - if (!implementsInterfaceOrIsSubclassOf(callType, Iterator_TYPE)) return null; - GenericsType[] types = callType.getGenericsTypes(); - ClassNode contentType = OBJECT_TYPE; - if (types != null && types.length == 1) contentType = types[0].getType(); - PropertyExpression subExp = new PropertyExpression(varX("{}", contentType), pexp.getPropertyAsString()); - AtomicReference<ClassNode> result = new AtomicReference<>(); - if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) { - return extension.buildListType(result.get()); + if (pexp.isSpreadSafe()) { + MethodCallExpression mce = callX(varX("_", testClass), "iterator"); + mce.setImplicitThis(false); + mce.visit(this); + ClassNode iteratorType = getType(mce); + if (isOrImplements(iteratorType, Iterator_TYPE)) { + GenericsType[] gts = iteratorType.getGenericsTypes(); + ClassNode itemType = (gts != null && gts.length == 1 ? getCombinedBoundType(gts[0]) : OBJECT_TYPE); + + AtomicReference<ClassNode> propertyType = new AtomicReference<>(); + if (existsProperty(propX(varX("{}", itemType), pexp.getProperty()), true, new PropertyLookupVisitor(propertyType))) { + return extension.buildListType(propertyType.get()); + } + } } return null; } @@ -2228,7 +2229,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { private boolean looksLikeNamedArgConstructor(final ClassNode receiver, final ClassNode[] argumentTypes) { if (argumentTypes.length == 1 || argumentTypes.length == 2 && argumentTypes[0].equals(receiver.getOuterClass())) { - return argumentTypes[argumentTypes.length - 1].implementsInterface(MAP_TYPE); + return isOrImplements(argumentTypes[argumentTypes.length - 1], MAP_TYPE); } return false; } diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy index 345252b..6cc3a86 100644 --- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy +++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy @@ -2232,6 +2232,38 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase { } null ''' + + // GROOVY-9821 + config.with { + targetDirectory = File.createTempDir() + jointCompilationOptions = [memStub: true] + } + File parentDir = File.createTempDir() + try { + def a = new File(parentDir, 'Types.java') + a.write ''' + interface A { + java.util.Collection<? extends B> getBees(); + } + interface B { + Object getC(); + } + ''' + def b = new File(parentDir, 'Script.groovy') + b.write ''' + def test(A a) { + a.bees*.c + } + ''' + + def loader = new GroovyClassLoader(this.class.classLoader) + def cu = new JavaAwareCompilationUnit(config, loader) + cu.addSources(a, b) + cu.compile() + } finally { + parentDir.deleteDir() + config.targetDirectory.deleteDir() + } } // GROOVY-7804
