diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 390b0451e082..898c744286bc 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -262,13 +262,18 @@ public class StandardInstructionVisitor extends InstructionVisitor { MethodContract.ValueConstraint constraint = contract.arguments[i]; DfaConstValue expectedValue = constraint.getComparisonValue(factory); if (expectedValue == null) continue; - + + boolean nullContract = expectedValue == constFactory.getNull(); boolean invertCondition = constraint.shouldUseNonEqComparison(); DfaValue condition = factory.getRelationFactory().createRelation(argValue, expectedValue, EQEQ, invertCondition); if (condition == null) { if (!(argValue instanceof DfaConstValue)) { for (DfaMemoryState state : states) { - falseStates.add(state.createCopy()); + DfaMemoryState falseCopy = state.createCopy(); + if (nullContract) { + (invertCondition ? falseCopy : state).markEphemeral(); + } + falseStates.add(falseCopy); } continue; } @@ -277,7 +282,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { LinkedHashSet nextStates = ContainerUtil.newLinkedHashSet(); for (DfaMemoryState state : states) { - boolean unknownVsNull = expectedValue == constFactory.getNull() && + boolean unknownVsNull = nullContract && argValue instanceof DfaVariableValue && ((DfaMemoryStateImpl)state).getVariableState((DfaVariableValue)argValue).getNullability() == Nullness.UNKNOWN; DfaMemoryState falseCopy = state.createCopy(); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownMethodNullability.java b/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownMethodNullability.java new file mode 100644 index 000000000000..537a5044f646 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ContractPreservesUnknownMethodNullability.java @@ -0,0 +1,22 @@ +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Nullable; + +class TestCase { + + private void countWordsWarning() { + // no warnings should be here + String s = normalizeSpace(unknown()).trim(); + String s3 = normalizeSpaceInverted(unknown()).trim(); + + String s4 = normalizeSpace(null).trim(); + } + + public static native String unknown(); + + @Contract("null->null") + public static native String normalizeSpace(@Nullable String str); + + @Contract("!null->!null; _->null") + public static native String normalizeSpaceInverted(String str); + +} \ 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 84d9a3df5233..c65376379e40 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java @@ -222,6 +222,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase { public void testContractWithNullable() { doTest(); } public void testContractWithNotNull() { doTest(); } public void testContractPreservesUnknownNullability() { doTest(); } + public void testContractPreservesUnknownMethodNullability() { doTest(); } public void testContractSeveralClauses() { doTest(); } public void testContractVarargs() { doTest(); }