mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
initial IDEA-93584 allow autocompletion for overloaded constructors
This commit is contained in:
+1
-1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+93
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user