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

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

commit ce304c48f60cad12c0721e6bf000ef5e3a938c6d
Author: Eric Milles <eric.mil...@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   |  8 ++
 .../groovy/control/InstanceOfVerifier.java         | 58 +++++++++++++
 .../java/org/codehaus/groovy/syntax/Types.java     |  4 +
 src/test/groovy/bugs/Groovy9270.groovy             | 96 ++++++++++++++++++++++
 4 files changed, 166 insertions(+)

diff --git a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java 
b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
index 14847e7..7d476b7 100644
--- a/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/java/org/codehaus/groovy/control/CompilationUnit.java
@@ -802,6 +802,14 @@ public class CompilationUnit extends ProcessingUnit {
             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);
 
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 26e12b9..0464dc6 100644
--- a/src/main/java/org/codehaus/groovy/syntax/Types.java
+++ b/src/main/java/org/codehaus/groovy/syntax/Types.java
@@ -304,6 +304,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, 
!instanceof
 
     public static final int PREFIX_OPERATOR = 1200;  // ++, !, etc.
     public static final int POSTFIX_OPERATOR = 1210;  // ++, etc.
@@ -414,6 +415,9 @@ public class Types {
             case COMPARISON_OPERATOR:
                 return specific >= COMPARE_NOT_EQUAL && specific <= COMPARE_TO;
 
+            case INSTANCEOF_OPERATOR:
+                return specific == KEYWORD_INSTANCEOF || specific == 
COMPARE_NOT_INSTANCEOF;
+
             case MATH_OPERATOR:
                 return (specific >= PLUS && specific <= RIGHT_SHIFT_UNSIGNED) 
|| (specific >= NOT && specific <= LOGICAL_AND)
                         || (specific >= BITWISE_OR && specific <= BITWISE_XOR);
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/
+    }
+}

Reply via email to