mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
IDEA-188654 Stream API methods autocomplete
GitOrigin-RevId: c4e2caba222324726aad91148ab37c0acf4fd86a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
fb3d2a86d9
commit
847bb51000
@@ -49,7 +49,7 @@ class ChainedCallCompletion {
|
||||
}
|
||||
|
||||
final ElementFilter filter = ReferenceExpressionCompletionContributor.getReferenceFilter(place, true);
|
||||
for (final LookupElement item : ReferenceExpressionCompletionContributor.completeFinalReference(place, mockRef, filter, parameters)) {
|
||||
for (LookupElement item : ReferenceExpressionCompletionContributor.completeFinalReference(place, mockRef, filter, expectedType, parameters.getParameters())) {
|
||||
if (shouldChain(place, qualifierType, expectedType, item)) {
|
||||
result.consume(new JavaChainLookupElement(qualifierItem, item) {
|
||||
@Override
|
||||
|
||||
@@ -367,6 +367,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
final List<ExpectedTypeInfo> expected = Arrays.asList(ExpectedTypesProvider.getExpectedTypes((PsiExpression)parent, true));
|
||||
StreamConversion.addCollectConversion((PsiReferenceExpression)parent, expected,
|
||||
lookupElement -> items.add(JavaSmartCompletionContributor.decorate(lookupElement, expected)));
|
||||
items.addAll(StreamConversion.addToStreamConversion((PsiReferenceExpression)parent, parameters));
|
||||
}
|
||||
|
||||
if (IMPORT_REFERENCE.accepts(position)) {
|
||||
|
||||
@@ -41,7 +41,8 @@ public class JavaCompletionStatistician extends CompletionStatistician{
|
||||
if (o instanceof PsiLocalVariable || o instanceof PsiParameter ||
|
||||
o instanceof PsiThisExpression || o instanceof PsiKeyword ||
|
||||
element.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) != null ||
|
||||
FunctionalExpressionCompletionProvider.isFunExprItem(element)) {
|
||||
FunctionalExpressionCompletionProvider.isFunExprItem(element) ||
|
||||
element.as(StreamConversion.StreamMethodInvocation.class) != null) {
|
||||
return StatisticsInfo.EMPTY;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ public class ReferenceExpressionCompletionContributor {
|
||||
filter = new AndFilter(filter, new CheckInitialized(element));
|
||||
}
|
||||
|
||||
for (final LookupElement item : completeFinalReference(element, reference, filter, parameters)) {
|
||||
for (LookupElement item : completeFinalReference(element, reference, filter, parameters.getExpectedType(), parameters.getParameters())) {
|
||||
result.consume(item);
|
||||
}
|
||||
|
||||
@@ -109,9 +109,12 @@ public class ReferenceExpressionCompletionContributor {
|
||||
return null;
|
||||
}
|
||||
|
||||
static Set<LookupElement> completeFinalReference(final PsiElement element, PsiJavaCodeReferenceElement reference, ElementFilter filter,
|
||||
final JavaSmartCompletionParameters parameters) {
|
||||
final Set<PsiField> used = parameters.getParameters().getInvocationCount() < 2 ? findConstantsUsedInSwitch(element) : Collections.emptySet();
|
||||
static Set<LookupElement> completeFinalReference(PsiElement element,
|
||||
PsiJavaCodeReferenceElement reference,
|
||||
ElementFilter filter,
|
||||
PsiType expectedType,
|
||||
CompletionParameters parameters) {
|
||||
final Set<PsiField> used = parameters.getInvocationCount() < 2 ? findConstantsUsedInSwitch(element) : Collections.emptySet();
|
||||
|
||||
final Set<LookupElement> elements =
|
||||
JavaSmartCompletionContributor.completeReference(element, reference, new AndFilter(filter, new ElementFilter() {
|
||||
@@ -121,12 +124,10 @@ public class ReferenceExpressionCompletionContributor {
|
||||
final CandidateInfo info = (CandidateInfo)o;
|
||||
final PsiElement member = info.getElement();
|
||||
|
||||
final PsiType expectedType = parameters.getExpectedType();
|
||||
if (expectedType.equals(PsiType.VOID)) {
|
||||
return member instanceof PsiMethod;
|
||||
}
|
||||
|
||||
//noinspection SuspiciousMethodCalls
|
||||
if (member instanceof PsiEnumConstant && used.contains(CompletionUtil.getOriginalOrSelf(member))) {
|
||||
return false;
|
||||
}
|
||||
@@ -140,12 +141,12 @@ public class ReferenceExpressionCompletionContributor {
|
||||
public boolean isClassAcceptable(Class hintClass) {
|
||||
return true;
|
||||
}
|
||||
}), false, true, parameters.getParameters(), PrefixMatcher.ALWAYS_TRUE);
|
||||
}), false, true, parameters, PrefixMatcher.ALWAYS_TRUE);
|
||||
for (LookupElement lookupElement : elements) {
|
||||
if (lookupElement.getObject() instanceof PsiMethod) {
|
||||
final JavaMethodCallElement item = lookupElement.as(JavaMethodCallElement.CLASS_CONDITION_KEY);
|
||||
if (item != null) {
|
||||
item.setInferenceSubstitutorFromExpectedType(element, parameters.getExpectedType());
|
||||
item.setInferenceSubstitutorFromExpectedType(element, expectedType);
|
||||
if (JavaCompletionSorting.isTooGeneric(lookupElement, item.getObject())) {
|
||||
item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
// Copyright 2000-2018 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;
|
||||
|
||||
import com.intellij.application.options.CodeStyle;
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypesProvider;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.intellij.codeInsight.lookup.TypedLookupItem;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.filters.TrueFilter;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -21,13 +22,80 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collector;
|
||||
|
||||
import static com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor.getSpace;
|
||||
import static com.intellij.psi.CommonClassNames.*;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class StreamConversion {
|
||||
|
||||
|
||||
static List<LookupElement> addToStreamConversion(PsiReferenceExpression ref, CompletionParameters parameters) {
|
||||
PsiExpression qualifier = ref.getQualifierExpression();
|
||||
if (qualifier == null) return Collections.emptyList();
|
||||
|
||||
PsiType type = qualifier.getType();
|
||||
if (type instanceof PsiClassType) {
|
||||
PsiClass qualifierClass = ((PsiClassType)type).resolve();
|
||||
if (qualifierClass == null) return Collections.emptyList();
|
||||
|
||||
PsiMethod streamMethod = ContainerUtil.find(qualifierClass.findMethodsByName("stream", true), m ->
|
||||
!m.hasParameters() &&
|
||||
InheritanceUtil.isInheritor(m.getReturnType(), JAVA_UTIL_STREAM_BASE_STREAM));
|
||||
if (streamMethod == null) return Collections.emptyList();
|
||||
|
||||
return generateStreamSuggestions(parameters, qualifier, qualifier.getText() + ".stream()", context -> {
|
||||
String space = getSpace(CodeStyle.getLanguageSettings(context.getFile()).SPACE_WITHIN_EMPTY_METHOD_CALL_PARENTHESES);
|
||||
context.getDocument().insertString(context.getStartOffset(), "stream(" + space + ").");
|
||||
});
|
||||
}
|
||||
else if (type instanceof PsiArrayType) {
|
||||
String arraysStream = JAVA_UTIL_ARRAYS + ".stream";
|
||||
return generateStreamSuggestions(parameters, qualifier, arraysStream + "(" + qualifier.getText() + ")",
|
||||
context -> wrapQualifiedIntoMethodCall(context, arraysStream));
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<LookupElement> generateStreamSuggestions(CompletionParameters parameters,
|
||||
PsiExpression qualifier,
|
||||
String changedQualifier,
|
||||
Consumer<InsertionContext> beforeInsertion) {
|
||||
PsiReferenceExpression asStream = (PsiReferenceExpression)PsiElementFactory.getInstance(qualifier.getProject())
|
||||
.createExpressionFromText(changedQualifier + ".x", qualifier);
|
||||
|
||||
Set<LookupElement> streamSuggestions = ReferenceExpressionCompletionContributor
|
||||
.completeFinalReference(qualifier, asStream, TrueFilter.INSTANCE,
|
||||
PsiType.getJavaLangObject(qualifier.getManager(), qualifier.getResolveScope()),
|
||||
parameters);
|
||||
return ContainerUtil.map(streamSuggestions, e -> new StreamMethodInvocation(e, beforeInsertion));
|
||||
}
|
||||
|
||||
private static void wrapQualifiedIntoMethodCall(@NotNull InsertionContext context, @NotNull String methodQualifiedName) {
|
||||
PsiFile file = context.getFile();
|
||||
PsiReferenceExpression ref =
|
||||
PsiTreeUtil.findElementOfClassAtOffset(file, context.getStartOffset(), PsiReferenceExpression.class, false);
|
||||
if (ref != null) {
|
||||
PsiElement qualifier = ref.getQualifier();
|
||||
if (qualifier != null) {
|
||||
TextRange range = qualifier.getTextRange();
|
||||
int startOffset = range.getStartOffset();
|
||||
|
||||
String callSpace = getSpace(CodeStyle.getLanguageSettings(file).SPACE_WITHIN_METHOD_CALL_PARENTHESES);
|
||||
context.getDocument().insertString(range.getEndOffset(), callSpace + ")");
|
||||
context.getDocument().insertString(startOffset, methodQualifiedName + "(" + callSpace);
|
||||
|
||||
context.commitDocument();
|
||||
Project project = context.getProject();
|
||||
JavaCodeStyleManager.getInstance(project).shortenClassReferences(
|
||||
file, startOffset, startOffset + methodQualifiedName.length());
|
||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(context.getDocument());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void addCollectConversion(PsiReferenceExpression ref, Collection<? extends ExpectedTypeInfo> expectedTypes, Consumer<? super LookupElement> consumer) {
|
||||
PsiClass collectors = JavaPsiFacade.getInstance(ref.getProject()).findClass(JAVA_UTIL_STREAM_COLLECTORS, ref.getResolveScope());
|
||||
if (collectors == null) return;
|
||||
@@ -209,4 +277,25 @@ class StreamConversion {
|
||||
return myExpectedType;
|
||||
}
|
||||
}
|
||||
|
||||
static class StreamMethodInvocation extends LookupElementDecorator<LookupElement> {
|
||||
private final Consumer<? super InsertionContext> myBeforeInsertion;
|
||||
|
||||
StreamMethodInvocation(LookupElement e, Consumer<? super InsertionContext> beforeInsertion) {
|
||||
super(e);
|
||||
myBeforeInsertion = beforeInsertion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderElement(LookupElementPresentation presentation) {
|
||||
super.renderElement(presentation);
|
||||
presentation.setItemText("stream()." + presentation.getItemText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleInsert(@NotNull InsertionContext context) {
|
||||
myBeforeInsertion.consume(context);
|
||||
super.handleInsert(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class Foo {
|
||||
void foo(String[] array) {
|
||||
array.<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import java.util.Arrays;
|
||||
|
||||
class Foo {
|
||||
void foo(String[] array) {
|
||||
Arrays.stream(array).map(<caret>)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
void foo(MyList<String> list) {
|
||||
list.<caret>
|
||||
}
|
||||
}
|
||||
|
||||
class MyList<T> extends java.util.List<T> {
|
||||
void filter();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
void foo(MyList<String> list) {
|
||||
list.stream().map(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
class MyList<T> extends java.util.List<T> {
|
||||
void filter();
|
||||
}
|
||||
@@ -414,4 +414,28 @@ class Test88 {
|
||||
myFixture.completeBasic()
|
||||
assert myFixture.lookupElementStrings == ['wait']
|
||||
}
|
||||
|
||||
void testStreamMethodsOnCollection() {
|
||||
configureByTestName()
|
||||
myFixture.assertPreferredCompletionItems 0, 'filter'
|
||||
assert LookupElementPresentation.renderElement(myFixture.lookupElements[0]).itemText == 'filter'
|
||||
|
||||
myFixture.type('ma')
|
||||
myFixture.assertPreferredCompletionItems 0, 'map', 'mapToDouble'
|
||||
assert LookupElementPresentation.renderElement(myFixture.lookupElements[0]).itemText == 'stream().map'
|
||||
|
||||
myFixture.type('\n')
|
||||
checkResultByFileName()
|
||||
}
|
||||
|
||||
void testStreamMethodsOnArray() {
|
||||
configureByTestName()
|
||||
myFixture.assertPreferredCompletionItems 0, 'length', 'clone'
|
||||
|
||||
myFixture.type('ma')
|
||||
myFixture.assertPreferredCompletionItems 0, 'map', 'mapToDouble'
|
||||
|
||||
myFixture.type('\n')
|
||||
checkResultByFileName()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user