IDEA-88777 equlas() and == should be taken into account by nullability check

This commit is contained in:
peter
2012-07-17 18:54:47 +02:00
parent d92c416d82
commit ff89600364
6 changed files with 100 additions and 12 deletions
@@ -18,10 +18,7 @@ package com.intellij.codeInspection.dataFlow;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.codeInsight.NullableNotNullManager;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.dataFlow.value.DfaUnknownValue;
import com.intellij.codeInspection.dataFlow.value.DfaValue;
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.psi.*;
@@ -702,6 +699,16 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
return NOT_FOUND;
}
private static class ApplyNotNullInstruction extends Instruction {
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) {
DfaValue value = state.pop();
DfaValueFactory factory = runner.getFactory();
state.applyCondition(factory.getRelationFactory().create(value, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true));
return nextInstruction(runner, state);
}
}
class CatchDescriptor {
private final PsiType myType;
private PsiParameter myParameter;
@@ -1182,6 +1189,21 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
if (!myCatchStack.isEmpty()) {
addMethodThrows(expression.resolveMethod());
}
if (paramExprs.length == 1 && method instanceof PsiMethod &&
"equals".equals(((PsiMethod)method).getName()) && parameters.length == 1 &&
parameters[0].getType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) &&
PsiType.BOOLEAN.equals(((PsiMethod)method).getReturnType())) {
addInstruction(new PushInstruction(myFactory.getConstFactory().getFalse(), null));
addInstruction(new SwapInstruction());
addInstruction(new ConditionalGotoInstruction(getEndOffset(expression), true, null));
addInstruction(new PopInstruction());
addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null));
paramExprs[0].accept(this);
addInstruction(new ApplyNotNullInstruction());
}
}
finally {
finishElement(expression);
@@ -34,7 +34,6 @@ import com.intellij.codeInspection.*;
import com.intellij.codeInspection.dataFlow.instructions.*;
import com.intellij.codeInspection.ex.BaseLocalInspectionTool;
import com.intellij.ide.DataManager;
import com.intellij.lang.ASTFactory;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
@@ -42,7 +41,6 @@ import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.util.Pair;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.codeStyle.CodeFormatterFacade;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.ArrayUtil;
@@ -71,11 +69,6 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
return new OptionsPanel();
}
void test(@NotNull List l) {
final List list = null;
test(list);
}
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new JavaElementVisitor() {
@@ -507,6 +507,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
}
public boolean isNotNull(DfaVariableValue dfaVar) {
if (getVariableState(dfaVar).isNotNull()) {
return true;
}
DfaConstValue dfaNull = myFactory.getConstFactory().getNull();
Integer c1Index = getOrCreateEqClassIndex(dfaVar);
Integer c2Index = getOrCreateEqClassIndex(dfaNull);
@@ -266,13 +266,21 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
boolean negated = memState.canBeNaN(dfaLeft) || memState.canBeNaN(dfaRight);
DfaRelationValue dfaRelation = factory.getRelationFactory().create(dfaLeft, dfaRight, opSign, negated);
DfaRelationValue.Factory relationFactory = factory.getRelationFactory();
DfaRelationValue dfaRelation = relationFactory.create(dfaLeft, dfaRight, opSign, negated);
if (dfaRelation != null) {
myCanBeNullInInstanceof.add(instruction);
ArrayList<DfaInstructionState> states = new ArrayList<DfaInstructionState>();
final DfaMemoryState trueCopy = memState.createCopy();
if (trueCopy.applyCondition(dfaRelation)) {
if (dfaLeft instanceof DfaVariableValue && dfaRight instanceof DfaVariableValue) {
if (trueCopy.isNotNull((DfaVariableValue)dfaLeft)) {
trueCopy.applyCondition(relationFactory.create(dfaRight, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true));
} else if (trueCopy.isNotNull((DfaVariableValue)dfaRight)) {
trueCopy.applyCondition(relationFactory.create(dfaLeft, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true));
}
}
trueCopy.push(factory.getConstFactory().getTrue());
instruction.setTrueReachable();
states.add(new DfaInstructionState(next, trueCopy));
@@ -0,0 +1,59 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class Main {
@NotNull
private Object test1(@NotNull Object defVal, @Nullable final Object val) {
return defVal;
}
@NotNull
private Object test11(@NotNull Object defVal, @Nullable final Object val) {
if (val != null) {
return val;
}
return defVal;
}
@NotNull
private Object test5(@NotNull Object defVal, @Nullable final Object val) {
if (defVal == val) {
return val;
}
return defVal;
}
@NotNull
private Object test6(@NotNull Object defVal, @Nullable final Object val) {
if (val == defVal) {
return val;
}
return defVal;
}
@NotNull
private Object test7(@NotNull Object defVal, @Nullable final Object val) {
if (<warning descr="Method invocation 'val.equals(defVal)' may produce 'java.lang.NullPointerException'">val.equals(defVal)</warning>) {
return defVal;
}
return defVal;
}
@NotNull
private Object test8(@NotNull Object defVal, @Nullable final Object val) {
if (defVal.equals(val)) {
return val;
}
return defVal;
}
@NotNull private Object test9(@NotNull Object defVal, @Nullable final Object val) {
if (equals(val)) {
return val;
}
return defVal;
}
@NotNull private Object test10(@NotNull Object defVal, @Nullable final Object val) {
if (val != null) {
return val;
}
if (defVal.equals(val)) {
return <warning descr="Expression 'val' might evaluate to null but is returned by the method declared as @NotNull">val</warning>;
}
return defVal;
}
}
@@ -70,4 +70,6 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
public void testMultiCatch() throws Throwable { doTest(); }
public void testContinueFlushesLoopVariable() throws Throwable { doTest(); }
public void testEqualsNotNull() throws Throwable { doTest(); }
}