mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-10 13:17:09 +07:00
method ref completion: complete receiver typed method ref without param in valid lambda context (IDEA-140730)
This commit is contained in:
+62
-13
@@ -20,6 +20,8 @@ import com.intellij.codeInsight.generation.GenerateMembersUtil;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupElementBuilder;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.EditorModificationUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -27,28 +29,32 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
public class LambdaCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||
public class FunctionalExpressionCompletionProvider extends CompletionProvider<CompletionParameters> {
|
||||
@Override
|
||||
protected void addCompletions(@NotNull CompletionParameters parameters,
|
||||
ProcessingContext context,
|
||||
@NotNull CompletionResultSet result) {
|
||||
result.addAllElements(getLambdaVariants(parameters));
|
||||
result.addAllElements(getLambdaVariants(parameters, false));
|
||||
}
|
||||
|
||||
static List<LookupElement> getLambdaVariants(@NotNull CompletionParameters parameters) {
|
||||
static List<LookupElement> getLambdaVariants(@NotNull CompletionParameters parameters, boolean prioritize) {
|
||||
if (!PsiUtil.isLanguageLevel8OrHigher(parameters.getOriginalFile())) return Collections.emptyList();
|
||||
|
||||
List<LookupElement> result = ContainerUtil.newArrayList();
|
||||
@@ -56,15 +62,15 @@ public class LambdaCompletionProvider extends CompletionProvider<CompletionParam
|
||||
final PsiType defaultType = expectedType.getDefaultType();
|
||||
if (LambdaUtil.isFunctionalType(defaultType)) {
|
||||
final PsiType functionalInterfaceType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(defaultType);
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (method != null) {
|
||||
PsiParameter[] params = method.getParameterList().getParameters();
|
||||
final Project project = method.getProject();
|
||||
final PsiElement originalPosition = parameters.getOriginalPosition();
|
||||
final JVMElementFactory jvmElementFactory = originalPosition != null ? JVMElementFactories.getFactory(originalPosition.getLanguage(), project) : null;
|
||||
final PsiMethod functionalInterfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (functionalInterfaceMethod != null) {
|
||||
PsiParameter[] params = functionalInterfaceMethod.getParameterList().getParameters();
|
||||
final Project project = functionalInterfaceMethod.getProject();
|
||||
final PsiElement originalPosition = parameters.getPosition();
|
||||
final JVMElementFactory jvmElementFactory = JVMElementFactories.getFactory(originalPosition.getLanguage(), project);
|
||||
final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(functionalInterfaceMethod, PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
if (jvmElementFactory != null) {
|
||||
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(method, PsiUtil.resolveGenericsClassInType(functionalInterfaceType));
|
||||
params = GenerateMembersUtil.overriddenParameters(params, jvmElementFactory, javaCodeStyleManager, substitutor, originalPosition);
|
||||
}
|
||||
|
||||
@@ -82,14 +88,57 @@ public class LambdaCompletionProvider extends CompletionProvider<CompletionParam
|
||||
lambdaExpression = (PsiLambdaExpression)codeStyleManager.reformat(lambdaExpression);
|
||||
paramsString = lambdaExpression.getParameterList().getText();
|
||||
final LookupElementBuilder builder =
|
||||
LookupElementBuilder.create(paramsString).withPresentableText(paramsString + " -> {}").withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
LookupElementBuilder.create(functionalInterfaceMethod, paramsString).withPresentableText(paramsString + " -> {}").withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final Editor editor = context.getEditor();
|
||||
EditorModificationUtil.insertStringAtCaret(editor, " -> ");
|
||||
}
|
||||
});
|
||||
result.add(builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE));
|
||||
}).withIcon(AllIcons.Nodes.AnonymousClass);
|
||||
LookupElement lambdaElement = builder.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
if (prioritize) {
|
||||
lambdaElement = PrioritizedLookupElement.withPriority(lambdaElement, 1);
|
||||
}
|
||||
result.add(lambdaElement);
|
||||
|
||||
if (params.length == 1) {
|
||||
final PsiType expectedReturnType = substitutor.substitute(functionalInterfaceMethod.getReturnType());
|
||||
if (expectedReturnType != null) {
|
||||
final PsiClass paramClass = PsiUtil.resolveClassInClassTypeOnly(params[0].getType());
|
||||
if (paramClass != null && !paramClass.hasTypeParameters()) {
|
||||
final Set<String> visited = new HashSet<String>();
|
||||
for (PsiMethod psiMethod : paramClass.getAllMethods()) {
|
||||
final PsiType returnType = psiMethod.getReturnType();
|
||||
if (returnType != null &&
|
||||
psiMethod.getParameterList().getParametersCount() == 0 &&
|
||||
visited.add(psiMethod.getName()) &&
|
||||
!psiMethod.hasModifierProperty(PsiModifier.STATIC) &&
|
||||
JavaResolveUtil.isAccessible(psiMethod, null, psiMethod.getModifierList(), originalPosition, null, null) &&
|
||||
TypeConversionUtil.isAssignable(expectedReturnType, returnType)) {
|
||||
LookupElement methodRefLookupElement = LookupElementBuilder
|
||||
.create(psiMethod)
|
||||
.withPresentableText(paramClass.getName() + "::" + psiMethod.getName())
|
||||
.withInsertHandler(new InsertHandler<LookupElement>() {
|
||||
@Override
|
||||
public void handleInsert(InsertionContext context, LookupElement item) {
|
||||
final int startOffset = context.getStartOffset();
|
||||
final Document document = context.getDocument();
|
||||
final PsiFile file = context.getFile();
|
||||
document.insertString(startOffset, "::");
|
||||
JavaCompletionUtil.insertClassReference(paramClass, file, startOffset);
|
||||
}
|
||||
})
|
||||
.withIcon(AllIcons.Nodes.AnonymousClass)
|
||||
.withAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
if (prioritize && psiMethod.getContainingClass() == paramClass) {
|
||||
methodRefLookupElement = PrioritizedLookupElement.withPriority(methodRefLookupElement, 1);
|
||||
}
|
||||
result.add(methodRefLookupElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -225,9 +225,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
if (JavaSmartCompletionContributor.LAMBDA.accepts(parameters.getPosition())) {
|
||||
for (LookupElement element : LambdaCompletionProvider.getLambdaVariants(parameters)) {
|
||||
result.addElement(PrioritizedLookupElement.withPriority(element, 1));
|
||||
}
|
||||
result.addAllElements(FunctionalExpressionCompletionProvider.getLambdaVariants(parameters, true));
|
||||
}
|
||||
|
||||
PrefixMatcher matcher = result.getPrefixMatcher();
|
||||
|
||||
+1
-1
@@ -359,7 +359,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
});
|
||||
|
||||
extend(CompletionType.SMART, LAMBDA, new LambdaCompletionProvider());
|
||||
extend(CompletionType.SMART, LAMBDA, new FunctionalExpressionCompletionProvider());
|
||||
extend(CompletionType.SMART, METHOD_REFERENCE, new MethodReferenceCompletionProvider());
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import java.util.List;
|
||||
|
||||
class MyTest {
|
||||
|
||||
void m(List<Person> l) {
|
||||
l.stream().map(Person::getName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Person {
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import java.util.List;
|
||||
|
||||
class MyTest {
|
||||
|
||||
void m(List<Person> l) {
|
||||
l.stream().map(<caret>)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Person {
|
||||
String getName();
|
||||
}
|
||||
+4
@@ -123,6 +123,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
public void testSimpleMethodReference() throws Exception {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user