don't suggest keyword-named members in java completion (EA-90531 - IOE: PsiJavaParserFacadeImpl.createExpressionFromText)

This commit is contained in:
peter
2017-04-28 13:32:30 +02:00
parent 36180283cf
commit 2d6b3250b8
4 changed files with 81 additions and 27 deletions
@@ -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));
}
});
}
@@ -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<PsiMethod> overloads,
@NotNull PsiClass containingClass,
@@ -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<PsiMethod> 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<PsiMethod> 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<PsiMethod> overloads, @NotNull PsiClass containingClass, boolean shouldImport);
@@ -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<caret> }}'
myFixture.complete(CompletionType.BASIC, 2)
assert !(myFixture.lookupElementStrings.contains('const'))
assert !(myFixture.lookupElementStrings.contains('continue'))
}
}