From cefdfab87be2f8e058efebd6336d07b7696274ab Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 9 Jun 2017 12:23:33 +0200 Subject: [PATCH] IG: add option to ignore casts from int 128-255 to byte (IDEA-174125) --- .../siyeh/InspectionGadgetsBundle.properties | 5 +-- .../CastThatLosesPrecisionInspection.java | 32 ++++++++++++------- .../CastThatLosesPrecision.html | 5 +-- .../CastThatLosesPrecision.java | 29 +++++++++-------- .../CastThatLosesPrecisionInspectionTest.java | 19 ++++++++++- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 00491cad2657..db455067e1f3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1203,8 +1203,8 @@ normalize.declaration.quickfix=Split into multiple declarations remove.modifier.quickfix=Remove ''{0}'' modifier replace.inheritance.with.delegation.quickfix=Replace inheritance with delegation big.decimal.equals.replace.quickfix=Replace with 'compareTo()==0' -cast.that.loses.precision.problem.descriptor=Cast to #ref from ''{0}'' may result in loss of precision #loc -cast.that.loses.precision.negative.problem.descriptor=Cast to #ref from ''{0}'' may result in loss of precision #loc for negative argument +cast.that.loses.precision.problem.descriptor=Cast from ''{0}'' to #ref may result in loss of precision #loc +cast.that.loses.precision.negative.problem.descriptor=Cast from ''{0}'' to #ref may result in loss of precision for negative argument #loc comparison.to.nan.problem.descriptor1=Comparison to #ref is always false #loc comparison.to.nan.problem.descriptor2=Comparison to #ref is always true #loc comparison.to.nan.replace.quickfix=Replace with 'isNaN()' @@ -1686,6 +1686,7 @@ unnecessary.parentheses.conditional.option=Ignore parentheses around the conditi field.may.be.final.display.name=Field may be 'final' field.may.be.final.problem.descriptor=Field #ref may be 'final' #loc cast.that.loses.precision.option=Ignore casts from int to char +ignore.overflowing.byte.casts.option=Ignore casts from int 128-255 to byte variable.not.used.inside.if.display.name=Reference checked for 'null' is not used inside 'if' variable.not.used.inside.if.problem.descriptor=#ref checked for 'null' is not used inside 'if' #loc variable.not.used.inside.conditional.problem.descriptor=#ref checked for 'null' is not used inside conditional #loc diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java index 537011d42909..e808b905ba3c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/CastThatLosesPrecisionInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2017 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ package com.siyeh.ig.numeric; import com.intellij.codeInspection.dataFlow.*; import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; -import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; +import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel; import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -39,6 +39,9 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { @SuppressWarnings({"PublicField"}) public boolean ignoreIntegerCharCasts = false; + @SuppressWarnings({"PublicField"}) + public boolean ignoreOverflowingByteCasts = false; + @Pattern(VALID_ID_PATTERN) @Override @NotNull @@ -58,15 +61,18 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { public String buildErrorString(Object... infos) { final PsiType operandType = (PsiType)infos[0]; boolean negativeOnly = (boolean)infos[1]; - return InspectionGadgetsBundle - .message(negativeOnly ? "cast.that.loses.precision.negative.problem.descriptor" : "cast.that.loses.precision.problem.descriptor", - operandType.getPresentableText()); + return InspectionGadgetsBundle.message(negativeOnly ? + "cast.that.loses.precision.negative.problem.descriptor" : + "cast.that.loses.precision.problem.descriptor", + operandType.getPresentableText()); } @Override public JComponent createOptionsPanel() { - return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("cast.that.loses.precision.option"), - this, "ignoreIntegerCharCasts"); + final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this); + panel.addCheckbox(InspectionGadgetsBundle.message("cast.that.loses.precision.option"), "ignoreIntegerCharCasts"); + panel.addCheckbox(InspectionGadgetsBundle.message("ignore.overflowing.byte.casts.option"), "ignoreOverflowingByteCasts"); + return panel; } @Override @@ -90,10 +96,8 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { if (!ClassUtils.isPrimitiveNumericType(operandType) || !TypeUtils.isNarrowingConversion(operandType, castType)) { return; } - if (ignoreIntegerCharCasts) { - if (PsiType.INT.equals(operandType) && PsiType.CHAR.equals(castType)) { - return; - } + if (ignoreIntegerCharCasts && PsiType.INT.equals(operandType) && PsiType.CHAR.equals(castType)) { + return; } if (PsiType.LONG.equals(operandType) && PsiType.INT.equals(castType)) { final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class, true, PsiClass.class, PsiLambdaExpression.class); @@ -107,6 +111,12 @@ public class CastThatLosesPrecisionInspection extends BaseInspection { } if (result instanceof Number) { final Number number = (Number)result; + if (ignoreOverflowingByteCasts && PsiType.INT.equals(operandType) && PsiType.BYTE.equals(castType)) { + final int i = number.intValue(); + if (i > Byte.MIN_VALUE && i <= 255) { + return; + } + } if (valueIsContainableInType(number, castType)) { return; } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html index 3d8d0b791b5d..8d177746f8aa 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CastThatLosesPrecision.html @@ -5,12 +5,13 @@ result in loss of precision. Such casts are not necessarily a problem, but may r trace bugs if the loss of precision is unexpected.

