From 41f136134dfc0650dfda376521abbc6064d94a95 Mon Sep 17 00:00:00 2001 From: peter Date: Wed, 14 Oct 2009 23:40:35 +0100 Subject: [PATCH] =?UTF-8?q?move=20smart=20completion=20assignability=20che?= =?UTF-8?q?cking=20closer=20to=20reference=20processor=20to=20fix=20IDEADE?= =?UTF-8?q?V-40813=20Smart=20completion=20inside=20"=E2=80=8Bif"=20stateme?= =?UTF-8?q?nt=20with=20"=E2=80=8Binstanceof"=20in=20condition=20doesn?= =?UTF-8?q?=E2=80=8B'=E2=80=8Bt=20suggest=20method=20with=20generic=20retu?= =?UTF-8?q?rn=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BasicExpressionCompletionContributor.java | 14 ++-- .../CollectionsUtilityMethodsProvider.java | 24 +++++-- .../ExpressionSmartCompletionContributor.java | 1 - .../completion/JavaCompletionUtil.java | 5 ++ .../completion/JavaMethodCallElement.java | 33 ++++++++- .../JavaSmartCompletionContributor.java | 53 +++------------ .../completion/PreferNonGenericWeigher.java | 7 +- ...erenceExpressionCompletionContributor.java | 66 +++++++++++++++--- .../completion/SmartCompletionDecorator.java | 39 +---------- .../codeInsight/lookup/KeywordLookupItem.java | 15 ++++- .../codeInsight/lookup/LookupItemUtil.java | 31 +++++---- .../lookup/VariableLookupItem.java | 30 +++++++++ .../com/intellij/psi/filters/FilterUtil.java | 67 ++++++++++--------- .../psi/filters/getters/MembersGetter.java | 3 +- .../filters/types/AssignableFromFilter.java | 14 ++-- 15 files changed, 236 insertions(+), 166 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java index cb130012000e..dbe8eb18d240 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/BasicExpressionCompletionContributor.java @@ -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() { - 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 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; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java index 1d323e3f6a6b..e39df303d589 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/CollectionsUtilityMethodsProvider.java @@ -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 { - public static final ExpressionSmartCompletionContributor[] CONTRIBUTORS = {new BasicExpressionCompletionContributor()}; private final List, CompletionProvider>> myList = new ArrayList, CompletionProvider>>(); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java index bf4249e16221..7dba0984fba8 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java @@ -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); diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java index f7675e16705a..e5cc8333f0b4 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaMethodCallElement.java @@ -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 { +public class JavaMethodCallElement extends LookupItem implements TypedLookupItem { + private static final Key INFERENCE_SUBSTITUTOR = Key.create("INFERENCE_SUBSTITUTOR"); public JavaMethodCallElement(PsiMethod method) { super(method, method.getName()); @@ -33,4 +38,28 @@ public class JavaMethodCallElement extends LookupItem { 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; + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java index 0a6d79495ac4..1742e1f3ee54 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaSmartCompletionContributor.java @@ -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 _infos) { - final PsiElement position = params.getPosition(); final Set infos = ApplicationManager.getApplication().runReadAction(new Computable>() { public Set compute() { return new THashSet(_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 consumer = new Consumer() { + final CompletionService service = CompletionService.getCompletionService(); + new BasicExpressionCompletionContributor().fillCompletionVariants(parameters, service.createResultSet(parameters, new Consumer() { 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() { + 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); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java index 8b543a18e9bf..8dd81941bab9 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferNonGenericWeigher.java @@ -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; } 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 3d9486bb3020..067f69687574 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/ReferenceExpressionCompletionContributor.java @@ -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() { public void consume(LookupElement baseItem) { @@ -130,6 +141,43 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom }); } + private static Set completeFinalReference(final PsiElement element, PsiReference reference, ElementFilter filter, + final JavaSmartCompletionParameters parameters) { + final Set 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)); } diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java index 2aedb036da85..9c564df978aa 100644 --- a/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java +++ b/java/java-impl/src/com/intellij/codeInsight/completion/SmartCompletionDecorator.java @@ -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 { @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 diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/KeywordLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/KeywordLookupItem.java index 671c766e3d46..854cf3488fba 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/KeywordLookupItem.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/KeywordLookupItem.java @@ -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 { - public KeywordLookupItem(final PsiKeyword keyword) { +public class KeywordLookupItem extends LookupItem 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 { public int hashCode() { return getLookupString().hashCode(); } + + public PsiType getType() { + return FilterUtil.getKeywordItemType(myPosition, getLookupString()); + } } diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/LookupItemUtil.java b/java/java-impl/src/com/intellij/codeInsight/lookup/LookupItemUtil.java index 5c4f13a48d9a..66fdcca2462f 100644 --- a/java/java-impl/src/com/intellij/codeInsight/lookup/LookupItemUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/LookupItemUtil.java @@ -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; } diff --git a/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java new file mode 100644 index 000000000000..3ba346cd588d --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/lookup/VariableLookupItem.java @@ -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 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); + } + +} diff --git a/java/java-impl/src/com/intellij/psi/filters/FilterUtil.java b/java/java-impl/src/com/intellij/psi/filters/FilterUtil.java index 08b62b69525d..89033fae439f 100644 --- a/java/java-impl/src/com/intellij/psi/filters/FilterUtil.java +++ b/java/java-impl/src/com/intellij/psi/filters/FilterUtil.java @@ -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; diff --git a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java index b8c3ae9c90cc..5606d343ccab 100644 --- a/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java +++ b/java/java-impl/src/com/intellij/psi/filters/getters/MembersGetter.java @@ -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); } diff --git a/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java b/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java index a82c486ab832..1b588598be8e 100644 --- a/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java +++ b/java/java-impl/src/com/intellij/psi/filters/types/AssignableFromFilter.java @@ -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();