From 3aea481c1f986073fa7980c88a305a3fa839ccd3 Mon Sep 17 00:00:00 2001 From: Peter Gromov Date: Mon, 15 Jun 2020 14:01:23 +0200 Subject: [PATCH] IDEA-145958 Suggest chained calls of expected type in basic & autopopup completion GitOrigin-RevId: b2d1ed10839ffac236b724c224f856e6bb99cb14 --- .../completion/JavaCompletionContributor.java | 141 ++++++++++++------ ...erenceExpressionCompletionContributor.java | 36 ++--- .../completion/SlowerTypeConversions.java | 75 ++++------ .../scope/JavaCompletionProcessor.java | 34 ++++- .../normal/SuggestChainsOfExpectedType.java | 13 ++ .../SuggestChainsOfExpectedType_after.java | 13 ++ .../reflectionParameters/Variable.java | 2 +- .../reflectionParameters/Variable_after.java | 2 +- .../completion/smartType/return/after3.java | 9 +- .../completion/smartType/return/before3.java | 7 +- .../completion/NormalCompletionTest.groovy | 2 + .../completion/SmartTypeCompletionTest.java | 6 + 12 files changed, 203 insertions(+), 137 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType.java create mode 100644 java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType_after.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java index 6ec03454d990..a722256df922 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionContributor.java @@ -245,6 +245,13 @@ public class JavaCompletionContributor extends CompletionContributor { if (position instanceof PsiIdentifier) { addIdentifierVariants(parameters, position, result, session, matcher); + Set 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 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 refSuggestions = Collections.emptyList(); + if (parent instanceof PsiJavaCodeReferenceElement && mayCompleteReference) { + refSuggestions = completeReference(parameters, (PsiJavaCodeReferenceElement)parent, session, expectedInfos); + List 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 allRefSuggestions) { + private static List filterReferenceSuggestions(boolean smart, + CompletionResultSet result, + PsiJavaCodeReferenceElement parent, + Set expectedInfos, + List refSuggestions) { + if (smart) { + refSuggestions = ReferenceExpressionCompletionContributor.smartCompleteReference(refSuggestions, expectedInfos); + } + List 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 infos = ContainerUtil.newHashSet(JavaSmartCompletionContributor.getExpectedTypes(parameters)); - Set mergedInfos = new THashSet<>(infos, JavaSmartCompletionContributor.EXPECTED_TYPE_INFO_STRATEGY); - List 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 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 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 completeReference(CompletionParameters parameters, PsiJavaCodeReferenceElement ref, - JavaCompletionSession session) { + JavaCompletionSession session, + Set 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 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 result) { + private static boolean addExpectedTypeMembers(CompletionParameters parameters, + boolean searchInheritors, + Collection types, + Consumer 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 consumer = e -> result.consume(smart ? JavaSmartCompletionContributor.decorate(e, Arrays.asList(types)) : e); + Consumer 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) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java index d73a183e7bdd..bc1e0597efb8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -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 allRefSuggestions, - Set infos, - List chainedEtc, - Consumer 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 smartCompleteReference(List allRefSuggestions, Set infos) { + List 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 infos) { + return ContainerUtil.exists(infos, info -> matchesExpectedType(item, info.getType())); } private static boolean matchesExpectedType(LookupElement item, PsiType type) { diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SlowerTypeConversions.java b/java/java-impl/src/com/intellij/codeInsight/completion/SlowerTypeConversions.java index 4622bb40fed2..77c1971eb72a 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SlowerTypeConversions.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SlowerTypeConversions.java @@ -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 expectedInfos, + List base) { + PsiElement position = parameters.getPosition(); + PsiJavaCodeReferenceElement reference = (PsiJavaCodeReferenceElement)position.getParent(); + List 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 myBase; - private final PsiElement myElement; - private final PsiJavaCodeReferenceElement myReference; - private final JavaSmartCompletionParameters myParameters; - private final Consumer myResult; + for (ExpectedTypeInfo info : expectedInfos) { + Set> 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 base, - PsiElement element, - PsiJavaCodeReferenceElement reference, - JavaSmartCompletionParameters parameters, Consumer result) { - myBase = base; - myElement = element; - myReference = reference; - myParameters = parameters; - myResult = result; + } } - @Override - public void run() { - final Set> 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, diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java index 96e627e4e18e..47c958a9144f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/scope/JavaCompletionProcessor.java @@ -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 dispreferStaticAfterInstance(PsiJavaCodeReferenceElement position, List items) { + if (allowStaticAfterInstanceQualifier(position)) return items; + + PsiElement qualifier = position.getQualifier(); + if (qualifier == null || + qualifier instanceof PsiJavaCodeReferenceElement && ((PsiJavaCodeReferenceElement)qualifier).resolve() instanceof PsiClass) { + return items; + } + + List 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)) { diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType.java new file mode 100644 index 000000000000..5228ff0f8e1c --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType.java @@ -0,0 +1,13 @@ +class Bar { + Goo getGoo(); +} +class Goo {} + +class Foo { + Bar getBar() {} + + + void x(Goo unmatched) { + Goo g = getG + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType_after.java b/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType_after.java new file mode 100644 index 000000000000..f82dcbb86fc1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/completion/normal/SuggestChainsOfExpectedType_after.java @@ -0,0 +1,13 @@ +class Bar { + Goo getGoo(); +} +class Goo {} + +class Foo { + Bar getBar() {} + + + void x(Goo unmatched) { + Goo g = getBar().getGoo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable.java b/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable.java index b85dc5238482..f7f3e58bb206 100644 --- a/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable.java +++ b/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable.java @@ -2,7 +2,7 @@ import foo.bar.*; import foo.baz.Baz; class Main { void foo() throws ReflectiveOperationException { - Class aType = Baz.class; + Class aType = Baz.class; Test.class.getAnnotation(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable_after.java b/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable_after.java index fdd7410ec6ad..1bd3146b612d 100644 --- a/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable_after.java +++ b/java/java-tests/testData/codeInsight/completion/reflectionParameters/Variable_after.java @@ -2,7 +2,7 @@ import foo.bar.*; import foo.baz.Baz; class Main { void foo() throws ReflectiveOperationException { - Class aType = Baz.class; + Class aType = Baz.class; Test.class.getAnnotation(aType); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/return/after3.java b/java/java-tests/testData/codeInsight/completion/smartType/return/after3.java index 02ab02bc6ce7..770ca99b4906 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/return/after3.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/return/after3.java @@ -1,12 +1,7 @@ class A{ - class B{ - int fooo(){ - } - } - int fooo(){ - A b = null; + A a = null; - return fo + return a.fooo(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/completion/smartType/return/before3.java b/java/java-tests/testData/codeInsight/completion/smartType/return/before3.java index 02ab02bc6ce7..ef39b6a886fe 100644 --- a/java/java-tests/testData/codeInsight/completion/smartType/return/before3.java +++ b/java/java-tests/testData/codeInsight/completion/smartType/return/before3.java @@ -1,11 +1,6 @@ class A{ - class B{ - int fooo(){ - } - } - int fooo(){ - A b = null; + A a = null; return fo } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy index 2eca18bf1cbc..141ed66baf8d 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/NormalCompletionTest.groovy @@ -2019,4 +2019,6 @@ class Abc { selectItem(myItems[1]) checkResult() } + + void testSuggestChainsOfExpectedType() { doTest() } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java index a2374b98a5bf..af22da9f8efa 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/completion/SmartTypeCompletionTest.java @@ -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"); + } }