static method reference completion (IDEA-124043)

This commit is contained in:
Anna Kozlova
2014-04-24 17:58:58 +02:00
parent 78dafa03c5
commit b898f91f84
6 changed files with 85 additions and 10 deletions
@@ -804,7 +804,7 @@ public class JavaCompletionUtil {
}
}
private static boolean insertTail(InsertionContext context, LookupElement item, TailType tailType, boolean hasTail) {
public static boolean insertTail(InsertionContext context, LookupElement item, TailType tailType, boolean hasTail) {
TailType toInsert = tailType;
LookupItem<?> lookupItem = item.as(LookupItem.CLASS_CONDITION_KEY);
if (lookupItem == null || lookupItem.getAttribute(LookupItem.TAIL_TYPE_ATTR) != TailType.UNKNOWN) {
@@ -108,8 +108,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
final PsiElement rulezzRef = element.getParent();
return rulezzRef != null &&
rulezzRef instanceof PsiMethodReferenceExpression &&
((PsiReferenceExpression)rulezzRef).getQualifier() != element &&
LambdaUtil.isValidLambdaContext(rulezzRef.getParent());
}});
@@ -17,9 +17,12 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypeInfoImpl;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
import com.intellij.psi.util.PsiUtil;
@@ -44,7 +47,8 @@ public class MethodReferenceCompletionProvider extends CompletionProvider<Comple
final PsiType functionalType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(defaultType);
final PsiType returnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalType);
if (returnType != null) {
final PsiMethodReferenceExpression ref = (PsiMethodReferenceExpression)parameters.getPosition().getParent();
final PsiElement position = parameters.getPosition();
final PsiElement refPlace = position.getParent();
final ExpectedTypeInfoImpl typeInfo =
new ExpectedTypeInfoImpl(returnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, returnType, TailType.UNKNOWN, null,
ExpectedTypeInfoImpl.NULL);
@@ -54,15 +58,17 @@ public class MethodReferenceCompletionProvider extends CompletionProvider<Comple
public void consume(final LookupElement lookupElement) {
final PsiElement element = lookupElement.getPsiElement();
if (element instanceof PsiMethod) {
final PsiMethodReferenceExpression referenceExpression = (PsiMethodReferenceExpression)ref.copy();
final PsiElement referenceNameElement = referenceExpression.getReferenceNameElement();
LOG.assertTrue(referenceNameElement != null, referenceExpression);
referenceNameElement.replace(JavaPsiFacade.getElementFactory(element.getProject()).createIdentifier(((PsiMethod)element).getName()));
final PsiMethodReferenceExpression referenceExpression = createMethodReferenceExpression((PsiMethod)element);
if (referenceExpression == null) {
return;
}
final PsiType added = map.put(referenceExpression, functionalType);
try {
final PsiElement resolve = referenceExpression.resolve();
if (resolve == element && PsiMethodReferenceUtil.checkMethodReferenceContext(referenceExpression, resolve, functionalType) == null) {
result.addElement(lookupElement);
if (resolve != null && PsiEquivalenceUtil.areElementsEquivalent(element, resolve) &&
PsiMethodReferenceUtil.checkMethodReferenceContext(referenceExpression, resolve, functionalType) == null) {
result.addElement(new JavaMethodReferenceElement((PsiMethod)element, refPlace, referenceExpression));
}
}
finally {
@@ -72,6 +78,26 @@ public class MethodReferenceCompletionProvider extends CompletionProvider<Comple
}
}
}
private PsiMethodReferenceExpression createMethodReferenceExpression(PsiMethod method) {
if (refPlace instanceof PsiMethodReferenceExpression) {
final PsiMethodReferenceExpression referenceExpression = (PsiMethodReferenceExpression)refPlace.copy();
final PsiElement referenceNameElement = referenceExpression.getReferenceNameElement();
LOG.assertTrue(referenceNameElement != null, referenceExpression);
referenceNameElement.replace(JavaPsiFacade.getElementFactory(method.getProject()).createIdentifier(method.getName()));
return referenceExpression;
}
else if (method.hasModifierProperty(PsiModifier.STATIC)) {
final PsiClass aClass = method.getContainingClass();
LOG.assertTrue(aClass != null);
final String qualifiedName = aClass.getQualifiedName();
return (PsiMethodReferenceExpression)JavaPsiFacade.getElementFactory(method.getProject()).createExpressionFromText(
qualifiedName + "::" + method.getName(), refPlace);
}
else {
return null;
}
}
};
final Runnable runnable = ReferenceExpressionCompletionContributor
@@ -83,4 +109,35 @@ public class MethodReferenceCompletionProvider extends CompletionProvider<Comple
}
}
}
private static class JavaMethodReferenceElement extends JavaMethodCallElement {
private final PsiMethod myMethod;
private final PsiElement myRefPlace;
private PsiMethodReferenceExpression myReferenceExpression;
public JavaMethodReferenceElement(PsiMethod method, PsiElement refPlace, PsiMethodReferenceExpression referenceExpression) {
super(method);
myMethod = method;
myRefPlace = refPlace;
myReferenceExpression = referenceExpression;
}
@Override
public void handleInsert(InsertionContext context) {
if (!(myRefPlace instanceof PsiMethodReferenceExpression)) {
final PsiClass containingClass = myMethod.getContainingClass();
LOG.assertTrue(containingClass != null);
final String qualifiedName = containingClass.getQualifiedName();
LOG.assertTrue(qualifiedName != null);
final Editor editor = context.getEditor();
final Document document = editor.getDocument();
final int startOffset = context.getStartOffset();
document.insertString(startOffset, qualifiedName + "::");
JavaCompletionUtil.shortenReference(context.getFile(), startOffset + qualifiedName.length() - 1);
JavaCompletionUtil.insertTail(context, this, handleCompletionChar(context.getEditor(), this, context.getCompletionChar()), false);
}
}
}
}
@@ -0,0 +1,8 @@
import java.util.ArrayList;
class B {
static void bar(String s){}
{
new ArrayList<String>().forEach(B::bar);
}
}
@@ -0,0 +1,8 @@
import java.util.ArrayList;
class B {
static void bar(String s){}
{
new ArrayList<String>().forEach(<caret>);
}
}
@@ -93,6 +93,10 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase {
doTest(false);
}
public void testNoQualifier() throws Exception {
doTest();
}
public void testFilterAmbiguity() throws Exception {
configureByFile("/" + getTestName(false) + ".java");
assertNotNull(myItems);