From cf9be48742ac240b9d48adc4df0a1a1e91184c91 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 19 Sep 2022 18:56:26 +0200 Subject: [PATCH] [java-completion] Restore references in switch labels (IDEA-301950) Likely, regression after IDEA-278622 GitOrigin-RevId: cc77068631608e388e95cb4f103b3d8155aa58e9 --- .../completion/JavaCompletionContributor.java | 42 ++++++++++++------- .../CompleteReferencesInExpressionSwitch.java | 11 +++++ ...eteReferencesInExpressionSwitch_after.java | 11 +++++ .../completion/NormalCompletionTest.groovy | 1 + .../NormalPatternsCompletionTest.java | 4 +- .../NormalSwitchCompletionTest.groovy | 5 +++ 6 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index fe941ae4693c..63decf94fe7d 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -58,6 +58,7 @@ import com.intellij.psi.impl.java.stubs.index.JavaSourceModuleNameIndex; import com.intellij.psi.impl.light.LightJavaModule; import com.intellij.psi.impl.source.PsiJavaCodeReferenceElementImpl; import com.intellij.psi.impl.source.PsiLabelReference; +import com.intellij.psi.impl.source.resolve.JavaResolveUtil; import com.intellij.psi.scope.ElementClassFilter; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectScope; @@ -265,17 +266,18 @@ public final class JavaCompletionContributor extends CompletionContributor imple @Override public boolean isAcceptable(Object element, PsiElement context) { PsiVariable variable; - if (element instanceof PsiField) { - variable = (PsiField)element; - if (variable.hasModifierProperty(PsiModifier.FINAL) && variable.hasModifierProperty(PsiModifier.STATIC)) { - return true; + if (element instanceof PsiField field) { + if (!field.hasModifierProperty(PsiModifier.FINAL) || !field.hasModifierProperty(PsiModifier.STATIC) || + !JavaResolveUtil.isAccessible(field, field.getContainingClass(), field.getModifierList(), context, null, null)) { + return false; } + variable = field; } - else if (element instanceof PsiLocalVariable) { - variable = (PsiLocalVariable)element; - if (variable.hasModifierProperty(PsiModifier.FINAL)) { - return true; + else if (element instanceof PsiLocalVariable local) { + if (!local.hasModifierProperty(PsiModifier.FINAL)) { + return false; } + variable = local; } else { return false; @@ -284,12 +286,22 @@ public final class JavaCompletionContributor extends CompletionContributor imple } }; - if (isPrimitive(selectorType)) return constantVariablesFilter; - - if (!HighlightingFeature.PATTERNS_IN_SWITCH.isAvailable(position)) { - return TypeUtils.isJavaLangString(selectorType) - ? constantVariablesFilter - : TrueFilter.INSTANCE; + if (!HighlightingFeature.PATTERNS_IN_SWITCH.isAvailable(position) || + isPrimitive(selectorType) || TypeUtils.isJavaLangString(selectorType)) { + ClassFilter classFilter = new ClassFilter(PsiClass.class) { + @Override + public boolean isAcceptable(Object element, PsiElement context) { + // Accept only classes with inner classes or with suitable fields + if (!(element instanceof PsiClass psiClass)) return false; + for (PsiClass aClass : psiClass.getInnerClasses()) { + if (JavaResolveUtil.isAccessible(aClass, psiClass, aClass.getModifierList(), context, null, null)) { + return true; + } + } + return ContainerUtil.exists(psiClass.getAllFields(), field -> constantVariablesFilter.isAcceptable(field, context)); + } + }; + return new OrFilter(classFilter, constantVariablesFilter); } if (TypeUtils.isJavaLangObject(selectorType)) { @@ -301,7 +313,7 @@ public final class JavaCompletionContributor extends CompletionContributor imple ClassFilter inheritorsFilter = new ClassFilter(PsiClass.class) { @Override public boolean isAcceptable(Object element, PsiElement context) { - return element instanceof PsiClass && InheritanceUtil.isInheritorOrSelf((PsiClass)element, typeClass, true); + return element instanceof PsiClass psiClass && InheritanceUtil.isInheritorOrSelf(psiClass, typeClass, true); } }; diff --git a/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch.java b/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch.java new file mode 100644 index 000000000000..b148f03a5a4f --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch.java @@ -0,0 +1,11 @@ +class Foo { + public int foo(String str) { + return switch (str) { + case MyCons + }; + } +} + +class MyConstants { + public static final String STRING_ONE = "1"; +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch_after.java b/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch_after.java new file mode 100644 index 000000000000..2870726565ec --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/CompleteReferencesInExpressionSwitch_after.java @@ -0,0 +1,11 @@ +class Foo { + public int foo(String str) { + return switch (str) { + case MyConstants + }; + } +} + +class MyConstants { + public static final String STRING_ONE = "1"; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index b176f0ca77e0..1453db8f32d5 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -874,6 +874,7 @@ public class ListUtils { void testReturnInCase() throws Throwable { doTest() } + @NeedsIndex.ForStandardLibrary void testUnboxedConstantsInCase() throws Throwable { doTest() } void testAnnotationWithoutValueMethod() throws Throwable { diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalPatternsCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalPatternsCompletionTest.java index bba976d2fb6f..0b4f3106ef24 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalPatternsCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalPatternsCompletionTest.java @@ -164,7 +164,9 @@ public class NormalPatternsCompletionTest extends NormalCompletionTestCase { } }"""); myFixture.completeBasic(); - assertEquals(List.of(), myFixture.getLookupElementStrings()); + // Options contributed by TypoTolerantMatcher; these classes contain nested public classes, + // so we allow them, as they may potentially contain string constants + assertEquals(List.of("ForkJoinPool", "ThreadPoolExecutor"), myFixture.getLookupElementStrings()); } @NeedsIndex.Full diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalSwitchCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalSwitchCompletionTest.groovy index 48c82dc04991..f9f372070402 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalSwitchCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalSwitchCompletionTest.groovy @@ -58,6 +58,11 @@ class NormalSwitchCompletionTest extends NormalCompletionTestCase { void testCompleteSwitchObjectSelectorPostfix() { doTestPostfixCompletion() } void testCompleteSwitchSealedSelectorPostfix() { doTestPostfixCompletion() } + @NeedsIndex.ForStandardLibrary + void testCompleteReferencesInExpressionSwitch() { + doTest() + } + private void doTestPostfixCompletion() { LiveTemplateCompletionContributor.setShowTemplatesInTests(true, myFixture.testRootDisposable) configure()