update checkstyle for latest build one of the rules we previously used is no longer included
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/13522f88 Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/13522f88 Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/13522f88 Branch: refs/heads/GROOVY_2_5_X Commit: 13522f8871d768e1d65c522325bbc47a88d77a2e Parents: dafabb2 Author: paulk <[email protected]> Authored: Tue Dec 19 20:25:08 2017 +1000 Committer: paulk <[email protected]> Committed: Tue Dec 19 20:25:08 2017 +1000 ---------------------------------------------------------------------- Groovy7037.patch | 71 ++++ Groovy8295.patch | 61 +++ config/checkstyle/checkstyle.xml | 3 +- groovy8260Extras.patch | 388 +++++++++++++++++++ groovy8260c.patch | 188 +++++++++ ivy_snapshot.patch | 24 ++ pr502.patch | 118 ++++++ pr507.patch | 25 ++ pr555.patch | 312 +++++++++++++++ pr555a.patch | 94 +++++ pr565.patch | 168 ++++++++ pr584.patch | 57 +++ pr597.patch | 26 ++ pr603.patch | 102 +++++ pr607.patch | 60 +++ pr617.patch | 293 ++++++++++++++ pr622.patch | 237 +++++++++++ pr625.patch | 65 ++++ src/main/groovy/transform/MapArguments.java.bak | 33 ++ .../MapArgumentsASTTransformation.java.bak | 165 ++++++++ .../stubgenerator/Groovy8224Bug.groovy.bak | 53 +++ 21 files changed, 2542 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/Groovy7037.patch ---------------------------------------------------------------------- diff --git a/Groovy7037.patch b/Groovy7037.patch new file mode 100644 index 0000000..2417534 --- /dev/null +++ b/Groovy7037.patch @@ -0,0 +1,71 @@ +Index: src/test/groovy/bugs/Groovy7037Bug.groovy +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/groovy/bugs/Groovy7037Bug.groovy (revision ) ++++ src/test/groovy/bugs/Groovy7037Bug.groovy (revision ) +@@ -0,0 +1,40 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one ++ * or more contributor license agreements. See the NOTICE file ++ * distributed with this work for additional information ++ * regarding copyright ownership. The ASF licenses this file ++ * to you under the Apache License, Version 2.0 (the ++ * "License"); you may not use this file except in compliance ++ * with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, ++ * software distributed under the License is distributed on an ++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ++ * KIND, either express or implied. See the License for the ++ * specific language governing permissions and limitations ++ * under the License. ++ */ ++package groovy.bugs ++ ++class Groovy7037Bug extends GroovyTestCase { ++ void testGetAtShouldWorkWithVarArgs() { ++ assertScript ''' ++ class Test { ++ def getAt(Integer x, Long y) { "A: $x $y" } ++ def getAt(Integer x, Long... y) { "B: $x ${y.join(' ')}" } ++ } ++ ++ def t = new Test() ++ assert t[2, 4L] == 'A: 2 4' ++ def items = [2, 4L] ++ assert t[*items] == 'A: 2 4' ++ assert t.getAt(2, 4L) == 'A: 2 4' ++ assert t[2] == 'B: 2 ' ++ assert t.getAt(2) == 'B: 2 ' ++ assert t.getAt(2, 4L, 5L) == 'B: 2 4 5' ++ assert t[2, 4L, 5L] == 'B: 2 4 5' ++ ''' ++ } ++} +Index: src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java (date 1472272655000) ++++ src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java (revision ) +@@ -242,6 +242,15 @@ + if (controller.getCompileStack().isLHS()) { + evaluateEqual(expression, false); + } else { ++ Expression arguments = expression.getRightExpression(); ++ if (arguments instanceof ListExpression) { ++ Expression newArgs = new ArgumentListExpression(((ListExpression) arguments).getExpressions()); ++ newArgs.setSourcePosition(arguments); ++ controller.getInvocationWriter().makeCall( ++ expression, expression.getLeftExpression(), new ConstantExpression("getAt"), ++ newArgs, InvocationWriter.invokeMethod, false, false, false); ++ break; ++ } + evaluateBinaryExpression("getAt", expression); + } + break; http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/Groovy8295.patch ---------------------------------------------------------------------- diff --git a/Groovy8295.patch b/Groovy8295.patch new file mode 100644 index 0000000..4545691 --- /dev/null +++ b/Groovy8295.patch @@ -0,0 +1,61 @@ +--- C:\Users\U0076777\Groovyc-2.4.12.txt 2017-08-29 17:54:18.050000000 -0500 ++++ C:\Users\U0076777\Groovyc-edited.txt 2017-08-29 17:55:43.727000000 -0500 +@@ -1006,7 +1006,7 @@ + commandLineList.add(javaHome + separator + "bin" + separator + "java"); + } + commandLineList.add("-classpath"); +- commandLineList.add(classpath.toString()); ++ commandLineList.add(classpath.toString().replace(getProject().getBaseDir().getAbsolutePath(), ".")); + + final String fileEncodingProp = System.getProperty("file.encoding"); + if ((fileEncodingProp != null) && !fileEncodingProp.equals("")) { +@@ -1036,7 +1036,7 @@ + + private void doNormalCommandLineList(List<String> commandLineList, List<String> jointOptions, Path classpath) { + commandLineList.add("--classpath"); +- commandLineList.add(classpath.toString()); ++ commandLineList.add(classpath.toString().replace(getProject().getBaseDir().getAbsolutePath(), ".")); + if (jointCompilation) { + commandLineList.add("-j"); + commandLineList.addAll(jointOptions); +@@ -1100,18 +1100,12 @@ + } + + private String[] makeCommandLine(List<String> commandLineList) { +- final String[] commandLine = new String[commandLineList.size()]; +- for (int i = 0; i < commandLine.length; ++i) { +- commandLine[i] = commandLineList.get(i); +- } +- log.verbose("Compilation arguments:"); +- log.verbose(DefaultGroovyMethods.join(commandLine, "\n")); +- return commandLine; ++ log.verbose("Compilation arguments:\n" + DefaultGroovyMethods.join(commandLineList, "\n")); ++ return commandLineList.toArray(new String[commandLineList.size()]); + } + + private void runForked(String[] commandLine) { +- // use the main method in FileSystemCompiler +- final Execute executor = new Execute(); // new LogStreamHandler ( attributes , Project.MSG_INFO , Project.MSG_WARN ) ) ; ++ final Execute executor = new Execute(); + executor.setAntRun(getProject()); + executor.setWorkingDirectory(getProject().getBaseDir()); + executor.setCommandline(commandLine); +@@ -1280,12 +1274,12 @@ + * may not exist in the classpath yet + */ + if (!found && new File(cpEntry).exists()) { +- try { +- antLoader.addPathElement(cpEntry); +- } +- catch(BuildException e) { +- log.warn("The classpath entry " + cpEntry + " is not a valid Java resource"); +- } ++ try { ++ antLoader.addPathElement(cpEntry); ++ } ++ catch(BuildException e) { ++ log.warn("The classpath entry " + cpEntry + " is not a valid Java resource"); ++ } + } + } + } http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/config/checkstyle/checkstyle.xml ---------------------------------------------------------------------- diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 34aebe1..339228e 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -154,7 +154,8 @@ <module name="UpperEll"/> <!-- off for now - to allow parentheses which add clarity --> <!--<module name="UnnecessaryParentheses"/>--> - <module name="JUnitTestCase"/> + <!-- removed in recent versions of checkstyle --> + <!--<module name="JUnitTestCase"/>--> <module name="FinalClass"/> <!-- good to have but pollutes coverage --> <!--<module name="HideUtilityClassConstructor"/>--> http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/groovy8260Extras.patch ---------------------------------------------------------------------- diff --git a/groovy8260Extras.patch b/groovy8260Extras.patch new file mode 100644 index 0000000..24f20e6 --- /dev/null +++ b/groovy8260Extras.patch @@ -0,0 +1,388 @@ +Index: src/test/groovy/transform/stc/MiscSTCTest.groovy +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/groovy/transform/stc/MiscSTCTest.groovy (revision 456aa4dd37dbcebcfb263db2914b2d84246bc30f) ++++ src/test/groovy/transform/stc/MiscSTCTest.groovy (revision ) +@@ -275,5 +275,64 @@ + public static class MiscSTCTestSupport { + static def foo() { '123' } + } ++ ++ void testTernaryParam() { ++ assertScript ''' ++ Date ternaryParam(Object input) { ++ input instanceof Date ? input : null ++ } ++ def d = new Date() ++ assert ternaryParam(42) == null ++ assert ternaryParam('foo') == null ++ assert ternaryParam(d) == d ++ ''' ++ } ++ ++ void testTernaryLocalVar() { ++ assertScript ''' ++ Date ternaryLocalVar(Object input) { ++ Object copy = input ++ copy instanceof Date ? copy : null ++ } ++ def d = new Date() ++ assert ternaryLocalVar(42) == null ++ assert ternaryLocalVar('foo') == null ++ assert ternaryLocalVar(d) == d ++ ''' ++ } ++ ++ void testIfThenElseParam() { ++ assertScript ''' ++ Date ifThenElseParam(Object input) { ++ if (input instanceof Date) { ++ input ++ } else { ++ null ++ } ++ } ++ def d = new Date() ++ assert ifThenElseParam(42) == null ++ assert ifThenElseParam('foo') == null ++ assert ifThenElseParam(d) == d ++ ''' ++ } ++ ++ void testIfThenElseLocalVar() { ++ assertScript ''' ++ Date ifThenElseLocalVar(Object input) { ++ Date result ++ if (input instanceof Date) { ++ result = input ++ } else { ++ result = null ++ } ++ result ++ } ++ def d = new Date() ++ assert ifThenElseLocalVar(42) == null ++ assert ifThenElseLocalVar('foo') == null ++ assert ifThenElseLocalVar(d) == d ++ ''' ++ } + } + +Index: src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java (revision 456aa4dd37dbcebcfb263db2914b2d84246bc30f) ++++ src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java (revision ) +@@ -112,7 +112,6 @@ + import static org.codehaus.groovy.syntax.Types.COMPARE_EQUAL; + import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL; + import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_IN; +-import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_INSTANCEOF; + import static org.codehaus.groovy.syntax.Types.COMPARE_TO; + import static org.codehaus.groovy.syntax.Types.DIVIDE; + import static org.codehaus.groovy.syntax.Types.DIVIDE_EQUAL; +@@ -483,7 +482,20 @@ + } + } + +- if (! (vexp.getAccessedVariable() instanceof DynamicVariable)) return; ++ if (! (vexp.getAccessedVariable() instanceof DynamicVariable)) { ++ //if (vexp.getAccessedVariable() instanceof Parameter) { ++ ClassNode inferredTypeFromTempInfo = getInferredTypeFromTempInfo(vexp, null); ++ if (inferredTypeFromTempInfo != null) { ++ storeType(vexp, inferredTypeFromTempInfo); ++ } ++// } else if (vexp.getAccessedVariable() instanceof VariableExpression) { ++// ClassNode inferredTypeFromTempInfo = getInferredTypeFromTempInfo((Expression) vexp.getAccessedVariable(), null); ++// if (inferredTypeFromTempInfo != null) { ++// storeType((Expression) vexp.getAccessedVariable(), inferredTypeFromTempInfo); ++// } ++// } ++ return; ++ } + + // a dynamic variable is either an undeclared variable + // or a member of a class used in a 'with' +@@ -668,6 +680,9 @@ + if (typeCheckingContext.ifElseForWhileAssignmentTracker != null && leftExpression instanceof VariableExpression + && !isNullConstant(rightExpression)) { + Variable accessedVariable = ((VariableExpression) leftExpression).getAccessedVariable(); ++ if (accessedVariable instanceof Parameter) { ++ accessedVariable = new ParameterVariableExpression((Parameter) accessedVariable); ++ } + if (accessedVariable instanceof VariableExpression) { + VariableExpression var = (VariableExpression) accessedVariable; + List<ClassNode> types = typeCheckingContext.ifElseForWhileAssignmentTracker.get(var); +@@ -1947,40 +1962,48 @@ + protected ClassNode[] getArgumentTypes(ArgumentListExpression args) { + List<Expression> arglist = args.getExpressions(); + ClassNode[] ret = new ClassNode[arglist.size()]; +- int i = 0; +- Map<Object, List<ClassNode>> info = typeCheckingContext.temporaryIfBranchTypeInformation.empty() ? null : typeCheckingContext.temporaryIfBranchTypeInformation.peek(); +- for (Expression exp : arglist) { +- if (isNullConstant(exp)) { ++ for (int i = 0; i < arglist.size(); i++) { ++ if (isNullConstant(arglist.get(i))) { + ret[i] = UNKNOWN_PARAMETER_TYPE; + } else { +- ret[i] = getType(exp); +- if (exp instanceof VariableExpression && info != null) { +- List<ClassNode> classNodes = getTemporaryTypesForExpression(exp); +- if (classNodes != null && !classNodes.isEmpty()) { +- ArrayList<ClassNode> arr = new ArrayList<ClassNode>(classNodes.size() + 1); +- arr.add(ret[i]); +- arr.addAll(classNodes); +- // GROOVY-7333: filter out Object +- Iterator<ClassNode> iterator = arr.iterator(); +- while (iterator.hasNext()) { +- ClassNode next = iterator.next(); +- if (ClassHelper.OBJECT_TYPE.equals(next)) { +- iterator.remove(); +- } +- } +- if (arr.isEmpty()) { +- ret[i] = ClassHelper.OBJECT_TYPE.getPlainNodeReference(); +- } else if (arr.size()==1) { +- ret[i] = arr.get(0); +- } else { +- ret[i] = new UnionTypeClassNode(arr.toArray(new ClassNode[arr.size()])); +- } +- } ++ ret[i] = getInferredType(arglist.get(i)); ++ } ++ } ++ return ret; ++ } ++ ++ private ClassNode getInferredType(Expression exp) { ++ ClassNode result = getType(exp); ++ result = getInferredTypeFromTempInfo(exp, result); ++ return result; ++ } ++ ++ private ClassNode getInferredTypeFromTempInfo(Expression exp, ClassNode result) { ++ Map<Object, List<ClassNode>> info = typeCheckingContext.temporaryIfBranchTypeInformation.empty() ? null : typeCheckingContext.temporaryIfBranchTypeInformation.peek(); ++ if (exp instanceof VariableExpression && info != null) { ++ List<ClassNode> classNodes = getTemporaryTypesForExpression(exp); ++ if (classNodes != null && !classNodes.isEmpty()) { ++ ArrayList<ClassNode> arr = new ArrayList<ClassNode>(classNodes.size() + 1); ++ if (result != null) arr.add(result); ++ arr.addAll(classNodes); ++ // GROOVY-7333: filter out Object ++ Iterator<ClassNode> iterator = arr.iterator(); ++ while (iterator.hasNext()) { ++ ClassNode next = iterator.next(); ++ if (ClassHelper.OBJECT_TYPE.equals(next)) { ++ iterator.remove(); ++ } ++ } ++ if (arr.isEmpty()) { ++ result = ClassHelper.OBJECT_TYPE.getPlainNodeReference(); ++ } else if (arr.size()==1) { ++ result = arr.get(0); ++ } else { ++ result = new UnionTypeClassNode(arr.toArray(new ClassNode[arr.size()])); + } + } +- i++; + } +- return ret; ++ return result; + } + + @Override +@@ -4026,6 +4049,9 @@ + List<ClassNode> temporaryTypesForExpression = getTemporaryTypesForExpression(vexp); + if (temporaryTypesForExpression == null || temporaryTypesForExpression.isEmpty()) { + type = typeCheckingContext.controlStructureVariables.get(parameter); ++// } else { ++// ClassNode temp = getInferredTypeFromTempInfo((Expression) exp, null); ++// type = temp; + } + // now check for closure override + TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); +@@ -4849,4 +4875,65 @@ + } + } + ++ /** ++ * Wrapper for a Parameter so it can be treated like a VariableExpression ++ * and tracked in the ifElseForWhileAssignmentTracker. ++ * ++ * This class purposely does not adhere to the normal equals and hashCode ++ * contract on the Object class and delegates those calls to the wrapped ++ * variable. ++ */ ++ private static class ParameterVariableExpression extends VariableExpression { ++ ++ private final Parameter parameter; ++ ++ ParameterVariableExpression(Parameter parameter) { ++ super(parameter); ++ this.parameter = parameter; ++ ClassNode inferred = parameter.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE); ++ if (inferred == null) { ++ parameter.setNodeMetaData(StaticTypesMarker.INFERRED_TYPE, parameter.getOriginType()); ++ } ++ } ++ ++ @Override ++ public void copyNodeMetaData(ASTNode other) { ++ parameter.copyNodeMetaData(other); ++ } ++ ++ @Override ++ public Object putNodeMetaData(Object key, Object value) { ++ return parameter.putNodeMetaData(key, value); ++ } ++ ++ @Override ++ public void removeNodeMetaData(Object key) { ++ parameter.removeNodeMetaData(key); ++ } ++ ++ @Override ++ public Map<?, ?> getNodeMetaData() { ++ return parameter.getNodeMetaData(); ++ } ++ ++ @Override ++ public <T> T getNodeMetaData(Object key) { ++ return parameter.getNodeMetaData(key); ++ } ++ ++ @Override ++ public void setNodeMetaData(Object key, Object value) { ++ parameter.setNodeMetaData(key, value); ++ } ++ ++ @Override ++ public int hashCode() { ++ return parameter.hashCode(); ++ } ++ ++ @Override ++ public boolean equals(Object other) { ++ return parameter.equals(other); ++ } ++ } + } +Index: src/test/groovy/transform/stc/STCAssignmentTest.groovy +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- src/test/groovy/transform/stc/STCAssignmentTest.groovy (revision 456aa4dd37dbcebcfb263db2914b2d84246bc30f) ++++ src/test/groovy/transform/stc/STCAssignmentTest.groovy (revision ) +@@ -446,6 +446,21 @@ + ''', 'Cannot find matching method java.io.Serializable#toInteger()' + } + ++ void testIfElseBranchParameter() { ++ shouldFailWithMessages ''' ++ def foo(x) { ++ def y = 'foo' ++ if (y) { ++ x = new HashSet() ++ } else { ++ x = '123' ++ } ++ x.toInteger() ++ } ++ foo('bar') ++ ''', 'Cannot find matching method java.lang.Object#toInteger()' ++ } ++ + void testIfOnly() { + shouldFailWithMessages ''' + def x = '123' +@@ -457,6 +472,20 @@ + ''', 'Cannot find matching method java.io.Serializable#toInteger()' + } + ++ void testIfOnlyParameter() { ++ shouldFailWithMessages ''' ++ def foo(x) { ++ def y = 'foo' ++ if (y) { ++ x = new HashSet() ++ assert x.isEmpty() ++ } ++ x.toInteger() ++ } ++ foo('123') ++ ''', 'Cannot find matching method java.lang.Object#toInteger()' ++ } ++ + void testIfWithCommonInterface() { + assertScript ''' + interface Foo { void foo() } +@@ -872,5 +901,63 @@ + } + ''' + } +-} ++ ++ // GROOVY-8220 ++ void testFlowTypingParameterTempTypeAssignmentTracking() { ++ assertScript ''' ++ class Foo { ++ CharSequence makeEnv( env, StringBuilder result = new StringBuilder() ) { ++ if (env instanceof File) { ++ env = env.toPath() ++ } ++ if (env instanceof String && env.contains('=')) { ++ result << 'export ' << env << ';' ++ } ++ return result.toString() ++ } ++ } ++ assert new Foo().makeEnv('X=1') == 'export X=1;' ++ ''' ++ // GROOVY-8237 ++ assertScript ''' ++ class Foo { ++ String parse(Reader reader) { ++ if (reader == null) ++ reader = new BufferedReader(reader) ++ int i = reader.read() ++ return (i != -1) ? 'bar' : 'baz' ++ } ++ } ++ assert new Foo().parse(new StringReader('foo')) == 'bar' ++ ''' ++ } + ++ void testFlowTypingParameterTempTypeAssignmentTrackingWithGenerics() { ++ assertScript ''' ++ class M { ++ Map<String, List<Object>> mvm = new HashMap<String, List<Object>>() ++ void setProperty(String name, value) { ++ if (value instanceof File) { ++ value = new File(value, 'bar.txt') ++ } ++ else if (value instanceof URL) { ++ value = value.toURI() ++ } ++ else if (value instanceof InputStream) { ++ value = new BufferedInputStream(value) ++ } ++ else if (value instanceof GString) { ++ value = value.toString() ++ } ++ if (mvm[name]) { ++ mvm[name].add value ++ } else { ++ mvm.put(name, [value]) ++ } ++ } ++ } ++ new M().setProperty('foo', 'bar') ++ ''' ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/groovy8260c.patch ---------------------------------------------------------------------- diff --git a/groovy8260c.patch b/groovy8260c.patch new file mode 100644 index 0000000..f7598cd --- /dev/null +++ b/groovy8260c.patch @@ -0,0 +1,188 @@ +commit 26d11337cfa4d66eed6eca1f99f5a5309427ebd9 +Author: paulk <[email protected]> +Date: Fri Sep 29 22:35:54 2017 +1000 + + GROOVY-8260: Static compilation requires casting inside instanceof check (handle additional cases) + +diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +index 807449a1a..bda414bb8 100644 +--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java ++++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +@@ -480,7 +480,30 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { + } + } + +- if (! (vexp.getAccessedVariable() instanceof DynamicVariable)) return; ++ if (!(vexp.getAccessedVariable() instanceof DynamicVariable)) { ++ VariableExpression variable = null; ++ if (vexp.getAccessedVariable() instanceof Parameter) { ++ variable = new ParameterVariableExpression((Parameter) vexp.getAccessedVariable()); ++ } else if (vexp.getAccessedVariable() instanceof VariableExpression) { ++ variable = (VariableExpression) vexp.getAccessedVariable(); ++ } ++ if (variable != null) { ++ ClassNode inferredType = getInferredTypeFromTempInfo(variable, variable.getNodeMetaData(StaticTypesMarker.INFERRED_TYPE)); ++ if (inferredType != null && !inferredType.getName().equals("java.lang.Object")) { ++ if (typeCheckingContext.getEnclosingBinaryExpression() != null) { ++ // TODO narrow this down to assignment ++ if (typeCheckingContext.getEnclosingBinaryExpression().getRightExpression() == vexp) { ++ vexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, inferredType); ++ } ++ } else { ++ // stash away type info that will be lost later to handle case ++ // where this expression has return added later - piggy back on existing key ++ vexp.putNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE, inferredType); ++ } ++ } ++ } ++ return; ++ } + + // a dynamic variable is either an undeclared variable + // or a member of a class used in a 'with' +@@ -1833,6 +1856,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { + if (typeCheckingContext.getEnclosingClosure()!=null) { + return type; + } ++ if ((expression instanceof VariableExpression) && hasInferredReturnType(expression)) { ++ type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); ++ } + MethodNode enclosingMethod = typeCheckingContext.getEnclosingMethod(); + if (enclosingMethod != null && typeCheckingContext.getEnclosingClosure()==null) { + if (!enclosingMethod.isVoidMethod() +@@ -3205,7 +3231,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { + int depth = typeCheckingContext.temporaryIfBranchTypeInformation.size(); + while (classNodes == null && depth > 0) { + final Map<Object, List<ClassNode>> tempo = typeCheckingContext.temporaryIfBranchTypeInformation.get(--depth); +- Object key = extractTemporaryTypeInfoKey(objectExpression); ++ Object key = objectExpression instanceof ParameterVariableExpression ++ ? ((ParameterVariableExpression) objectExpression).parameter ++ : extractTemporaryTypeInfoKey(objectExpression); + classNodes = tempo.get(key); + } + return classNodes; +@@ -3393,6 +3421,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { + typeCheckingContext.popTemporaryTypeInfo(); + falseExpression.visit(this); + ClassNode resultType; ++ ClassNode typeOfFalse = getType(falseExpression); ++ ClassNode typeOfTrue = getType(trueExpression); ++ if (hasInferredReturnType(falseExpression)) { ++ typeOfFalse = falseExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); ++ } ++ if (hasInferredReturnType(trueExpression)) { ++ typeOfTrue = trueExpression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); ++ } + if (isNullConstant(trueExpression) || isNullConstant(falseExpression)) { + BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression(); + if (enclosingBinaryExpression != null && enclosingBinaryExpression.getRightExpression()==expression) { +@@ -3400,20 +3436,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport { + } else if (isNullConstant(trueExpression) && isNullConstant(falseExpression)) { + resultType = OBJECT_TYPE; + } else if (isNullConstant(trueExpression)) { +- resultType = wrapTypeIfNecessary(getType(falseExpression)); ++ resultType = wrapTypeIfNecessary(typeOfFalse); + } else { +- resultType = wrapTypeIfNecessary(getType(trueExpression)); ++ resultType = wrapTypeIfNecessary(typeOfTrue); + } + } else { + // store type information +- final ClassNode typeOfTrue = getType(trueExpression); +- final ClassNode typeOfFalse = getType(falseExpression); + resultType = lowestUpperBound(typeOfTrue, typeOfFalse); + } + storeType(expression, resultType); + popAssignmentTracking(oldTracker); + } + ++ private boolean hasInferredReturnType(Expression expression) { ++ ClassNode type = expression.getNodeMetaData(StaticTypesMarker.INFERRED_RETURN_TYPE); ++ return type != null && !type.getName().equals("java.lang.Object"); ++ } ++ + @Override + public void visitTryCatchFinally(final TryCatchStatement statement) { + final List<CatchStatement> catchStatements = statement.getCatchStatements(); +diff --git a/src/test/groovy/transform/stc/MiscSTCTest.groovy b/src/test/groovy/transform/stc/MiscSTCTest.groovy +index 13bdb40c6..fadac0afa 100644 +--- a/src/test/groovy/transform/stc/MiscSTCTest.groovy ++++ b/src/test/groovy/transform/stc/MiscSTCTest.groovy +@@ -22,8 +22,6 @@ import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor + + /** + * Unit tests for static type checking : miscellaneous tests. +- * +- * @author Cedric Champeau + */ + class MiscSTCTest extends StaticTypeCheckingTestCase { + +@@ -272,8 +270,67 @@ class MiscSTCTest extends StaticTypeCheckingTestCase { + } + } + +- public static class MiscSTCTestSupport { ++ static class MiscSTCTestSupport { + static def foo() { '123' } + } ++ ++ void testTernaryParam() { ++ assertScript ''' ++ Date ternaryParam(Object input) { ++ input instanceof Date ? input : null ++ } ++ def d = new Date() ++ assert ternaryParam(42) == null ++ assert ternaryParam('foo') == null ++ assert ternaryParam(d) == d ++ ''' ++ } ++ ++ void testTernaryLocalVar() { ++ assertScript ''' ++ Date ternaryLocalVar(Object input) { ++ Object copy = input ++ copy instanceof Date ? copy : null ++ } ++ def d = new Date() ++ assert ternaryLocalVar(42) == null ++ assert ternaryLocalVar('foo') == null ++ assert ternaryLocalVar(d) == d ++ ''' ++ } ++ ++ void testIfThenElseParam() { ++ assertScript ''' ++ Date ifThenElseParam(Object input) { ++ if (input instanceof Date) { ++ input ++ } else { ++ null ++ } ++ } ++ def d = new Date() ++ assert ifThenElseParam(42) == null ++ assert ifThenElseParam('foo') == null ++ assert ifThenElseParam(d) == d ++ ''' ++ } ++ ++ void testIfThenElseLocalVar() { ++ assertScript ''' ++ Date ifThenElseLocalVar(Object input) { ++ Date result ++ if (input instanceof Date) { ++ result = input ++ } else { ++ result = null ++ } ++ result ++ } ++ def d = new Date() ++ assert ifThenElseLocalVar(42) == null ++ assert ifThenElseLocalVar('foo') == null ++ assert ifThenElseLocalVar(d) == d ++ ''' ++ } + } + http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/ivy_snapshot.patch ---------------------------------------------------------------------- diff --git a/ivy_snapshot.patch b/ivy_snapshot.patch new file mode 100644 index 0000000..3ce0c68 --- /dev/null +++ b/ivy_snapshot.patch @@ -0,0 +1,24 @@ +Index: build.gradle +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +--- build.gradle (revision 8301ba03d2a38b36b9f718db54f46b935e1aba5d) ++++ build.gradle (revision ) +@@ -94,6 +94,7 @@ + } + jcenter() + maven { url 'http://dl.bintray.com/melix/thirdparty-apache' } // openbeans ++ maven { url 'https://repository.apache.org/snapshots/' } + } + + apply plugin: 'groovy' +@@ -168,7 +169,7 @@ + eclipseOsgiVersion = '3.9.1-v20140110-1610' + gparsVersion = '1.2.1' + gradleVersion = '3.5.1' +- ivyVersion = '2.4.0' ++ ivyVersion = '2.5.0-SNAPSHOT' + jansiVersion = '1.13' + jarjarVersion = '1.4.1' + jlineVersion = '2.14.5' http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr502.patch ---------------------------------------------------------------------- diff --git a/pr502.patch b/pr502.patch new file mode 100644 index 0000000..b63c727 --- /dev/null +++ b/pr502.patch @@ -0,0 +1,118 @@ +From 764388a34b9f6fbf1c605fbbf02700b8ebed82d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Christoffer=20Hammarstr=C3=B6m?= + <[email protected]> +Date: Wed, 22 Feb 2017 02:18:52 +0100 +Subject: [PATCH] Add tests to prove that calling + CompilerConfiguration.setScriptBaseClass with a Java class causes ModuleNode + to generate a constructor that prevents Field initialization from Binding + context. + +--- + src/test/groovy/lang/BindingScript.java | 32 +++++++++++++++++ + src/test/groovy/lang/GroovyShellTest2.groovy | 54 ++++++++++++++++++++++++++++ + 2 files changed, 86 insertions(+) + create mode 100644 src/test/groovy/lang/BindingScript.java + +diff --git a/src/test/groovy/lang/BindingScript.java b/src/test/groovy/lang/BindingScript.java +new file mode 100644 +index 0000000..81cda00 +--- /dev/null ++++ b/src/test/groovy/lang/BindingScript.java +@@ -0,0 +1,32 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one ++ * or more contributor license agreements. See the NOTICE file ++ * distributed with this work for additional information ++ * regarding copyright ownership. The ASF licenses this file ++ * to you under the Apache License, Version 2.0 (the ++ * "License"); you may not use this file except in compliance ++ * with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, ++ * software distributed under the License is distributed on an ++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ++ * KIND, either express or implied. See the License for the ++ * specific language governing permissions and limitations ++ * under the License. ++ */ ++package groovy.lang; ++ ++/** ++ * A Script which requires a Binding passed in the constructor and disallows calling the default constructor. ++ */ ++public abstract class BindingScript extends Script { ++ protected BindingScript() { ++ throw new UnsupportedOperationException("\n\t*******\n\tBindingScript() should not be called! Should be calling BindingScript(Binding)!\n\t*******"); ++ } ++ ++ protected BindingScript(Binding binding) { ++ super(binding); ++ } ++} +diff --git a/src/test/groovy/lang/GroovyShellTest2.groovy b/src/test/groovy/lang/GroovyShellTest2.groovy +index 27259bf..c883553 100644 +--- a/src/test/groovy/lang/GroovyShellTest2.groovy ++++ b/src/test/groovy/lang/GroovyShellTest2.groovy +@@ -43,6 +43,60 @@ class GroovyShellTest2 extends GroovyTestCase { + assert result == arg0 + } + ++ void testBindingsInFieldInitializersWithAnnotatedJavaBaseScript() { ++ def shell = new GroovyShell(); ++ def scriptText = ''' ++ @groovy.transform.BaseScript groovy.lang.BindingScript baseScript ++ @groovy.transform.Field def script_args = getProperty('args') ++ ++ assert script_args[0] == 'Hello Groovy' ++ script_args[0] ++''' ++ ++ def arg0 = 'Hello Groovy' ++ def result = shell.run scriptText, 'TestBindingsInFieldInitializersWithAnnotatedJavaBaseScript.groovy', [arg0] ++ assert result == arg0 ++ } ++ ++ /** ++ This test fails because {@link org.codehaus.groovy.ast.ModuleNode#setScriptBaseClassFromConfig(org.codehaus.groovy.ast.ClassNode)} ++ calls .setSuperClass(ClassHelper.make(baseClassName)) on the Scripts ClassNode. ++ ++ The ClassNode created for this scriptBaseClass has lazyInitDone = true and constructors = null so when ++ .getSuperClass().getDeclaredConstructor(SCRIPT_CONTEXT_CTOR) is called by {@link org.codehaus.groovy.ast.ModuleNode#createStatementsClass()} ++ then ClassNode.constructors is set to an empty ArrayList in {@link org.codehaus.groovy.ast.ClassNode#getDeclaredConstructors()} ++ ++ The script constructor is then generated as ++ Constructor(Binding context) { ++ super(); // Fields are initialized after the call to super() ++ setBinding(context); // Fields are initalized before the call to setBinding(context) ++ } ++ ++ instead of ++ Constructor(Binding context) { ++ super(context); // Fields are initialized after the call to super(context) ++ } ++ ++ Fields are initialized between the call to super() and the setBinding(context) ++ which means Field initializers don't have access to the Binding context. ++ */ ++ void testBindingsInFieldInitializersWithConfigJavaBaseScript() { ++ def config = new org.codehaus.groovy.control.CompilerConfiguration() ++ config.scriptBaseClass = BindingScript.class.name ++ ++ def shell = new GroovyShell(config); ++ def scriptText = ''' ++ @groovy.transform.Field def script_args = getProperty('args') ++ ++ assert script_args[0] == 'Hello Groovy' ++ script_args[0] ++''' ++ ++ def arg0 = 'Hello Groovy' ++ def result = shell.run scriptText, 'TestBindingsInFieldInitializersWithConfigJavaBaseScript.groovy', [arg0] ++ assert result == arg0 ++ } ++ + void testBindingsInScriptFieldInitializers() { + def shell = new GroovyShell(); + def scriptText = ''' http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr507.patch ---------------------------------------------------------------------- diff --git a/pr507.patch b/pr507.patch new file mode 100644 index 0000000..72d74a1 --- /dev/null +++ b/pr507.patch @@ -0,0 +1,25 @@ +From: AarjavP <[email protected]> +Date: Wed, 30 Aug 2017 17:39:44 +0200 +Subject: [PATCH] Fix wildcard arg handling in startGroovy.bat (closes #507) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Aarjav Patel +--- + src/bin/startGroovy.bat | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/bin/startGroovy.bat b/src/bin/startGroovy.bat +index 1b7988218..f869ff7938b5a4262be297007178ef6f68aafaff 100644 +--- a/src/bin/startGroovy.bat ++++ b/src/bin/startGroovy.bat +@@ -177,7 +177,7 @@ + goto process_arg + + :get_arg +-rem remove quotes around first arg ++rem remove quotes around first arg and don't expand wildcards + for /f %%i in (%1) do set _ARG=%_ARG% %%~i + rem set the remaining args + set _ARGS=%2 http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr555.patch ---------------------------------------------------------------------- diff --git a/pr555.patch b/pr555.patch new file mode 100644 index 0000000..67423c6 --- /dev/null +++ b/pr555.patch @@ -0,0 +1,312 @@ +From 11a0b159d8d04f3c1e518613566a1b459ecda44d Mon Sep 17 00:00:00 2001 +From: noamt <[email protected]> +Date: Wed, 31 May 2017 20:57:04 +0200 +Subject: [PATCH 1/5] GROOVY-8200 - Shorthand |= results in NPE: Fixing the NPE + with an explicit test and assignment of the right-hand boolean operator. + Assigning a primitive boolean variable with null, like `boolean x = null`, + will end up as `false`. I think it only makes sense to apply the same + behavior to the right hand operator. + +--- + .../groovy/runtime/DefaultGroovyMethods.java | 12 ++++++++ + .../groovy/runtime/DefaultGroovyMethodsTest.groovy | 36 ++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +index 76b9fa6378..da50255833 100644 +--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java ++++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +@@ -15760,6 +15760,9 @@ public static BigInteger toBigInteger(Number self) { + * @since 1.0 + */ + public static Boolean and(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left && right; + } + +@@ -15772,6 +15775,9 @@ public static Boolean and(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean or(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left || right; + } + +@@ -15784,6 +15790,9 @@ public static Boolean or(Boolean left, Boolean right) { + * @since 1.8.3 + */ + public static Boolean implies(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return !left || right; + } + +@@ -15796,6 +15805,9 @@ public static Boolean implies(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean xor(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left ^ right; + } + +diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +index 087b301bc3..c0e4e1a990 100644 +--- a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy ++++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +@@ -239,4 +239,40 @@ public class DefaultGroovyMethodsTest extends GroovyTestCase { + private static class MyList extends ArrayList { + public MyList() {} + } ++ ++ public void testBooleanOr() { ++ assertTrue(DefaultGroovyMethods.or(true, true)) ++ assertTrue(DefaultGroovyMethods.or(true, false)) ++ assertTrue(DefaultGroovyMethods.or(false, true)) ++ assertFalse(DefaultGroovyMethods.or(false, false)) ++ assertFalse(DefaultGroovyMethods.or(false, null)) ++ assertTrue(DefaultGroovyMethods.or(true, null)) ++ } ++ ++ public void testBooleanAnd() { ++ assertTrue(DefaultGroovyMethods.and(true, true)) ++ assertFalse(DefaultGroovyMethods.and(true, false)) ++ assertFalse(DefaultGroovyMethods.and(false, true)) ++ assertFalse(DefaultGroovyMethods.and(false, false)) ++ assertFalse(DefaultGroovyMethods.and(false, null)) ++ assertFalse(DefaultGroovyMethods.and(true, null)) ++ } ++ ++ public void testBooleanXor() { ++ assertFalse(DefaultGroovyMethods.xor(true, true)) ++ assertTrue(DefaultGroovyMethods.xor(true, false)) ++ assertTrue(DefaultGroovyMethods.xor(false, true)) ++ assertFalse(DefaultGroovyMethods.xor(false, false)) ++ assertFalse(DefaultGroovyMethods.xor(false, null)) ++ assertTrue(DefaultGroovyMethods.xor(true, null)) ++ } ++ ++ public void testBooleanImplication() { ++ assertTrue(DefaultGroovyMethods.implies(true, true)) ++ assertTrue(DefaultGroovyMethods.xor(true, false)) ++ assertTrue(DefaultGroovyMethods.xor(false, true)) ++ assertFalse(DefaultGroovyMethods.xor(false, false)) ++ assertFalse(DefaultGroovyMethods.xor(false, null)) ++ assertTrue(DefaultGroovyMethods.xor(true, null)) ++ } + } + +From 2d8fc8957a82658ec000e77cb1cab66565ef2a6a Mon Sep 17 00:00:00 2001 +From: noamt <[email protected]> +Date: Thu, 1 Jun 2017 15:02:40 +0200 +Subject: [PATCH 2/5] GROOVY-8200 - Shorthand |= results in NPE: Using a + cleaner, safe assignment of the right hand operator + +--- + .../codehaus/groovy/runtime/DefaultGroovyMethods.java | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +index da50255833..f359f44dfd 100644 +--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java ++++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +@@ -15760,9 +15760,7 @@ public static BigInteger toBigInteger(Number self) { + * @since 1.0 + */ + public static Boolean and(Boolean left, Boolean right) { +- if (right == null) { +- right = Boolean.FALSE; +- } ++ right = Boolean.TRUE.equals(right); + return left && right; + } + +@@ -15775,9 +15773,7 @@ public static Boolean and(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean or(Boolean left, Boolean right) { +- if (right == null) { +- right = Boolean.FALSE; +- } ++ right = Boolean.TRUE.equals(right); + return left || right; + } + +@@ -15790,9 +15786,7 @@ public static Boolean or(Boolean left, Boolean right) { + * @since 1.8.3 + */ + public static Boolean implies(Boolean left, Boolean right) { +- if (right == null) { +- right = Boolean.FALSE; +- } ++ right = Boolean.TRUE.equals(right); + return !left || right; + } + +@@ -15805,9 +15799,7 @@ public static Boolean implies(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean xor(Boolean left, Boolean right) { +- if (right == null) { +- right = Boolean.FALSE; +- } ++ right = Boolean.TRUE.equals(right); + return left ^ right; + } + + +From 9d9f2d49db0cd149349b74549f5556a650bc5c7f Mon Sep 17 00:00:00 2001 +From: noamt <[email protected]> +Date: Wed, 7 Jun 2017 12:33:13 +0300 +Subject: [PATCH 3/5] GROOVY-8200 - Shorthand |= results in NPE: Reducing the + expression to a one liner + +--- + .../org/codehaus/groovy/runtime/DefaultGroovyMethods.java | 12 ++++-------- + 1 file changed, 4 insertions(+), 8 deletions(-) + +diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +index f359f44dfd..193a7bf655 100644 +--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java ++++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +@@ -15760,8 +15760,7 @@ public static BigInteger toBigInteger(Number self) { + * @since 1.0 + */ + public static Boolean and(Boolean left, Boolean right) { +- right = Boolean.TRUE.equals(right); +- return left && right; ++ return left && Boolean.TRUE.equals(right); + } + + /** +@@ -15773,8 +15772,7 @@ public static Boolean and(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean or(Boolean left, Boolean right) { +- right = Boolean.TRUE.equals(right); +- return left || right; ++ return left || Boolean.TRUE.equals(right); + } + + /** +@@ -15786,8 +15784,7 @@ public static Boolean or(Boolean left, Boolean right) { + * @since 1.8.3 + */ + public static Boolean implies(Boolean left, Boolean right) { +- right = Boolean.TRUE.equals(right); +- return !left || right; ++ return !left || Boolean.TRUE.equals(right); + } + + /** +@@ -15799,8 +15796,7 @@ public static Boolean implies(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean xor(Boolean left, Boolean right) { +- right = Boolean.TRUE.equals(right); +- return left ^ right; ++ return left ^ Boolean.TRUE.equals(right); + } + + // public static Boolean negate(Boolean left) { + +From aa715bcc38fa2cfb13de7cbccbda5c6aaba2cf14 Mon Sep 17 00:00:00 2001 +From: noamt <[email protected]> +Date: Thu, 8 Jun 2017 14:03:19 +0300 +Subject: [PATCH 4/5] GROOVY-8200 - Shorthand |= results in NPE: Fix copy-pasta + mistake in DefaultGroovyMethodsTest + +--- + .../codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +index c0e4e1a990..713e29b431 100644 +--- a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy ++++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +@@ -269,10 +269,10 @@ public class DefaultGroovyMethodsTest extends GroovyTestCase { + + public void testBooleanImplication() { + assertTrue(DefaultGroovyMethods.implies(true, true)) +- assertTrue(DefaultGroovyMethods.xor(true, false)) +- assertTrue(DefaultGroovyMethods.xor(false, true)) +- assertFalse(DefaultGroovyMethods.xor(false, false)) +- assertFalse(DefaultGroovyMethods.xor(false, null)) +- assertTrue(DefaultGroovyMethods.xor(true, null)) ++ assertFalse(DefaultGroovyMethods.implies(true, false)) ++ assertTrue(DefaultGroovyMethods.implies(false, true)) ++ assertTrue(DefaultGroovyMethods.implies(false, false)) ++ assertTrue(DefaultGroovyMethods.implies(false, null)) ++ assertFalse(DefaultGroovyMethods.implies(true, null)) + } + } + +From 0e95399596b828c1ad14f571290e79ad03eef2b2 Mon Sep 17 00:00:00 2001 +From: noamt <[email protected]> +Date: Thu, 8 Jun 2017 14:04:06 +0300 +Subject: [PATCH 5/5] GROOVY-8200 - Shorthand |= results in NPE: Adding tests + for the shorthand logical operators + +--- + src/spec/test/OperatorsTest.groovy | 44 +++++++++++++++++++++++++++++++++++++- + 1 file changed, 43 insertions(+), 1 deletion(-) + +diff --git a/src/spec/test/OperatorsTest.groovy b/src/spec/test/OperatorsTest.groovy +index a0eddf38d8..46b87f7e7b 100644 +--- a/src/spec/test/OperatorsTest.groovy ++++ b/src/spec/test/OperatorsTest.groovy +@@ -607,4 +607,46 @@ assert (b1 + 11).size == 15 + assert str1 == str2 + ''' + } +-} ++ ++ void testBooleanOr() { ++ assertScript ''' ++boolean trueValue1 = true, trueValue2 = true, trueValue3 = true ++boolean falseValue1 = false, falseValue2 = false, falseValue3 = false ++ ++assert (trueValue1 |= true) ++assert (trueValue2 |= false) ++assert (trueValue3 |= null) ++assert (falseValue1 |= true) ++assert !(falseValue2 |= false) ++assert !(falseValue3 |= null) ++''' ++ } ++ ++ void testBooleanAnd() { ++ assertScript ''' ++boolean trueValue1 = true, trueValue2 = true, trueValue3 = true ++boolean falseValue1 = false, falseValue2 = false, falseValue3 = false ++ ++assert (trueValue1 &= true) ++assert !(trueValue2 &= false) ++assert !(trueValue3 &= null) ++assert !(falseValue1 &= true) ++assert !(falseValue2 &= false) ++assert !(falseValue3 &= null) ++''' ++ } ++ ++ void testBooleanXor() { ++ assertScript ''' ++boolean trueValue1 = true, trueValue2 = true, trueValue3 = true ++boolean falseValue1 = false, falseValue2 = false, falseValue3 = false ++ ++assert !(trueValue1 ^= true) ++assert (trueValue2 ^= false) ++assert (trueValue3 ^= null) ++assert (falseValue1 ^= true) ++assert !(falseValue2 ^= false) ++assert !(falseValue3 ^= null) ++''' ++ } ++} +\ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr555a.patch ---------------------------------------------------------------------- diff --git a/pr555a.patch b/pr555a.patch new file mode 100644 index 0000000..9e54187 --- /dev/null +++ b/pr555a.patch @@ -0,0 +1,94 @@ + .../groovy/runtime/DefaultGroovyMethods.java | 12 ++++++++ + .../groovy/runtime/DefaultGroovyMethodsTest.groovy | 36 ++++++++++++++++++++++ + 2 files changed, 48 insertions(+) + +diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +index 76b9fa6378..da50255833 100644 +--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java ++++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +@@ -15760,6 +15760,9 @@ public static BigInteger toBigInteger(Number self) { + * @since 1.0 + */ + public static Boolean and(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left && right; + } + +@@ -15772,6 +15775,9 @@ public static Boolean and(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean or(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left || right; + } + +@@ -15784,6 +15790,9 @@ public static Boolean or(Boolean left, Boolean right) { + * @since 1.8.3 + */ + public static Boolean implies(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return !left || right; + } + +@@ -15796,6 +15805,9 @@ public static Boolean implies(Boolean left, Boolean right) { + * @since 1.0 + */ + public static Boolean xor(Boolean left, Boolean right) { ++ if (right == null) { ++ right = Boolean.FALSE; ++ } + return left ^ right; + } + +diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +index 087b301bc3..c0e4e1a990 100644 +--- a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy ++++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy +@@ -239,4 +239,40 @@ public class DefaultGroovyMethodsTest extends GroovyTestCase { + private static class MyList extends ArrayList { + public MyList() {} + } ++ ++ public void testBooleanOr() { ++ assertTrue(DefaultGroovyMethods.or(true, true)) ++ assertTrue(DefaultGroovyMethods.or(true, false)) ++ assertTrue(DefaultGroovyMethods.or(false, true)) ++ assertFalse(DefaultGroovyMethods.or(false, false)) ++ assertFalse(DefaultGroovyMethods.or(false, null)) ++ assertTrue(DefaultGroovyMethods.or(true, null)) ++ } ++ ++ public void testBooleanAnd() { ++ assertTrue(DefaultGroovyMethods.and(true, true)) ++ assertFalse(DefaultGroovyMethods.and(true, false)) ++ assertFalse(DefaultGroovyMethods.and(false, true)) ++ assertFalse(DefaultGroovyMethods.and(false, false)) ++ assertFalse(DefaultGroovyMethods.and(false, null)) ++ assertFalse(DefaultGroovyMethods.and(true, null)) ++ } ++ ++ public void testBooleanXor() { ++ assertFalse(DefaultGroovyMethods.xor(true, true)) ++ assertTrue(DefaultGroovyMethods.xor(true, false)) ++ assertTrue(DefaultGroovyMethods.xor(false, true)) ++ assertFalse(DefaultGroovyMethods.xor(false, false)) ++ assertFalse(DefaultGroovyMethods.xor(false, null)) ++ assertTrue(DefaultGroovyMethods.xor(true, null)) ++ } ++ ++ public void testBooleanImplication() { ++ assertTrue(DefaultGroovyMethods.implies(true, true)) ++ assertTrue(DefaultGroovyMethods.xor(true, false)) ++ assertTrue(DefaultGroovyMethods.xor(false, true)) ++ assertFalse(DefaultGroovyMethods.xor(false, false)) ++ assertFalse(DefaultGroovyMethods.xor(false, null)) ++ assertTrue(DefaultGroovyMethods.xor(true, null)) ++ } + } + http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr565.patch ---------------------------------------------------------------------- diff --git a/pr565.patch b/pr565.patch new file mode 100644 index 0000000..31c7ce7 --- /dev/null +++ b/pr565.patch @@ -0,0 +1,168 @@ +From b3a0e1634749dbd703f705795a767b71c11a7bec Mon Sep 17 00:00:00 2001 +From: paulk <[email protected]> +Date: Sun, 25 Jun 2017 21:57:36 +1000 +Subject: [PATCH] GROOVY-8236: Report more meaningful error for versions of + Groovy not supporting @Repeatable + +--- + .../codehaus/groovy/classgen/ExtendedVerifier.java | 58 +++++++++++++++++++--- + src/test/gls/annotations/AnnotationTest.groovy | 38 ++++++++++++++ + 2 files changed, 89 insertions(+), 7 deletions(-) + +diff --git a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java +index bad5acc649..e1cb4182a1 100644 +--- a/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java ++++ b/src/main/org/codehaus/groovy/classgen/ExtendedVerifier.java +@@ -19,7 +19,9 @@ + package org.codehaus.groovy.classgen; + + import org.codehaus.groovy.ast.*; ++import org.codehaus.groovy.ast.expr.ClassExpression; + import org.codehaus.groovy.ast.expr.DeclarationExpression; ++import org.codehaus.groovy.ast.expr.Expression; + import org.codehaus.groovy.ast.stmt.ReturnStatement; + import org.codehaus.groovy.ast.stmt.Statement; + import org.codehaus.groovy.ast.tools.ParameterUtils; +@@ -34,6 +36,7 @@ + import java.util.ArrayList; + import java.util.Arrays; + import java.util.HashMap; ++import java.util.LinkedHashMap; + import java.util.List; + import java.util.Map; + +@@ -135,21 +138,62 @@ protected void visitAnnotations(AnnotatedNode node, int target) { + addError("Annotations are not supported in the current runtime. " + JVM_ERROR_MESSAGE, node); + return; + } ++ Map<String, List<AnnotationNode>> runtimeAnnotations = new LinkedHashMap<String, List<AnnotationNode>>(); + for (AnnotationNode unvisited : node.getAnnotations()) { + AnnotationNode visited = visitAnnotation(unvisited); +- boolean isTargetAnnotation = visited.getClassNode().isResolved() && +- visited.getClassNode().getName().equals("java.lang.annotation.Target"); ++ String name = visited.getClassNode().getName(); ++ if (visited.hasRuntimeRetention()) { ++ List<AnnotationNode> seen = runtimeAnnotations.get(name); ++ if (seen == null) { ++ seen = new ArrayList<AnnotationNode>(); ++ } ++ seen.add(visited); ++ runtimeAnnotations.put(name, seen); ++ } ++ boolean isTargetAnnotation = name.equals("java.lang.annotation.Target"); + + // Check if the annotation target is correct, unless it's the target annotating an annotation definition + // defining on which target elements the annotation applies + if (!isTargetAnnotation && !visited.isTargetAllowed(target)) { +- addError("Annotation @" + visited.getClassNode().getName() +- + " is not allowed on element " + AnnotationNode.targetToName(target), +- visited); ++ addError("Annotation @" + name + " is not allowed on element " ++ + AnnotationNode.targetToName(target), visited); + } + visitDeprecation(node, visited); + visitOverride(node, visited); + } ++ checkForDuplicateAnnotations(runtimeAnnotations); ++ } ++ ++ private void checkForDuplicateAnnotations(Map<String, List<AnnotationNode>> runtimeAnnotations) { ++ for (Map.Entry<String, List<AnnotationNode>> next : runtimeAnnotations.entrySet()) { ++ if (next.getValue().size() > 1) { ++ String repeatableName = null; ++ AnnotationNode repeatee = next.getValue().get(0); ++ List<AnnotationNode> repeateeAnnotations = repeatee.getClassNode().getAnnotations(); ++ for (AnnotationNode anno : repeateeAnnotations) { ++ ClassNode annoClassNode = anno.getClassNode(); ++ if (annoClassNode.getName().equals("java.lang.annotation.Repeatable")) { ++ Expression value = anno.getMember("value"); ++ if (value instanceof ClassExpression) { ++ ClassExpression ce = (ClassExpression) value; ++ if (ce.getType() != null && ce.getType().isAnnotationDefinition()) { ++ repeatableName = ce.getType().getName(); ++ } ++ } ++ break; ++ } ++ } ++ // TODO: further checks: that repeatableName is valid and has RUNTIME retention? ++ if (repeatableName != null) { ++ addError("Annotation @" + next.getKey() + " has RUNTIME retention and " + next.getValue().size() ++ + " occurrences. Automatic repeated annotations are not supported in this version of Groovy. " + ++ "Consider using the explicit @" + repeatableName + " collector annotation instead.", next.getValue().get(1)); ++ } else { ++ addError("Annotation @" + next.getKey() + " has RUNTIME retention and " + next.getValue().size() ++ + " occurrences. Duplicate annotations not allowed.", next.getValue().get(1)); ++ } ++ } ++ } + } + + private static void visitDeprecation(AnnotatedNode node, AnnotationNode visited) { +@@ -222,7 +266,7 @@ private static boolean isOverrideMethod(MethodNode method) { + } + ClassNode superClass = next.getUnresolvedSuperClass(); + if (superClass != null) { +- next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); ++ next = correctToGenericsSpecRecurse(updatedGenericsSpec, superClass); + } else { + next = null; + } +@@ -231,7 +275,7 @@ private static boolean isOverrideMethod(MethodNode method) { + } + + private static MethodNode getDeclaredMethodCorrected(Map genericsSpec, MethodNode mn, ClassNode correctedNext) { +- for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { ++ for (MethodNode orig : correctedNext.getDeclaredMethods(mn.getName())) { + MethodNode method = correctToGenericsSpec(genericsSpec, orig); + if (ParameterUtils.parametersEqual(method.getParameters(), mn.getParameters())) { + return method; +diff --git a/src/test/gls/annotations/AnnotationTest.groovy b/src/test/gls/annotations/AnnotationTest.groovy +index 80e42427ac..9f306ff1e4 100644 +--- a/src/test/gls/annotations/AnnotationTest.groovy ++++ b/src/test/gls/annotations/AnnotationTest.groovy +@@ -704,6 +704,44 @@ class AnnotationTest extends CompilableTestSupport { + ''' + } + ++ // GROOVY-8236 ++ void testAnnotationWithRepeated() { ++ def errorMessage = shouldNotCompile ''' ++ import java.lang.annotation.* ++ ++ class MyClass { ++ @MyAnnotation(value = "val1") ++ @MyAnnotation(value = "val2") ++ //change annotation to next line and the code will work ++ //@MyAnnotationArray( [@MyAnnotation("val1"), @MyAnnotation("val2")] ) ++ String annotatedMethod() { ++ 'foo' ++ } ++ static void main(String... args) { ++ MyClass myc = new MyClass() ++ assert 'foo' == myc.annotatedMethod() ++ def m = myc.getClass().getMethod("annotatedMethod") ++ List annos = m.getAnnotations() ++ assert annos.size() == 1 ++ } ++ } ++ ++ @Target(ElementType.METHOD) ++ @Retention(RetentionPolicy.RUNTIME) ++ @Repeatable(MyAnnotationArray) ++ @interface MyAnnotation { ++ String value() default "val0" ++ } ++ ++ @Retention(RetentionPolicy.RUNTIME) ++ @interface MyAnnotationArray { ++ MyAnnotation[] value() ++ } ++ ''' ++ assert errorMessage.contains('Automatic repeated annotations are not supported') ++ assert errorMessage.contains('Consider using the explicit @MyAnnotationArray collector annotation') ++ } ++ + //Parametrized tests in Spock would allow to make it much more readable + private static String codeWithMetaAnnotationWithTarget(String targetElementTypeName) { + """ http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr584.patch ---------------------------------------------------------------------- diff --git a/pr584.patch b/pr584.patch new file mode 100644 index 0000000..ec5c5fe --- /dev/null +++ b/pr584.patch @@ -0,0 +1,57 @@ +From 2c11c1b72ff47e6c5ccb2134a7ea86da8cabc028 Mon Sep 17 00:00:00 2001 +From: John Wagenleitner <[email protected]> +Date: Sun, 13 Aug 2017 17:15:00 -0700 +Subject: [PATCH] GROOVY-8249: Newify local variable declaration fails to + resolve class expression + +--- + .../groovy/classgen/VariableScopeVisitor.java | 1 + + .../groovy/transform/NewifyTransformTest.groovy | 24 ++++++++++++++++++++++ + 2 files changed, 25 insertions(+) + +diff --git a/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java +index 7a99014fed..f920211e32 100644 +--- a/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java ++++ b/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java +@@ -330,6 +330,7 @@ public void visitIfElse(IfStatement ifElse) { + } + + public void visitDeclarationExpression(DeclarationExpression expression) { ++ visitAnnotations(expression); + // visit right side first to avoid the usage of a + // variable before its declaration + expression.getRightExpression().visit(this); +diff --git a/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy b/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy +index d585c8a32c..c2cce48ef0 100644 +--- a/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy ++++ b/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy +@@ -211,4 +211,28 @@ class NewifyTransformTest extends GroovyShellTestCase { + assert Foo.answer == 42 + ''' + } ++ ++ // GROOVY-8249 ++ void testLocalVariableDeclResolvesClass() { ++ assertScript ''' ++ class A { ++ final int id ++ A(int id) { this.id = id + 10 } ++ } ++ class Foo { ++ static String test() { ++ @Newify(String) ++ String answer = String('bar') ++ answer ++ } ++ static int test2() { ++ @Newify(A) ++ int answer = A(32).id ++ answer ++ } ++ } ++ assert Foo.test() == 'bar' ++ assert Foo.test2() == 42 ++ ''' ++ } + } +\ No newline at end of file http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr597.patch ---------------------------------------------------------------------- diff --git a/pr597.patch b/pr597.patch new file mode 100644 index 0000000..3678787 --- /dev/null +++ b/pr597.patch @@ -0,0 +1,26 @@ +From 9740919cee991a573a45e288f8aa7d4490dfcc4f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Aur=C3=A9lien=20Pupier?= <[email protected]> +Date: Wed, 30 Aug 2017 17:39:44 +0200 +Subject: [PATCH] GROOVY-8305: Fix default Ivy settings file for local m2 path +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Aurélien Pupier <[email protected]> +--- + src/resources/groovy/grape/defaultGrapeConfig.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resources/groovy/grape/defaultGrapeConfig.xml b/src/resources/groovy/grape/defaultGrapeConfig.xml +index 11161d37f4..a9f03062af 100644 +--- a/src/resources/groovy/grape/defaultGrapeConfig.xml ++++ b/src/resources/groovy/grape/defaultGrapeConfig.xml +@@ -26,7 +26,7 @@ + <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/> + <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision](-[classifier]).[ext]"/> + </filesystem> +- <ibiblio name="localm2" root="file:${user.home}/.m2/repository/" checkmodified="true" changingPattern=".*" changingMatcher="regexp" m2compatible="true"/> ++ <ibiblio name="localm2" root="file:/${user.home}/.m2/repository/" checkmodified="true" changingPattern=".*" changingMatcher="regexp" m2compatible="true"/> + <!-- todo add 'endorsed groovy extensions' resolver here --> + <ibiblio name="jcenter" root="https://jcenter.bintray.com/" m2compatible="true"/> + <ibiblio name="ibiblio" m2compatible="true"/> http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr603.patch ---------------------------------------------------------------------- diff --git a/pr603.patch b/pr603.patch new file mode 100644 index 0000000..db060a1 --- /dev/null +++ b/pr603.patch @@ -0,0 +1,102 @@ +From e8fd90ae974fa97817682c1c4f8936feef2d2a66 Mon Sep 17 00:00:00 2001 +From: paulk <[email protected]> +Date: Mon, 18 Sep 2017 13:37:59 +1000 +Subject: [PATCH] GROOVY-8260: Static compilation requires casting inside + instanceof check + +--- + .../transform/stc/StaticTypeCheckingVisitor.java | 14 ++++-- + src/test/groovy/bugs/Groovy8260Bug.groovy | 57 ++++++++++++++++++++++ + 2 files changed, 67 insertions(+), 4 deletions(-) + create mode 100644 src/test/groovy/bugs/Groovy8260Bug.groovy + +diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +index 12ea2b50f2..8c66eb7b9d 100644 +--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java ++++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +@@ -4018,12 +4018,18 @@ protected ClassNode getType(ASTNode exp) { + } + if (variable instanceof Parameter) { + Parameter parameter = (Parameter) variable; +- ClassNode type = typeCheckingContext.controlStructureVariables.get(parameter); ++ ClassNode type = null; ++ // check if param part of control structure - but not if inside instanceof ++ List<ClassNode> temporaryTypesForExpression = getTemporaryTypesForExpression(vexp); ++ if (temporaryTypesForExpression == null || temporaryTypesForExpression.isEmpty()) { ++ type = typeCheckingContext.controlStructureVariables.get(parameter); ++ } ++ // now check for closure override + TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure(); +- ClassNode[] closureParamTypes = (ClassNode[])(enclosingClosure!=null?enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS):null); +- if (type==null && enclosingClosure !=null && "it".equals(variable.getName()) && closureParamTypes!=null) { ++ ClassNode[] closureParamTypes = (ClassNode[]) (enclosingClosure != null ? enclosingClosure.getClosureExpression().getNodeMetaData(StaticTypesMarker.CLOSURE_ARGUMENTS) : null); ++ if (type == null && enclosingClosure != null && "it".equals(variable.getName()) && closureParamTypes != null) { + final Parameter[] parameters = enclosingClosure.getClosureExpression().getParameters(); +- if (parameters.length==0 && getTemporaryTypesForExpression(vexp)==null && closureParamTypes.length!=0) { ++ if (parameters.length == 0 && temporaryTypesForExpression == null && closureParamTypes.length != 0) { + type = closureParamTypes[0]; + } + } +diff --git a/src/test/groovy/bugs/Groovy8260Bug.groovy b/src/test/groovy/bugs/Groovy8260Bug.groovy +new file mode 100644 +index 0000000000..e69d68bdd3 +--- /dev/null ++++ b/src/test/groovy/bugs/Groovy8260Bug.groovy +@@ -0,0 +1,57 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one ++ * or more contributor license agreements. See the NOTICE file ++ * distributed with this work for additional information ++ * regarding copyright ownership. The ASF licenses this file ++ * to you under the Apache License, Version 2.0 (the ++ * "License"); you may not use this file except in compliance ++ * with the License. You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, ++ * software distributed under the License is distributed on an ++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ++ * KIND, either express or implied. See the License for the ++ * specific language governing permissions and limitations ++ * under the License. ++ */ ++package groovy.bugs ++ ++class Groovy8260Bug extends GroovyTestCase { ++ ++ void testNoCastForInstanceofInsideLoop() { ++ assertScript ''' ++ import groovy.transform.CompileStatic ++ ++ interface FooI { ++ def intfMethod() ++ } ++ ++ class Foo implements FooI { ++ def intfMethod() { 'Foo Interface method' } ++ def implMethod() { 'Foo Implementation method' } ++ } ++ ++ @CompileStatic ++ def method(FooI propIn, List result) { ++ if (propIn instanceof Foo) { ++ result << propIn.implMethod() ++ } else { ++ result << propIn?.intfMethod() ++ } ++ for (FooI propLoop : [null, new Foo()]) { ++ result << propLoop?.intfMethod() ++ if (propLoop instanceof Foo) { ++ result << propLoop.implMethod() ++ } ++ } ++ } ++ ++ def result = [] ++ method(null, result) ++ assert result == [null, null, 'Foo Interface method', 'Foo Implementation method'] ++ ''' ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/groovy/blob/13522f88/pr607.patch ---------------------------------------------------------------------- diff --git a/pr607.patch b/pr607.patch new file mode 100644 index 0000000..8a5206b --- /dev/null +++ b/pr607.patch @@ -0,0 +1,60 @@ +From f30d2e5dd6ce8045eb6656d1993f0dd9b07edfc5 Mon Sep 17 00:00:00 2001 +From: "alexey.afanasiev" <[email protected]> +Date: Tue, 26 Sep 2017 17:43:15 +0300 +Subject: [PATCH] GROOVY-8330: Wrong 'Inconvertible types' error on casting + interface + +--- + .../transform/stc/StaticTypeCheckingVisitor.java | 2 ++ + .../groovy/transform/stc/STCAssignmentTest.groovy | 26 ++++++++++++++++++++++ + 2 files changed, 28 insertions(+) + +diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +index cbb2798470..4c55eeafb8 100644 +--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java ++++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java +@@ -3369,6 +3369,8 @@ protected boolean checkCast(final ClassNode targetType, final Expression source) + return false; + } else if ((expressionType.getModifiers()& Opcodes.ACC_FINAL)==0 && targetType.isInterface()) { + return true; ++ } else if ((targetType.getModifiers()& Opcodes.ACC_FINAL)==0 && expressionType.isInterface()) { ++ return true; + } else if (!isAssignableTo(targetType, expressionType) && !implementsInterfaceOrIsSubclassOf(expressionType, targetType)) { + return false; + } +diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy +index 3c00185b90..acb1c7532b 100644 +--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy ++++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy +@@ -872,5 +872,31 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase { + } + ''' + } ++ ++ void testNarrowingConversion() { ++ assertScript ''' ++ interface A1{} ++ interface A2 extends A1{} ++ ++ class C1 implements A1{} ++ ++ def m(A2 a2) { ++ C1 c1 = (C1) a2 ++ } ++ ''' ++ } ++ ++ void testFinalNarrowingConversion() { ++ shouldFailWithMessages ''' ++ interface A1{} ++ interface A2 extends A1{} ++ ++ final class C1 implements A1{} ++ ++ def m(A2 a2) { ++ C1 c1 = (C1) a2 ++ } ++ ''', "Inconvertible types: cannot cast A2 to C1" ++ } + } +