-Use the checkbox below to indicate that this inspection should ignore casts from +Use the first checkbox below to indicate that this inspection should ignore casts from int to char. This type of cast is often used when implementing I/O operations, because the read() method of the class java.io.Reader returns an int.

- + Use the second checkbox below to ignore casts of constant values 128-255 from int to byte. + Such values will overflow to negative numbers that still fit inside a byte. \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/cast_that_loses_precision/CastThatLosesPrecision.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/cast_that_loses_precision/CastThatLosesPrecision.java index 35497b1ee496..8eadb7b5c9c4 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/cast_that_loses_precision/CastThatLosesPrecision.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/cast_that_loses_precision/CastThatLosesPrecision.java @@ -12,29 +12,26 @@ public class CastThatLosesPrecision int i; char ch; - - - - i = (int) f; + i = (int) f; System.out.println("i = " + i); - ch = (char) d; + ch = (char) d; System.out.println("ch = " + ch); - i = (int) d; + i = (int) d; System.out.println("i = " + i); - i = (int) l; + i = (int) l; System.out.println("i = " + i); - b = (byte) l; + b = (byte) l; System.out.println("b = " + b); - l = (long) d; + l = (long) d; System.out.println("l = " + l); - l = (long) f; + l = (long) f; System.out.println("l = " + l); d = (double) f; System.out.println("d = " + d); - f = (float) d; + f = (float) d; System.out.println("f = " + f); } @@ -52,7 +49,7 @@ public class CastThatLosesPrecision System.out.println("i = " + i); i = (int) 0L; System.out.println("i = " + i); - b = (byte) l; + b = (byte) l; System.out.println("b = " + b); l = (long) 0.0; @@ -74,7 +71,7 @@ public class CastThatLosesPrecision @Override public int hashCode() { int result = (int) (aLong ^ (aLong >>> 32)); - long temp = d != +0.0d ? (int) d : 0L; + long temp = d != +0.0d ? (int) d : 0L; result = 31 * result + (int) (temp ^ temp >>> 32); return result; } @@ -83,7 +80,7 @@ public class CastThatLosesPrecision if (longNumberOfAgents > Integer.MAX_VALUE) { throw new IllegalArgumentException("Too many agents: " + longNumberOfAgents); } - int intNumberOfAgents = (int)longNumberOfAgents; + int intNumberOfAgents = (int)longNumberOfAgents; System.out.println(intNumberOfAgents); } @@ -97,4 +94,8 @@ public class CastThatLosesPrecision int intNumberOfAgents = (int)longNumberOfAgents; System.out.println(intNumberOfAgents); } + + void bytes() { + byte[] bytes = { (byte) 0xb2, (byte) 0x80 }; + } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/CastThatLosesPrecisionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/CastThatLosesPrecisionInspectionTest.java index 8268e635f392..bb647c70a1d0 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/CastThatLosesPrecisionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/CastThatLosesPrecisionInspectionTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed 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 com.siyeh.ig.numeric; import com.intellij.codeInspection.InspectionProfileEntry; @@ -13,6 +28,8 @@ public class CastThatLosesPrecisionInspectionTest extends LightInspectionTestCas @Nullable @Override protected InspectionProfileEntry getInspection() { - return new CastThatLosesPrecisionInspection(); + final CastThatLosesPrecisionInspection inspection = new CastThatLosesPrecisionInspection(); + inspection.ignoreOverflowingByteCasts = true; + return inspection; } } \ No newline at end of file