diff --git a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java index 94ef5e8afc..fa67b28a3f 100644 --- a/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java +++ b/base-test/org.eclipse.jdt.groovy.core.tests.compiler/src/org/eclipse/jdt/groovy/core/tests/xform/TypeCheckedTests.java @@ -1861,6 +1861,29 @@ public void testTypeChecked8917a() { runConformTest(sources, "[null]"); } + @Test + public void testTypeChecked8965() { + //@formatter:off + String[] sources = { + "Main.groovy", + "@groovy.transform.TypeChecked\n" + + "def test(o) {\n" + + " if (o instanceof Integer || o instanceof Double)\n" + + " o.floatValue()\n" + // CCE: Double cannot be cast to Integer + "}\n" + + "print test(1.2d)\n", + }; + //@formatter:on + + runNegativeTest(sources, + "----------\n" + + "1. ERROR in Main.groovy (at line 4)\n" + + "\to.floatValue()\n" + + "\t^^^^^^^^^^^^^^\n" + + "Groovy:[Static type checking] - Cannot find matching method java.lang.Object#floatValue(). Please check if the declared type is correct and if the method exists.\n" + + "----------\n"); + } + @Test public void testTypeChecked8974() { //@formatter:off @@ -5930,4 +5953,53 @@ public void testTypeChecked10667() { runConformTest(sources, "foo"); } + + @Test + public void testTypeChecked10668() { + //@formatter:off + String[] sources = { + "Main.groovy", + "@groovy.transform.TypeChecked\n" + + "def toArray(value) {\n" + + " def result\n" + + " if (value instanceof List)\n" + + " result = value.toArray()\n" + + " else if (value instanceof String || value instanceof GString)\n" + + " result = value.toString().split(',')\n" + + " else\n" + + " throw new Exception('not supported')\n" + + " return result\n" + + "}\n" + + "print(toArray([1,2,3]))\n" + + "print(toArray('1,2,3'))\n", + }; + //@formatter:on + + runConformTest(sources, "[1, 2, 3][1, 2, 3]"); + } + + @Test + public void testTypeChecked10673() { + //@formatter:off + String[] sources = { + "Main.groovy", + "import java.util.function.Consumer\n" + + "void proc(Consumer action) {\n" + + " action.accept(1.234)\n" + + "}\n" + + "@groovy.transform.TypeChecked\n" + + "void test() {\n" + + " proc { n ->\n" + + " def c = {\n" + + " print n.intValue()\n" + + " }\n" + + " c()\n" + + " }\n" + + "}\n" + + "test()\n", + }; + //@formatter:on + + runConformTest(sources, "1"); + } } diff --git a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index ca3603dd94..a65d4a08ff 100644 --- a/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy25/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -5879,9 +5879,8 @@ protected ClassNode getType(final ASTNode exp) { type = typeCheckingContext.controlStructureVariables.get(parameter); } // now check for closure override - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) { - type = getTypeFromClosureArguments(parameter, enclosingClosure); + if (type == null && temporaryTypesForExpression == null) { + type = getTypeFromClosureArguments(parameter); } if (type != null) { storeType(vexp, type); @@ -5970,25 +5969,26 @@ protected ClassNode getType(final ASTNode exp) { return ((Expression) exp).getType(); } - private ClassNode getTypeFromClosureArguments(Parameter parameter, TypeCheckingContext.EnclosingClosure enclosingClosure) { - ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); - ClassNode[] closureParamTypes = (ClassNode[]) closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS); - if (closureParamTypes == null) return null; - final Parameter[] parameters = closureExpression.getParameters(); - String name = parameter.getName(); - - if (parameters != null) { - if (parameters.length == 0) { - return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null; - } - - for (int index = 0; index < parameters.length; index++) { - if (name.equals(parameters[index].getName())) { - return closureParamTypes.length > index ? closureParamTypes[index] : null; + private ClassNode getTypeFromClosureArguments(final Parameter parameter) { + for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) { + ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); + ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS); + if (closureParamTypes != null) { + Parameter[] parameters = closureExpression.getParameters(); + if (parameters != null) { + final int n = parameters.length; + String parameterName = parameter.getName(); + if (n == 0 && parameterName.equals("it")) { + return closureParamTypes.length > 0 ? closureParamTypes[0] : null; + } + for (int i = 0; i < n; i += 1) { + if (parameterName.equals(parameters[i].getName())) { + return closureParamTypes.length > i ? closureParamTypes[i] : null; + } + } } } } - return null; } @@ -7021,8 +7021,7 @@ private class ParameterVariableExpression extends VariableExpression { if (inferredType == null) { inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure if (inferredType == null) { - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure); + inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion } setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); } diff --git a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 8eaeb381ff..36cd5e0784 100644 --- a/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy30/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -757,10 +757,9 @@ public void visitBinaryExpression(final BinaryExpression expression) { typeCheckingContext.pushEnclosingBinaryExpression(expression); try { int op = expression.getOperation().getType(); - // GRECLIPSE add - if (op == LOGICAL_OR) { + // GRECLIPSE add -- GROOVY-7971, GROOVY-8965 + if (op == LOGICAL_OR) typeCheckingContext.pushTemporaryTypeInfo(); - } // GRECLIPSE end Expression leftExpression = expression.getLeftExpression(); Expression rightExpression = expression.getRightExpression(); @@ -4192,19 +4191,6 @@ protected List> makeOwnerList(final Expression objectExpression Receiver.make(typeCheckingContext.getEnclosingClassNode())); addReceivers(owners, enclosingClass, typeCheckingContext.delegationMetadata.getParent(), "owner."); } else { - if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { // GROOVY-10180, et al. - List instanceofTypes = getTemporaryTypesForExpression(objectExpression); - if (instanceofTypes != null && !instanceofTypes.isEmpty()) { - ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0) - : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY)); - owners.add(Receiver.make(instanceofType)); - } - } - if (typeCheckingContext.lastImplicitItType != null - && objectExpression instanceof VariableExpression - && ((Variable) objectExpression).getName().equals("it")) { - owners.add(Receiver.make(typeCheckingContext.lastImplicitItType)); - } if (isClassClassNodeWrappingConcreteType(receiver)) { ClassNode staticType = receiver.getGenericsTypes()[0].getType(); owners.add(Receiver.make(staticType)); // Type from Class @@ -4218,6 +4204,19 @@ protected List> makeOwnerList(final Expression objectExpression owners.add(Receiver.make(OBJECT_TYPE)); } } + if (typeCheckingContext.lastImplicitItType != null + && objectExpression instanceof VariableExpression + && ((Variable) objectExpression).getName().equals("it")) { + owners.add(Receiver.make(typeCheckingContext.lastImplicitItType)); + } + if (!typeCheckingContext.temporaryIfBranchTypeInformation.isEmpty()) { + List instanceofTypes = getTemporaryTypesForExpression(objectExpression); + if (instanceofTypes != null && !instanceofTypes.isEmpty()) { + ClassNode instanceofType = instanceofTypes.size() == 1 ? instanceofTypes.get(0) + : new UnionTypeClassNode(instanceofTypes.toArray(ClassNode.EMPTY_ARRAY)); + owners.add(Receiver.make(instanceofType)); + } + } } return owners; } @@ -5509,9 +5508,8 @@ protected ClassNode getType(final ASTNode exp) { type = typeCheckingContext.controlStructureVariables.get(parameter); } // now check for closure override - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) { - type = getTypeFromClosureArguments(parameter, enclosingClosure); + if (type == null && temporaryTypesForExpression == null) { + type = getTypeFromClosureArguments(parameter); } if (type != null) { storeType(vexp, type); @@ -5601,25 +5599,26 @@ protected ClassNode getType(final ASTNode exp) { return ((Expression) exp).getType(); } - private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) { - ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); - ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS); - if (closureParamTypes == null) return null; - Parameter[] parameters = closureExpression.getParameters(); - String name = parameter.getName(); - - if (parameters != null) { - if (parameters.length == 0) { - return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null; - } - - for (int index = 0; index < parameters.length; index++) { - if (name.equals(parameters[index].getName())) { - return closureParamTypes.length > index ? closureParamTypes[index] : null; + private ClassNode getTypeFromClosureArguments(final Parameter parameter) { + for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) { + ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); + ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS); + if (closureParamTypes != null) { + Parameter[] parameters = closureExpression.getParameters(); + if (parameters != null) { + final int n = parameters.length; + String parameterName = parameter.getName(); + if (n == 0 && parameterName.equals("it")) { + return closureParamTypes.length > 0 ? closureParamTypes[0] : null; + } + for (int i = 0; i < n; i += 1) { + if (parameterName.equals(parameters[i].getName())) { + return closureParamTypes.length > i ? closureParamTypes[i] : null; + } + } } } } - return null; } @@ -6664,8 +6663,7 @@ private class ParameterVariableExpression extends VariableExpression { if (inferredType == null) { inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure if (inferredType == null) { - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure); + inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion } setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // to parameter } diff --git a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java index 1735345b2d..d111568c29 100644 --- a/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +++ b/base/org.codehaus.groovy40/src/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java @@ -5078,9 +5078,8 @@ protected ClassNode getType(final ASTNode node) { type = typeCheckingContext.controlStructureVariables.get(parameter); } // now check for closure override - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) { - type = getTypeFromClosureArguments(parameter, enclosingClosure); + if (type == null && temporaryTypesForExpression == null) { + type = getTypeFromClosureArguments(parameter); } if (type != null) { storeType(vexp, type); @@ -5159,25 +5158,26 @@ protected ClassNode getType(final ASTNode node) { return ((Expression) node).getType(); } - private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) { - ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); - ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS); - if (closureParamTypes == null) return null; - Parameter[] parameters = closureExpression.getParameters(); - String name = parameter.getName(); - - if (parameters != null) { - if (parameters.length == 0) { - return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null; - } - - for (int index = 0; index < parameters.length; index++) { - if (name.equals(parameters[index].getName())) { - return closureParamTypes.length > index ? closureParamTypes[index] : null; + private ClassNode getTypeFromClosureArguments(final Parameter parameter) { + for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) { + ClosureExpression closureExpression = enclosingClosure.getClosureExpression(); + ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS); + if (closureParamTypes != null) { + Parameter[] parameters = closureExpression.getParameters(); + if (parameters != null) { + final int n = parameters.length; + String parameterName = parameter.getName(); + if (n == 0 && parameterName.equals("it")) { + return closureParamTypes.length > 0 ? closureParamTypes[0] : null; + } + for (int i = 0; i < n; i += 1) { + if (parameterName.equals(parameters[i].getName())) { + return closureParamTypes.length > i ? closureParamTypes[i] : null; + } + } } } } - return null; } @@ -6009,8 +6009,7 @@ private class ParameterVariableExpression extends VariableExpression { if (inferredType == null) { inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure if (inferredType == null) { - TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); - if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure); + inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion } setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // GROOVY-10651 }