From 83c4c9b7ee8e806adb67e8e92ca6cda0943f8d24 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Mon, 10 Jan 2022 12:54:25 +0100 Subject: [PATCH] IG: check prefix expressions correctly in "Unnecessary explicit numeric cast" inspection (IDEA-286284) GitOrigin-RevId: 5a51a771dab46183da4345a88298a732701d36bb --- ...ecessaryExplicitNumericCastInspection.java | 41 +++--- .../UnnecessaryExplicitNumericCast.after.java | 137 ++++++++++++++++++ .../UnnecessaryExplicitNumericCast.java | 10 +- ...saryExplicitNumericCastInspectionTest.java | 3 +- 4 files changed, 170 insertions(+), 21 deletions(-) create mode 100644 plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.after.java diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java index 8031abc89dc0..949eef8a0027 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspection.java @@ -1,18 +1,4 @@ -/* - * Copyright 2011-2017 Bas Leijdekkers - * - * 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. - */ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.numeric; import com.intellij.codeInspection.ProblemDescriptor; @@ -31,6 +17,9 @@ import org.jetbrains.annotations.NotNull; import java.util.Set; +/** + * @author Bas Leijdekkers + */ public final class UnnecessaryExplicitNumericCastInspection extends BaseInspection { private static final Set binaryPromotionOperators = Set.of( JavaTokenType.ASTERISK, @@ -129,14 +118,28 @@ public final class UnnecessaryExplicitNumericCastInspection extends BaseInspecti if (!ClassUtils.isPrimitiveNumericType(operandType)) { return false; } - if (castType.equals(operandType)) { - // cast to the same type is caught by "Redundant type cast" inspection - return false; - } PsiElement parent = expression.getParent(); while (parent instanceof PsiParenthesizedExpression) { parent = parent.getParent(); } + if (parent instanceof PsiPrefixExpression) { + // JLS 5.6 Numeric Contexts + final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)parent; + final IElementType tokenType = prefixExpression.getOperationTokenType(); + if (JavaTokenType.MINUS == tokenType || JavaTokenType.PLUS == tokenType || JavaTokenType.TILDE == tokenType) { + if (TypeUtils.isNarrowingConversion(operandType, castType)) { + return false; + } + if (PsiType.INT.equals(castType)) { + return !PsiType.LONG.equals(operandType) && !PsiType.FLOAT.equals(operandType) && !PsiType.DOUBLE.equals(operandType); + } + } + return false; + } + if (castType.equals(operandType)) { + // cast to the same type is caught by "Redundant type cast" inspection + return false; + } if (parent instanceof PsiPolyadicExpression) { final PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent; final IElementType tokenType = polyadicExpression.getOperationTokenType(); diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.after.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.after.java new file mode 100644 index 000000000000..7e995cdaf5e8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.after.java @@ -0,0 +1,137 @@ +package com.siyeh.igtest.numeric.unnecessary_explicit_numeric_cast; + + + + +public class UnnecessaryExplicitNumericCast { + + void a(byte b) { + double d = 1; + d = 1.0f; + d = b; + char c = 1; + b = (int)7; + } + + double b(int a, byte b) { + return (double)a * b; + } + + public static void main(String[] args) { + int i = 10; + + double d = 123.0 / (456.0 * i); + } + + void unary() { + byte b = 2; + int a[] = new int[b]; + final int c = a[b]; + int[] a2 = new int[]{b}; + int[] a3 = {b}; + final int result = b << 1; + c(b); + new UnnecessaryExplicitNumericCast(b); + } + + void c(int i) {} + UnnecessaryExplicitNumericCast(long i) {} + + void c(int cols, int no) { + int rows = (int) Math.ceil((double) no / cols); + } + + void source() { + target((int)'a'); + target2('b'); + } + void target(int c) {} + void target(char c) {} + void target2(int d) {} + + void foo() { + float x = 2; + target((int) x); // this line complains: 'x' unnecessarily cast to 'int' + } + + void a(float angleFromTo) { + float f = (float) Math.cos(0.5) * 1.0f; // necessary + final long l = i() * 9L; + float angle2 = angleFromTo + (float) (Math.PI / 2); + } + + int i() { + return 10; + } + + boolean redundantTypeCast(long l) { + return 0L == (long)l; + } + + void necessary() { + char[] keyChar = {'\t', '\n', '\r', '\f', 'a', '0'}; + for (char cc : keyChar) { + String result; + if (cc < 28) { + result = "Ascii " + (int)cc; + } + else { + result = "k " + cc + " (" + (int)cc + ')'; + } + System.out.println(result); + } + } + + public static long negate(int x) { + return -(long)x; + } + + public static int negate2(int x) { + return -x; + } + +} +enum Numeric { + A((byte)10); + + Numeric(byte b) {} +} +class S { + + static void doSomething() { + // V --- this cast is reported as unnecessary + if ( (int) whatever() < 0 ) { + } + } + + @SuppressWarnings("unchecked") + private static T whatever() { + return (T) (Object) 0; + } + + void polyadic() { + int a=1; + int b=2; + System.out.println(((double) a) / b / 10.0); + double c = 3.5; + System.out.println(a / c / 10.0); + System.out.println(19/ (double)a / c / 10.0); + } + + private static void foo(int i) { + } + + void bar(int i) { + foo(0); + foo((short)i); + int bar = 123; + boolean[] booleans = new boolean[6]; + byte[] bytes = new byte[(int) 2]; + var v = (short) 666; + } + + void noWarnOnRedCode() { + foo((long)0); + int x = (long)0; + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java index 0d8b872bf9c7..9d51bf017420 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/numeric/unnecessary_explicit_numeric_cast/UnnecessaryExplicitNumericCast.java @@ -6,7 +6,7 @@ package com.siyeh.igtest.numeric.unnecessary_explicit_numeric_cast; public class UnnecessaryExplicitNumericCast { void a(byte b) { - double d = (double) 1; + double d = (double) 1; d = (double) 1.0f; d = (double) b; char c = (char) 1; @@ -82,6 +82,14 @@ public class UnnecessaryExplicitNumericCast { } } + public static long negate(int x) { + return -(long)x; + } + + public static int negate2(int x) { + return -(int)x; + } + } enum Numeric { A((byte)10); diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java index d339b6dea037..310f05a562ff 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/numeric/UnnecessaryExplicitNumericCastInspectionTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.siyeh.ig.numeric; import com.intellij.codeInspection.InspectionProfileEntry; @@ -11,6 +11,7 @@ public class UnnecessaryExplicitNumericCastInspectionTest extends LightJavaInspe public void testUnnecessaryExplicitNumericCast() { doTest(); + checkQuickFixAll(); } @Nullable