From 88c8ac79e5b39fc25a129ae74835d1173e96570c Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 17 Jun 2014 19:43:42 +0200 Subject: [PATCH] dfa: handle variable comparisons to unknown not-null values --- .../dataFlow/DfaMemoryStateImpl.java | 9 ++++++++- .../dataFlow/value/DfaRelationValue.java | 5 ++++- .../dataFlow/fixture/ComparingNullToNotNull.java | 14 ++++++++++++++ .../fixture/ComparingNullableToNullable.java | 16 ++++++++++++++++ .../fixture/ComparingNullableToUnknown.java | 16 ++++++++++++++++ .../codeInspection/DataFlowInspectionTest.java | 3 +++ 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 3b44c82f9398..1b6d1dfedfec 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -583,7 +583,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (dfaLeft instanceof DfaVariableValue) { DfaVariableValue dfaVar = (DfaVariableValue)dfaLeft; if (isUnknownState(dfaVar)) return true; - + + if (!dfaRelation.isInstanceOf()) { + if (((DfaTypeValue)dfaRight).isNotNull() && isNull(dfaVar)) { + return isNegated; + } + return true; + } + if (isNegated) { DfaVariableState newState = getVariableState(dfaVar).withNotInstanceofValue((DfaTypeValue)dfaRight); if (newState != null) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java index 8343fc9e6a2c..3e70b2d4b673 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaRelationValue.java @@ -52,7 +52,6 @@ public class DfaRelationValue extends DfaValue { } 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; if (dfaLeft instanceof DfaVariableValue || dfaLeft instanceof DfaBoxedValue || dfaLeft instanceof DfaUnboxedValue @@ -169,6 +168,10 @@ public class DfaRelationValue extends DfaValue { return myRelation == EQEQ && myIsNegated || myRelation == GT && !myIsNegated || myRelation == GE && myIsNegated; } + public boolean isInstanceOf() { + return myRelation == INSTANCEOF_KEYWORD; + } + @NonNls public String toString() { return (isNegated() ? "not " : "") + myLeftOperand + " " + myRelation + " " + myRightOperand; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java new file mode 100644 index 000000000000..a9f17f7e9a06 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullToNotNull.java @@ -0,0 +1,14 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == "") { + System.out.println(element.hashCode()); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java new file mode 100644 index 000000000000..5e3ce3c0b69b --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToNullable.java @@ -0,0 +1,16 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == nullableString()) { + System.out.println(element.hashCode()); + } + } + + @Nullable String nullableString() { return null; } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java new file mode 100644 index 000000000000..b15c6c7a52f7 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ComparingNullableToUnknown.java @@ -0,0 +1,16 @@ +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +class Bar3 { + + public void foo(@Nullable Object element) { + final String elementType = element != null ? element.toString() : null; + if (elementType == someString()) { + System.out.println(element.hashCode()); + } + } + + String someString() { return null; } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java index d15527e3c49c..833b5196d74a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -71,6 +71,9 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testGeneratedEquals() throws Throwable { doTest(); } public void testIDEA84489() throws Throwable { doTest(); } + public void testComparingNullToNotNull() { doTest(); } + public void testComparingNullableToNullable() { doTest(); } + public void testComparingNullableToUnknown() { doTest(); } public void testComparingToNotNullShouldNotAffectNullity() throws Throwable { doTest(); } public void testComparingToNullableShouldNotAffectNullity() throws Throwable { doTest(); } public void testStringTernaryAlwaysTrue() throws Throwable { doTest(); }