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:
peter
2009-10-14 23:43:34 +01:00
parent 2d561686f4
commit 41f136134d
15 changed files with 236 additions and 166 deletions
@@ -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;
}
}
@@ -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();
@@ -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;
}
}
@@ -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;
}
@@ -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));
}
@@ -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();