mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-145958 Suggest chained calls of expected type in basic & autopopup completion
GitOrigin-RevId: b2d1ed10839ffac236b724c224f856e6bb99cb14
This commit is contained in:
committed by
intellij-monorepo-bot
parent
60db1bd88c
commit
3aea481c1f
+94
-47
@@ -245,6 +245,13 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
if (position instanceof PsiIdentifier) {
|
||||
addIdentifierVariants(parameters, position, result, session, matcher);
|
||||
|
||||
Set<ExpectedTypeInfo> expectedInfos = ContainerUtil.newHashSet(JavaSmartCompletionContributor.getExpectedTypes(parameters));
|
||||
boolean shouldAddExpressionVariants = shouldAddExpressionVariants(parameters);
|
||||
|
||||
boolean hasTypeMatchingSuggestions =
|
||||
shouldAddExpressionVariants && addExpectedTypeMembers(parameters, false, expectedInfos,
|
||||
item -> session.registerBatchItems(Collections.singleton(item)));
|
||||
|
||||
if (!smart) {
|
||||
PsiAnnotation anno = findAnnotationWhoseAttributeIsCompleted(position);
|
||||
if (anno != null) {
|
||||
@@ -264,21 +271,30 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
result.stopHere();
|
||||
}
|
||||
|
||||
List<LookupElement> refBasedSuggestions = parent instanceof PsiJavaCodeReferenceElement && mayCompleteReference
|
||||
? completeReference(parameters, (PsiJavaCodeReferenceElement)parent, session)
|
||||
: Collections.emptyList();
|
||||
if (!smart) {
|
||||
TailType switchLabelTail = IN_SWITCH_LABEL.accepts(position)
|
||||
? TailTypes.forSwitchLabel(Objects.requireNonNull(PsiTreeUtil.getParentOfType(position, PsiSwitchBlock.class)))
|
||||
: null;
|
||||
session.registerBatchItems(ContainerUtil.map(refBasedSuggestions, e -> switchLabelTail != null ? new IndentingDecorator(TailTypeDecorator.withTail(e, switchLabelTail)) : e));
|
||||
List<LookupElement> refSuggestions = Collections.emptyList();
|
||||
if (parent instanceof PsiJavaCodeReferenceElement && mayCompleteReference) {
|
||||
refSuggestions = completeReference(parameters, (PsiJavaCodeReferenceElement)parent, session, expectedInfos);
|
||||
List<LookupElement> filtered = filterReferenceSuggestions(smart, result, (PsiJavaCodeReferenceElement)parent, expectedInfos, refSuggestions);
|
||||
hasTypeMatchingSuggestions |= ContainerUtil.exists(filtered, item ->
|
||||
ReferenceExpressionCompletionContributor.matchesExpectedType(item, expectedInfos));
|
||||
session.registerBatchItems(filtered);
|
||||
result.stopHere();
|
||||
}
|
||||
|
||||
session.flushBatchItems();
|
||||
|
||||
if (smart) {
|
||||
addSmartCompletionSuggestions(parameters, result, refBasedSuggestions);
|
||||
hasTypeMatchingSuggestions |= smartCompleteExpression(parameters, result, expectedInfos);
|
||||
smartCompleteNonExpression(parameters, result);
|
||||
}
|
||||
|
||||
if ((!hasTypeMatchingSuggestions || parameters.getInvocationCount() >= 2) &&
|
||||
JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position)) {
|
||||
SlowerTypeConversions.addChainedSuggestions(parameters, result, expectedInfos, refSuggestions);
|
||||
}
|
||||
|
||||
if (smart && parameters.getInvocationCount() > 1 && shouldAddExpressionVariants) {
|
||||
addExpectedTypeMembers(parameters, true, expectedInfos, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,31 +337,23 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
|
||||
private static void addSmartCompletionSuggestions(CompletionParameters parameters,
|
||||
CompletionResultSet result,
|
||||
List<LookupElement> allRefSuggestions) {
|
||||
private static List<LookupElement> filterReferenceSuggestions(boolean smart,
|
||||
CompletionResultSet result,
|
||||
PsiJavaCodeReferenceElement parent,
|
||||
Set<ExpectedTypeInfo> expectedInfos,
|
||||
List<LookupElement> refSuggestions) {
|
||||
if (smart) {
|
||||
refSuggestions = ReferenceExpressionCompletionContributor.smartCompleteReference(refSuggestions, expectedInfos);
|
||||
}
|
||||
List<LookupElement> matching = ContainerUtil.findAll(refSuggestions, result.getPrefixMatcher()::prefixMatches);
|
||||
return JavaCompletionProcessor.dispreferStaticAfterInstance(parent, matching);
|
||||
}
|
||||
|
||||
private static void smartCompleteNonExpression(CompletionParameters parameters, CompletionResultSet result) {
|
||||
PsiElement position = parameters.getPosition();
|
||||
Set<ExpectedTypeInfo> infos = ContainerUtil.newHashSet(JavaSmartCompletionContributor.getExpectedTypes(parameters));
|
||||
Set<ExpectedTypeInfo> mergedInfos = new THashSet<>(infos, JavaSmartCompletionContributor.EXPECTED_TYPE_INFO_STRATEGY);
|
||||
List<SlowerTypeConversions> chainedEtc = new ArrayList<>();
|
||||
PsiElement parent = position.getParent();
|
||||
if (!SmartCastProvider.shouldSuggestCast(parameters) && parent instanceof PsiJavaCodeReferenceElement) {
|
||||
JavaSmartCompletionContributor.addClassReferenceSuggestions(parameters, result, position, (PsiJavaCodeReferenceElement)parent);
|
||||
|
||||
if (JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position)) {
|
||||
ReferenceExpressionCompletionContributor.addSmartReferenceSuggestions(
|
||||
parameters, allRefSuggestions, mergedInfos, chainedEtc,
|
||||
e -> result.addElement(JavaSmartCompletionContributor.decorate(e, infos)));
|
||||
|
||||
for (ExpectedTypeInfo info : mergedInfos) {
|
||||
BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(parameters, info), lookupElement -> {
|
||||
final PsiType psiType = JavaCompletionUtil.getLookupElementType(lookupElement);
|
||||
if (psiType != null && info.getType().isAssignableFrom(psiType)) {
|
||||
result.addElement(JavaSmartCompletionContributor.decorate(lookupElement, infos));
|
||||
}
|
||||
}, result.getPrefixMatcher());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (InstanceofTypeProvider.AFTER_INSTANCEOF.accepts(position)) {
|
||||
InstanceofTypeProvider.addCompletions(parameters, result);
|
||||
@@ -359,14 +367,29 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
if (psiElement().afterLeaf("::").withParent(PsiMethodReferenceExpression.class).accepts(position)) {
|
||||
MethodReferenceCompletionProvider.addCompletions(parameters, result);
|
||||
}
|
||||
}
|
||||
|
||||
for (Runnable runnable : chainedEtc) {
|
||||
runnable.run();
|
||||
private static boolean smartCompleteExpression(CompletionParameters parameters,
|
||||
CompletionResultSet result,
|
||||
Set<ExpectedTypeInfo> infos) {
|
||||
PsiElement position = parameters.getPosition();
|
||||
if (SmartCastProvider.shouldSuggestCast(parameters) ||
|
||||
!JavaSmartCompletionContributor.INSIDE_EXPRESSION.accepts(position) ||
|
||||
!(position.getParent() instanceof PsiJavaCodeReferenceElement)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() > 1 && shouldAddExpressionVariants(parameters)) {
|
||||
addExpectedTypeMembers(parameters, true, result);
|
||||
boolean[] hadItems = new boolean[1];
|
||||
for (ExpectedTypeInfo info : new THashSet<>(infos, JavaSmartCompletionContributor.EXPECTED_TYPE_INFO_STRATEGY)) {
|
||||
BasicExpressionCompletionContributor.fillCompletionVariants(new JavaSmartCompletionParameters(parameters, info), lookupElement -> {
|
||||
final PsiType psiType = JavaCompletionUtil.getLookupElementType(lookupElement);
|
||||
if (psiType != null && info.getType().isAssignableFrom(psiType)) {
|
||||
hadItems[0] = true;
|
||||
result.addElement(JavaSmartCompletionContributor.decorate(lookupElement, infos));
|
||||
}
|
||||
}, result.getPrefixMatcher());
|
||||
}
|
||||
return hadItems[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -487,7 +510,6 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
|
||||
private static void addExpressionVariants(@NotNull CompletionParameters parameters, PsiElement position, Consumer<? super LookupElement> result) {
|
||||
if (shouldAddExpressionVariants(parameters)) {
|
||||
addExpectedTypeMembers(parameters, false, result);
|
||||
if (SameSignatureCallParametersProvider.IN_CALL_ARGUMENT.accepts(position)) {
|
||||
new SameSignatureCallParametersProvider().addSignatureItems(position, result);
|
||||
}
|
||||
@@ -524,11 +546,28 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
|
||||
private static List<LookupElement> completeReference(CompletionParameters parameters,
|
||||
PsiJavaCodeReferenceElement ref,
|
||||
JavaCompletionSession session) {
|
||||
JavaCompletionSession session,
|
||||
Set<ExpectedTypeInfo> expectedTypes) {
|
||||
PsiElement position = parameters.getPosition();
|
||||
ElementFilter filter = getReferenceFilter(position);
|
||||
if (filter == null) return Collections.emptyList();
|
||||
|
||||
boolean smart = parameters.getCompletionType() == CompletionType.SMART;
|
||||
if (smart) {
|
||||
if (JavaSmartCompletionContributor.INSIDE_TYPECAST_EXPRESSION.accepts(position) || SmartCastProvider.shouldSuggestCast(parameters)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ElementFilter smartRestriction = ReferenceExpressionCompletionContributor.getReferenceFilter(position, false);
|
||||
if (smartRestriction != TrueFilter.INSTANCE) {
|
||||
filter = new AndFilter(filter, smartRestriction);
|
||||
}
|
||||
}
|
||||
|
||||
TailType switchLabelTail = !smart && IN_SWITCH_LABEL.accepts(position)
|
||||
? TailTypes.forSwitchLabel(Objects.requireNonNull(PsiTreeUtil.getParentOfType(position, PsiSwitchBlock.class)))
|
||||
: null;
|
||||
|
||||
List<LookupElement> items = new ArrayList<>();
|
||||
if (INSIDE_CONSTRUCTOR.accepts(position) &&
|
||||
(parameters.getInvocationCount() <= 1 || CheckInitialized.isInsideConstructorCall(position))) {
|
||||
@@ -537,25 +576,25 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
PsiFile originalFile = parameters.getOriginalFile();
|
||||
|
||||
boolean first = parameters.getInvocationCount() <= 1;
|
||||
PsiType[] expectedTypes = ExpectedTypesGetter.getExpectedTypes(parameters.getPosition(), true);
|
||||
boolean smart = parameters.getCompletionType() == CompletionType.SMART;
|
||||
JavaCompletionProcessor.Options options =
|
||||
JavaCompletionProcessor.Options.DEFAULT_OPTIONS
|
||||
.withCheckAccess(first)
|
||||
.withFilterStaticAfterInstance(first)
|
||||
.withFilterStaticAfterInstance(false)
|
||||
.withShowInstanceInStaticContext(!first && !smart);
|
||||
|
||||
PrefixMatcher matcher = smart ? PrefixMatcher.ALWAYS_TRUE : session.getMatcher();
|
||||
for (LookupElement element : JavaCompletionUtil.processJavaReference(position,
|
||||
ref,
|
||||
new ElementExtractorFilter(filter),
|
||||
options,
|
||||
matcher, parameters)) {
|
||||
PrefixMatcher.ALWAYS_TRUE, parameters)) {
|
||||
if (session.alreadyProcessed(element)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LookupItem<?> item = element.as(LookupItem.CLASS_CONDITION_KEY);
|
||||
if (switchLabelTail != null) {
|
||||
element = new IndentingDecorator(TailTypeDecorator.withTail(element, switchLabelTail));
|
||||
}
|
||||
if (originalFile instanceof PsiJavaCodeReferenceCodeFragment &&
|
||||
!((PsiJavaCodeReferenceCodeFragment)originalFile).isClassesAccepted() && item != null) {
|
||||
item.setTailType(TailType.NONE);
|
||||
@@ -565,10 +604,11 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
final PsiMethod method = call.getObject();
|
||||
if (method.getTypeParameters().length > 0) {
|
||||
PsiType returned = TypeConversionUtil.erasure(method.getReturnType());
|
||||
PsiType matchingExpectation = returned == null ? null : ContainerUtil.find(expectedTypes, type ->
|
||||
type.isAssignableFrom(returned) || AssignableFromFilter.isAcceptable(method, position, type, call.getSubstitutor()));
|
||||
ExpectedTypeInfo matchingExpectation = returned == null ? null : ContainerUtil.find(expectedTypes, info ->
|
||||
info.getDefaultType().isAssignableFrom(returned) ||
|
||||
AssignableFromFilter.isAcceptable(method, position, info.getDefaultType(), call.getSubstitutor()));
|
||||
if (matchingExpectation != null) {
|
||||
call.setInferenceSubstitutorFromExpectedType(position, matchingExpectation);
|
||||
call.setInferenceSubstitutorFromExpectedType(position, matchingExpectation.getDefaultType());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -999,11 +1039,17 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addExpectedTypeMembers(CompletionParameters parameters, boolean searchInheritors, final Consumer<? super LookupElement> result) {
|
||||
private static boolean addExpectedTypeMembers(CompletionParameters parameters,
|
||||
boolean searchInheritors,
|
||||
Collection<ExpectedTypeInfo> types,
|
||||
Consumer<? super LookupElement> result) {
|
||||
boolean[] added = new boolean[1];
|
||||
boolean smart = parameters.getCompletionType() == CompletionType.SMART;
|
||||
if (smart || parameters.getInvocationCount() <= 1) { // on second basic completion, StaticMemberProcessor will suggest those
|
||||
ExpectedTypeInfo[] types = JavaSmartCompletionContributor.getExpectedTypes(parameters);
|
||||
Consumer<LookupElement> consumer = e -> result.consume(smart ? JavaSmartCompletionContributor.decorate(e, Arrays.asList(types)) : e);
|
||||
Consumer<LookupElement> consumer = e -> {
|
||||
added[0] = true;
|
||||
result.consume(smart ? JavaSmartCompletionContributor.decorate(e, types) : e);
|
||||
};
|
||||
for (ExpectedTypeInfo info : types) {
|
||||
new JavaMembersGetter(info.getType(), parameters).addMembers(searchInheritors, consumer);
|
||||
if (!info.getType().equals(info.getDefaultType())) {
|
||||
@@ -1011,6 +1057,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
}
|
||||
}
|
||||
return added[0];
|
||||
}
|
||||
|
||||
private static void addModuleReferences(PsiElement moduleRef, PsiFile originalFile, CompletionResultSet result) {
|
||||
|
||||
+12
-24
@@ -12,7 +12,6 @@ import com.intellij.psi.filters.element.ModifierFilter;
|
||||
import com.intellij.psi.filters.types.AssignableFromFilter;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -67,32 +66,21 @@ public class ReferenceExpressionCompletionContributor {
|
||||
return TrueFilter.INSTANCE;
|
||||
}
|
||||
|
||||
static void addSmartReferenceSuggestions(CompletionParameters parameters,
|
||||
List<LookupElement> allRefSuggestions,
|
||||
Set<ExpectedTypeInfo> infos,
|
||||
List<SlowerTypeConversions> chainedEtc,
|
||||
Consumer<? super LookupElement> result) {
|
||||
final PsiElement element = parameters.getPosition();
|
||||
if (JavaSmartCompletionContributor.INSIDE_TYPECAST_EXPRESSION.accepts(element)) return;
|
||||
|
||||
ElementFilter filter = getReferenceFilter(element, false);
|
||||
allRefSuggestions = ContainerUtil.filter(allRefSuggestions, item -> filter.isAcceptable(item.getObject(), element));
|
||||
|
||||
for (ExpectedTypeInfo info : infos) {
|
||||
for (LookupElement item : allRefSuggestions) {
|
||||
if (matchesExpectedType(item, info.getType())) {
|
||||
if (item instanceof JavaMethodCallElement) {
|
||||
checkTooGeneric((JavaMethodCallElement)item);
|
||||
}
|
||||
result.consume(item);
|
||||
static List<LookupElement> smartCompleteReference(List<LookupElement> allRefSuggestions, Set<ExpectedTypeInfo> infos) {
|
||||
List<LookupElement> result = new ArrayList<>();
|
||||
for (LookupElement item : allRefSuggestions) {
|
||||
if (matchesExpectedType(item, infos)) {
|
||||
if (item instanceof JavaMethodCallElement) {
|
||||
checkTooGeneric((JavaMethodCallElement)item);
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() >= 2) {
|
||||
chainedEtc.add(new SlowerTypeConversions(new HashSet<>(allRefSuggestions), element, (PsiJavaCodeReferenceElement) element.getParent(),
|
||||
new JavaSmartCompletionParameters(parameters, info), result));
|
||||
result.add(JavaSmartCompletionContributor.decorate(item, infos));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static boolean matchesExpectedType(LookupElement item, Set<ExpectedTypeInfo> infos) {
|
||||
return ContainerUtil.exists(infos, info -> matchesExpectedType(item, info.getType()));
|
||||
}
|
||||
|
||||
private static boolean matchesExpectedType(LookupElement item, PsiType type) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
@@ -12,61 +13,47 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor.getSpace;
|
||||
import static com.intellij.patterns.PsiJavaPatterns.psiElement;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class SlowerTypeConversions implements Runnable {
|
||||
private static final PrefixMatcher TRUE_MATCHER = new PrefixMatcher("") {
|
||||
@Override
|
||||
public boolean prefixMatches(@NotNull String name) {
|
||||
return true;
|
||||
}
|
||||
class SlowerTypeConversions {
|
||||
static void addChainedSuggestions(CompletionParameters parameters,
|
||||
CompletionResultSet result,
|
||||
Set<ExpectedTypeInfo> expectedInfos,
|
||||
List<LookupElement> base) {
|
||||
PsiElement position = parameters.getPosition();
|
||||
PsiJavaCodeReferenceElement reference = (PsiJavaCodeReferenceElement)position.getParent();
|
||||
List<LookupElement> chainable = ContainerUtil.filter(base, item -> isChainable(item.getObject()));
|
||||
if (chainable.isEmpty()) return;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PrefixMatcher cloneWithPrefix(@NotNull String prefix) {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
private final Set<? extends LookupElement> myBase;
|
||||
private final PsiElement myElement;
|
||||
private final PsiJavaCodeReferenceElement myReference;
|
||||
private final JavaSmartCompletionParameters myParameters;
|
||||
private final Consumer<? super LookupElement> myResult;
|
||||
for (ExpectedTypeInfo info : expectedInfos) {
|
||||
Set<Pair<LookupElement, String>> processedChains = new HashSet<>();
|
||||
JavaSmartCompletionParameters smartParams = new JavaSmartCompletionParameters(parameters, info);
|
||||
for (LookupElement item : chainable) {
|
||||
addSecondCompletionVariants(position, reference, item, smartParams, lookupElement -> {
|
||||
ContainerUtil.addIfNotNull(processedChains, chainInfo(lookupElement));
|
||||
result.consume(JavaSmartCompletionContributor.decorate(lookupElement, expectedInfos));
|
||||
});
|
||||
}
|
||||
if (!reference.isQualified()) {
|
||||
BasicExpressionCompletionContributor.processDataflowExpressionTypes(smartParams, null, PrefixMatcher.ALWAYS_TRUE,
|
||||
baseItem -> addSecondCompletionVariants(position, reference, baseItem, smartParams, lookupElement -> {
|
||||
if (!processedChains.contains(chainInfo(lookupElement))) {
|
||||
result.consume(JavaSmartCompletionContributor.decorate(lookupElement, expectedInfos));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
SlowerTypeConversions(Set<? extends LookupElement> base,
|
||||
PsiElement element,
|
||||
PsiJavaCodeReferenceElement reference,
|
||||
JavaSmartCompletionParameters parameters, Consumer<? super LookupElement> result) {
|
||||
myBase = base;
|
||||
myElement = element;
|
||||
myReference = reference;
|
||||
myParameters = parameters;
|
||||
myResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final Set<Pair<LookupElement, String>> processedChains = new HashSet<>();
|
||||
for (final LookupElement item : myBase) {
|
||||
addSecondCompletionVariants(myElement, myReference, item, myParameters, lookupElement -> {
|
||||
ContainerUtil.addIfNotNull(processedChains, chainInfo(lookupElement));
|
||||
myResult.consume(lookupElement);
|
||||
});
|
||||
}
|
||||
if (!psiElement().afterLeaf(".").accepts(myElement)) {
|
||||
BasicExpressionCompletionContributor.processDataflowExpressionTypes(myParameters, null, TRUE_MATCHER,
|
||||
baseItem -> addSecondCompletionVariants(myElement, myReference, baseItem, myParameters, lookupElement -> {
|
||||
if (!processedChains.contains(chainInfo(lookupElement))) {
|
||||
myResult.consume(lookupElement);
|
||||
}
|
||||
}));
|
||||
}
|
||||
private static boolean isChainable(Object object) {
|
||||
return object instanceof PsiVariable || object instanceof PsiMethod || object instanceof PsiExpression;
|
||||
}
|
||||
|
||||
private static void addSecondCompletionVariants(PsiElement element, PsiReference reference, LookupElement baseItem,
|
||||
|
||||
+27
-7
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.codeInsight.completion.scope;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInspection.SuppressManager;
|
||||
import com.intellij.codeInspection.accessStaticViaInstance.AccessStaticViaInstanceBase;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
@@ -24,10 +25,7 @@ import com.intellij.util.containers.hash.LinkedHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class JavaCompletionProcessor implements PsiScopeProcessor, ElementClassHint {
|
||||
|
||||
@@ -92,12 +90,34 @@ public class JavaCompletionProcessor implements PsiScopeProcessor, ElementClassH
|
||||
myQualifierType = JavaPsiFacade.getElementFactory(element.getProject()).createType(qualifierClass);
|
||||
}
|
||||
|
||||
myAllowStaticWithInstanceQualifier = !options.filterStaticAfterInstance ||
|
||||
SuppressManager.getInstance().isSuppressedFor(element, AccessStaticViaInstanceBase.ACCESS_STATIC_VIA_INSTANCE) ||
|
||||
Registry.is("ide.java.completion.suggest.static.after.instance");
|
||||
myAllowStaticWithInstanceQualifier = !options.filterStaticAfterInstance || allowStaticAfterInstanceQualifier(element);
|
||||
|
||||
}
|
||||
|
||||
private static boolean allowStaticAfterInstanceQualifier(@NotNull PsiElement position) {
|
||||
return SuppressManager.getInstance().isSuppressedFor(position, AccessStaticViaInstanceBase.ACCESS_STATIC_VIA_INSTANCE) ||
|
||||
Registry.is("ide.java.completion.suggest.static.after.instance");
|
||||
}
|
||||
|
||||
public static List<LookupElement> dispreferStaticAfterInstance(PsiJavaCodeReferenceElement position, List<LookupElement> items) {
|
||||
if (allowStaticAfterInstanceQualifier(position)) return items;
|
||||
|
||||
PsiElement qualifier = position.getQualifier();
|
||||
if (qualifier == null ||
|
||||
qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiClass) {
|
||||
return items;
|
||||
}
|
||||
|
||||
List<LookupElement> preferred = new ArrayList<>();
|
||||
for (LookupElement item : items) {
|
||||
Object object = item.getObject();
|
||||
if (!(object instanceof PsiModifierListOwner) || !((PsiModifierListOwner)object).hasModifierProperty(PsiModifier.STATIC)) {
|
||||
preferred.add(item);
|
||||
}
|
||||
}
|
||||
return preferred.isEmpty() ? items : preferred;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull Event event, Object associated){
|
||||
if (JavaScopeProcessorEvent.isEnteringStaticScope(event, associated)) {
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class Bar {
|
||||
Goo getGoo();
|
||||
}
|
||||
class Goo {}
|
||||
|
||||
class Foo {
|
||||
Bar getBar() {}
|
||||
|
||||
|
||||
void x(Goo unmatched) {
|
||||
Goo g = getG<caret>
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
class Bar {
|
||||
Goo getGoo();
|
||||
}
|
||||
class Goo {}
|
||||
|
||||
class Foo {
|
||||
Bar getBar() {}
|
||||
|
||||
|
||||
void x(Goo unmatched) {
|
||||
Goo g = getBar().getGoo();<caret>
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import foo.bar.*;
|
||||
import foo.baz.Baz;
|
||||
class Main {
|
||||
void foo() throws ReflectiveOperationException {
|
||||
Class<Annotation> aType = Baz.class;
|
||||
Class<Baz> aType = Baz.class;
|
||||
Test.class.getAnnotation(<caret>);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@ import foo.bar.*;
|
||||
import foo.baz.Baz;
|
||||
class Main {
|
||||
void foo() throws ReflectiveOperationException {
|
||||
Class<Annotation> aType = Baz.class;
|
||||
Class<Baz> aType = Baz.class;
|
||||
Test.class.getAnnotation(aType);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
class A{
|
||||
class B{
|
||||
int fooo(){
|
||||
}
|
||||
}
|
||||
|
||||
int fooo(){
|
||||
A b = null;
|
||||
A a = null;
|
||||
|
||||
return fo<caret>
|
||||
return a.fooo();<caret>
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,6 @@
|
||||
class A{
|
||||
class B{
|
||||
int fooo(){
|
||||
}
|
||||
}
|
||||
|
||||
int fooo(){
|
||||
A b = null;
|
||||
A a = null;
|
||||
|
||||
return fo<caret>
|
||||
}
|
||||
|
||||
+2
@@ -2019,4 +2019,6 @@ class Abc {
|
||||
selectItem(myItems[1])
|
||||
checkResult()
|
||||
}
|
||||
|
||||
void testSuggestChainsOfExpectedType() { doTest() }
|
||||
}
|
||||
|
||||
+6
@@ -1344,4 +1344,10 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
|
||||
assertTrue(PsiUtil.getLanguageLevel(getProject()).isLessThan(LanguageLevel.JDK_1_8));
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testSuggestChainsWhenNoDirectMatches() {
|
||||
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject("second/MethodAsQualifier.java", "a.java"));
|
||||
myFixture.complete(CompletionType.SMART);
|
||||
checkResultByFile("second/MethodAsQualifier-out.java");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user