You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/11/12 04:19:18 UTC

[groovy] branch GROOVY_2_5_X updated (6d10b79 -> 91838d1)

This is an automated email from the ASF dual-hosted git repository.

paulk pushed a change to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git.


    from 6d10b79  GROOVY-6996: adjust 6834 workaround to apply to synthetic variables only
     new e9e20f7  GROOVY-9244: prevent ambiguous constructor if using @InheritConstructors
     new 897ca06  GROOVY-9240: relax signature of RGM.traverse(File, Map, ...)
     new 91838d1  GROOVY-9270: add checks for invalid instanceof reference types

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../codehaus/groovy/control/CompilationUnit.java   |  24 +++--
 .../groovy/control/InstanceOfVerifier.java         |  58 ++++++++++
 .../groovy/runtime/ResourceGroovyMethods.java      |  30 ++++--
 .../java/org/codehaus/groovy/syntax/Types.java     |  12 +--
 .../InheritConstructorsASTTransformation.java      |  38 +++----
 .../bugs/{Groovy9136.groovy => Groovy9240.groovy}  |  29 +++--
 src/test/groovy/bugs/Groovy9244.groovy             | 117 +++++++++++++++++++++
 src/test/groovy/bugs/Groovy9270.groovy             |  96 +++++++++++++++++
 8 files changed, 343 insertions(+), 61 deletions(-)
 create mode 100644 src/main/java/org/codehaus/groovy/control/InstanceOfVerifier.java
 copy src/test/groovy/bugs/{Groovy9136.groovy => Groovy9240.groovy} (61%)
 create mode 100644 src/test/groovy/bugs/Groovy9244.groovy
 create mode 100644 src/test/groovy/bugs/Groovy9270.groovy


[groovy] 01/03: GROOVY-9244: prevent ambiguous constructor if using @InheritConstructors

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit e9e20f795a67724b571ebaf8738c51ac548fbecc
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Oct 4 11:18:56 2019 -0500

    GROOVY-9244: prevent ambiguous constructor if using @InheritConstructors
    
        class Base {
          Base(Number n) {}
          Base(String s) {}
        }
        @groovy.transform.InheritConstructors
        class Impl {
        }
        new Impl((String) null) // should trigger Base(String)
---
 .../InheritConstructorsASTTransformation.java      |  38 +++----
 src/test/groovy/bugs/Groovy9244.groovy             | 117 +++++++++++++++++++++
 2 files changed, 133 insertions(+), 22 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
index 42f95f9..8333930 100644
--- a/src/main/java/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
@@ -38,6 +38,7 @@ import static org.apache.groovy.ast.tools.ClassNodeUtils.addGeneratedConstructor
 import static org.codehaus.groovy.ast.ClassHelper.make;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.castX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorSuperS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
