initial IDEA-93584 allow autocompletion for overloaded constructors

This commit is contained in:
peter
2016-08-29 17:55:34 +02:00
parent eb304631cb
commit e698c47bb7
8 changed files with 147 additions and 29 deletions
@@ -192,7 +192,7 @@ public class ConstructorInsertHandler implements InsertHandler<LookupElementDeco
LookupElement delegate,
final PsiClass psiClass,
final boolean forAnonymous) {
if (context.getCompletionChar() == '[') {
if (context.getCompletionChar() == '[' || JavaConstructorCallElement.isWrapped(delegate)) {
return false;
}
@@ -162,7 +162,7 @@ public class JavaClassNameCompletionContributor extends CompletionContributor {
AllClassesGetter.isAcceptableInContext(insertedElement, eachClass, filterByScope, pkgContext);
for (JavaPsiClassReferenceElement element : createClassLookupItems(psiClass, afterNew, JAVA_CLASS_INSERT_HANDLER, condition)) {
element.setLookupString(prefix + element.getLookupString());
consumer.consume(element);
JavaConstructorCallElement.wrap(element, insertedElement).forEach(consumer::consume);
}
}
} else {
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -40,13 +41,24 @@ public class JavaCompletionSession implements Consumer<LookupElement> {
@Override
public void consume(LookupElement lookupElement) {
final Object object = lookupElement.getObject();
if (object instanceof PsiClass) {
registerClass((PsiClass)object);
PsiClass psiClass = extractClass(lookupElement);
if (psiClass != null) {
registerClass(psiClass);
}
myResult.addElement(AutoCompletionPolicy.NEVER_AUTOCOMPLETE.applyPolicy(lookupElement));
}
@Nullable private static PsiClass extractClass(LookupElement lookupElement) {
final Object object = lookupElement.getObject();
if (object instanceof PsiClass) {
return (PsiClass)object;
}
if (object instanceof PsiMethod && ((PsiMethod)object).isConstructor()) {
return ((PsiMethod)object).getContainingClass();
}
return null;
}
public void registerClass(@NotNull PsiClass psiClass) {
ContainerUtil.addIfNotNull(myAddedClasses, getClassName(psiClass));
}
@@ -58,8 +70,8 @@ public class JavaCompletionSession implements Consumer<LookupElement> {
}
public boolean alreadyProcessed(@NotNull LookupElement element) {
final Object object = element.getObject();
return object instanceof PsiClass && alreadyProcessed((PsiClass)object);
final PsiClass psiClass = extractClass(element);
return psiClass != null && alreadyProcessed(psiClass);
}
public boolean alreadyProcessed(@NotNull PsiClass object) {
@@ -53,8 +53,11 @@ import com.intellij.psi.scope.util.PsiScopesUtil;
import com.intellij.psi.util.*;
import com.intellij.psi.util.proximity.ReferenceListWeigher;
import com.intellij.ui.JBColor;
import com.intellij.util.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.NullableFunction;
import com.intellij.util.PairFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.JBIterable;
import com.siyeh.ig.psiutils.SideEffectChecker;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
@@ -308,7 +311,7 @@ public class JavaCompletionUtil {
final Set<PsiMember> mentioned = new THashSet<>();
for (CompletionElement completionElement : processor.getResults()) {
for (LookupElement item : createLookupElements(completionElement, javaReference, processor)) {
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)) {
@@ -509,7 +512,7 @@ public class JavaCompletionUtil {
return false;
}
static List<? extends LookupElement> createLookupElements(CompletionElement completionElement, PsiJavaReference reference, JavaCompletionProcessor processor) {
static Iterable<? extends LookupElement> createLookupElements(CompletionElement completionElement, PsiJavaReference reference) {
Object completion = completionElement.getElement();
assert !(completion instanceof LookupElement);
@@ -520,10 +523,15 @@ public class JavaCompletionUtil {
}
if (completion instanceof PsiClass) {
return JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion,
JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference),
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
Conditions.<PsiClass>alwaysTrue());
List<JavaPsiClassReferenceElement> classItems = JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion,
JavaClassNameCompletionContributor.AFTER_NEW
.accepts(reference),
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
Conditions.alwaysTrue());
if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) {
return JBIterable.from(classItems).flatMap(i -> JavaConstructorCallElement.wrap(i, reference.getElement()));
}
return classItems;
}
}
@@ -534,7 +542,13 @@ public class JavaCompletionUtil {
PsiSubstitutor substitutor = completionElement.getSubstitutor();
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
if (completion instanceof PsiClass) {
return Collections.singletonList(JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true).setSubstitutor(substitutor));
JavaPsiClassReferenceElement classItem =
JavaClassNameCompletionContributor.createClassLookupItem((PsiClass)completion, true).setSubstitutor(substitutor);
if (JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference)) {
return JavaConstructorCallElement.wrap(classItem, reference.getElement());
}
return Collections.singletonList(classItem);
}
if (completion instanceof PsiMethod) {
JavaMethodCallElement item = new JavaMethodCallElement((PsiMethod)completion).setQualifierSubstitutor(substitutor);
@@ -554,15 +568,12 @@ public class JavaCompletionUtil {
final PsiClass psiClass = PsiUtil.resolveClassInType(type);
if (psiClass == null || psiClass.isEnum() || psiClass.isAnnotationType()) return false;
if (!(psiClass instanceof PsiCompiledElement)) return true;
PsiMethod[] methods = psiClass.getConstructors();
return methods.length == 0 || Arrays.stream(methods).anyMatch(JavaCompletionUtil::isConstructorCompletable);
}
final PsiMethod[] methods = psiClass.getConstructors();
if (methods.length == 0) return true;
for (final PsiMethod method : methods) {
if (!method.hasModifierProperty(PsiModifier.PRIVATE)) return true;
}
return false;
static boolean isConstructorCompletable(@NotNull PsiMethod constructor) {
return !(constructor instanceof PsiCompiledElement) || !constructor.hasModifierProperty(PsiModifier.PRIVATE);
}
public static Set<String> getAllLookupStrings(@NotNull PsiMember member) {
@@ -0,0 +1,93 @@
/*
* Copyright 2000-2016 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 com.intellij.codeInsight.completion;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.util.containers.JBIterable;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
/**
* @author peter
*/
public class JavaConstructorCallElement extends JavaMethodCallElement {
private static final Key<JavaConstructorCallElement> WRAPPING_CONSTRUCTOR_CALL = Key.create("WRAPPING_CONSTRUCTOR_CALL");
@NotNull private final LookupElement myClassItem;
@NotNull private final Supplier<PsiType> myType;
private JavaConstructorCallElement(@NotNull LookupElement classItem, @NotNull PsiMethod constructor, @NotNull Supplier<PsiType> type) {
super(constructor);
myClassItem = classItem;
myType = type;
setQualifierSubstitutor(((PsiClassType) type.get()).resolveGenerics().getSubstitutor());
LookupElement delegate = classItem;
while (true) {
delegate.putUserData(WRAPPING_CONSTRUCTOR_CALL, this);
if (!(delegate instanceof LookupElementDecorator)) break;
delegate = ((LookupElementDecorator)delegate).getDelegate();
}
}
@NotNull
@Override
public PsiType getType() {
return myType.get();
}
@Override
public void handleInsert(InsertionContext context) {
myClassItem.handleInsert(context);
super.handleInsert(context);
}
@Override
public void renderElement(LookupElementPresentation presentation) {
myClassItem.renderElement(presentation);
String itemText = presentation.getItemText();
super.renderElement(presentation);
presentation.setItemText(itemText);
}
static List<? extends LookupElement> wrap(JavaPsiClassReferenceElement classItem, PsiElement position) {
PsiClass psiClass = classItem.getObject();
return wrap(classItem, psiClass, position, () -> JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, PsiSubstitutor.EMPTY));
}
static List<? extends LookupElement> wrap(LookupElement classItem, PsiClass psiClass, PsiElement position, Supplier<PsiType> type) {
if (Registry.is("java.completion.show.constructors") && JavaClassNameCompletionContributor.AFTER_NEW.accepts(position)) {
return JBIterable.of(psiClass.getConstructors()).
filter(JavaCompletionUtil::isConstructorCompletable).
map(c -> new JavaConstructorCallElement(classItem, c, type)).
toList();
}
return Collections.singletonList(classItem);
}
static boolean isWrapped(LookupElement element) {
return element.getUserData(WRAPPING_CONSTRUCTOR_CALL) != null;
}
}
@@ -18,10 +18,7 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CodeInsightUtil;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightClassUtil;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementDecorator;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
import com.intellij.codeInsight.lookup.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -43,6 +40,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
@@ -89,7 +87,8 @@ public class JavaInheritorsGetter extends CompletionProvider<CompletionParameter
processInheritors(parameters, classTypes, prefixMatcher, type -> {
final LookupElement element = addExpectedType(type, parameters);
if (element != null) {
consumer.consume(element);
Supplier<PsiType> itemType = () -> ObjectUtils.assertNotNull(element.as(TypedLookupItem.CLASS_CONDITION_KEY)).getType();
JavaConstructorCallElement.wrap(element, (PsiClass)element.getObject(), parameters.getPosition(), itemType).forEach(consumer::consume);
}
if (arraysWelcome) {
consumer.consume(createNewArrayItem(parameters.getPosition(), type.createArrayType()));
@@ -48,7 +48,7 @@ class SuperCalls {
fakeSuper.processVariants(superProcessor);
for (CompletionElement completionElement : superProcessor.getResults()) {
for (LookupElement item : JavaCompletionUtil.createLookupElements(completionElement, javaReference, superProcessor)) {
for (LookupElement item : JavaCompletionUtil.createLookupElements(completionElement, javaReference)) {
set.add(withQualifiedSuper(className, item));
}
}
@@ -318,6 +318,9 @@ java.completion.make.outer.variables.final.description=Make variables accessed f
java.completion.argument.live.template=false
java.completion.argument.live.template.description=When completing a method call, start a live template with all arguments
java.completion.show.constructors=false
java.completion.show.constructors.description=Show separate constructors when completing constructor call, instead of a single class name
java.annotations.inference.nullable.method=false
java.annotations.inference.nullable.method.description=Restart is required; infer @Nullable annotation for method results
java.annotations.inference.nullable.method.transitivity=true