From 827f379576a3c1ceceb8e9aa9f20ea6a7a7bde90 Mon Sep 17 00:00:00 2001 From: Nikita Eshkeev Date: Mon, 26 Jul 2021 21:53:57 +0300 Subject: [PATCH] [java][guarded pattern] IDEA-273957 - Good code red: 'cannot resolve symbol' introduced in instanceof pattern IDEA didn't use to consider that there might be instanceof patterns in the guard expression, so it ignored this part during resolution. Now IDEA tries to resolve a reference against both the pattern variable and guarding expression. GitOrigin-RevId: 249ce6ec8ec6db84f9a5fc4622b4433550b38bf4 --- .../tree/java/PsiGuardedPatternImpl.java | 6 +++- .../GuardWithInstanceOfPatternMatching.java | 16 +++++++++ ...uardWithInstanceOfPatternMatchingInIf.java | 10 ++++++ ...WithInstanceOfPatternMatchingInSwitch.java | 11 ++++++ ...ightPatternsForSwitchHighlightingTest.java | 4 +++ .../navigation/GotoDeclarationTest.java | 34 ++++++++++++++----- 6 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatternsInSwitch/GuardWithInstanceOfPatternMatching.java create mode 100644 java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInIf.java create mode 100644 java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInSwitch.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiGuardedPatternImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiGuardedPatternImpl.java index 61255f993222..9326cba69b96 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiGuardedPatternImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiGuardedPatternImpl.java @@ -47,6 +47,10 @@ public class PsiGuardedPatternImpl extends CompositePsiElement implements PsiGua PsiElement lastParent, @NotNull PsiElement place) { final PsiPrimaryPattern patternVariable = getPrimaryPattern(); - return patternVariable.processDeclarations(processor, state, null, place); + if (!patternVariable.processDeclarations(processor, state, null, place)) return false; + + final PsiExpression expression = getGuardingExpression(); + if (expression == null) return true; + return expression.processDeclarations(processor, state, lastParent, place); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatternsInSwitch/GuardWithInstanceOfPatternMatching.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatternsInSwitch/GuardWithInstanceOfPatternMatching.java new file mode 100644 index 000000000000..aa04a81da82e --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingPatternsInSwitch/GuardWithInstanceOfPatternMatching.java @@ -0,0 +1,16 @@ + +class Main { + void f(Object o) { + if (o instanceof (CharSequence cs && cs instanceof String s)) { + System.out.println(s); + } + } + + void g(Object o) { + switch (o) { + case Integer i && o instanceof String s: + System.out.println(s); + default: + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInIf.java b/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInIf.java new file mode 100644 index 000000000000..0441f8619c1e --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInIf.java @@ -0,0 +1,10 @@ + +class Main { + private String s = ""; + + void f(Object o) { + if (o instanceof (CharSequence cs && cs instanceof String s)) { + System.out.println(s); + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInSwitch.java b/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInSwitch.java new file mode 100644 index 000000000000..f49d3e6d1deb --- /dev/null +++ b/java/java-tests/testData/codeInsight/gotoDeclaration/GuardWithInstanceOfPatternMatchingInSwitch.java @@ -0,0 +1,11 @@ + +class Main { + private String s = ""; + + void g(Object o) { + switch (o) { + case Integer i && o instanceof String s: + System.out.println(s); + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsForSwitchHighlightingTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsForSwitchHighlightingTest.java index 2f87bab580e8..02c3bd570034 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsForSwitchHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightPatternsForSwitchHighlightingTest.java @@ -72,6 +72,10 @@ public class LightPatternsForSwitchHighlightingTest extends LightJavaCodeInsight assertSize(2, IdentifierHighlighterPass.getUsages(element, file, true)); } + public void testGuardWithInstanceOfPatternMatching() { + doTest(); + } + private void doTest() { myFixture.configureByFile(getTestName(false) + ".java"); myFixture.checkHighlighting(); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/GotoDeclarationTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/GotoDeclarationTest.java index e442273d03f7..fc88fb28056b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/GotoDeclarationTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/navigation/GotoDeclarationTest.java @@ -13,6 +13,7 @@ import org.jetbrains.annotations.NotNull; import java.util.Arrays; import java.util.Collection; +import java.util.Iterator; import static com.intellij.testFramework.assertions.Assertions.assertThat; @@ -46,15 +47,13 @@ public class GotoDeclarationTest extends LightJavaCodeInsightTestCase { } public void testGotoDirectory() { - String name = getTestName(false); - configureByFile("/codeInsight/gotoDeclaration/" + name + ".java"); + configure(); PsiDirectory element = (PsiDirectory)GotoDeclarationAction.findTargetElement(getProject(), getEditor(), getEditor().getCaretModel().getOffset()); assertEquals("java.lang", JavaDirectoryService.getInstance().getPackage(element).getQualifiedName()); } private void doTestMultipleConstructors() { - String name = getTestName(false); - configureByFile("/codeInsight/gotoDeclaration/" + name + ".java"); + configure(); final int offset = getEditor().getCaretModel().getOffset(); final PsiElement[] elements = GotoDeclarationAction.findAllTargetElements(getProject(), getEditor(), offset); @@ -76,8 +75,7 @@ public class GotoDeclarationTest extends LightJavaCodeInsightTestCase { } public void testMultipleConstructorsButArrayCreation() { - String name = getTestName(false); - configureByFile("/codeInsight/gotoDeclaration/" + name + ".java"); + configure(); final int offset = getEditor().getCaretModel().getOffset(); final PsiReference reference = getFile().findReferenceAt(offset); assertNotNull(reference); @@ -134,12 +132,32 @@ public class GotoDeclarationTest extends LightJavaCodeInsightTestCase { doTestPatternMatchingGuard(); } + public void testGuardWithInstanceOfPatternMatchingInIf() { + doTestGoToPatternVariable(); + } + + public void testGuardWithInstanceOfPatternMatchingInSwitch() { + doTestGoToPatternVariable(); + } + private void doTestPatternMatchingGuard() { - String name = getTestName(false); - configureByFile("/codeInsight/gotoDeclaration/" + name + ".java"); + configure(); final PsiJavaFile file = (PsiJavaFile)getFile(); final PsiField field = PsiTreeUtil.findChildOfType(file, PsiField.class); final PsiElement element = GotoDeclarationAction.findTargetElement(getProject(), getEditor(), getEditor().getCaretModel().getOffset()); assertThat(element).isEqualTo(field); } + + private void doTestGoToPatternVariable() { + configure(); + final Iterator iterator = PsiTreeUtil.findChildrenOfType(getFile(), PsiPatternVariable.class).iterator(); + iterator.next(); + final PsiElement element = GotoDeclarationAction.findTargetElement(getProject(), getEditor(), getEditor().getCaretModel().getOffset()); + assertThat(element).isEqualTo(iterator.next()); + } + + private void configure() { + String name = getTestName(false); + configureByFile("/codeInsight/gotoDeclaration/" + name + ".java"); + } }