diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index 1742c7979f91..eff31fe313f0 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -329,7 +329,7 @@ public class JavaCompletionUtil { final StaticMemberProcessor memberProcessor = new JavaStaticMemberProcessor(parameters); memberProcessor.processMembersOfRegisteredClasses(matcher, (member, psiClass) -> { if (!mentioned.contains(member) && processor.satisfies(member, ResolveState.initial())) { - set.add(memberProcessor.createLookupElement(member, psiClass, true)); + ContainerUtil.addIfNotNull(set, memberProcessor.createLookupElement(member, psiClass, true)); } }); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java index 4609309f2aa6..0be2eac0fa42 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaStaticMemberProcessor.java @@ -21,7 +21,9 @@ import com.intellij.codeInsight.lookup.VariableLookupItem; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; @@ -46,13 +48,14 @@ public class JavaStaticMemberProcessor extends StaticMemberProcessor { } } - @NotNull + @Nullable @Override protected LookupElement createLookupElement(@NotNull PsiMember member, @NotNull final PsiClass containingClass, boolean shouldImport) { shouldImport |= myOriginalPosition != null && PsiTreeUtil.isAncestor(containingClass, myOriginalPosition, false); - String exprText = member.getName() + (member instanceof PsiMethod ? "()" : ""); - PsiReference ref = JavaPsiFacade.getElementFactory(member.getProject()).createExpressionFromText(exprText, myOriginalPosition).findReferenceAt(0); + PsiReference ref = createReferenceToMemberName(member); + if (ref == null) return null; + if (ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).multiResolve(true).length > 0) { shouldImport = false; } @@ -70,6 +73,16 @@ public class JavaStaticMemberProcessor extends StaticMemberProcessor { }); } + private PsiReference createReferenceToMemberName(@NotNull PsiMember member) { + try { + String exprText = member.getName() + (member instanceof PsiMethod ? "()" : ""); + return JavaPsiFacade.getElementFactory(member.getProject()).createExpressionFromText(exprText, myOriginalPosition).findReferenceAt(0); + } + catch (IncorrectOperationException e) { + return null; + } + } + @Override protected LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java index aa760f03e2da..503e5031e53c 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/StaticMemberProcessor.java @@ -19,6 +19,7 @@ import com.intellij.codeInsight.daemon.impl.quickfix.StaticImportMemberFix; import com.intellij.codeInsight.lookup.LookupElement; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.java.stubs.index.JavaStaticMemberNameIndex; import com.intellij.psi.search.GlobalSearchScope; @@ -29,10 +30,7 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; +import java.util.*; /** * @author peter @@ -67,35 +65,41 @@ public abstract class StaticMemberProcessor { assert containingClass != null : member.getName() + "; " + member + "; " + member.getClass(); if (JavaCompletionUtil.isSourceLevelAccessible(myPosition, containingClass, myPackagedContext)) { + if (member instanceof PsiMethod && !classes.add(containingClass)) continue; + final boolean shouldImport = myStaticImportedClasses.contains(containingClass); showHint(shouldImport); - if (member instanceof PsiMethod && classes.add(containingClass)) { - final PsiMethod[] allMethods = containingClass.getAllMethods(); - final List overloads = ContainerUtil.findAll(allMethods, psiMethod -> memberName.equals(psiMethod.getName()) && isStaticallyImportable(psiMethod)); - - assert !overloads.isEmpty(); - if (overloads.size() == 1) { - assert member == overloads.get(0); - consumer.consume(createLookupElement(member, containingClass, shouldImport)); - } else { - if (overloads.get(0).getParameterList().getParametersCount() == 0) { - overloads.add(0, overloads.remove(1)); - } - consumer.consume(createLookupElement(overloads, containingClass, shouldImport)); - } - } else if (member instanceof PsiField) { - consumer.consume(createLookupElement(member, containingClass, shouldImport)); - } + LookupElement item = member instanceof PsiMethod ? createItemWithOverloads((PsiMethod)member, containingClass, shouldImport) : + member instanceof PsiField ? createLookupElement(member, containingClass, shouldImport) : + null; + if (item != null) consumer.consume(item); } } } } } + @Nullable + private LookupElement createItemWithOverloads(PsiMethod method, PsiClass containingClass, boolean shouldImport) { + List overloads = ContainerUtil.findAll(containingClass.findMethodsByName(method.getName(), true), + this::isStaticallyImportable); + + assert !overloads.isEmpty(); + if (overloads.size() == 1) { + assert method == overloads.get(0); + return createLookupElement(method, containingClass, shouldImport); + } + + if (overloads.get(0).getParameterList().getParametersCount() == 0) { + overloads.add(0, overloads.remove(1)); + } + return createLookupElement(overloads, containingClass, shouldImport); + } + private void showHint(boolean shouldImport) { if (!myHintShown && !shouldImport) { final String shortcut = CompletionContributor.getActionShortcut(IdeActions.ACTION_SHOW_INTENTION_ACTIONS); - if (shortcut != null) { + if (StringUtil.isNotEmpty(shortcut)) { CompletionService.getCompletionService().setAdvertisementText("To import a method statically, press " + shortcut); } myHintShown = true; @@ -132,7 +136,7 @@ public abstract class StaticMemberProcessor { return myResolveHelper.isAccessible(member, myPosition, null); } - @NotNull + @Nullable protected abstract LookupElement createLookupElement(@NotNull PsiMember member, @NotNull PsiClass containingClass, boolean shouldImport); protected abstract LookupElement createLookupElement(@NotNull List overloads, @NotNull PsiClass containingClass, boolean shouldImport); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/JavaWithGroovyCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/JavaWithGroovyCompletionTest.groovy new file mode 100644 index 000000000000..8c0e80856e10 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/completion/JavaWithGroovyCompletionTest.groovy @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.completion + +import com.intellij.codeInsight.completion.CompletionType; + +/** + * @author peter + */ +class JavaWithGroovyCompletionTest extends GroovyCompletionTestBase { + + void "test using java keywords in member names"() { + myFixture.addFileToProject 'a.groovy', ''' +class Foo { + static void "const"() {} + static final int "continue" = 2; +} +''' + myFixture.configureByText 'a.java', 'class Bar {{ con }}' + myFixture.complete(CompletionType.BASIC, 2) + assert !(myFixture.lookupElementStrings.contains('const')) + assert !(myFixture.lookupElementStrings.contains('continue')) + } +}