This is an automated email from the ASF dual-hosted git repository. emilles pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push: new 65ce840a7c GROOVY-11348: STC: check loss of precision for `(short) 1234` literals 65ce840a7c is described below commit 65ce840a7cde7460637e52b716d20741cf1d2f77 Author: Eric Milles <eric.mil...@thomsonreuters.com> AuthorDate: Tue Jul 9 12:33:01 2024 -0500 GROOVY-11348: STC: check loss of precision for `(short) 1234` literals --- .../transform/stc/StaticTypeCheckingSupport.java | 105 ++++++++++----------- .../groovy/transform/stc/STCAssignmentTest.groovy | 80 ++++++++++------ 2 files changed, 101 insertions(+), 84 deletions(-) diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java index 4714beb24e..286283a4ec 100644 --- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java +++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java @@ -767,74 +767,65 @@ public abstract class StaticTypeCheckingSupport { return (node.getCompileUnit() != null); } - @Deprecated(forRemoval = true, since = "3.0.0") - static boolean checkPossibleLooseOfPrecision(final ClassNode left, final ClassNode right, final Expression rightExpr) { - return checkPossibleLossOfPrecision(left, right, rightExpr); - } - static boolean checkPossibleLossOfPrecision(final ClassNode left, final ClassNode right, final Expression rightExpr) { if (left == right || left.equals(right)) return false; // identical types int leftIndex = NUMBER_TYPES.get(left); int rightIndex = NUMBER_TYPES.get(right); if (leftIndex >= rightIndex) return false; - // here we must check if the right number is short enough to fit in the left type - if (rightExpr instanceof ConstantExpression) { - Object value = ((ConstantExpression) rightExpr).getValue(); - if (!(value instanceof Number)) return true; + + // check if the right number will fit in the left type + Expression valueExpr = rightExpr; + if (valueExpr instanceof CastExpression) // "(short) 1234" + valueExpr = ((CastExpression) valueExpr).getExpression(); + if (valueExpr instanceof ConstantExpression) { + Object value = ((ConstantExpression) valueExpr).getValue(); + if (!(value instanceof Number)) return true; // null or ... Number number = (Number) value; switch (leftIndex) { - case 0: { // byte - byte val = number.byteValue(); - if (number instanceof Short) { - return !Short.valueOf(val).equals(number); - } - if (number instanceof Integer) { - return !Integer.valueOf(val).equals(number); - } - if (number instanceof Long) { - return !Long.valueOf(val).equals(number); - } - if (number instanceof Float) { - return !Float.valueOf(val).equals(number); - } - return !Double.valueOf(val).equals(number); + case 0: // byte + switch (rightIndex) { + case 1: + return Short .compare(number.byteValue(), number. shortValue()) != 0; + case 2: + return Integer.compare(number.byteValue(), number. intValue()) != 0; + case 3: + return Long .compare(number.byteValue(), number. longValue()) != 0; + case 4: + return Float .compare(number.byteValue(), number. floatValue()) != 0; + default: + return Double .compare(number.byteValue(), number.doubleValue()) != 0; } - case 1: { // short - short val = number.shortValue(); - if (number instanceof Integer) { - return !Integer.valueOf(val).equals(number); - } - if (number instanceof Long) { - return !Long.valueOf(val).equals(number); - } - if (number instanceof Float) { - return !Float.valueOf(val).equals(number); - } - return !Double.valueOf(val).equals(number); + case 1: // short + switch (rightIndex) { + case 2: + return Integer.compare(number.shortValue(), number. intValue()) != 0; + case 3: + return Long .compare(number.shortValue(), number. longValue()) != 0; + case 4: + return Float .compare(number.shortValue(), number. floatValue()) != 0; + default: + return Double .compare(number.shortValue(), number.doubleValue()) != 0; } - case 2: { // integer - int val = number.intValue(); - if (number instanceof Long) { - return !Long.valueOf(val).equals(number); - } - if (number instanceof Float) { - return !Float.valueOf(val).equals(number); - } - return !Double.valueOf(val).equals(number); - } - case 3: { // long - long val = number.longValue(); - if (number instanceof Float) { - return !Float.valueOf(val).equals(number); - } - return !Double.valueOf(val).equals(number); + case 2: // int + switch (rightIndex) { + case 3: + return Long .compare(number.intValue(), number. longValue()) != 0; + case 4: + return Float .compare(number.intValue(), number. floatValue()) != 0; + default: + return Double.compare(number.intValue(), number.doubleValue()) != 0; } - case 4: { // float - float val = number.floatValue(); - return !Double.valueOf(val).equals(number); + case 3: // long + switch (rightIndex) { + case 4: + return Float .compare(number.longValue(), number. floatValue()) != 0; + default: + return Double.compare(number.longValue(), number.doubleValue()) != 0; } - default: // double - return false; // no possible loss here + case 4: // float + return Double.compare(number.floatValue(), number.doubleValue()) != 0; + default: // double + return false; // no possible loss here } } return true; // possible loss of precision diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy index db6e5e1bbd..8df0dec4ae 100644 --- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy +++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy @@ -107,6 +107,30 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase { ''' } + void testAssignmentToNumbers() { + for (type in ['byte','short','int','long','float','double', + 'java.lang.Byte','java.lang.Short','java.lang.Integer', + 'java.lang.Long','java.lang.Float','java.lang.Double']) { + boolean primitive = !type.contains('.') + shouldFailWithMessages """ + $type x = 0 + x = (byte)1 + x = (char)2 // cannot assign + x =(short)3 // possible loss -- GROOVY-11348 + x = 4 + x = 5L + x = 6f + x = 7d + x = 8g // cannot assign + //x = 9.0g // okay for float and double + x = (Number)10 + """, + "Cannot assign value of type ${primitive ? 'char' : 'java.lang.Character'} to variable of type $type", + "Cannot assign value of type java.math.BigInteger to variable of type $type", + "Cannot assign value of type java.lang.Number to variable of type $type" + } + } + void testAssignmentToBoolean() { assertScript ''' boolean b = new Object() @@ -219,70 +243,72 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase { } void testPossibleLossOfPrecision1() { - shouldFailWithMessages ''' - long a = Long.MAX_VALUE - int b = a - ''', - 'Possible loss of precision from long to int' - } - - void testPossibleLossOfPrecision2() { - assertScript ''' - int b = 0L - ''' - } - - void testPossibleLossOfPrecision3() { assertScript ''' byte b = 127 ''' } - void testPossibleLossOfPrecision4() { + void testPossibleLossOfPrecision2() { shouldFailWithMessages ''' byte b = 128 // will not fit in a byte ''', 'Possible loss of precision from int to byte' } - void testPossibleLossOfPrecision5() { + void testPossibleLossOfPrecision3() { assertScript ''' - short b = 128 + short s = 128 ''' } - void testPossibleLossOfPrecision6() { + void testPossibleLossOfPrecision4() { shouldFailWithMessages ''' - short b = 32768 // will not fit in a short + short s = 32768 // will not fit in a short ''', 'Possible loss of precision from int to short' } - void testPossibleLossOfPrecision7() { + void testPossibleLossOfPrecision5() { assertScript ''' - int b = 32768L // mark it as a long, but it fits into an int + int i = 32768L // mark it as a long, but it fits into an int ''' } - void testPossibleLossOfPrecision8() { + void testPossibleLossOfPrecision6() { assertScript ''' - int b = 32768.0f // mark it as a float, but it fits into an int + int i = 32768f // mark it as a float, but it fits into an int ''' } - void testPossibleLossOfPrecision9() { + void testPossibleLossOfPrecision7() { assertScript ''' - int b = 32768.0d // mark it as a double, but it fits into an int + int i = 32768d // mark it as a double, but it fits into an int ''' } - void testPossibleLossOfPrecision10() { + void testPossibleLossOfPrecision8() { shouldFailWithMessages ''' - int b = 32768.1d + int i = 32768.1d ''', 'Possible loss of precision from double to int' } + void testPossibleLossOfPrecision9() { + shouldFailWithMessages ''' + int i = Long.MAX_VALUE + ''', + 'Possible loss of precision from long to int' + } + + void testPossibleLossOfPrecision10() { + assertScript ''' + byte b = 0L + short s = 0L + int i = 0L + float f = 0L + ''' + } + //-------------------------------------------------------------------------- void testPlusEqualsOnInt() {