mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
equals implies not-nullness of its argument (IDEA-88777, IDEA-92809, IDEA-16979)
This commit is contained in:
@@ -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;
|
||||
|
||||
+5
-1
@@ -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(); }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user