IG: check prefix expressions correctly in "Unnecessary explicit numeric cast" inspection (IDEA-286284)

GitOrigin-RevId: 5a51a771dab46183da4345a88298a732701d36bb
This commit is contained in:
Bas Leijdekkers
2022-01-13 20:26:18 +00:00
committed by intellij-monorepo-bot
parent 44bf98e41d
commit 83c4c9b7ee
4 changed files with 170 additions and 21 deletions
@@ -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<IElementType> 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();
@@ -0,0 +1,137 @@
package com.siyeh.igtest.numeric.unnecessary_explicit_numeric_cast;
public class UnnecessaryExplicitNumericCast {
void a(byte b) {
double d = <caret>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> 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;
}
}
@@ -6,7 +6,7 @@ package com.siyeh.igtest.numeric.unnecessary_explicit_numeric_cast;
public class UnnecessaryExplicitNumericCast {
void a(byte b) {
double d = (<warning descr="'1' unnecessarily cast to 'double'">double</warning>) 1;
double d = (<warning descr="'1' unnecessarily cast to 'double'"><caret>double</warning>) 1;
d = (<warning descr="'1.0f' unnecessarily cast to 'double'">double</warning>) 1.0f;
d = (<warning descr="'b' unnecessarily cast to 'double'">double</warning>) b;
char c = (<warning descr="'1' unnecessarily cast to 'char'">char</warning>) 1;
@@ -82,6 +82,14 @@ public class UnnecessaryExplicitNumericCast {
}
}
public static long negate(int x) {
return -(long)x;
}
public static int negate2(int x) {
return -(<warning descr="'x' unnecessarily cast to 'int'">int</warning>)x;
}
}
enum Numeric {
A((byte)10);
@@ -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