You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2020/01/11 18:32:15 UTC

[groovy] 01/01: GROOVY-9336: integer target type for shift RHS in constant initializer

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

emilles pushed a commit to branch GROOVY-9336
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit b1c65ef23efa7b3039a306d84bea60358004c55b
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Jan 11 12:23:47 2020 -0600

    GROOVY-9336: integer target type for shift RHS in constant initializer
---
 .../apache/groovy/ast/tools/ExpressionUtils.java   | 52 +++++++++-------------
 src/test/groovy/bugs/Groovy9336.groovy             | 42 +++++++++++++++++
 2 files changed, 64 insertions(+), 30 deletions(-)

diff --git a/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java b/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java
index 349e469..648a295 100644
--- a/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java
+++ b/src/main/java/org/apache/groovy/ast/tools/ExpressionUtils.java
@@ -33,7 +33,7 @@ import org.codehaus.groovy.runtime.typehandling.NumberMath;
 
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
+import java.util.Arrays;
 
 import static org.codehaus.groovy.syntax.Types.BITWISE_AND;
 import static org.codehaus.groovy.syntax.Types.BITWISE_OR;
@@ -48,20 +48,13 @@ import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT;
 import static org.codehaus.groovy.syntax.Types.RIGHT_SHIFT_UNSIGNED;
 
 public class ExpressionUtils {
-    private static ArrayList<Integer> handledTypes = new ArrayList<Integer>();
-    static {
-        handledTypes.add(PLUS);
-        handledTypes.add(MINUS);
-        handledTypes.add(MULTIPLY);
-        handledTypes.add(DIVIDE);
-        handledTypes.add(LEFT_SHIFT);
-        handledTypes.add(RIGHT_SHIFT);
-        handledTypes.add(RIGHT_SHIFT_UNSIGNED);
-        handledTypes.add(BITWISE_OR);
-        handledTypes.add(BITWISE_AND);
-        handledTypes.add(BITWISE_XOR);
-        handledTypes.add(POWER);
-    }
+
+    // NOTE: values are sorted in ascending order
+    private static final int[] HANDLED_TYPES = {
+        PLUS, MINUS, MULTIPLY, DIVIDE, POWER,
+        LEFT_SHIFT, RIGHT_SHIFT, RIGHT_SHIFT_UNSIGNED,
+        BITWISE_OR, BITWISE_AND, BITWISE_XOR,
+    };
 
     private ExpressionUtils() {
     }
@@ -74,22 +67,22 @@ public class ExpressionUtils {
      * @param targetType the type of the result
      * @return the transformed expression or the original if no transformation was performed
      */
-    public static ConstantExpression transformBinaryConstantExpression(BinaryExpression be, ClassNode targetType) {
+    public static ConstantExpression transformBinaryConstantExpression(final BinaryExpression be, final ClassNode targetType) {
         ClassNode wrapperType = ClassHelper.getWrapper(targetType);
         if (isTypeOrArrayOfType(targetType, ClassHelper.STRING_TYPE, false)) {
             if (be.getOperation().getType() == PLUS) {
                 Expression left = transformInlineConstants(be.getLeftExpression(), targetType);
                 Expression right = transformInlineConstants(be.getRightExpression(), targetType);
                 if (left instanceof ConstantExpression && right instanceof ConstantExpression) {
-                    return configure(be, new ConstantExpression((String) ((ConstantExpression) left).getValue() +
-                            ((ConstantExpression) right).getValue()));
+                    return configure(be, new ConstantExpression((String) ((ConstantExpression) left).getValue() + ((ConstantExpression) right).getValue()));
                 }
             }
         } else if (isNumberOrArrayOfNumber(wrapperType, false)) {
             int type = be.getOperation().getType();
-            if (handledTypes.contains(type)) {
+            if (Arrays.binarySearch(HANDLED_TYPES, type) >= 0) {
+                boolean isShift = (type >= LEFT_SHIFT && type <= RIGHT_SHIFT_UNSIGNED);
                 Expression leftX = transformInlineConstants(be.getLeftExpression(), targetType);
-                Expression rightX = transformInlineConstants(be.getRightExpression(), targetType);
+                Expression rightX = transformInlineConstants(be.getRightExpression(), isShift ? ClassHelper.int_TYPE : targetType);
                 if (leftX instanceof ConstantExpression && rightX instanceof ConstantExpression) {
                     Number left = safeNumber((ConstantExpression) leftX);
                     Number right = safeNumber((ConstantExpression) rightX);
@@ -157,13 +150,13 @@ public class ExpressionUtils {
         return null;
     }
 
-    private static Number safeNumber(ConstantExpression constX) {
+    private static Number safeNumber(final ConstantExpression constX) {
         Object value = constX.getValue();
         if (value instanceof Number) return (Number) value;
         return null;
     }
 
-    private static ConstantExpression configure(Expression origX, ConstantExpression newX) {
+    private static ConstantExpression configure(final Expression origX, final ConstantExpression newX) {
         newX.setSourcePosition(origX);
         return newX;
     }
@@ -176,7 +169,7 @@ public class ExpressionUtils {
      * @param recurse true if we can have multi-dimension arrays; should be false for annotation member types
      * @return true if the type equals the targetType or array thereof
      */
-    public static boolean isTypeOrArrayOfType(ClassNode targetType, ClassNode type, boolean recurse) {
+    public static boolean isTypeOrArrayOfType(final ClassNode targetType, final ClassNode type, final boolean recurse) {
         if (targetType == null) return false;
         return type.equals(targetType) ||
                 (targetType.isArray() && recurse
@@ -191,7 +184,7 @@ public class ExpressionUtils {
      * @param recurse true if we can have multi-dimension arrays; should be false for annotation member types
      * @return true if the type equals the targetType or array thereof
      */
-    public static boolean isNumberOrArrayOfNumber(ClassNode targetType, boolean recurse) {
+    public static boolean isNumberOrArrayOfNumber(final ClassNode targetType, final boolean recurse) {
         if (targetType == null) return false;
         return targetType.isDerivedFrom(ClassHelper.Number_TYPE) ||
                 (targetType.isArray() && recurse
@@ -271,7 +264,7 @@ public class ExpressionUtils {
      * @param attrType the target type
      * @return the transformed list or the original if nothing was changed
      */
-    public static Expression transformListOfConstants(ListExpression origList, ClassNode attrType) {
+    public static Expression transformListOfConstants(final ListExpression origList, final ClassNode attrType) {
         ListExpression newList = new ListExpression();
         boolean changed = false;
         for (Expression e : origList.getExpressions()) {
@@ -336,11 +329,10 @@ public class ExpressionUtils {
         return exp;
     }
 
-    private static Expression findConstant(FieldNode fn) {
-        if (fn != null && !fn.isEnum() && fn.isStatic() && fn.isFinal()) {
-            if (fn.getInitialValueExpression() instanceof ConstantExpression) {
-                return fn.getInitialValueExpression();
-            }
+    private static Expression findConstant(final FieldNode fn) {
+        if (fn != null && !fn.isEnum() && fn.isStatic() && fn.isFinal()
+                && fn.getInitialValueExpression() instanceof ConstantExpression) {
+            return fn.getInitialValueExpression();
         }
         return null;
     }
diff --git a/src/test/groovy/bugs/Groovy9336.groovy b/src/test/groovy/bugs/Groovy9336.groovy
new file mode 100644
index 0000000..5aa837e
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy9336.groovy
@@ -0,0 +1,42 @@
+/*
+ *  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 Groovy9336 {
+
+    @Test
+    void testShiftInStaticFieldInitializer() {
+        assertScript '''
+            class Groovy9336 {
+                // initializer evaluated like (2 as double) << ((16 - 1) as double); need int on RHS
+                public static double N = 2 << 16 - 1
+
+                static main(args) {
+                    assert N == 65536.0d
+                }
+            }
+        '''
+    }
+}