IDEA-83744 Always insert '()' when class name is completed after 'new' keyword

This commit is contained in:
peter
2012-06-22 14:44:11 +02:00
parent b40af47e25
commit 3a3548f2a2
18 changed files with 242 additions and 162 deletions
@@ -158,9 +158,11 @@ public class AllClassesGetter {
}).forEach(new Processor<PsiClass>() {
public boolean process(PsiClass psiClass) {
assert psiClass != null;
if (isSuitable(context, packagePrefix, qnames, psiClass, filterByScope, pkgContext)) {
qnames.add(psiClass.getQualifiedName());
consumer.consume(psiClass);
if (isAcceptableInContext(context, psiClass, filterByScope, pkgContext)) {
String qName = psiClass.getQualifiedName();
if (qName != null && qName.startsWith(packagePrefix) && qnames.add(qName)) {
consumer.consume(psiClass);
}
}
return true;
}
@@ -181,9 +183,9 @@ public class AllClassesGetter {
return j > 0 ? prefix.substring(0, j) : "";
}
private static boolean isSuitable(@NotNull final PsiElement context, final String packagePrefix, final Set<String> qnames,
@NotNull final PsiClass psiClass,
final boolean filterByScope, final boolean pkgContext) {
public static boolean isAcceptableInContext(@NotNull final PsiElement context,
@NotNull final PsiClass psiClass,
final boolean filterByScope, final boolean pkgContext) {
ProgressManager.checkCanceled();
if (!context.isValid() || !psiClass.isValid()) return false;
@@ -191,9 +193,7 @@ public class AllClassesGetter {
if (JavaCompletionUtil.isInExcludedPackage(psiClass, false)) return false;
final String qualifiedName = psiClass.getQualifiedName();
if (qualifiedName == null || !qualifiedName.startsWith(packagePrefix)) return false;
if (qnames.contains(qualifiedName)) return false;
if (qualifiedName == null) return false;
if (!filterByScope && !(psiClass instanceof PsiCompiledElement)) return true;
@@ -44,9 +44,7 @@ public class InheritorsHolder implements Consumer<LookupElement> {
public void consume(LookupElement lookupElement) {
final Object object = lookupElement.getObject();
if (object instanceof PsiClass) {
final PsiClass psiClass = (PsiClass)object;
if (JavaCompletionUtil.hasAccessibleInnerClass(psiClass, myPosition)) return;
registerClass(psiClass);
registerClass((PsiClass)object);
}
myResult.addElement(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(lookupElement));
}
@@ -19,12 +19,12 @@ import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.LangBundle;
import com.intellij.lang.StdLanguages;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.PsiJavaElementPattern;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.psi.*;
import com.intellij.psi.filters.ClassFilter;
import com.intellij.psi.filters.ElementFilter;
@@ -35,15 +35,18 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ProcessingContext;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
/**
* @author peter
*/
public class JavaClassNameCompletionContributor extends CompletionContributor {
private static final PsiJavaElementPattern.Capture<PsiElement> AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW);
public static final PsiJavaElementPattern.Capture<PsiElement> AFTER_NEW = psiElement().afterLeaf(PsiKeyword.NEW);
private static final PsiJavaElementPattern.Capture<PsiElement> IN_TYPE_PARAMETER =
psiElement().afterLeaf(PsiKeyword.EXTENDS, PsiKeyword.SUPER, "&").withParent(
psiElement(PsiReferenceList.class).withParent(PsiTypeParameter.class));
@@ -92,7 +95,8 @@ public class JavaClassNameCompletionContributor extends CompletionContributor {
}
final boolean inJavaContext = parameters.getPosition() instanceof PsiIdentifier;
if (AFTER_NEW.accepts(insertedElement)) {
final boolean afterNew = AFTER_NEW.accepts(insertedElement);
if (afterNew) {
final PsiExpression expr = PsiTreeUtil.getContextOfType(insertedElement, PsiExpression.class, true);
for (final ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes(expr, true)) {
final PsiType type = info.getType();
@@ -104,20 +108,34 @@ public class JavaClassNameCompletionContributor extends CompletionContributor {
if (!defaultType.equals(type)) {
final PsiClass defClass = PsiUtil.resolveClassInType(defaultType);
if (defClass != null) {
consumer.consume(createClassLookupItem(defClass, inJavaContext));
consumer.consume(createClassLookupItem(defClass, true));
}
}
}
}
final boolean lookingForAnnotations = PsiJavaPatterns.psiElement().afterLeaf("@").accepts(insertedElement);
final boolean lookingForAnnotations = psiElement().afterLeaf("@").accepts(insertedElement);
final boolean pkgContext = JavaCompletionUtil.inSomePackage(insertedElement);
AllClassesGetter.processJavaClasses(parameters, matcher, filterByScope, new Consumer<PsiClass>() {
@Override
public void consume(PsiClass psiClass) {
if (lookingForAnnotations && !psiClass.isAnnotationType()) return;
if (filter.isAcceptable(psiClass, insertedElement)) {
consumer.consume(createClassLookupItem(psiClass, inJavaContext));
if (!inJavaContext) {
consumer.consume(AllClassesGetter.createLookupItem(psiClass, AllClassesGetter.TRY_SHORTENING));
} else {
for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew,
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
return filter.isAcceptable(psiClass, insertedElement) &&
AllClassesGetter.isAcceptableInContext(insertedElement, psiClass, filterByScope, pkgContext);
}
})) {
consumer.consume(element);
}
}
}
}
});
@@ -128,6 +146,31 @@ public class JavaClassNameCompletionContributor extends CompletionContributor {
: AllClassesGetter.TRY_SHORTENING);
}
public static List<JavaPsiClassReferenceElement> createClassLookupItems(final PsiClass psiClass,
boolean withInners,
InsertHandler<JavaPsiClassReferenceElement> insertHandler,
Condition<PsiClass> condition) {
List<JavaPsiClassReferenceElement> result = new SmartList<JavaPsiClassReferenceElement>();
if (condition.value(psiClass)) {
result.add(AllClassesGetter.createLookupItem(psiClass, insertHandler));
}
String name = psiClass.getName();
if (withInners && name != null) {
for (PsiClass inner : psiClass.getInnerClasses()) {
if (inner.hasModifierProperty(PsiModifier.STATIC)) {
for (JavaPsiClassReferenceElement lookupInner : createClassLookupItems(inner, withInners, insertHandler, condition)) {
String forced = lookupInner.getForcedPresentableName();
lookupInner.setForcedPresentableName(name + "." + (forced != null ? forced : inner.getName()));
result.add(lookupInner);
}
}
}
}
return result;
}
@Override
public String handleEmptyLookup(@NotNull final CompletionParameters parameters, final Editor editor) {
if (!(parameters.getOriginalFile() instanceof PsiJavaFile)) return null;
@@ -145,6 +188,6 @@ public class JavaClassNameCompletionContributor extends CompletionContributor {
private static boolean shouldShowSecondSmartCompletionHint(final CompletionParameters parameters) {
return parameters.getCompletionType() == CompletionType.CLASS_NAME &&
parameters.getInvocationCount() == 1 &&
parameters.getOriginalFile().getLanguage() == StdLanguages.JAVA;
parameters.getOriginalFile().getLanguage().isKindOf(JavaLanguage.INSTANCE);
}
}
@@ -32,9 +32,6 @@ import com.intellij.psi.filters.FilterPositionUtil;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.hash.HashSet;
import java.util.Set;
/**
* @author peter
@@ -91,8 +88,9 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
}
PsiTypeLookupItem.addImportForItem(context, psiClass);
context.setTailOffset(context.getOffset(refEnd));
if (shouldInsertParentheses(psiClass, file.findElementAt(context.getTailOffset() - 1))) {
if (shouldInsertParentheses(file.findElementAt(context.getTailOffset() - 1))) {
if (ConstructorInsertHandler.insertParentheses(context, item, psiClass, false)) {
fillTypeArgs |= psiClass.hasTypeParameters() && PsiUtil.getLanguageLevel(file).isAtLeast(LanguageLevel.JDK_1_5);
}
@@ -122,7 +120,7 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
}
}
private static boolean shouldInsertParentheses(PsiClass psiClass, PsiElement position) {
private static boolean shouldInsertParentheses(PsiElement position) {
final PsiJavaCodeReferenceElement ref = PsiTreeUtil.getParentOfType(position, PsiJavaCodeReferenceElement.class);
if (ref == null) {
return false;
@@ -135,13 +133,13 @@ class JavaClassNameInsertHandler implements InsertHandler<JavaPsiClassReferenceE
final PsiElement prevElement = FilterPositionUtil.searchNonSpaceNonCommentBack(ref);
if (prevElement != null && prevElement.getParent() instanceof PsiNewExpression) {
Set<PsiType> expectedTypes = new HashSet<PsiType>();
for (ExpectedTypeInfo info : ExpectedTypesProvider.getExpectedTypes((PsiExpression)prevElement.getParent(), true)) {
expectedTypes.add(info.getType());
if (info.getType() instanceof PsiArrayType) {
return false;
}
}
return JavaCompletionUtil.isDefinitelyExpected(psiClass, expectedTypes, position);
return true;
}
return false;
@@ -31,6 +31,7 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
@@ -282,12 +283,14 @@ public class JavaCompletionContributor extends CompletionContributor {
final Set<String> usedWords = new HashSet<String>();
final PsiElement position = parameters.getPosition();
final boolean checkAccess = parameters.getInvocationCount() <= 1;
final boolean isSwitchLabel = SWITCH_LABEL.accepts(position);
final boolean isAfterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position);
final boolean pkgContext = JavaCompletionUtil.inSomePackage(position);
LegacyCompletionContributor.processReferences(parameters, result, new PairConsumer<PsiReference, CompletionResultSet>() {
public void consume(final PsiReference reference, final CompletionResultSet result) {
if (reference instanceof PsiJavaReference) {
final ElementFilter filter = getReferenceFilter(position);
if (filter != null) {
final boolean isSwitchLabel = SWITCH_LABEL.accepts(position);
final PsiFile originalFile = parameters.getOriginalFile();
for (LookupElement element : JavaCompletionUtil.processJavaReference(position,
(PsiJavaReference)reference,
@@ -332,11 +335,17 @@ public class JavaCompletionContributor extends CompletionContributor {
result.addElement((LookupElement)completion);
}
else if (completion instanceof PsiClass) {
if (!inheritors.alreadyProcessed((PsiClass)completion)) {
JavaPsiClassReferenceElement item = JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true);
for (JavaPsiClassReferenceElement item : JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion, isAfterNew,
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER, new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
return !inheritors.alreadyProcessed(psiClass) && JavaCompletionUtil.isSourceLevelAccessible(position, psiClass, pkgContext);
}
})) {
usedWords.add(item.getLookupString());
result.addElement(item);
}
}
else {
LookupElement element = LookupItemUtil.objectToLookupItem(completion);
@@ -69,10 +69,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static com.intellij.patterns.PlatformPatterns.psiElement;
@@ -450,8 +447,7 @@ public class JavaCompletionUtil {
final Set<PsiMember> mentioned = new THashSet<PsiMember>();
for (CompletionElement completionElement : processor.getResults()) {
LookupElement item = createLookupElement(completionElement, javaReference);
if (item != null) {
for (LookupElement item : createLookupElements(completionElement, javaReference)) {
item.putUserData(QUALIFIER_TYPE_ATTR, qualifierType);
final Object o = item.getObject();
if (o instanceof PsiClass && !isSourceLevelAccessible(element, (PsiClass)o, pkgContext)) {
@@ -604,25 +600,33 @@ public class JavaCompletionUtil {
}), 1);
}
private static LookupElement createLookupElement(CompletionElement completionElement, PsiJavaReference reference) {
private static List<? extends LookupElement> createLookupElements(CompletionElement completionElement, PsiJavaReference reference) {
Object completion = completionElement.getElement();
assert !(completion instanceof LookupElement);
if (completion instanceof PsiMethod &&
reference instanceof PsiJavaCodeReferenceElement &&
((PsiJavaCodeReferenceElement)reference).getParent() instanceof PsiImportStaticStatement) {
return JavaLookupElementBuilder.forMethod((PsiMethod)completion, PsiSubstitutor.EMPTY);
if (reference instanceof PsiJavaCodeReferenceElement) {
if (completion instanceof PsiMethod &&
((PsiJavaCodeReferenceElement)reference).getParent() instanceof PsiImportStaticStatement) {
return Arrays.asList(JavaLookupElementBuilder.forMethod((PsiMethod)completion, PsiSubstitutor.EMPTY));
}
if (completion instanceof PsiClass) {
return JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion,
JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference),
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
Condition.TRUE);
}
}
LookupElement _ret = LookupItemUtil.objectToLookupItem(completion);
if (_ret == null || !(_ret instanceof LookupItem)) return null;
if (_ret == null || !(_ret instanceof LookupItem)) return Collections.emptyList();
final PsiSubstitutor substitutor = completionElement.getSubstitutor();
if (substitutor != null) {
((LookupItem<?>)_ret).setAttribute(LookupItem.SUBSTITUTOR, substitutor);
}
return _ret;
return Arrays.asList(_ret);
}
public static boolean hasAccessibleConstructor(PsiType type) {
@@ -878,19 +882,6 @@ public class JavaCompletionUtil {
}
}
public static boolean hasAccessibleInnerClass(@NotNull PsiClass psiClass, @NotNull PsiElement position) {
final PsiClass[] inners = psiClass.getInnerClasses();
if (inners.length > 0) {
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(position.getProject()).getResolveHelper();
for (PsiClass inner : inners) {
if (inner.hasModifierProperty(PsiModifier.STATIC) && resolveHelper.isAccessible(inner, position, null)) {
return true;
}
}
}
return false;
}
public static boolean inSomePackage(PsiElement context) {
PsiFile contextFile = context.getContainingFile();
return contextFile instanceof PsiClassOwner && StringUtil.isNotEmpty(((PsiClassOwner)contextFile).getPackageName());
@@ -914,19 +905,6 @@ public class JavaCompletionUtil {
return true;
}
public static boolean isDefinitelyExpected(PsiClass psiClass, Set<PsiType> expectedTypes, PsiElement position) {
final PsiClassType classType = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass);
for (PsiType expectedType : expectedTypes) {
if (expectedType instanceof PsiArrayType) return false;
}
for (PsiType type : expectedTypes) {
if (type instanceof PsiClassType && ((PsiClassType)type).rawType().isAssignableFrom(classType)) {
return true;
}
}
return !hasAccessibleInnerClass(psiClass, position);
}
public static boolean promptTypeArgs(InsertionContext context, int offset) {
if (offset < 0) {
return false;
@@ -31,6 +31,9 @@ import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Set;
/**
* @author peter
*/
@@ -38,6 +41,7 @@ public class JavaPsiClassReferenceElement extends LookupItem<Object> {
public static final ClassConditionKey<JavaPsiClassReferenceElement> CLASS_CONDITION_KEY = ClassConditionKey.create(JavaPsiClassReferenceElement.class);
private final Object myClass;
private final String myQualifiedName;
private String myForcedPresentableName;
public JavaPsiClassReferenceElement(PsiClass psiClass) {
super(psiClass.getName(), psiClass.getName());
@@ -48,6 +52,32 @@ public class JavaPsiClassReferenceElement extends LookupItem<Object> {
setTailType(TailType.NONE);
}
public String getForcedPresentableName() {
return myForcedPresentableName;
}
@NotNull
@Override
public String getLookupString() {
if (myForcedPresentableName != null) {
return myForcedPresentableName;
}
return super.getLookupString();
}
@Override
public Set<String> getAllLookupStrings() {
if (myForcedPresentableName != null) {
return Collections.singleton(myForcedPresentableName);
}
return super.getAllLookupStrings();
}
public void setForcedPresentableName(String forcedPresentableName) {
myForcedPresentableName = forcedPresentableName;
}
@NotNull
@Override
public PsiClass getObject() {
@@ -126,6 +156,13 @@ public class JavaPsiClassReferenceElement extends LookupItem<Object> {
}
private static String getName(final PsiClass psiClass, final LookupItem<?> item, boolean diamond) {
if (item instanceof JavaPsiClassReferenceElement) {
String forced = ((JavaPsiClassReferenceElement)item).getForcedPresentableName();
if (forced != null) {
return forced;
}
}
String name = PsiUtilCore.getName(psiClass);
if (item.getAttribute(LookupItem.FORCE_QUALIFY) != null) {
@@ -2,6 +2,6 @@ import pack.WithInnerAClass;
public class Test1 {
public void foo() {
new WithInnerAClass<caret>
new WithInnerAClass()<caret>
}
}
@@ -1,6 +1,11 @@
class Foo {
{
Zzoo l = new Zzoo()<caret>
Zzoo l = new Zzoo() {
@Override
public void run() {
<selection>//To change body of implemented methods use File | Settings | File Templates.</selection>
}
}
}
}
@@ -2,7 +2,7 @@ public class TestClass {
public TestClass create() {
final int value = 1;
return new Xxx<caret>(value);
return new Xxx(<caret>value);
}
}
@@ -64,6 +64,7 @@ public class ClassNameCompletionTest extends CompletionTestCase {
checkResultByFile(path + "/after1.java");
configureByFile(path + "/before2.java");
selectItem(myItems[0]);
checkResultByFile(path + "/after2.java");
}
@@ -24,7 +24,6 @@ import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.lang.java.JavaLanguage
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.fileTypes.StdFileTypes
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
@@ -695,21 +694,15 @@ public class ListUtils {
public void _testClassBeforeCast() throws Throwable { doTest '\n' }
public void testNoAllClassesOnQualifiedReference() throws Throwable {
configureByFile(getTestName(false) + ".java");
assertEmpty(myItems);
checkResultByFile(getTestName(false) + ".java");
doAntiTest()
}
public void testFinishClassNameWithDot() throws Throwable {
configureByFile(getTestName(false) + ".java");
type('.');
checkResult()
doTest('.')
}
public void testFinishClassNameWithLParen() throws Throwable {
configureByFile(getTestName(false) + ".java");
type('(');
checkResult()
doTest('(')
}
public void testSelectNoParameterSignature() throws Throwable {
@@ -722,12 +715,7 @@ public class ListUtils {
public void testCompletionInsideClassLiteral() throws Throwable {
configureByFile(getTestName(false) + ".java");
new WriteCommandAction.Simple(getProject(), new PsiFile[0]) {
@Override
protected void run() throws Throwable {
getLookup().finishLookup(Lookup.NORMAL_SELECT_CHAR);
}
}.execute().throwException();
type('\n')
checkResult()
}
@@ -797,18 +785,19 @@ public class ListUtils {
}
public void testClassNameGenerics() throws Throwable {
configure()
type '\n'
checkResult();
doTest('\n')
}
public void testClassNameAnonymous() throws Throwable {
configure()
type '\n'
checkResult();
doTest('\n')
}
public void testClassNameWithInner() throws Throwable { doTest() }
public void testClassNameWithInner() throws Throwable {
configure()
assertStringItems 'Zzoo', 'Zzoo.Impl'
type '\n'
checkResult()
}
public void testClassNameWithInner2() throws Throwable { doTest() }
public void testClassNameWithInstanceInner() throws Throwable { doTest('\n') }
@@ -987,7 +976,7 @@ public class ListUtils {
public void testPrimitiveMethodParameter() throws Throwable { doTest(); }
public void testNewExpectedClassParens() throws Throwable { doTest(); }
public void testNewExpectedClassParens() throws Throwable { doTest('\n'); }
public void testQualifyInnerMembers() throws Throwable { doTest('\n') }
@@ -145,7 +145,7 @@ public class AutoPopupController implements Disposable {
myAlarm.cancelAllRequests();
}
public void autoPopupParameterInfo(final Editor editor, final PsiElement highlightedMethod){
public void autoPopupParameterInfo(final Editor editor, @Nullable final PsiElement highlightedMethod){
if (ApplicationManager.getApplication().isUnitTestMode()) return;
if (DumbService.isDumb(myProject)) return;
@@ -168,7 +168,7 @@ public class AutoPopupController implements Disposable {
documentManager.commitAllDocuments();
int lbraceOffset = editor.getCaretModel().getOffset() - 1;
try {
new ShowParameterInfoHandler().invoke(myProject, editor, file1, lbraceOffset, highlightedMethod);
ShowParameterInfoHandler.invoke(myProject, editor, file1, lbraceOffset, highlightedMethod);
}
catch (IndexNotReadyException ignored) { //anything can happen on alarm
}
@@ -18,11 +18,9 @@ package org.jetbrains.plugins.groovy.lang.completion;
import com.intellij.codeInsight.completion.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
@@ -62,7 +60,7 @@ public class GroovyClassNameInsertHandler implements InsertHandler<JavaPsiClassR
}
PsiElement position = file.findElementAt(endOffset - 1);
boolean parens = shouldInsertParentheses(position, item.getObject());
boolean parens = shouldInsertParentheses(position);
final PsiClass psiClass = item.getObject();
if (isInVariable(position) || GroovyCompletionContributor.isInPossibleClosureParameter(position)) {
@@ -96,10 +94,10 @@ public class GroovyClassNameInsertHandler implements InsertHandler<JavaPsiClassR
}
private static boolean shouldInsertParentheses(PsiElement position, PsiClass psiClass) {
private static boolean shouldInsertParentheses(PsiElement position) {
final GrNewExpression newExpression = findNewExpression(position);
return newExpression != null && JavaCompletionUtil
.isDefinitelyExpected(psiClass, GroovyExpectedTypesProvider.getDefaultExpectedTypes(newExpression), position);
return newExpression != null && ContainerUtil.findInstance(GroovyExpectedTypesProvider.getDefaultExpectedTypes(newExpression),
PsiArrayType.class) == null;
}
private static boolean isInVariable(PsiElement position) {
@@ -22,6 +22,7 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
@@ -191,15 +192,21 @@ public class GroovyCompletionContributor extends CompletionContributor {
final InheritorsHolder inheritors, final PrefixMatcher matcher) {
final PsiElement position = parameters.getPosition();
final ElementFilter filter = getClassFilter(position);
AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() <= 1,
new Consumer<PsiClass>() {
@Override
public void consume(PsiClass psiClass) {
if (!inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position)) {
consumer.consume(GroovyCompletionUtil.createClassLookupItem(psiClass));
}
}
});
final boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position);
AllClassesGetter.processJavaClasses(parameters, matcher, parameters.getInvocationCount() <= 1, new Consumer<PsiClass>() {
@Override
public void consume(PsiClass psiClass) {
for (JavaPsiClassReferenceElement element : JavaClassNameCompletionContributor
.createClassLookupItems(psiClass, afterNew, new GroovyClassNameInsertHandler(), new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
return !inheritors.alreadyProcessed(psiClass) && filter.isAcceptable(psiClass, position);
}
})) {
consumer.consume(element);
}
}
});
}
private static ElementFilter getClassFilter(PsiElement position) {
@@ -451,52 +458,62 @@ public class GroovyCompletionContributor extends CompletionContributor {
final ElementFilter classFilter = getClassFilter(position);
final boolean afterNew = JavaClassNameCompletionContributor.AFTER_NEW.accepts(position);
final List<LookupElement> items = arrayList();
reference.processVariants(matcher, parameters, new Consumer<Object>() {
public void consume(Object element) {
if (element instanceof PsiClass && inheritorsHolder.alreadyProcessed((PsiClass)element)) {
return;
}
if (element instanceof LookupElement && inheritorsHolder.alreadyProcessed((LookupElement)element)) {
return;
}
if (element instanceof LookupElement && ((LookupElement)element).getObject() instanceof PsiClass) {
element = ((LookupElement)element).getObject();
}
LookupElement lookupElement = element instanceof PsiClass
? GroovyCompletionUtil.createClassLookupItem(CompletionUtil.getOriginalOrSelf((PsiClass)element))
: GroovyCompletionUtil.getLookupElement(element);
Object object = lookupElement.getObject();
if (object instanceof GroovyResolveResult) {
object = ((GroovyResolveResult)object).getElement();
}
if (object instanceof GrReferenceExpression && unresolvedProps.contains(((GrReferenceExpression)object).getName())) {
return;
}
if (object instanceof PsiMember && JavaCompletionUtil.isInExcludedPackage((PsiMember)object, true)) {
return;
}
int priority = assignPriority(lookupElement, qualifierType);
lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType,
PrioritizedLookupElement.withPriority(lookupElement, priority), object);
if ((object instanceof PsiMethod || object instanceof PsiField) &&
((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) {
if (lookupElement.getLookupString().equals(((PsiMember)object).getName())) {
staticMembers.put((PsiModifierListOwner)object, lookupElement);
List<? extends LookupElement> lookupElements;
if (element instanceof PsiClass) {
if (!matcher.prefixMatches(((PsiClass)element).getName())) {
return;
}
}
if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) {
return;
lookupElements = JavaClassNameCompletionContributor
.createClassLookupItems((PsiClass)element, afterNew, new GroovyClassNameInsertHandler(), Condition.TRUE);
} else {
lookupElements = Arrays.asList(GroovyCompletionUtil.getLookupElement(element));
}
items.add(lookupElement);
for (LookupElement lookupElement : lookupElements) {
if (!matcher.prefixMatches(lookupElement)) {
continue;
}
Object object = lookupElement.getObject();
if (object instanceof GroovyResolveResult) {
object = ((GroovyResolveResult)object).getElement();
}
if (object instanceof PsiClass && inheritorsHolder.alreadyProcessed((PsiClass)object) ||
object instanceof LookupElement && inheritorsHolder.alreadyProcessed((LookupElement)object)) {
continue;
}
if (object instanceof GrReferenceExpression && unresolvedProps.contains(((GrReferenceExpression)object).getName())) {
continue;
}
if (object instanceof PsiMember && JavaCompletionUtil.isInExcludedPackage((PsiMember)object, true)) {
continue;
}
int priority = assignPriority(lookupElement, qualifierType);
lookupElement = JavaCompletionUtil.highlightIfNeeded(qualifierType,
PrioritizedLookupElement.withPriority(lookupElement, priority), object);
if ((object instanceof PsiMethod || object instanceof PsiField) &&
((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) {
if (lookupElement.getLookupString().equals(((PsiMember)object).getName())) {
staticMembers.put((PsiModifierListOwner)object, lookupElement);
continue;
}
}
if (object instanceof PsiClass && !classFilter.isAcceptable(object, position)) {
continue;
}
items.add(lookupElement);
}
}
});
@@ -216,7 +216,12 @@ public class GroovyCompletionUtil {
public static List<Object> getCompletionVariants(GroovyResolveResult[] candidates) {
List<Object> result = CollectionFactory.arrayList();
for (GroovyResolveResult candidate : candidates) {
result.add(createCompletionVariant(candidate));
if (candidate.getElement() instanceof PsiClass) {
result.add(candidate);
} else {
result.add(createCompletionVariant(candidate));
}
ProgressManager.checkCanceled();
}
@@ -249,9 +254,6 @@ public class GroovyCompletionUtil {
else if (element instanceof PsiMethod) {
return setupLookupBuilder(element, candidate.getSubstitutor(), LookupElementBuilder.create(candidate, ((PsiMethod)element).getName()));
}
if (element instanceof PsiClass) {
return createClassLookupItem((PsiClass)element);
}
if (element instanceof PsiNamedElement) {
return setupLookupBuilder(element, candidate.getSubstitutor(),
@@ -628,6 +628,7 @@ class A {
}"""
configure "Zzoo l = new Zz<caret>"
myFixture.completeBasic()
myFixture.type '\n'
myFixture.checkResult "Zzoo l = new Zzoo()<caret>"
}
@@ -738,6 +739,8 @@ format(<caret>)"""
myFixture.addClass "class Fooooo { interface Bar {} }"
myFixture.configureByText "a.groovy", "Fooooo f = new Foo<caret>"
myFixture.completeBasic()
assert myFixture.lookupElementStrings == ['Fooooo', 'Fooooo.Bar']
myFixture.type '\n'
myFixture.checkResult "Fooooo f = new Fooooo()<caret>"
}
@@ -745,7 +748,9 @@ format(<caret>)"""
myFixture.addClass "class Fooooo { interface Bar {} }"
myFixture.configureByText "a.groovy", "Fooooo.Bar f = new Foo<caret>"
myFixture.completeBasic()
myFixture.checkResult "Fooooo.Bar f = new Fooooo<caret>"
assert myFixture.lookupElementStrings == ['Fooooo', 'Fooooo.Bar']
myFixture.type '\n'
myFixture.checkResult "Fooooo.Bar f = new Fooooo()<caret>"
}
public void testOnlyExceptionsInCatch() {
@@ -60,7 +60,7 @@ abstract public class GroovyCompletionTestBase extends LightCodeInsightFixtureTe
public void checkSingleItemCompletion(String before, String after) {
myFixture.configureByText("a.groovy", before);
myFixture.completeBasic();
assert !myFixture.completeBasic();
myFixture.checkResult(after);
}