mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IDEA-88777 equlas() and == should be taken into account by nullability check
This commit is contained in:
@@ -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);
|
||||
|
||||
+9
-1
@@ -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(); }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user