@@ -51,31 +52,28 @@ import static org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGener
 @GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
 public class InheritConstructorsASTTransformation extends AbstractASTTransformation {
 
-    private static final Class MY_CLASS = InheritConstructors.class;
-    private static final ClassNode MY_TYPE = make(MY_CLASS);
-    private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
+    private static final ClassNode INHERIT_CONSTRUCTORS_TYPE = make(InheritConstructors.class);
+    private static final String ANNOTATION = "@" + INHERIT_CONSTRUCTORS_TYPE.getNameWithoutPackage();
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         init(nodes, source);
-        AnnotatedNode parent = (AnnotatedNode) nodes[1];
-        AnnotationNode node = (AnnotationNode) nodes[0];
-        if (!MY_TYPE.equals(node.getClassNode())) return;
-
-        if (parent instanceof ClassNode) {
-            processClass((ClassNode) parent, node);
+        AnnotationNode anno = (AnnotationNode) nodes[0];
+        AnnotatedNode target = (AnnotatedNode) nodes[1];
+        if (INHERIT_CONSTRUCTORS_TYPE.equals(anno.getClassNode()) && target instanceof ClassNode) {
+            processClass((ClassNode) target, anno);
         }
     }
 
     private void processClass(ClassNode cNode, AnnotationNode node) {
         if (cNode.isInterface()) {
             addError("Error processing interface '" + cNode.getName() +
-                    "'. " + MY_TYPE_NAME + " only allowed for classes.", cNode);
+                    "'. " + ANNOTATION + " only allowed for classes.", cNode);
             return;
         }
         boolean copyConstructorAnnotations = memberHasValue(node, "constructorAnnotations", true);
         boolean copyParameterAnnotations = memberHasValue(node, "parameterAnnotations", true);
         ClassNode sNode = cNode.getSuperClass();
-        List<AnnotationNode> superAnnotations = sNode.getAnnotations(MY_TYPE);
+        List<AnnotationNode> superAnnotations = sNode.getAnnotations(INHERIT_CONSTRUCTORS_TYPE);
         if (superAnnotations.size() == 1) {
             // We need @InheritConstructors from parent classes processed first
             // so force that order here. The transformation is benign on an already
@@ -98,31 +96,27 @@ public class InheritConstructorsASTTransformation extends AbstractASTTransformat
         if (isExisting(classNode, params)) return;
         ConstructorNode added = addGeneratedConstructor(classNode, consNode.getModifiers(), params, consNode.getExceptions(), block(ctorSuperS(args(theArgs))));
         if (copyConstructorAnnotations) {
-            added.addAnnotations(copyAnnotatedNodeAnnotations(consNode, MY_TYPE_NAME));
+            added.addAnnotations(copyAnnotatedNodeAnnotations(consNode, ANNOTATION));
         }
     }
 
     private List<Expression> buildParams(Parameter[] origParams, Parameter[] params, Map<String, ClassNode> genericsSpec, boolean copyParameterAnnotations) {
-        List<Expression> theArgs = new ArrayList<Expression>();
-        for (int i = 0; i < origParams.length; i++) {
+        List<Expression> theArgs = new ArrayList<>();
+        for (int i = 0, n = origParams.length; i < n; i += 1) {
             Parameter p = origParams[i];
             ClassNode newType = correctToGenericsSpecRecurse(genericsSpec, p.getType());
             params[i] = p.hasInitialExpression() ? param(newType, p.getName(), p.getInitialExpression()) : param(newType, p.getName());
             if (copyParameterAnnotations) {
-                params[i].addAnnotations(copyAnnotatedNodeAnnotations(origParams[i], MY_TYPE_NAME));
+                params[i].addAnnotations(copyAnnotatedNodeAnnotations(origParams[i], ANNOTATION));
             }
-            theArgs.add(varX(p.getName(), newType));
+            // cast argument to parameter type in case the value is null
+            theArgs.add(castX(p.getType(), varX(p.getName(), newType)));
         }
         return theArgs;
     }
 
     private static boolean isExisting(ClassNode classNode, Parameter[] params) {
-        for (ConstructorNode consNode : classNode.getDeclaredConstructors()) {
-            if (matchingTypes(params, consNode.getParameters())) {
-                return true;
-            }
-        }
-        return false;
+        return classNode.getDeclaredConstructors().stream().anyMatch(ctor -> matchingTypes(params, ctor.getParameters()));
     }
 
     private static boolean matchingTypes(Parameter[] params, Parameter[] existingParams) {
diff --git a/src/test/groovy/bugs/Groovy9244.groovy b/src/test/groovy/bugs/Groovy9244.groovy
new file mode 100644
index 0000000..3ce3235
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9244.groovy
@@ -0,0 +1,117 @@
+/*
+ *  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
+
+import groovy.test.NotYetImplemented
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+final class Groovy9244 {
+
+    @Test
+    void testSuperConstructorsAndNullArgument1() {
+        assertScript '''
+            abstract class Base {
+                Base(Number n) { which = 'Number' }
+                Base(String s) { which = 'String' }
+                public String which
+            }
+
+            class Impl extends Base {
+                Impl(Number n) { super((Number) n) }
+                Impl(String s) { super((String) s) }
+            }
+
+            def impl = new Impl((String) null)
+            assert impl.which == 'String'
+        '''
+    }
+
+    @Test
+    void testSuperConstructorsAndNullArgument2() {
+        assertScript '''
+            abstract class Base {
+                Base(Number n) { which = 'Number' }
+                Base(String s) { which = 'String' }
+                public String which
+            }
+
+            @groovy.transform.CompileStatic
+            class Impl extends Base {
+                Impl(Number n) { super(n) }
+                Impl(String s) { super(s) }
+            }
+
+            def impl = new Impl((String) null)
+            assert impl.which == 'String'
+        '''
+    }
+
+    @Test
+    void testSuperConstructorsAndNullArgument3() {
+        assertScript '''
+            abstract class Base {
+                Base(Number n) { which = 'Number' }
+                Base(String s) { which = 'String' }
+                public String which
+            }
+
+            @groovy.transform.InheritConstructors
+            class Impl extends Base {
+            }
+
+            def impl = new Impl((String) null)
+            assert impl.which == 'String'
+        '''
+    }
+
+    @Test @NotYetImplemented
+    void testSuperConstructorsAndNullArgument4() {
+        assertScript '''
+            abstract class Base {
+                Base(Number n) { which = 'Number' }
+                Base(String s) { which = 'String' }
+                public String which
+            }
+
+            class Impl extends Base {
+                Impl(Number n) { super(n) }
+                Impl(String s) { super(s) }
+            }
+
+            def impl = new Impl((String) null)
+            assert impl.which == 'String'
+        '''
+    }
+
+    @Test @NotYetImplemented
+    void testSuperConstructorsAndNullArgument5() {
+        assertScript '''
+            abstract class Base {
+                Base(Number n) { which = 'Number' }
+                Base(String s) { which = 'String' }
+                public String which
+            }
+
+            def impl = new Base((String) null) {}
+            assert iompl.which == 'String'
+        '''
+    }
+}


[groovy] 03/03: GROOVY-9270: add checks for invalid instanceof reference types

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 91838d121b06196217753647e032633762479ea8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Oct 7 14:16:13 2019 -0500

    GROOVY-9270: add checks for invalid instanceof reference types
    
    http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.20.2
---
 .../codehaus/groovy/control/CompilationUnit.java   | 24 ++++--
 .../groovy/control/InstanceOfVerifier.java         | 58 +++++++++++++
 .../java/org/codehaus/groovy/syntax/Types.java     | 12 ++-
 src/test/groovy/bugs/Groovy9270.groovy             | 96 ++++++++++++++++++++++
 4 files changed, 177 insertions(+), 13 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 0aa7372..293403b 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -26,6 +26,7 @@ import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CompileUnit;
+import org.codehaus.groovy.ast.GroovyClassVisitor;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
@@ -810,8 +811,19 @@ public class CompilationUnit extends ProcessingUnit {
                 );
             }
 
-            LabelVerifier lv = new LabelVerifier(source);
-            lv.visitClass(classNode);
+            GroovyClassVisitor visitor = new LabelVerifier(source);
+            visitor.visitClass(classNode);
+
+            visitor = new InstanceOfVerifier() {
+                @Override
+                protected SourceUnit getSourceUnit() {
+                    return source;
+                }
+            };
+            visitor.visitClass(classNode);
+
+            visitor = new ClassCompletionVerifier(source);
+            visitor.visitClass(classNode);
 
             ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source);
             completionVerifier.visitClass(classNode);
@@ -826,7 +838,7 @@ public class CompilationUnit extends ProcessingUnit {
             //
             // Prep the generator machinery
             //
-            ClassVisitor visitor = createClassVisitor();
+            ClassVisitor classVisitor = createClassVisitor();
             
             String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
             // only show the file name and its extension like javac does in its stacktraces rather than the full path
@@ -835,21 +847,21 @@ public class CompilationUnit extends ProcessingUnit {
                 sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
             //TraceClassVisitor tracer = new TraceClassVisitor(visitor, new PrintWriter(System.err,true));
             //AsmClassGenerator generator = new AsmClassGenerator(source, context, tracer, sourceName);
-            AsmClassGenerator generator = new AsmClassGenerator(source, context, visitor, sourceName);
+            AsmClassGenerator generator = new AsmClassGenerator(source, context, classVisitor, sourceName);
 
             //
             // Run the generation and create the class (if required)
             //
             generator.visitClass(classNode);
 
-            byte[] bytes = ((ClassWriter) visitor).toByteArray();
+            byte[] bytes = ((ClassWriter) classVisitor).toByteArray();
             generatedClasses.add(new GroovyClass(classNode.getName(), bytes));
 
             //
             // Handle any callback that's been set
             //
             if (CompilationUnit.this.classgenCallback != null) {
-                classgenCallback.call(visitor, classNode);
+                classgenCallback.call(classVisitor, classNode);
             }
 
             //
diff --git a/src/main/java/org/codehaus/groovy/control/InstanceOfVerifier.java b/src/main/java/org/codehaus/groovy/control/InstanceOfVerifier.java
new file mode 100644
index 0000000..8eacaf2
--- /dev/null
+++ b/src/main/java/org/codehaus/groovy/control/InstanceOfVerifier.java
@@ -0,0 +1,58 @@
+/*
+ *  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 org.codehaus.groovy.control;
+
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.syntax.Types;
+
+public abstract class InstanceOfVerifier extends ClassCodeVisitorSupport {
+
+    @Override
+    public void visitBinaryExpression(BinaryExpression expression) {
+        if (expression.getOperation().isA(Types.INSTANCEOF_OPERATOR) &&
+                expression.getRightExpression() instanceof ClassExpression) {
+            ClassNode referenceType = expression.getRightExpression().getType();
+
+            if (ClassHelper.isPrimitiveType(referenceType)) {
+                addTypeError(expression.getRightExpression(), "primitive type " + referenceType.getName());
+            } else {
+                while (referenceType.isArray()) {
+                    referenceType = referenceType.getComponentType();
+                }
+
+                if (referenceType.isGenericsPlaceHolder()) {
+                    addTypeError(expression.getRightExpression(), "type parameter " + referenceType.getUnresolvedName() +
+                        ". Use its erasure " + referenceType.getNameWithoutPackage() + " instead since further generic type information will be erased at runtime");
+                } else if (referenceType.getGenericsTypes() != null) {
+                    // TODO: Cannot perform instanceof check against parameterized type Class<Type>. Use the form Class<?> instead since further eneric type information will be erased at runtime
+                }
+            }
+        }
+        super.visitBinaryExpression(expression);
+    }
+
+    private void addTypeError(Expression referenceExpr, String referenceType) {
+        addError("Cannot perform instanceof check against " + referenceType, referenceExpr);
+    }
+}
diff --git a/src/main/java/org/codehaus/groovy/syntax/Types.java b/src/main/java/org/codehaus/groovy/syntax/Types.java
index 3b2aa70..463efe8 100644
--- a/src/main/java/org/codehaus/groovy/syntax/Types.java
+++ b/src/main/java/org/codehaus/groovy/syntax/Types.java
@@ -301,6 +301,7 @@ public class Types  {
     public static final int REGEX_COMPARISON_OPERATOR   = 1105;  // =~, etc.
     public static final int DEREFERENCE_OPERATOR        = 1106;  // ., ->
     public static final int BITWISE_OPERATOR            = 1107;  // |, &, <<, >>, >>>, ^, ~
+    public static final int INSTANCEOF_OPERATOR         = 1108;  // instanceof
 
     public static final int PREFIX_OPERATOR             = 1200;  // ++, !, etc.
     public static final int POSTFIX_OPERATOR            = 1210;  // ++, etc.
@@ -343,8 +344,6 @@ public class Types  {
     public static final int SIMPLE_EXPRESSION           = 1910;  // LITERAL, this, true, false, null
     public static final int COMPLEX_EXPRESSION          = 1911;  // SIMPLE_EXPRESSION, and various molecules
 
-
-
     //
     // TYPE GROUPS (OPERATIONS SUPPORT)
 
@@ -361,14 +360,9 @@ public class Types  {
 
     public static final int PRECLUDES_CAST_OPERATOR     = 2008;  // anything that prevents (X) from being a cast
 
-
-
-
-
   //---------------------------------------------------------------------------
   // TYPE HIERARCHIES
 
-
    /**
     *  Given two types, returns true if the second describes the first.
     */
@@ -418,6 +412,9 @@ public class Types  {
             case COMPARISON_OPERATOR:
                 return specific >= COMPARE_NOT_EQUAL && specific <= COMPARE_TO;
 
+            case INSTANCEOF_OPERATOR:
+                return specific == KEYWORD_INSTANCEOF;
+
             case MATH_OPERATOR:
                 return (specific >= PLUS && specific <= RIGHT_SHIFT_UNSIGNED) || (specific >= NOT && specific <= LOGICAL_AND)
                                  || (specific >= BITWISE_OR && specific <= BITWISE_XOR);
@@ -1405,6 +1402,7 @@ public class Types  {
         addDescription( PREFIX_OPERATOR             , "<prefix operator>"            );
         addDescription( POSTFIX_OPERATOR            , "<postfix operator>"           );
         addDescription( INFIX_OPERATOR              , "<infix operator>"             );
+        addDescription( INSTANCEOF_OPERATOR         , "<instanceof operator>"        );
         addDescription( KEYWORD                     , "<keyword>"                    );
         addDescription( LITERAL                     , "<literal>"                    );
         addDescription( NUMBER                      , "<number>"                     );
diff --git a/src/test/groovy/bugs/Groovy9270.groovy b/src/test/groovy/bugs/Groovy9270.groovy
new file mode 100644
index 0000000..c4c794a
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9270.groovy
@@ -0,0 +1,96 @@
+/*
+ *  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
+
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+import static groovy.test.GroovyAssert.shouldFail
+
+@CompileStatic
+final class Groovy9270 {
+
+    @Test
+    void testInstanceOfPrimitive1() {
+        def err = shouldFail '''
+            void meth(obj) {
+                if (obj instanceof int) {
+                    // ...
+                }
+            }
+        '''
+
+        assert err =~ / Cannot perform instanceof check against primitive type int/
+    }
+
+    @Test
+    void testInstanceOfPrimitive2() {
+        def err = shouldFail '''
+            void meth(obj) {
+                if (obj !instanceof int) {
+                    // ...
+                }
+            }
+        '''
+
+        assert err =~ / Cannot perform instanceof check against primitive type int/
+    }
+
+    @Test
+    void testInstanceOfPrimitiveArray() {
+        assertScript '''
+            void meth(obj) {
+                if (obj instanceof double[]) {
+                    // ...
+                }
+            }
+        '''
+    }
+
+    @Test
+    void testInstanceOfTypeParameter1() {
+        def err = shouldFail '''
+            class C<T extends Number> {
+                void meth(obj) {
+                    if (obj instanceof T) {
+                        // ...
+                    }
+                }
+            }
+        '''
+
+        assert err =~ / Cannot perform instanceof check against type parameter T/
+    }
+
+    @Test
+    void testInstanceOfTypeParameter2() {
+        def err = shouldFail '''
+            class C<T> {
+                void meth(obj) {
+                    if (obj instanceof T[]) {
+                        // ...
+                    }
+                }
+            }
+        '''
+
+        assert err =~ / Cannot perform instanceof check against type parameter T/
+    }
+}


[groovy] 02/03: GROOVY-9240: relax signature of RGM.traverse(File, Map, ...)

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk pushed a commit to branch GROOVY_2_5_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 897ca066607603b871524c1843e20ae1d8672ea8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Aug 30 13:54:17 2019 -0500

    GROOVY-9240: relax signature of RGM.traverse(File, Map, ...)
---
 .../groovy/runtime/ResourceGroovyMethods.java      | 30 ++++++++++-----
 src/test/groovy/bugs/Groovy9240.groovy             | 43 ++++++++++++++++++++++
 2 files changed, 63 insertions(+), 10 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
index 647f47d..9f59c91 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
@@ -69,8 +69,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
 
-import static org.codehaus.groovy.runtime.DefaultGroovyMethods.get;
-
 /**
  * This class defines new groovy methods for Readers, Writers, InputStreams and
  * OutputStreams which appear on normal JDK classes inside the Groovy environment.
@@ -1310,13 +1308,24 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see groovy.io.FileType
      * @since 1.7.1
      */
-    public static void traverse(final File self, final Map<String, Object> options, @ClosureParams(value = SimpleType.class, options = "java.io.File") final Closure closure)
+    public static void traverse(final File self, final Map<String, ?> options, @ClosureParams(value = SimpleType.class, options = "java.io.File") final Closure closure)
             throws FileNotFoundException, IllegalArgumentException {
-        Number maxDepthNumber = DefaultGroovyMethods.asType(options.remove("maxDepth"), Number.class);
-        int maxDepth = maxDepthNumber == null ? -1 : maxDepthNumber.intValue();
-        Boolean visitRoot = DefaultGroovyMethods.asType(get(options, "visitRoot", false), Boolean.class);
-        Boolean preRoot = DefaultGroovyMethods.asType(get(options, "preRoot", false), Boolean.class);
-        Boolean postRoot = DefaultGroovyMethods.asType(get(options, "postRoot", false), Boolean.class);
+        final int maxDepth;
+        final boolean preRoot;
+        final boolean postRoot;
+        final boolean visitRoot;
+
+        {
+            Object maxDepthValue = options.remove("maxDepth");
+            maxDepth = maxDepthValue == null ? -1 : DefaultGroovyMethods.asType(maxDepthValue, Number.class).intValue();
+            Object preRootValue = options.get("preRoot");
+            preRoot = preRootValue == null ? false : DefaultGroovyMethods.asType(preRootValue, Boolean.class).booleanValue();
+            Object postRootValue = options.get("postRoot");
+            postRoot = postRootValue == null ? false : DefaultGroovyMethods.asType(postRootValue, Boolean.class).booleanValue();
+            Object visitRootValue = options.get("visitRoot");
+            visitRoot = visitRootValue == null ? false : DefaultGroovyMethods.asType(visitRootValue, Boolean.class).booleanValue();
+        }
+
         final Closure pre = (Closure) options.get("preDir");
         final Closure post = (Closure) options.get("postDir");
         final FileType type = (FileType) options.get("type");
@@ -1324,6 +1333,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
         final Object nameFilter = options.get("nameFilter");
         final Object excludeFilter = options.get("excludeFilter");
         final Object excludeNameFilter = options.get("excludeNameFilter");
+
         Object preResult = null;
         if (preRoot && pre != null) {
             preResult = pre.call(self);
@@ -1405,13 +1415,13 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #traverse(java.io.File, java.util.Map, groovy.lang.Closure)
      * @since 1.7.1
      */
-    public static void traverse(final File self, final Map<String, Object> options)
+    public static void traverse(final File self, final Map<String, ?> options)
             throws FileNotFoundException, IllegalArgumentException {
         final Closure visit = (Closure) options.remove("visit");
         traverse(self, options, visit);
     }
 
-    private static FileVisitResult traverse(final File self, final Map<String, Object> options, final Closure closure, final int maxDepth)
+    private static FileVisitResult traverse(final File self, final Map<String, ?> options, final Closure closure, final int maxDepth)
             throws FileNotFoundException, IllegalArgumentException {
         checkDir(self);
         final Closure pre = (Closure) options.get("preDir");
diff --git a/src/test/groovy/bugs/Groovy9240.groovy b/src/test/groovy/bugs/Groovy9240.groovy
new file mode 100644
index 0000000..c25f045
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9240.groovy
@@ -0,0 +1,43 @@
+/*
+ *  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
+
+import groovy.transform.CompileStatic
+import org.junit.Test
+
+import static groovy.test.GroovyAssert.assertScript
+
+@CompileStatic
+final class Groovy9240 {
+
+    @Test
+    void testTraverse() {
+        assertScript '''
+            @groovy.transform.CompileStatic
+            void meth(File folder) {
+                // was: [Static type checking] - Cannot call java.io.File#traverse(java.util.Map <java.lang.String, java.lang.Object>, groovy.lang.Closure) with arguments [java.util.LinkedHashMap <java.lang.String, java.io.Serializable>, groovy.lang.Closure]
+                folder.traverse([
+                    type: groovy.io.FileType.FILES,
+                    nameFilter: ~/.*\\.(?i)pdf/
+                ]) { println it }
+            }
+            meth(File.createTempDir())
+        '''
+    }
+}