From 0de99ed3198ab8c1fefadef4a9393a8ab4f9690d Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 3 Jan 2025 10:06:16 +0100 Subject: [PATCH] [java-dfa] IDEA-365304 Data flow analysis: ignore instanceof statements if operand type or check type is not fully resolved GitOrigin-RevId: fad95d5a40cccc2b2a36d1a2180c3ac08b70fa5b --- .../dataFlow/java/ControlFlowAnalyzer.java | 4 +- .../templates/castvar/typeAnnotations.java | 2 +- .../castvar/typeAnnotations_after.java | 2 +- .../fixture/IncompleteSwitchEnum.java | 2 +- .../fixture/InstanceOfUnresolvedType.java | 51 +++++++++++++++++++ .../DataFlowInspection21Test.java | 1 + .../SeveralMethodsSample.expected.k2.kt | 4 +- 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/InstanceOfUnresolvedType.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java index 7f943c734234..876aaae5c529 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/ControlFlowAnalyzer.java @@ -1209,7 +1209,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor { checkType = TypeConversionUtil.erasure(checkType); if (patternType == null || ((checkType instanceof PsiPrimitiveType || patternType instanceof PsiPrimitiveType) && - (!PsiUtil.isAvailable(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS, context) || !TypeConversionUtil.areTypesConvertible(checkType, patternType)))) { + (!PsiUtil.isAvailable(JavaFeature.PRIMITIVE_TYPES_IN_PATTERNS, context) || !TypeConversionUtil.areTypesConvertible(checkType, patternType))) || + (checkType instanceof PsiClassType ct && ct.resolve() == null) || + (patternType instanceof PsiClassType pt && pt.resolve() == null)) { addInstruction(new PopInstruction()); pushUnknown(); return; diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations.java b/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations.java index 690857c75b77..2f2ee5b6bdee 100644 --- a/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations.java +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations.java @@ -1,7 +1,7 @@ @Target(ElementType.TYPE_USE) @interface N {} class M { - void m(Oject o) { + void m(Object o) { if (o instanceof @N String) { o.castvar } diff --git a/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations_after.java b/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations_after.java index 48956d660917..ec4e7a8cd2b6 100644 --- a/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations_after.java +++ b/java/java-tests/testData/codeInsight/template/postfix/templates/castvar/typeAnnotations_after.java @@ -1,7 +1,7 @@ @Target(ElementType.TYPE_USE) @interface N {} class M { - void m(Oject o) { + void m(Object o) { if (o instanceof @N String) { String s = (String) o; } diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java b/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java index 4068c51a5acb..e20204a1aa9e 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java @@ -4,7 +4,7 @@ public enum Test { void test() { Integer code = getCode(); switch (code) { - case VALUE.value() + case VALUE.value() } if (code == VALUE.value()) { getCode(); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/InstanceOfUnresolvedType.java b/java/java-tests/testData/inspection/dataFlow/fixture/InstanceOfUnresolvedType.java new file mode 100644 index 000000000000..38757f10c69f --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/InstanceOfUnresolvedType.java @@ -0,0 +1,51 @@ +public class InstanceOfUnresolvedType { + void test(Object o) { + int i = 0; + if (o instanceof Unresolved) { + i = 1; + } + else if (o instanceof Unresolved2) { + i = 2; + } + else { + i = 3; + } + if (i == 0) { + + } + else if (i == 1) { + + } + else if (i == 2) { + + } + else if (i == 3) { + + } + } + + void test2(Unresolved u) { + int i = 0; + if (u instanceof CharSequence cs) { + i = 1; + } + else if (u instanceof Number n) { + i = 2; + } + else { + i = 3; + } + if (i == 0) { + + } + else if (i == 1) { + + } + else if (i == 2) { + + } + else if (i == 3) { + + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java index 5a50879ed708..8726b035d42b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection21Test.java @@ -131,6 +131,7 @@ public class DataFlowInspection21Test extends DataFlowInspectionTestCase { public void testArrayElementWrappedInPureMethod() { doTest(); } public void testArrayAddedIntoCollection() { doTest(); } + public void testInstanceOfUnresolvedType() { doTest(); } public void testInstanceOfPatternAffectNullity() { doTest(); } diff --git a/plugins/kotlin/j2k/shared/tests/testData/copyPaste/SeveralMethodsSample.expected.k2.kt b/plugins/kotlin/j2k/shared/tests/testData/copyPaste/SeveralMethodsSample.expected.k2.kt index 8d55dd8549bf..c68f1ac53597 100644 --- a/plugins/kotlin/j2k/shared/tests/testData/copyPaste/SeveralMethodsSample.expected.k2.kt +++ b/plugins/kotlin/j2k/shared/tests/testData/copyPaste/SeveralMethodsSample.expected.k2.kt @@ -8,7 +8,7 @@ class A { val bindingContext: BindingContext = AnalyzerFacadeWithCache.analyzeFileWithCache(element.getContainingJetFile()).getBindingContext() - val declarationDescriptor: DeclarationDescriptor? = + val declarationDescriptor: DeclarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) if (declarationDescriptor is CallableMemberDescriptor) { val containingDescriptor: DeclarationDescriptor? = declarationDescriptor.getContainingDeclaration() @@ -25,7 +25,7 @@ class A { assert( element is PsiMethod ) { "Method accepts only kotlin functions/properties and java methods, but '" + element.getText() + "' was found" } - return JetRefactoringUtil.formatPsiMethod(element as PsiMethod, true, false) + return JetRefactoringUtil.formatPsiMethod(element as PsiMethod?, true, false) } protected override fun getDimensionServiceKey(): String {