mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
java redundant cast: cleanup: refexpr
GitOrigin-RevId: d4a111e2a47885ef97983979200056612db26c93
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fdc80d017c
commit
c3bda2dac0
@@ -21,7 +21,10 @@ import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class RedundantCastUtil {
|
||||
private static final Logger LOG = Logger.getInstance(RedundantCastUtil.class);
|
||||
@@ -213,63 +216,9 @@ public class RedundantCastUtil {
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
|
||||
processCall(expression);
|
||||
|
||||
checkForVirtual(expression);
|
||||
super.visitMethodCallExpression(expression);
|
||||
}
|
||||
|
||||
private void checkForVirtual(PsiMethodCallExpression methodCall) {
|
||||
PsiReferenceExpression methodExpr = methodCall.getMethodExpression();
|
||||
PsiExpression qualifier = methodExpr.getQualifierExpression();
|
||||
if (!(qualifier instanceof PsiParenthesizedExpression)) return;
|
||||
PsiExpression operand = deparenthesizeExpression(qualifier);
|
||||
if (!(operand instanceof PsiTypeCastExpression)) return;
|
||||
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)operand;
|
||||
PsiExpression castOperand = typeCast.getOperand();
|
||||
if (castOperand == null) return;
|
||||
|
||||
PsiType type = castOperand.getType();
|
||||
if (type == null) return;
|
||||
if (type instanceof PsiPrimitiveType) return;
|
||||
|
||||
final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
|
||||
PsiMethod targetMethod = (PsiMethod)resolveResult.getElement();
|
||||
if (targetMethod == null) return;
|
||||
if (targetMethod.hasModifierProperty(PsiModifier.STATIC)) return;
|
||||
|
||||
try {
|
||||
Project project = methodExpr.getProject();
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
|
||||
final PsiExpression expressionFromText = factory.createExpressionFromText(methodCall.getText(), methodCall);
|
||||
if (!(expressionFromText instanceof PsiMethodCallExpression)) return;
|
||||
PsiMethodCallExpression newCall = (PsiMethodCallExpression)expressionFromText;
|
||||
PsiExpression newQualifier = newCall.getMethodExpression().getQualifierExpression();
|
||||
PsiTypeCastExpression newCast = Objects.requireNonNull((PsiTypeCastExpression)deparenthesizeExpression(newQualifier));
|
||||
PsiExpression newOperand = Objects.requireNonNull(newCast.getOperand());
|
||||
newQualifier.replace(newOperand);
|
||||
|
||||
final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
|
||||
if (!newResult.isValidResult()) return;
|
||||
final PsiMethod newTargetMethod = (PsiMethod)newResult.getElement();
|
||||
PsiType newReturnType = newCall.getType();
|
||||
PsiType oldReturnType = methodCall.getType();
|
||||
if (newReturnType instanceof PsiCapturedWildcardType && oldReturnType instanceof PsiCapturedWildcardType) {
|
||||
newReturnType = ((PsiCapturedWildcardType)newReturnType).getUpperBound();
|
||||
oldReturnType = ((PsiCapturedWildcardType)oldReturnType).getUpperBound();
|
||||
}
|
||||
if (Comparing.equal(newReturnType, oldReturnType) &&
|
||||
(Comparing.equal(newTargetMethod, targetMethod) ||
|
||||
!(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) &&
|
||||
MethodSignatureUtil.isSuperMethod(newTargetMethod, targetMethod) &&
|
||||
// see SCR11555, SCR14559
|
||||
areThrownExceptionsCompatible(targetMethod, newTargetMethod) &&
|
||||
areNullabilityCompatible(targetMethod, newTargetMethod))) {
|
||||
addToResults(typeCast);
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException ignore) { }
|
||||
}
|
||||
|
||||
private static boolean areNullabilityCompatible(final PsiMethod oldTargetMethod,
|
||||
final PsiMethod newTargetMethod) {
|
||||
// the cast may be for the @NotNull which newTargetMethod has whereas the oldTargetMethod doesn't
|
||||
@@ -307,31 +256,87 @@ public class RedundantCastUtil {
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
if (!(expression.getParent() instanceof PsiMethodCallExpression)) {
|
||||
PsiExpression qualifier = deparenthesizeExpression(expression.getQualifierExpression());
|
||||
if (qualifier instanceof PsiTypeCastExpression) {
|
||||
PsiExpression operand = deparenthesizeExpression(((PsiTypeCastExpression)qualifier).getOperand());
|
||||
if (operand == null) return;
|
||||
PsiTypeElement typeElement = ((PsiTypeCastExpression)qualifier).getCastType();
|
||||
if (typeElement == null) return;
|
||||
PsiType opType = operand.getType();
|
||||
if (operand instanceof PsiFunctionalExpression) return;
|
||||
if (typeElement.getType() instanceof PsiClassType && opType instanceof PsiPrimitiveType) return; //explicit boxing
|
||||
//Check accessibility
|
||||
if (opType instanceof PsiClassType) {
|
||||
PsiElement element = expression.resolve();
|
||||
if (!(element instanceof PsiMember)) return;
|
||||
PsiClass accessClass = ((PsiClassType)opType).resolve();
|
||||
if (accessClass == null) return;
|
||||
if (!JavaPsiFacade.getInstance(expression.getProject()).getResolveHelper().isAccessible((PsiMember)element, qualifier, accessClass)) return;
|
||||
if (!isCastRedundantInRefExpression(expression, operand)) return;
|
||||
addIfNarrowing((PsiTypeCastExpression)qualifier, opType, null);
|
||||
}
|
||||
PsiExpression qualifier = deparenthesizeExpression(expression.getQualifierExpression());
|
||||
if (qualifier instanceof PsiTypeCastExpression) {
|
||||
PsiTypeCastExpression typeCast = (PsiTypeCastExpression)qualifier;
|
||||
PsiExpression operand = deparenthesizeExpression(typeCast.getOperand());
|
||||
while (operand instanceof PsiTypeCastExpression) {
|
||||
operand = deparenthesizeExpression(((PsiTypeCastExpression)operand).getOperand());
|
||||
}
|
||||
if (operand == null) return;
|
||||
|
||||
PsiTypeElement typeElement = typeCast.getCastType();
|
||||
if (typeElement == null) return;
|
||||
PsiType opType = operand.getType();
|
||||
if (opType == null) return;
|
||||
|
||||
if (!(operand instanceof PsiFunctionalExpression || opType instanceof PsiPrimitiveType) &&
|
||||
isCastInReferenceQualifierRedundant(expression, operand)) {
|
||||
addToResults(typeCast);
|
||||
}
|
||||
}
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
|
||||
private static boolean isCastInReferenceQualifierRedundant(final PsiReferenceExpression refExpression,
|
||||
final PsiExpression castOperand) {
|
||||
final JavaResolveResult resolveResult = refExpression.advancedResolve(false);
|
||||
PsiElement oldMember = resolveResult.getElement();
|
||||
if (oldMember == null) return false;
|
||||
try {
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(refExpression.getParent());
|
||||
if (parent instanceof PsiMethodCallExpression) {
|
||||
PsiMethod targetMethod = (PsiMethod)oldMember;
|
||||
if (targetMethod.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
return false;
|
||||
}
|
||||
PsiMethodCallExpression newCall =
|
||||
(PsiMethodCallExpression)copyCallExpression(((PsiMethodCallExpression)parent), PsiTypesUtil.getExpectedTypeByParent(parent));
|
||||
if (newCall == null) return false;
|
||||
PsiExpression newQualifier = newCall.getMethodExpression().getQualifierExpression();
|
||||
LOG.assertTrue(newQualifier != null);
|
||||
newQualifier.replace(castOperand);
|
||||
|
||||
final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
|
||||
if (!newResult.isValidResult()) return false;
|
||||
|
||||
final PsiMethod newTargetMethod = (PsiMethod)newResult.getElement();
|
||||
PsiType newReturnType = newCall.getType();
|
||||
PsiType oldReturnType = ((PsiMethodCallExpression)parent).getType();
|
||||
if (newReturnType instanceof PsiCapturedWildcardType && oldReturnType instanceof PsiCapturedWildcardType) {
|
||||
oldReturnType = ((PsiCapturedWildcardType)oldReturnType).getUpperBound();
|
||||
newReturnType = ((PsiCapturedWildcardType)newReturnType).getUpperBound();
|
||||
}
|
||||
|
||||
if (Comparing.equal(PsiUtil.recaptureWildcards(newReturnType, parent), oldReturnType) &&
|
||||
(Comparing.equal(newTargetMethod, targetMethod) ||
|
||||
!(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) &&
|
||||
MethodSignatureUtil.isSuperMethod(newTargetMethod, targetMethod) &&
|
||||
// see SCR11555, SCR14559
|
||||
areThrownExceptionsCompatible(targetMethod, newTargetMethod) &&
|
||||
areNullabilityCompatible(targetMethod, newTargetMethod))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(castOperand.getProject());
|
||||
final PsiReferenceExpression newExpression = (PsiReferenceExpression)elementFactory.createExpressionFromText(refExpression.getText(), castOperand);
|
||||
final PsiExpression newQualifier = newExpression.getQualifierExpression();
|
||||
LOG.assertTrue(newQualifier != null);
|
||||
newQualifier.replace(castOperand);
|
||||
|
||||
JavaResolveResult newResult = newExpression.advancedResolve(false);
|
||||
if (!newResult.isValidResult()) return false;
|
||||
|
||||
return oldMember.equals(newResult.getElement());
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException ignore) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void processCall(PsiCall expression){
|
||||
PsiExpressionList argumentList = expression.getArgumentList();
|
||||
if (argumentList == null) return;
|
||||
@@ -874,26 +879,7 @@ public class RedundantCastUtil {
|
||||
super.visitArrayAccessExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isCastRedundantInRefExpression (final PsiReferenceExpression refExpression, final PsiExpression castOperand) {
|
||||
if (refExpression.getParent() instanceof PsiMethodCallExpression) return false;
|
||||
final PsiElement resolved = refExpression.resolve();
|
||||
try {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(refExpression.getProject());
|
||||
final PsiExpression copyExpression = elementFactory.createExpressionFromText(refExpression.getText(), refExpression);
|
||||
if (copyExpression instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression copy = (PsiReferenceExpression)copyExpression;
|
||||
final PsiExpression qualifier = copy.getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
qualifier.replace(castOperand);
|
||||
return copy.resolve() == resolved;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException ignore) { }
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private static boolean isTypeCastSemantic(PsiTypeCastExpression typeCast) {
|
||||
PsiExpression operand = typeCast.getOperand();
|
||||
if (operand == null) return false;
|
||||
|
||||
@@ -2,6 +2,7 @@ class Entry {
|
||||
private final Object obj;
|
||||
protected Entry(Directory parent) {
|
||||
obj = ((Entry)parent).obj; //cast is needed because 'obj' is not visible with 'Directory' access class
|
||||
String s = ((<warning descr="Casting '((Entry)(Entry)parent).obj' to 'Object' is redundant">Object</warning>)((Entry)(<warning descr="Casting 'parent' to 'Entry' is redundant">Entry</warning>)parent).obj).toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import java.util.*;
|
||||
|
||||
class MyTest {
|
||||
void m(List<? extends F> l) {
|
||||
int b = ((<warning descr="Casting 'l.get(...)' to 'F' is redundant">F</warning>) l.get(0)).i;
|
||||
}
|
||||
|
||||
static class F {
|
||||
int i;
|
||||
}
|
||||
|
||||
List<?> getWildcard() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<String> getConcrete() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
void test() {
|
||||
((<warning descr="Casting 'this' to 'MyTest' is redundant">MyTest</warning>)this).getConcrete();
|
||||
((<warning descr="Casting 'this' to 'MyTest' is redundant">MyTest</warning>)this).getWildcard();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,6 +58,7 @@ public class RedundantCast15Test extends LightJavaCodeInsightFixtureTestCase {
|
||||
public void testCaseThrowable() { doTest();}
|
||||
public void testSafeTempVarName() { doTest();}
|
||||
public void testBinaryComparison() { doTest();}
|
||||
public void testQualifierWithCapture() { doTest();}
|
||||
|
||||
public void testTypeParameterAccessChecksJava7() {
|
||||
doTest();
|
||||
|
||||
Reference in New Issue
Block a user