From fbc3d18f9e5a7f0aa4c52eeb16d650466f871564 Mon Sep 17 00:00:00 2001 From: Mike Strobel Date: Thu, 12 Sep 2013 21:43:10 +0400 Subject: [PATCH] IDEA-111450 false positive for "Redundant type cast" inspection --- .../intellij/psi/util/RedundantCastUtil.java | 21 +++++++--- .../advHighlighting7/IDEA111450.java | 38 +++++++++++++++++++ .../daemon/LightAdvHighlightingJdk7Test.java | 1 + 3 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/IDEA111450.java diff --git a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java index f3a325a5d540..7bb65a15234d 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/RedundantCastUtil.java @@ -638,10 +638,21 @@ public class RedundantCastUtil { } private static boolean wrapperCastChangeSemantics(PsiExpression operand, PsiExpression otherOperand, PsiExpression toCast) { - boolean isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()) || - TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType()); - boolean isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()) || - TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType()); + final boolean isPrimitiveComparisonWithCast; + final boolean isPrimitiveComparisonWithoutCast; + + if (TypeConversionUtil.isPrimitiveAndNotNull(otherOperand.getType())) { + // IDEA-111450: A primitive comparison requires one primitive operand and one primitive or wrapper operand. + isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNullOrWrapper(operand.getType()); + isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNullOrWrapper(toCast.getType()); + } + else { + // We do not check whether `otherOperand` is a wrapper, because a reference-to-primitive cast has a + // side effect regardless of whether we end up doing a primitive or reference comparison. + isPrimitiveComparisonWithCast = TypeConversionUtil.isPrimitiveAndNotNull(operand.getType()); + isPrimitiveComparisonWithoutCast = TypeConversionUtil.isPrimitiveAndNotNull(toCast.getType()); + } + // wrapper casted to primitive vs wrapper comparison return isPrimitiveComparisonWithCast != isPrimitiveComparisonWithoutCast; } @@ -673,4 +684,4 @@ public class RedundantCastUtil { return method instanceof PsiMethod && AnnotationUtil.isAnnotated((PsiMethod)method, CommonClassNames.JAVA_LANG_INVOKE_MH_POLYMORPHIC, false, true); } -} +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/IDEA111450.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/IDEA111450.java new file mode 100644 index 000000000000..026403ab32df --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting7/IDEA111450.java @@ -0,0 +1,38 @@ +import java.lang.Character; +import java.util.List; + +public class Test { + public static void test() { + Character c1 = '1'; + Character c2 = '2'; + Object o = '3'; + + // A cast on either operand is required to force a primitive comparison; not redundant. + System.out.println((char) c1 == c2); + System.out.println(c1 == (char) c2); + + // If one operand is a primitive, and the other is a wrapper, the wrapper need not be cast. + System.out.println((char) c1 == '*'); + System.out.println('*' == (char) c1); + + // The cast on the Object is required to force a primitive comparison; not redundant. + System.out.println((char) o == '*'); + System.out.println('*' == (char) o); + + // The cast on the Object is required to force a primitive comparison; not redundant. + System.out.println((Character) o == '*'); + System.out.println('*' == (Character) o); + + // The cast on the Object triggers an implicit unboxing of the wrapper; not redundant. + System.out.println((char) o == c1); + System.out.println(c1 == (char) o); + + // A cast on the Object is required for a primitive comparison, but the wrapper cast is redundant. + System.out.println((char) o == (char) c1); + System.out.println((char) c1 == (char) o); + + // Although a reference comparison, the cast on the wrapper has a side effect; not redundant. + System.out.println(o == (char) c1); + System.out.println((char) c1 == o); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java index 2ed507832efc..edd3fb0026be 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/LightAdvHighlightingJdk7Test.java @@ -179,4 +179,5 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase { public void testIDEA62056() { doTest(false, false); } public void testIDEA78916() { doTest(false, false); } public void testIDEA111420() { doTest(false, false); } + public void testIDEA111450() { doTest(true, false); } }