fixed yellow code in PersistentFSImpl where VEvent was casted to subclass for the method different not-nullness

This commit is contained in:
Alexey Kudravtsev
2017-06-09 11:08:23 +03:00
parent d474438a0f
commit 3c9c050b46
4 changed files with 76 additions and 15 deletions
@@ -16,6 +16,7 @@
package com.intellij.psi.util;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
@@ -44,11 +45,12 @@ public class RedundantCastUtil {
private RedundantCastUtil() { }
@NotNull
public static List<PsiTypeCastExpression> getRedundantCastsInside(PsiElement where) {
public static List<PsiTypeCastExpression> getRedundantCastsInside(@NotNull PsiElement where) {
MyCollectingVisitor visitor = new MyCollectingVisitor();
if (where instanceof PsiEnumConstant) {
where.accept(visitor);
} else {
}
else {
where.acceptChildren(visitor);
}
return new ArrayList<>(visitor.myFoundCasts);
@@ -242,7 +244,8 @@ public class RedundantCastUtil {
}
}
@Override public void visitMethodCallExpression(PsiMethodCallExpression expression) {
@Override
public void visitMethodCallExpression(PsiMethodCallExpression expression) {
processCall(expression);
checkForVirtual(expression);
@@ -269,8 +272,8 @@ public class RedundantCastUtil {
if (targetMethod.hasModifierProperty(PsiModifier.STATIC)) return;
try {
PsiManager manager = methodExpr.getManager();
PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
Project project = methodExpr.getProject();
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
final PsiExpression expressionFromText = factory.createExpressionFromText(methodCall.getText(), methodCall);
if (!(expressionFromText instanceof PsiMethodCallExpression)) return;
@@ -282,23 +285,38 @@ public class RedundantCastUtil {
final JavaResolveResult newResult = newCall.getMethodExpression().advancedResolve(false);
if (!newResult.isValidResult()) return;
final PsiMethod newTargetMethod = (PsiMethod)newResult.getElement();
PsiType newReturnType = newCall.getType(), oldReturnType = methodCall.getType();
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)) {
if (Comparing.equal(newTargetMethod, targetMethod) ||
(newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
!(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) && // see SCR11555, SCR14559
areThrownExceptionsCompatible(targetMethod, newTargetMethod))) {
addToResults(typeCast);
}
if (Comparing.equal(newReturnType, oldReturnType) &&
(Comparing.equal(newTargetMethod, targetMethod) ||
newTargetMethod.getSignature(newResult.getSubstitutor()).equals(targetMethod.getSignature(resolveResult.getSubstitutor())) &&
!(newTargetMethod.isDeprecated() && !targetMethod.isDeprecated()) &&
// see SCR11555, SCR14559
areThrownExceptionsCompatible(targetMethod, newTargetMethod) &&
areNullnessCompatible(project, targetMethod, newTargetMethod))) {
addToResults(typeCast);
}
}
catch (IncorrectOperationException ignore) { }
}
private static boolean areNullnessCompatible(Project project,
final PsiMethod oldTargetMethod,
final PsiMethod newTargetMethod) {
// the cast may be for the @NotNull which newTargetMethod has whereas the oldTargetMethod doesn't
NullableNotNullManager nnm = NullableNotNullManager.getInstance(project);
boolean oldNotNull = nnm.isNotNull(oldTargetMethod, true);
boolean newNotNull = nnm.isNotNull(newTargetMethod, true);
if (oldNotNull != newNotNull) return false;
boolean oldNullable = nnm.isNullable(oldTargetMethod, true);
boolean newNullable = nnm.isNullable(newTargetMethod, true);
return oldNullable == newNullable;
}
private static boolean areThrownExceptionsCompatible(final PsiMethod targetMethod, final PsiMethod newTargetMethod) {
final PsiClassType[] oldThrowsTypes = targetMethod.getThrowsList().getReferencedTypes();
final PsiClassType[] newThrowsTypes = newTargetMethod.getThrowsList().getReferencedTypes();
@@ -820,10 +838,11 @@ public class RedundantCastUtil {
otherOperand = firstOperand;
firstOperand = temp;
}
if (firstOperand != null && otherOperand != null && wrapperCastChangeSemantics(firstOperand, otherOperand, operand)) {
if (otherOperand != null && wrapperCastChangeSemantics(firstOperand, otherOperand, operand)) {
return true;
}
} else if (parent instanceof PsiConditionalExpression) {
}
else if (parent instanceof PsiConditionalExpression) {
if (opType instanceof PsiPrimitiveType && !(((PsiConditionalExpression)parent).getType() instanceof PsiPrimitiveType)) {
if (PsiPrimitiveType.getUnboxedType(PsiTypesUtil.getExpectedTypeByParent(parent)) != null) {
return true;
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<problem>
<file>A.java</file>
<line>5</line>
<problem_class>Redundant type cast</problem_class>
<description>Casting &lt;code&gt;a&lt;/code&gt; to &lt;code&gt;AA&lt;/code&gt; is redundant</description>
</problem>
</problems>
@@ -0,0 +1,32 @@
import org.jetbrains.annotations.*;
class A {
static String doit(A a) {
String d = ((AA)a).danuna();
String notNull = ((AA)a).doadd();
return notNull + d;
}
@Nullable
String doadd() {
return null;
}
@NotNull
String danuna() {
return "";
}
}
class AA extends A {
@NotNull
String doadd() {
return "";
}
@Override
@NotNull
String danuna() {
return "";
}
}
@@ -92,4 +92,5 @@ public class RedundantCast15Test extends InspectionTestCase {
final LocalInspectionToolWrapper tool = new LocalInspectionToolWrapper(castInspection);
doTest("redundantCast/generics/" + getTestName(false), tool, "java 1.5");
}
public void testDifferentNullness() throws Exception { doTest();}
}