mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 05:21:29 +07:00
java redundant cast: cleanup: extract foreach, instanceof, throws statements
GitOrigin-RevId: ac04ea8db453518f4c15d3e37e33d9a25a22ce35
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c6f03bad18
commit
1c35803b4a
@@ -167,15 +167,7 @@ public class RedundantCastUtil {
|
||||
if (rExpr instanceof PsiTypeCastExpression) {
|
||||
PsiExpression castOperand = deparenthesizeExpression(((PsiTypeCastExpression)rExpr).getOperand());
|
||||
if (castOperand != null) {
|
||||
PsiType operandType;
|
||||
if (castOperand instanceof PsiTypeCastExpression) {
|
||||
PsiExpression nestedCastOperand = ((PsiTypeCastExpression)castOperand).getOperand();
|
||||
while (nestedCastOperand instanceof PsiTypeCastExpression) {
|
||||
nestedCastOperand = deparenthesizeExpression(((PsiTypeCastExpression)nestedCastOperand).getOperand());
|
||||
}
|
||||
operandType = nestedCastOperand != null ? nestedCastOperand.getType() : null;
|
||||
}
|
||||
else if (castOperand instanceof PsiFunctionalExpression && lType != null) {
|
||||
if (castOperand instanceof PsiFunctionalExpression && lType != null) {
|
||||
final PsiTypeElement typeElement = ((PsiTypeCastExpression)rExpr).getCastType();
|
||||
final PsiType castType = typeElement != null ? typeElement.getType() : null;
|
||||
if (lType.equals(castType)) {
|
||||
@@ -183,9 +175,7 @@ public class RedundantCastUtil {
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
operandType = castOperand.getType();
|
||||
}
|
||||
PsiType operandType = getNestedCastOperandType(castOperand);
|
||||
if (operandType != null) {
|
||||
if (lType != null && TypeConversionUtil.isAssignable(lType, operandType, false)) {
|
||||
addToResults((PsiTypeCastExpression)rExpr);
|
||||
@@ -194,6 +184,22 @@ public class RedundantCastUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PsiType getNestedCastOperandType(PsiExpression castOperand) {
|
||||
if (castOperand instanceof PsiTypeCastExpression) {
|
||||
PsiExpression nestedCastOperand = ((PsiTypeCastExpression)castOperand).getOperand();
|
||||
while (nestedCastOperand instanceof PsiTypeCastExpression) {
|
||||
nestedCastOperand = deparenthesizeExpression(((PsiTypeCastExpression)nestedCastOperand).getOperand());
|
||||
}
|
||||
return nestedCastOperand != null ? nestedCastOperand.getType() : null;
|
||||
}
|
||||
else if (castOperand instanceof PsiFunctionalExpression) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return castOperand.getType();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
@@ -565,12 +571,95 @@ public class RedundantCastUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitForeachStatement(PsiForeachStatement statement) {
|
||||
PsiExpression iteratedValue = deparenthesizeExpression(statement.getIteratedValue());
|
||||
if (iteratedValue instanceof PsiTypeCastExpression) {
|
||||
PsiExpression operand = ((PsiTypeCastExpression)iteratedValue).getOperand();
|
||||
if (operand != null) {
|
||||
PsiType collectionItemType = JavaGenericsUtil.getCollectionItemType(operand.getType(), statement.getResolveScope());
|
||||
if (collectionItemType != null && TypeConversionUtil.isAssignable(statement.getIterationParameter().getType(), collectionItemType)) {
|
||||
addToResults((PsiTypeCastExpression)iteratedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visitForeachStatement(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
|
||||
final PsiTypeElement checkTypeElement = expression.getCheckType();
|
||||
if (checkTypeElement == null) return;
|
||||
PsiExpression typeCast = deparenthesizeExpression(expression.getOperand());
|
||||
if (typeCast instanceof PsiTypeCastExpression) {
|
||||
PsiExpression operand = ((PsiTypeCastExpression)typeCast).getOperand();
|
||||
if (operand != null) {
|
||||
PsiType opType = getNestedCastOperandType(operand);
|
||||
//15.20.2. Type Comparison Operator instanceof:
|
||||
//If a cast (p15.16) of the RelationalExpression to the ReferenceType would be rejected as a compile-time error,
|
||||
//then the instanceof relational expression likewise produces a compile-time error.
|
||||
if (opType != null &&
|
||||
!(opType instanceof PsiPrimitiveType) &&
|
||||
TypeConversionUtil.areTypesConvertible(opType, checkTypeElement.getType())) {
|
||||
addToResults((PsiTypeCastExpression)typeCast);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visitInstanceOfExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitThrowStatement(PsiThrowStatement statement) {
|
||||
PsiExpression typeCast = deparenthesizeExpression(statement.getException());
|
||||
if (typeCast instanceof PsiTypeCastExpression) {
|
||||
PsiExpression operand = ((PsiTypeCastExpression)typeCast).getOperand();
|
||||
if (operand != null) {
|
||||
PsiType opType = getNestedCastOperandType(operand);
|
||||
final PsiClass thrownClass = PsiUtil.resolveClassInType(opType);
|
||||
if (InheritanceUtil.isInheritor(thrownClass, false, CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION)) {
|
||||
addToResults((PsiTypeCastExpression)typeCast);
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(thrownClass, false, CommonClassNames.JAVA_LANG_THROWABLE)) {
|
||||
final PsiParameterListOwner listOwner = PsiTreeUtil.getParentOfType(statement, PsiMethod.class, PsiLambdaExpression.class);
|
||||
if (listOwner instanceof PsiMethod) {
|
||||
processThrowsList((PsiMethod)listOwner, PsiSubstitutor.EMPTY, (PsiTypeCastExpression)typeCast, opType);
|
||||
}
|
||||
else if (listOwner instanceof PsiLambdaExpression) {
|
||||
PsiType functionalInterfaceType = ((PsiLambdaExpression)listOwner).getFunctionalInterfaceType();
|
||||
final PsiClassType.ClassResolveResult functionalInterfaceResolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (interfaceMethod != null) {
|
||||
processThrowsList(interfaceMethod, LambdaUtil.getSubstitutor(interfaceMethod, functionalInterfaceResolveResult), (PsiTypeCastExpression)typeCast, opType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.visitThrowStatement(statement);
|
||||
}
|
||||
|
||||
private void processThrowsList(PsiMethod interfaceMethod,
|
||||
PsiSubstitutor psiSubstitutor,
|
||||
PsiTypeCastExpression typeCast,
|
||||
PsiType opType) {
|
||||
for (PsiClassType thrownType : interfaceMethod.getThrowsList().getReferencedTypes()) {
|
||||
PsiType left = psiSubstitutor.substitute(thrownType);
|
||||
if (left != null && TypeConversionUtil.isAssignable(left, opType, false)) {
|
||||
addToResults(typeCast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processAlreadyHasTypeCast(PsiTypeCastExpression typeCast){
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(typeCast.getParent());
|
||||
if (parent instanceof PsiExpressionList) return; // do not replace in arg lists - should be handled by parent
|
||||
if (parent instanceof PsiReturnStatement) return;
|
||||
if (parent instanceof PsiTypeCastExpression) return;
|
||||
if (parent instanceof PsiPolyadicExpression) return;
|
||||
if (parent instanceof PsiForeachStatement) return;
|
||||
if (parent instanceof PsiInstanceOfExpression) return;
|
||||
if (parent instanceof PsiThrowStatement) return;
|
||||
|
||||
if (parent instanceof PsiLambdaExpression) return;
|
||||
|
||||
@@ -680,43 +769,6 @@ public class RedundantCastUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (parent instanceof PsiForeachStatement) {
|
||||
PsiType collectionItemType = JavaGenericsUtil.getCollectionItemType(opType, typeCast.getResolveScope());
|
||||
if (collectionItemType != null && TypeConversionUtil.isAssignable(((PsiForeachStatement)parent).getIterationParameter().getType(), collectionItemType)) {
|
||||
addToResults(typeCast);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (parent instanceof PsiThrowStatement) {
|
||||
final PsiClass thrownClass = PsiUtil.resolveClassInType(opType);
|
||||
if (InheritanceUtil.isInheritor(thrownClass, false, CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION)) {
|
||||
addToResults(typeCast);
|
||||
return;
|
||||
}
|
||||
if (InheritanceUtil.isInheritor(thrownClass, false, CommonClassNames.JAVA_LANG_THROWABLE)) {
|
||||
final PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class);//todo lambda
|
||||
if (method != null) {
|
||||
for (PsiClassType thrownType : method.getThrowsList().getReferencedTypes()) {
|
||||
if (TypeConversionUtil.isAssignable(thrownType, opType, false)) {
|
||||
addToResults(typeCast);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parent instanceof PsiInstanceOfExpression) {
|
||||
if (opType instanceof PsiPrimitiveType) return;
|
||||
//15.20.2. Type Comparison Operator instanceof:
|
||||
//If a cast (p15.16) of the RelationalExpression to the ReferenceType would be rejected as a compile-time error,
|
||||
//then the instanceof relational expression likewise produces a compile-time error.
|
||||
final PsiTypeElement checkTypeElement = ((PsiInstanceOfExpression)parent).getCheckType();
|
||||
if (checkTypeElement != null && TypeConversionUtil.areTypesConvertible(opType, checkTypeElement.getType())) {
|
||||
addToResults(typeCast);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent instanceof PsiSwitchBlock &&
|
||||
opType instanceof PsiClassType && PsiPrimitiveType.getUnboxedType(opType) == null && !opType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
PsiClass aClass = ((PsiClassType)opType).resolve();
|
||||
@@ -825,9 +877,8 @@ public class RedundantCastUtil {
|
||||
if (isCastToSerializable(castType)) return true;
|
||||
}
|
||||
else if (stripParenthesisOperand instanceof PsiConditionalExpression) {
|
||||
final PsiExpression thenExpr = PsiUtil.skipParenthesizedExprDown(((PsiConditionalExpression)stripParenthesisOperand).getThenExpression());
|
||||
final PsiExpression elseExpr = PsiUtil.skipParenthesizedExprDown(((PsiConditionalExpression)stripParenthesisOperand).getElseExpression());
|
||||
if (thenExpr instanceof PsiFunctionalExpression || elseExpr instanceof PsiFunctionalExpression) {
|
||||
if (PsiUtil.skipParenthesizedExprDown(((PsiConditionalExpression)stripParenthesisOperand).getThenExpression()) instanceof PsiFunctionalExpression ||
|
||||
PsiUtil.skipParenthesizedExprDown(((PsiConditionalExpression)stripParenthesisOperand).getElseExpression()) instanceof PsiFunctionalExpression) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
interface SAM<T, R extends Throwable> {
|
||||
void m(T t) throws R;
|
||||
}
|
||||
|
||||
class MyTest {
|
||||
void f(E1 e1) {
|
||||
SAM<String, E1> s1 = s -> {
|
||||
if (s.length() > 0) throw (<warning descr="Casting '(E2)e1' to 'E1' is redundant">E1</warning>) (<warning descr="Casting 'e1' to 'E2' is redundant">E2</warning>) e1;
|
||||
throw (<warning descr="Casting '(E1)e1' to 'E2' is redundant">E2</warning>) (<warning descr="Casting 'e1' to 'E1' is redundant">E1</warning>)e1;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static class E1 extends Exception {}
|
||||
static class E2 extends E1 {}
|
||||
}
|
||||
@@ -3,11 +3,34 @@ public class RedundantCast{
|
||||
throw <error descr="Inconvertible types; cannot cast 'RedundantCast.IOEx' to 'RedundantCast.FileNotFoundEx'">(<warning descr="Casting 'e' to 'FileNotFoundEx' is redundant">FileNotFoundEx</warning>)e</error>;
|
||||
}
|
||||
|
||||
void foo(RuntimeException e) {
|
||||
throw (<warning descr="Casting 'e' to 'Ex' is redundant">Ex</warning>)e;
|
||||
void foo(RuntimeException e, boolean f) {
|
||||
if (f) {
|
||||
throw (<warning descr="Casting '(Object)e' to 'Ex' is redundant">Ex</warning>)(<warning descr="Casting 'e' to 'Object' is redundant">Object</warning>)e;
|
||||
}
|
||||
else if (!f && false) {
|
||||
throw <error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.Throwable'">(<warning descr="Casting 'e' to 'Object' is redundant">Object</warning>)e</error>;
|
||||
}
|
||||
throw (<warning descr="Casting '(Ex)e' to 'Ex' is redundant">Ex</warning>)(<warning descr="Casting 'e' to 'Ex' is redundant">Ex</warning>)e;
|
||||
}
|
||||
|
||||
void bar(E2 e) throws E1 {
|
||||
throw (<warning descr="Casting 'e' to 'E1' is redundant">E1</warning>)e;
|
||||
}
|
||||
|
||||
void bar(E1 e) throws E2 {
|
||||
if (true) {
|
||||
try {
|
||||
throw (E2)e;
|
||||
}
|
||||
catch (E2 e2) {}
|
||||
}
|
||||
throw (E2)e;
|
||||
}
|
||||
|
||||
static class Ex extends RuntimeException {}
|
||||
static class IOEx extends Exception {}
|
||||
static class FileNotFoundEx extends Exception {}
|
||||
|
||||
static class E1 extends Exception {}
|
||||
static class E2 extends E1 {}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ class RedundantCast {
|
||||
void redundantCasts() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String s : (<warning descr="Casting 'list' to 'ArrayList<String>' is redundant">ArrayList<String></warning>) list) {}
|
||||
for (String s : (<warning descr="Casting '(ArrayList<String>)list' to 'ArrayList<String>' is redundant">ArrayList<String></warning>) (<warning descr="Casting 'list' to 'ArrayList<String>' is redundant">ArrayList<String></warning>) list) {}
|
||||
|
||||
Object o = new ArrayList<>();
|
||||
for (String s : (ArrayList<String>) o) {}
|
||||
for (String s : (ArrayList<String>) (<warning descr="Casting 'o' to 'Object' is redundant">Object</warning>) o) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ class RedundantCast {
|
||||
boolean redundantCasts(Object o) {
|
||||
int p = 0;
|
||||
if ((Number)p instanceof Integer) {}
|
||||
if ((Number)(<warning descr="Casting 'p' to 'Object' is redundant">Object</warning>)p instanceof Integer) {}
|
||||
return (<warning descr="Casting 'o' to 'List' is redundant">List</warning>)o instanceof ArrayList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testLambdaWithCastInReturnStatement() { doTest(); }
|
||||
public void testCastInNeighbourArgument() { doTest(); }
|
||||
public void testErasedTargetType() { doTest(); }
|
||||
public void testThrowsStatementInLambdaBody() { doTest(); }
|
||||
public void testRejectReturnTypeChange() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user