equals implies not-nullness of its argument (IDEA-88777, IDEA-92809, IDEA-16979)

This commit is contained in:
peter
2012-10-29 12:57:23 +01:00
parent 733b09331a
commit 8114b9af49
7 changed files with 62 additions and 7 deletions
@@ -701,12 +701,24 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
}
private static class ApplyNotNullInstruction extends Instruction {
private PsiMethodCallExpression myCall;
private ApplyNotNullInstruction(PsiMethodCallExpression call) {
myCall = call;
}
@Override
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) {
DfaValue value = state.pop();
DfaValueFactory factory = runner.getFactory();
state.applyCondition(factory.getRelationFactory().createRelation(value, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true));
return nextInstruction(runner, state);
if (state.applyCondition(
factory.getRelationFactory().createRelation(value, factory.getConstFactory().getNull(), JavaTokenType.EQEQ, true))) {
return nextInstruction(runner, state);
}
if (visitor instanceof StandardInstructionVisitor) {
((StandardInstructionVisitor)visitor).skipConstantConditionReporting(myCall);
}
return DfaInstructionState.EMPTY_ARRAY;
}
}
@@ -1225,7 +1237,7 @@ class ControlFlowAnalyzer extends JavaElementVisitor {
addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null));
paramExprs[0].accept(this);
addInstruction(new ApplyNotNullInstruction());
addInstruction(new ApplyNotNullInstruction(expression));
}
}
finally {
@@ -615,7 +615,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
if (dfaRight == myFactory.getConstFactory().getNull() && dfaLeft instanceof DfaVariableValue) {
final DfaVariableState varState = getVariableState((DfaVariableValue)dfaLeft);
if (varState.isNotNull()) return isNegated;
varState.setNullable(true);
varState.setNullable(!isNegated);
}
if (dfaLeft instanceof DfaUnknownValue || dfaRight instanceof DfaUnknownValue) return true;
@@ -330,7 +330,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
if (isViaMethods(dfaLeft) || isViaMethods(dfaRight)) {
ContainerUtil.addIfNotNull(myNotToReportReachability, instruction.getPsiAnchor());
skipConstantConditionReporting(instruction.getPsiAnchor());
}
myCanBeNullInInstanceof.add(instruction);
@@ -363,6 +363,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return states.toArray(new DfaInstructionState[states.size()]);
}
public void skipConstantConditionReporting(@Nullable PsiElement anchor) {
ContainerUtil.addIfNotNull(myNotToReportReachability, anchor);
}
private static boolean isViaMethods(DfaValue dfa) {
return dfa instanceof DfaVariableValue && ((DfaVariableValue)dfa).isViaMethods();
}
@@ -51,7 +51,6 @@ public class DfaRelationValue extends DfaValue {
myStringToObject = new HashMap<String, ArrayList<DfaRelationValue>>();
}
@Nullable
public DfaRelationValue createRelation(DfaValue dfaLeft, DfaValue dfaRight, IElementType relation, boolean negated) {
if (dfaRight instanceof DfaTypeValue && INSTANCEOF_KEYWORD != relation) return null;
if (PLUS == relation) return null;
@@ -0,0 +1,24 @@
import org.jetbrains.annotations.NotNull;
class Test {
public static void main(String[] args) {
Object first = null;
for (int i = 0; i < 10; i++) {
if (!"b".equals(first)) {
first = "b";
}
System.out.println(first.toString());
}
}
public void buggyInspectionExample(Object parentNode) {
final String parentName = parentNode == null ? null : parentNode.toString();
if ("Topics".equals(parentName)) {
System.out.println(parentNode.toString());
} else if ("Queues".equals(parentName)) {
System.out.println(parentNode.toString());
}
System.out.println(<warning descr="Method invocation 'parentNode.toString()' may produce 'java.lang.NullPointerException'">parentNode.toString()</warning>);
}
}
@@ -52,8 +52,23 @@ public class Main {
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 val;
}
return defVal;
}
@NotNull
private static Object test(@NotNull Object defVal, @Nullable final Object val) {
if (val != null) {
return val;
}
if (defVal == val) {
return val;
}
if (defVal.equals(val)) {
return val;
}
return defVal;
}
}
@@ -101,5 +101,6 @@ public class DataFlowInspectionFixtureTest extends JavaCodeInsightFixtureTestCas
public void testPreserveNullableOnUncheckedCast() throws Throwable { doTest(); }
public void testPassingNullableIntoVararg() throws Throwable { doTest(); }
public void testEqualsImpliesNotNull() throws Throwable { doTest(); }
}