mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
move smart completion assignability checking closer to reference processor to fix
IDEADEV-40813 Smart completion inside "if" statement with "instanceof" in condition doesn't suggest method with generic return type
This commit is contained in:
+4
-10
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.completion;
|
||||
import com.intellij.codeInsight.guess.GuessManager;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.lookup.KeywordLookupItem;
|
||||
import com.intellij.codeInsight.lookup.VariableLookupItem;
|
||||
import com.intellij.codeInsight.template.SmartCompletionContextType;
|
||||
import com.intellij.codeInsight.template.impl.TemplateImpl;
|
||||
import com.intellij.codeInsight.template.impl.TemplateSettings;
|
||||
@@ -60,7 +61,7 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
|
||||
public LookupItem compute() {
|
||||
try {
|
||||
final PsiKeyword keyword = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createKeyword(s);
|
||||
return new KeywordLookupItem(keyword).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
|
||||
return new KeywordLookupItem(keyword, element).setAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
@@ -127,13 +128,6 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
|
||||
}
|
||||
});
|
||||
|
||||
final ReferenceExpressionCompletionContributor referenceContributor = new ReferenceExpressionCompletionContributor();
|
||||
extend(psiElement(), new CompletionProvider<JavaSmartCompletionParameters>() {
|
||||
protected void addCompletions(@NotNull final JavaSmartCompletionParameters parameters, final ProcessingContext context, @NotNull final CompletionResultSet result) {
|
||||
referenceContributor.fillCompletionVariants(parameters, result);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public static void processDataflowExpressionTypes(PsiElement position, @Nullable PsiType expectedType, final PrefixMatcher matcher, Consumer<LookupElement> consumer) {
|
||||
@@ -184,8 +178,8 @@ public class BasicExpressionCompletionContributor extends ExpressionSmartComplet
|
||||
if (!refExpr.isQualified()) {
|
||||
final PsiElement target = refExpr.resolve();
|
||||
if (target instanceof PsiVariable) {
|
||||
final LookupItem item = (LookupItem)LookupItemUtil.objectToLookupItem(target);
|
||||
item.setAttribute(LookupItem.SUBSTITUTOR, PsiSubstitutor.EMPTY);
|
||||
final VariableLookupItem item = new VariableLookupItem((PsiVariable)target);
|
||||
item.setSubstitutor(PsiSubstitutor.EMPTY);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-6
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import com.intellij.util.ProcessingContext;
|
||||
@@ -65,15 +66,26 @@ class CollectionsUtilityMethodsProvider extends CompletionProvider<JavaSmartComp
|
||||
private static void addCollectionMethod(final CompletionResultSet result, final PsiType expectedType,
|
||||
final PsiType defaultType, final String baseClassName,
|
||||
@NonNls final String method, @NotNull final PsiClass collectionsClass) {
|
||||
if (isClassType(expectedType, baseClassName) || isClassType(expectedType, JAVA_UTIL_COLLECTION) ||
|
||||
isClassType(defaultType, baseClassName) || isClassType(defaultType, JAVA_UTIL_COLLECTION)) {
|
||||
final PsiMethod[] methods = collectionsClass.findMethodsByName(method, false);
|
||||
if (methods.length != 0) {
|
||||
result.addElement(JavaCompletionUtil.qualify(new JavaMethodCallElement(methods[0]).setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE)));
|
||||
}
|
||||
if (isClassType(expectedType, baseClassName) || isClassType(expectedType, JAVA_UTIL_COLLECTION)) {
|
||||
addMethodItem(result, expectedType, method, collectionsClass);
|
||||
} else if (isClassType(defaultType, baseClassName) || isClassType(defaultType, JAVA_UTIL_COLLECTION)) {
|
||||
addMethodItem(result, defaultType, method, collectionsClass);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addMethodItem(CompletionResultSet result, PsiType expectedType, String methodName, PsiClass containingClass) {
|
||||
final PsiMethod[] methods = containingClass.findMethodsByName(methodName, false);
|
||||
if (methods.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiMethod method = methods[0];
|
||||
final JavaMethodCallElement item = new JavaMethodCallElement(method);
|
||||
JavaCompletionUtil.qualify(item).setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, expectedType));
|
||||
result.addElement(item);
|
||||
}
|
||||
|
||||
private static boolean isClassType(final PsiType type, final String className) {
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
|
||||
-1
@@ -27,7 +27,6 @@ import java.util.List;
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class ExpressionSmartCompletionContributor extends AbstractCompletionContributor<JavaSmartCompletionParameters> {
|
||||
public static final ExpressionSmartCompletionContributor[] CONTRIBUTORS = {new BasicExpressionCompletionContributor()};
|
||||
|
||||
private final List<Pair<ElementPattern<? extends PsiElement>, CompletionProvider<JavaSmartCompletionParameters>>> myList =
|
||||
new ArrayList<Pair<ElementPattern<? extends PsiElement>, CompletionProvider<JavaSmartCompletionParameters>>>();
|
||||
|
||||
@@ -792,6 +792,11 @@ public class JavaCompletionUtil {
|
||||
final PsiType qualifierType = getPsiType(element.getObject());
|
||||
final LookupItem lookupItem = element.as(LookupItem.class);
|
||||
if (lookupItem != null) {
|
||||
final Object o = lookupItem.getAttribute(LookupItem.TYPE);
|
||||
if (o instanceof PsiType) {
|
||||
return (PsiType)o;
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = (PsiSubstitutor)lookupItem.getAttribute(LookupItem.SUBSTITUTOR);
|
||||
if (substitutor != null) {
|
||||
return substitutor.substitute(qualifierType);
|
||||
|
||||
@@ -15,16 +15,21 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.completion.simple.PsiMethodInsertHandler;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.lookup.TypedLookupItem;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.psi.PsiMethod;
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class JavaMethodCallElement extends LookupItem<PsiMethod> {
|
||||
public class JavaMethodCallElement extends LookupItem<PsiMethod> implements TypedLookupItem {
|
||||
private static final Key<PsiSubstitutor> INFERENCE_SUBSTITUTOR = Key.create("INFERENCE_SUBSTITUTOR");
|
||||
|
||||
public JavaMethodCallElement(PsiMethod method) {
|
||||
super(method, method.getName());
|
||||
@@ -33,4 +38,28 @@ public class JavaMethodCallElement extends LookupItem<PsiMethod> {
|
||||
setInsertHandler(new PsiMethodInsertHandler(method));
|
||||
}
|
||||
|
||||
public PsiType getType() {
|
||||
return getSubstitutor().substitute(getInferenceSubstitutor().substitute(getObject().getReturnType()));
|
||||
|
||||
}
|
||||
|
||||
public void setInferenceSubstitutor(@NotNull final PsiSubstitutor substitutor) {
|
||||
setAttribute(INFERENCE_SUBSTITUTOR, substitutor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
final PsiSubstitutor substitutor = (PsiSubstitutor)getAttribute(LookupItem.SUBSTITUTOR);
|
||||
return substitutor == null ? PsiSubstitutor.EMPTY : substitutor;
|
||||
}
|
||||
|
||||
public void setSubstitutor(@NotNull PsiSubstitutor substitutor) {
|
||||
setAttribute(SUBSTITUTOR, substitutor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getInferenceSubstitutor() {
|
||||
final PsiSubstitutor substitutor = getAttribute(INFERENCE_SUBSTITUTOR);
|
||||
return substitutor == null ? PsiSubstitutor.EMPTY : substitutor;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-44
@@ -17,7 +17,6 @@ package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.codeInsight.*;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
@@ -198,7 +197,6 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
|
||||
extend(CompletionType.SMART, INSIDE_EXPRESSION, new ExpectedTypeBasedCompletionProvider() {
|
||||
protected void addCompletions(final CompletionParameters params, final CompletionResultSet result, final Collection<ExpectedTypeInfo> _infos) {
|
||||
final PsiElement position = params.getPosition();
|
||||
final Set<ExpectedTypeInfo> infos = ApplicationManager.getApplication().runReadAction(new Computable<Set<ExpectedTypeInfo>>() {
|
||||
public Set<ExpectedTypeInfo> compute() {
|
||||
return new THashSet<ExpectedTypeInfo>(_infos, EXPECTED_TYPE_INFO_STRATEGY);
|
||||
@@ -207,25 +205,9 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
for (final ExpectedTypeInfo info : infos) {
|
||||
final JavaSmartCompletionParameters parameters = new JavaSmartCompletionParameters(params, info);
|
||||
final PsiType type = info.getType();
|
||||
final boolean isVoid = PsiType.VOID.equals(type);
|
||||
final AssignableFromFilter assignableFromFilter = new AssignableFromFilter(type);
|
||||
final ElementFilter filter = new ElementFilter() {
|
||||
public boolean isAcceptable(Object element, PsiElement context) {
|
||||
if (isVoid) {
|
||||
return element instanceof PsiMethod;
|
||||
}
|
||||
return assignableFromFilter.isAcceptable(element, context);
|
||||
}
|
||||
|
||||
public boolean isClassAcceptable(Class hintClass) {
|
||||
if (isVoid && !ReflectionCache.isAssignable(PsiMethod.class, hintClass)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
final Consumer<LookupElement> consumer = new Consumer<LookupElement>() {
|
||||
final CompletionService service = CompletionService.getCompletionService();
|
||||
new BasicExpressionCompletionContributor().fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer<LookupElement>() {
|
||||
public void consume(final LookupElement lookupElement) {
|
||||
final TypedLookupItem typed = lookupElement.as(TypedLookupItem.class);
|
||||
if (typed != null) {
|
||||
@@ -233,28 +215,14 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
if (psiType != null && type.isAssignableFrom(psiType)) {
|
||||
result.addElement(decorate(lookupElement, _infos));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final Object object = lookupElement.getObject();
|
||||
|
||||
final PsiSubstitutor substitutor;
|
||||
final LookupItem item = lookupElement.as(LookupItem.class);
|
||||
if (item != null) {
|
||||
substitutor = (PsiSubstitutor)item.getAttribute(LookupItem.SUBSTITUTOR);
|
||||
}
|
||||
else {
|
||||
substitutor = null;
|
||||
}
|
||||
if (filter.isAcceptable(object, position) ||
|
||||
substitutor != null && object instanceof PsiElement && filter.isAcceptable(new CandidateInfo((PsiElement)object, substitutor), position)) {
|
||||
result.addElement(decorate(lookupElement, _infos));
|
||||
}
|
||||
}
|
||||
};
|
||||
for (ExpressionSmartCompletionContributor contributor : ExpressionSmartCompletionContributor.CONTRIBUTORS) {
|
||||
contributor.fillCompletionVariants(parameters, CompletionService.getCompletionService().createResultSet(parameters, consumer, JavaSmartCompletionContributor.this));
|
||||
}
|
||||
}, JavaSmartCompletionContributor.this));
|
||||
ReferenceExpressionCompletionContributor.fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer<LookupElement>() {
|
||||
public void consume(final LookupElement lookupElement) {
|
||||
result.addElement(decorate(lookupElement, _infos));
|
||||
}
|
||||
}, JavaSmartCompletionContributor.this));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -629,10 +597,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
|
||||
return ReflectionCache.isAssignable(PsiVariable.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(PsiMethod.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(PsiExpression.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(Template.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(CandidateInfo.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(PsiKeyword.class, hintClass);
|
||||
ReflectionCache.isAssignable(CandidateInfo.class, hintClass);
|
||||
}
|
||||
}, true, null, parameters);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,12 @@ public class PreferNonGenericWeigher extends CompletionWeigher {
|
||||
public Comparable weigh(@NotNull final LookupElement item, final CompletionLocation location) {
|
||||
final Object object = item.getObject();
|
||||
if (object instanceof PsiMethod) {
|
||||
final PsiType type = JavaCompletionUtil.getLookupElementType(item);
|
||||
PsiType type = ((PsiMethod)object).getReturnType();
|
||||
final JavaMethodCallElement callItem = item.as(JavaMethodCallElement.class);
|
||||
if (callItem != null) {
|
||||
type = callItem.getSubstitutor().substitute(type);
|
||||
}
|
||||
|
||||
if (type instanceof PsiClassType && ((PsiClassType) type).resolve() instanceof PsiTypeParameter) return -1;
|
||||
}
|
||||
|
||||
|
||||
+57
-9
@@ -35,7 +35,9 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.filters.*;
|
||||
import com.intellij.psi.filters.element.ModifierFilter;
|
||||
import com.intellij.psi.filters.types.AssignableFromFilter;
|
||||
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -47,10 +49,12 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class ReferenceExpressionCompletionContributor extends ExpressionSmartCompletionContributor{
|
||||
public class ReferenceExpressionCompletionContributor {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.ReferenceExpressionCompletionContributor");
|
||||
private static final PsiMethodPattern OBJECT_METHOD_PATTERN = psiMethod().withName(
|
||||
PsiJavaPatterns.string().oneOf("hashCode", "equals", "finalize", "wait", "notify", "notifyAll", "getClass", "clone", "toString")).
|
||||
@@ -68,6 +72,9 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
}
|
||||
};
|
||||
|
||||
private ReferenceExpressionCompletionContributor() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static ElementFilter getReferenceFilter(PsiElement element, boolean allowRecursion) {
|
||||
//throw foo
|
||||
@@ -96,7 +103,7 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
return TrueFilter.INSTANCE;
|
||||
}
|
||||
|
||||
public void fillCompletionVariants(final JavaSmartCompletionParameters parameters, final CompletionResultSet result) {
|
||||
public static void fillCompletionVariants(final JavaSmartCompletionParameters parameters, final CompletionResultSet result) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
final PsiElement element = parameters.getPosition();
|
||||
@@ -106,17 +113,21 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
final PsiReference reference = element.getContainingFile().findReferenceAt(offset);
|
||||
if (reference != null) {
|
||||
final ElementFilter filter = getReferenceFilter(element, false);
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(element, reference, filter, false, parameters)) {
|
||||
for (final LookupElement item : completeFinalReference(element, reference, filter, parameters)) {
|
||||
result.addElement(item);
|
||||
|
||||
addSingleArrayElementAccess(element, item, parameters, result);
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() >= 2) {
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(element, reference, filter, false, parameters)) {
|
||||
final boolean secondTime = parameters.getInvocationCount() >= 2;
|
||||
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(element, reference, filter, false, parameters)) {
|
||||
addSingleArrayElementAccess(element, item, parameters, result);
|
||||
|
||||
if (secondTime) {
|
||||
addSecondCompletionVariants(element, reference, item, parameters, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (secondTime) {
|
||||
if (!psiElement().afterLeaf(".").accepts(element)) {
|
||||
BasicExpressionCompletionContributor.processDataflowExpressionTypes(element, null, TRUE_MATCHER, new Consumer<LookupElement>() {
|
||||
public void consume(LookupElement baseItem) {
|
||||
@@ -130,6 +141,43 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
});
|
||||
}
|
||||
|
||||
private static Set<LookupElement> completeFinalReference(final PsiElement element, PsiReference reference, ElementFilter filter,
|
||||
final JavaSmartCompletionParameters parameters) {
|
||||
final Set<LookupElement> elements =
|
||||
JavaSmartCompletionContributor.completeReference(element, reference, new AndFilter(filter, new ElementFilter() {
|
||||
public boolean isAcceptable(Object o, PsiElement context) {
|
||||
if (o instanceof CandidateInfo) {
|
||||
final CandidateInfo info = (CandidateInfo)o;
|
||||
final PsiElement member = info.getElement();
|
||||
|
||||
final PsiType expectedType = parameters.getExpectedType();
|
||||
if (expectedType.equals(PsiType.VOID)) {
|
||||
return member instanceof PsiMethod;
|
||||
}
|
||||
|
||||
return AssignableFromFilter.isAcceptable(member, element, expectedType, info.getSubstitutor());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isClassAcceptable(Class hintClass) {
|
||||
return true;
|
||||
}
|
||||
}), false, parameters);
|
||||
for (LookupElement lookupElement : elements) {
|
||||
if (lookupElement.getObject() instanceof PsiMethod) {
|
||||
final JavaMethodCallElement item = lookupElement.as(JavaMethodCallElement.class);
|
||||
assert item != null;
|
||||
final PsiMethod method = (PsiMethod)lookupElement.getObject();
|
||||
if (SmartCompletionDecorator.hasUnboundTypeParams(method)) {
|
||||
item.setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor(method, parameters.getExpectedType()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
private static void addSingleArrayElementAccess(PsiElement element, LookupElement item, JavaSmartCompletionParameters parameters,
|
||||
CompletionResultSet result) {
|
||||
if (item.getObject() instanceof PsiLocalVariable) {
|
||||
@@ -333,7 +381,7 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
private static void addChainedCallVariants(final PsiElement place, final LookupElement qualifierItem,
|
||||
final CompletionResultSet result,
|
||||
PsiType qualifierType,
|
||||
final PsiType expectedType, CompletionParameters parameters) throws IncorrectOperationException {
|
||||
final PsiType expectedType, JavaSmartCompletionParameters parameters) throws IncorrectOperationException {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(place.getProject()).getElementFactory();
|
||||
final String typeText = qualifierType instanceof PsiEllipsisType ? ((PsiEllipsisType)qualifierType).getComponentType().getCanonicalText() + "[]" : qualifierType.getCanonicalText();
|
||||
final JavaCodeFragment block = elementFactory.createCodeBlockCodeFragment(typeText + " xxx;xxx.xxx;", place, false);
|
||||
@@ -345,7 +393,7 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
final PsiReferenceExpression mockRef = (PsiReferenceExpression) expressionStatement.getExpression();
|
||||
|
||||
final ElementFilter filter = getReferenceFilter(place, true);
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(place, mockRef, filter, false, parameters)) {
|
||||
for (final LookupElement item : completeFinalReference(place, mockRef, filter, parameters)) {
|
||||
if (shoudChain(place, qualifierType, expectedType, item)) {
|
||||
result.addElement(JavaChainLookupElement.chainElements(qualifierItem, item));
|
||||
}
|
||||
|
||||
+1
-38
@@ -21,13 +21,11 @@ import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.LookupItem;
|
||||
import com.intellij.codeInsight.lookup.TailTypeDecorator;
|
||||
import com.intellij.codeInsight.lookup.TypedLookupItem;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.filters.FilterUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
@@ -107,42 +105,7 @@ public class SmartCompletionDecorator extends TailTypeDecorator<LookupElement> {
|
||||
|
||||
@Nullable
|
||||
private PsiType getItemType(LookupElement element) {
|
||||
final TypedLookupItem typed = element.as(TypedLookupItem.class);
|
||||
if (typed != null) {
|
||||
return typed.getType();
|
||||
}
|
||||
|
||||
final LookupItem item = element.as(LookupItem.class);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiType attrType = (PsiType)item.getAttribute(LookupItem.TYPE);
|
||||
if (attrType != null) {
|
||||
return attrType;
|
||||
}
|
||||
|
||||
PsiSubstitutor substitutor = (PsiSubstitutor)item.getAttribute(LookupItem.SUBSTITUTOR);
|
||||
if (element.getObject() instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)element.getObject();
|
||||
for (final ExpectedTypeInfo _type : myExpectedTypeInfos) {
|
||||
if (hasUnboundTypeParams(method)) {
|
||||
PsiSubstitutor retSubstitutor = calculateMethodReturnTypeSubstitutor(method, _type.getType());
|
||||
if (substitutor == null) {
|
||||
substitutor = retSubstitutor;
|
||||
} else {
|
||||
substitutor = substitutor.putAll(retSubstitutor);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PsiType byElement = FilterUtil.getTypeByElement((PsiElement)element.getObject(), myPosition);
|
||||
if (substitutor != null) {
|
||||
return substitutor.substitute(byElement);
|
||||
}
|
||||
return byElement;
|
||||
return JavaCompletionUtil.getLookupElementType(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,14 +15,21 @@
|
||||
*/
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.filters.FilterUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class KeywordLookupItem extends LookupItem<PsiKeyword> {
|
||||
public KeywordLookupItem(final PsiKeyword keyword) {
|
||||
public class KeywordLookupItem extends LookupItem<PsiKeyword> implements TypedLookupItem {
|
||||
private final PsiElement myPosition;
|
||||
|
||||
public KeywordLookupItem(final PsiKeyword keyword, @NotNull PsiElement position) {
|
||||
super(keyword, keyword.getText());
|
||||
myPosition = position;
|
||||
setBold();
|
||||
}
|
||||
|
||||
@@ -35,4 +42,8 @@ public class KeywordLookupItem extends LookupItem<PsiKeyword> {
|
||||
public int hashCode() {
|
||||
return getLookupString().hashCode();
|
||||
}
|
||||
|
||||
public PsiType getType() {
|
||||
return FilterUtil.getKeywordItemType(myPosition, getLookupString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.completion.CompletionUtil;
|
||||
import com.intellij.codeInsight.completion.JavaMethodCallElement;
|
||||
import com.intellij.codeInsight.completion.JavaPsiClassReferenceElement;
|
||||
import com.intellij.codeInsight.completion.PrefixMatcher;
|
||||
import com.intellij.codeInsight.completion.JavaMethodCallElement;
|
||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher;
|
||||
import com.intellij.codeInsight.template.Template;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -97,29 +96,29 @@ public class LookupItemUtil{
|
||||
if (object instanceof PsiMethod) {
|
||||
return new JavaMethodCallElement((PsiMethod)object);
|
||||
}
|
||||
if (object instanceof PsiVariable) {
|
||||
return new VariableLookupItem((PsiVariable)object);
|
||||
}
|
||||
if (object instanceof PsiKeyword) {
|
||||
return new KeywordLookupItem((PsiKeyword)object, (PsiKeyword)object);
|
||||
}
|
||||
if (object instanceof PsiExpression) {
|
||||
return new ExpressionLookupItem((PsiExpression) object);
|
||||
}
|
||||
if (object instanceof PsiType) {
|
||||
return PsiTypeLookupItem.createLookupItem((PsiType)object);
|
||||
}
|
||||
|
||||
String s = null;
|
||||
LookupItem item = new LookupItem(object, "");
|
||||
if (object instanceof PsiElement){
|
||||
s = PsiUtilBase.getName((PsiElement) object);
|
||||
}
|
||||
if (object instanceof PsiEnumConstant) {
|
||||
item.addLookupStrings(((PsiEnumConstant)object).getName());
|
||||
}
|
||||
TailType tailType = TailType.NONE;
|
||||
if (object instanceof PsiPackage) {
|
||||
tailType = TailType.DOT;
|
||||
s = StringUtil.notNullize(s);
|
||||
}
|
||||
else if (object instanceof PsiKeyword) {
|
||||
return new KeywordLookupItem((PsiKeyword)object).setTailType(tailType);
|
||||
}
|
||||
else if (object instanceof PsiExpression) {
|
||||
return new ExpressionLookupItem((PsiExpression) object).setTailType(tailType);
|
||||
}
|
||||
else if (object instanceof PsiType) {
|
||||
return PsiTypeLookupItem.createLookupItem((PsiType)object);
|
||||
}
|
||||
else if (object instanceof PsiMetaData) {
|
||||
s = ((PsiMetaData)object).getName();
|
||||
}
|
||||
@@ -133,7 +132,7 @@ public class LookupItemUtil{
|
||||
s = ((PresentableLookupValue)object).getPresentation();
|
||||
}
|
||||
|
||||
if (object instanceof LookupValueWithUIHint && ((LookupValueWithUIHint) object).isBold() || object instanceof PsiKeyword) {
|
||||
if (object instanceof LookupValueWithUIHint && ((LookupValueWithUIHint) object).isBold()) {
|
||||
item.setBold();
|
||||
}
|
||||
|
||||
@@ -145,7 +144,7 @@ public class LookupItemUtil{
|
||||
}
|
||||
item.setLookupString(s);
|
||||
|
||||
item.setAttribute(CompletionUtil.TAIL_TYPE_ATTR, tailType);
|
||||
item.setTailType(tailType);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.intellij.codeInsight.lookup;
|
||||
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiVariable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class VariableLookupItem extends LookupItem<PsiVariable> implements TypedLookupItem {
|
||||
public VariableLookupItem(PsiVariable object) {
|
||||
super(object, object.getName());
|
||||
}
|
||||
|
||||
public PsiType getType() {
|
||||
return getSubstitutor().substitute(getObject().getType());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor getSubstitutor() {
|
||||
final PsiSubstitutor substitutor = (PsiSubstitutor)getAttribute(LookupItem.SUBSTITUTOR);
|
||||
return substitutor == null ? PsiSubstitutor.EMPTY : substitutor;
|
||||
}
|
||||
|
||||
public void setSubstitutor(@NotNull PsiSubstitutor substitutor) {
|
||||
setAttribute(SUBSTITUTOR, substitutor);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,48 +39,53 @@ public class FilterUtil{
|
||||
if(element instanceof PsiClass){
|
||||
return JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createType((PsiClass)element);
|
||||
}
|
||||
else if(element instanceof PsiMethod){
|
||||
if(element instanceof PsiMethod){
|
||||
return ((PsiMethod)element).getReturnType();
|
||||
}
|
||||
else if(element instanceof PsiVariable){
|
||||
if(element instanceof PsiVariable){
|
||||
return ((PsiVariable)element).getType();
|
||||
}
|
||||
else if(element instanceof PsiKeyword){
|
||||
if(PsiKeyword.CLASS.equals(element.getText())){
|
||||
return PsiType.getJavaLangClass(element.getManager(), element.getResolveScope());
|
||||
}
|
||||
else if(PsiKeyword.TRUE.equals(element.getText()) || PsiKeyword.FALSE.equals(element.getText())){
|
||||
return PsiType.BOOLEAN;
|
||||
}
|
||||
else if(PsiKeyword.THIS.equals(element.getText())){
|
||||
PsiElement previousElement = getPreviousElement(context, false);
|
||||
if(previousElement != null && ".".equals(previousElement.getText())){
|
||||
previousElement = getPreviousElement(previousElement, false);
|
||||
assert previousElement != null;
|
||||
|
||||
final String className = previousElement.getText();
|
||||
PsiElement walker = context;
|
||||
while(walker != null){
|
||||
if(walker instanceof PsiClass && !(walker instanceof PsiAnonymousClass)){
|
||||
if(className.equals(((PsiClass)walker).getName()))
|
||||
return getTypeByElement(walker, context);
|
||||
}
|
||||
walker = walker.getContext();
|
||||
}
|
||||
}
|
||||
else{
|
||||
final PsiClass owner = PsiTreeUtil.getContextOfType(context, PsiClass.class, true);
|
||||
return getTypeByElement(owner, context);
|
||||
}
|
||||
}
|
||||
if(element instanceof PsiKeyword){
|
||||
return getKeywordItemType(context, element.getText());
|
||||
}
|
||||
else if(element instanceof PsiExpression){
|
||||
if(element instanceof PsiExpression){
|
||||
return ((PsiExpression)element).getType();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PsiType getKeywordItemType(PsiElement context, final String keyword) {
|
||||
if(PsiKeyword.CLASS.equals(keyword)){
|
||||
return PsiType.getJavaLangClass(context.getManager(), context.getResolveScope());
|
||||
}
|
||||
else if(PsiKeyword.TRUE.equals(keyword) || PsiKeyword.FALSE.equals(keyword)){
|
||||
return PsiType.BOOLEAN;
|
||||
}
|
||||
else if(PsiKeyword.THIS.equals(keyword)){
|
||||
PsiElement previousElement = getPreviousElement(context, false);
|
||||
if(previousElement != null && ".".equals(previousElement.getText())){
|
||||
previousElement = getPreviousElement(previousElement, false);
|
||||
assert previousElement != null;
|
||||
|
||||
final String className = previousElement.getText();
|
||||
PsiElement walker = context;
|
||||
while(walker != null){
|
||||
if(walker instanceof PsiClass && !(walker instanceof PsiAnonymousClass)){
|
||||
if(className.equals(((PsiClass)walker).getName()))
|
||||
return getTypeByElement(walker, context);
|
||||
}
|
||||
walker = walker.getContext();
|
||||
}
|
||||
}
|
||||
else{
|
||||
final PsiClass owner = PsiTreeUtil.getContextOfType(context, PsiClass.class, true);
|
||||
return getTypeByElement(owner, context);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiElement getPreviousElement(final PsiElement element, boolean skipReference){
|
||||
PsiElement prev = element;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.psi.filters.getters;
|
||||
|
||||
import com.intellij.codeInsight.completion.CompletionResultSet;
|
||||
import com.intellij.codeInsight.completion.JavaMethodCallElement;
|
||||
import com.intellij.codeInsight.completion.SmartCompletionDecorator;
|
||||
import com.intellij.codeInsight.completion.JavaCompletionUtil;
|
||||
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
|
||||
@@ -112,7 +113,7 @@ public class MembersGetter {
|
||||
item.setAutoCompletionPolicy(AutoCompletionPolicy.NEVER_AUTOCOMPLETE);
|
||||
JavaCompletionUtil.qualify(item);
|
||||
if (member instanceof PsiMethod) {
|
||||
item.setAttribute(LookupItem.SUBSTITUTOR, SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor((PsiMethod) member, expectedType));
|
||||
((JavaMethodCallElement) item).setInferenceSubstitutor(SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor((PsiMethod) member, expectedType));
|
||||
}
|
||||
results.addElement(item);
|
||||
}
|
||||
|
||||
@@ -71,11 +71,15 @@ public class AssignableFromFilter implements ElementFilter{
|
||||
element = info.getElement();
|
||||
}
|
||||
|
||||
if (element instanceof PsiMethod && isReturnTypeInferrable((PsiMethod)element, context, type, substitutor)) {
|
||||
return isAcceptable((PsiElement)element, context, type, substitutor);
|
||||
}
|
||||
|
||||
public static boolean isAcceptable(PsiElement element, PsiElement context, PsiType expectedType, PsiSubstitutor substitutor) {
|
||||
if (element instanceof PsiMethod && isReturnTypeInferrable((PsiMethod)element, context, expectedType, substitutor)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
PsiType typeByElement = FilterUtil.getTypeByElement((PsiElement)element, context);
|
||||
PsiType typeByElement = FilterUtil.getTypeByElement(element, context);
|
||||
if (typeByElement == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -84,11 +88,11 @@ public class AssignableFromFilter implements ElementFilter{
|
||||
typeByElement = substitutor.substitute(typeByElement);
|
||||
}
|
||||
|
||||
if (!allowBoxing(context) && (type instanceof PsiPrimitiveType != typeByElement instanceof PsiPrimitiveType)) {
|
||||
if (!allowBoxing(context) && (expectedType instanceof PsiPrimitiveType != typeByElement instanceof PsiPrimitiveType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return type.isAssignableFrom(typeByElement);
|
||||
return expectedType.isAssignableFrom(typeByElement);
|
||||
}
|
||||
|
||||
private static boolean allowBoxing(PsiElement place) {
|
||||
@@ -102,7 +106,7 @@ public class AssignableFromFilter implements ElementFilter{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isReturnTypeInferrable(PsiMethod method, PsiElement place, PsiType expectedType, @Nullable PsiSubstitutor substitutor) {
|
||||
private static boolean isReturnTypeInferrable(PsiMethod method, PsiElement place, PsiType expectedType, @Nullable PsiSubstitutor substitutor) {
|
||||
final PsiResolveHelper helper = JavaPsiFacade.getInstance(method.getProject()).getResolveHelper();
|
||||
for (final PsiTypeParameter parameter : method.getTypeParameters()) {
|
||||
PsiType returnType = method.getReturnType();
|
||||
|
||||
Reference in New Issue
Block a user