diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java index 07df81eeaf39..a2e6e02dd89f 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/TypeConstraint.java @@ -192,8 +192,19 @@ public final class TypeConstraint { instanceOfTypes = withSuper(this.myInstanceofValues); instanceOfTypes.retainAll(withSuper(other.myInstanceofValues)); } - TypeConstraint constraint = StreamEx.of(instanceOfTypes).foldLeft(EMPTY, TypeConstraint::withInstanceofValue); - return StreamEx.of(notTypes).foldLeft(constraint, TypeConstraint::withNotInstanceofValue); + TypeConstraint constraint = EMPTY; + for (DfaPsiType type: instanceOfTypes) { + constraint = constraint.withInstanceofValue(type); + if (constraint == null) { + // Should not happen normally, but may happen with inconsistent hierarchy (e.g. if final class is extended) + return EMPTY; + } + } + for (DfaPsiType type: notTypes) { + constraint = constraint.withNotInstanceofValue(type); + if (constraint == null) return EMPTY; + } + return constraint; } private static Set withSuper(Set instanceofValues) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa.java b/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa.java new file mode 100644 index 000000000000..f4c87c855f5d --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa.java @@ -0,0 +1,14 @@ +import java.util.*; + +class Foo { + final class X {} + class Y extends X {} + class YY extends X {} + interface Z {}; + + void test(Object o) { + if((o instanceof Y && o instanceof Z) || (o instanceof YY && o instanceof Z)) { + o.hashC + } + } +} diff --git a/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa_after.java b/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa_after.java new file mode 100644 index 000000000000..0c7f4da09db2 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/InconsistentHierarchyDfa_after.java @@ -0,0 +1,14 @@ +import java.util.*; + +class Foo { + final class X {} + class Y extends X {} + class YY extends X {} + interface Z {}; + + void test(Object o) { + if((o instanceof Y && o instanceof Z) || (o instanceof YY && o instanceof Z)) { + o.hashCode() + } + } +} diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionDfaTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionDfaTest.groovy index a676336654c9..a5f1c55c38d6 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionDfaTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionDfaTest.groovy @@ -60,6 +60,7 @@ class NormalCompletionDfaTest extends NormalCompletionTestCase { void testNarrowingReturnTypeInVoidContext() { doTest() } void testNoUnnecessaryCastDfa() { doTest() } void testNoUnnecessaryCastRawDfa() { doTest() } + void testInconsistentHierarchyDfa() { doTest() } void testNoUnnecessaryCastDeepHierarchy() { doTest() } void testInstanceOfAfterFunction() { doTest() } void testInstanceOfDisjunction() { doTest() }