local variables and recursion checks are more important for relevance than expected types in basic completion

This commit is contained in:
Peter Gromov
2009-09-17 21:03:01 +04:00
parent 17ddda9d15
commit 4b53ed7039
6 changed files with 115 additions and 84 deletions
@@ -15,9 +15,9 @@ import com.intellij.psi.util.TypeConversionUtil;
/**
* @author peter
*/
public class SkipAbstractExpectedTypeWeigher extends CompletionPreselectSkipper {
public class AbstractExpectedTypeSkipper extends CompletionPreselectSkipper {
enum Result {
private enum Result {
NON_DEFAULT,
STRING,
ABSTRACT,
@@ -26,10 +26,14 @@ public class SkipAbstractExpectedTypeWeigher extends CompletionPreselectSkipper
@Override
public boolean skipElement(LookupElement element, CompletionLocation location) {
return skips(element, location);
}
public static boolean skips(LookupElement element, CompletionLocation location) {
return getSkippingStatus(element, location) != Result.ACCEPT;
}
public static Result getSkippingStatus(final LookupElement item, final CompletionLocation location) {
private static Result getSkippingStatus(final LookupElement item, final CompletionLocation location) {
if (location.getCompletionType() != CompletionType.SMART) return Result.ACCEPT;
final PsiExpression expression = PsiTreeUtil.getParentOfType(location.getCompletionParameters().getPosition(), PsiExpression.class);
@@ -680,7 +680,7 @@ public class JavaCompletionUtil {
}
@Nullable
public static PsiType getPsiType(final Object o) {
private static PsiType getPsiType(final Object o) {
if (o instanceof PsiVariable) {
return ((PsiVariable)o).getType();
}
@@ -768,28 +768,18 @@ public class JavaCompletionUtil {
@Nullable
public static PsiType getLookupElementType(final LookupElement element) {
PsiType qualifierType = null;
final TypedLookupItem typed = element.as(TypedLookupItem.class);
if (typed != null) {
return typed.getType();
}
final Object o = element.getObject();
if (o instanceof PsiVariable) {
qualifierType = ((PsiVariable)o).getType();
}
else if (o instanceof PsiMethod) {
qualifierType = ((PsiMethod)o).getReturnType();
}
else if (o instanceof PsiExpression) {
qualifierType = ((PsiExpression) o).getType();
}
final PsiType qualifierType = getPsiType(element.getObject());
final LookupItem lookupItem = element.as(LookupItem.class);
if (lookupItem != null) {
final PsiSubstitutor substitutor = (PsiSubstitutor)lookupItem.getAttribute(LookupItem.SUBSTITUTOR);
if (substitutor != null) {
qualifierType = substitutor.substitute(qualifierType);
return substitutor.substitute(qualifierType);
}
}
return qualifierType;
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved.
* Use is subject to license terms.
*/
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.NullableLazyKey;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.NullableFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public class PreferDefaultTypeWeigher extends CompletionWeigher {
private static final NullableLazyKey<PsiTypeParameter, CompletionLocation> TYPE_PARAMETER = NullableLazyKey.create("expectedTypes", new NullableFunction<CompletionLocation, PsiTypeParameter>() {
@Nullable
public PsiTypeParameter fun(final CompletionLocation location) {
final Pair<PsiClass,Integer> pair =
JavaSmartCompletionContributor.getTypeParameterInfo(location.getCompletionParameters().getPosition());
if (pair == null) return null;
return pair.first.getTypeParameters()[pair.second.intValue()];
}
});
private enum MyResult {
normal,
exactlyExpected,
ofDefaultType,
exactlyDefault,
expectedNoSelect
}
public MyResult weigh(@NotNull final LookupElement item, final CompletionLocation location) {
final Object object = item.getObject();
if (location.getCompletionType() != CompletionType.SMART) return MyResult.normal;
if (object instanceof PsiClass) {
final PsiTypeParameter parameter = TYPE_PARAMETER.getValue(location);
if (parameter != null && object.equals(PsiUtil.resolveClassInType(TypeConversionUtil.typeParameterErasure(parameter)))) {
return MyResult.exactlyExpected;
}
}
ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location);
if (expectedInfos == null) return MyResult.normal;
PsiType itemType = JavaCompletionUtil.getLookupElementType(item);
if (itemType == null || !itemType.isValid()) return MyResult.normal;
if (object instanceof PsiClass) {
for (final ExpectedTypeInfo info : expectedInfos) {
if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()).equals(TypeConversionUtil.erasure(itemType))) {
return AbstractExpectedTypeSkipper.skips(item, location) ? MyResult.expectedNoSelect : MyResult.exactlyExpected;
}
}
}
for (final ExpectedTypeInfo expectedInfo : expectedInfos) {
final PsiType defaultType = expectedInfo.getDefaultType();
final PsiType expectedType = expectedInfo.getType();
if (!expectedType.isValid()) {
return MyResult.normal;
}
if (defaultType != expectedType) {
if (defaultType.equals(itemType)) {
return MyResult.exactlyDefault;
}
if (defaultType.isAssignableFrom(itemType)) {
return MyResult.ofDefaultType;
}
}
if (PsiType.VOID.equals(itemType) && PsiType.VOID.equals(expectedType)) {
return MyResult.exactlyExpected;
}
}
return MyResult.normal;
}
}
@@ -6,75 +6,31 @@ package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupItem;
import com.intellij.openapi.util.NullableLazyKey;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeParameter;
import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.NullableFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author peter
*/
public class PreferExpectedTypeWeigher extends CompletionWeigher {
private static final NullableLazyKey<PsiTypeParameter, CompletionLocation> TYPE_PARAMETER = NullableLazyKey.create("expectedTypes", new NullableFunction<CompletionLocation, PsiTypeParameter>() {
@Nullable
public PsiTypeParameter fun(final CompletionLocation location) {
final Pair<PsiClass,Integer> pair =
JavaSmartCompletionContributor.getTypeParameterInfo(location.getCompletionParameters().getPosition());
if (pair == null) return null;
return pair.first.getTypeParameters()[pair.second.intValue()];
}
});
private enum MyResult {
normal,
expected,
exactlyExpected,
ofDefaultType,
exactlyDefault,
expectedNoSelect
}
public MyResult weigh(@NotNull final LookupElement item, final CompletionLocation location) {
final Object object = item.getObject();
if (object instanceof PsiClass && location.getCompletionType() != CompletionType.SMART) return MyResult.normal;
if (object instanceof PsiClass) {
final PsiTypeParameter parameter = TYPE_PARAMETER.getValue(location);
if (parameter != null && object.equals(PsiUtil.resolveClassInType(TypeConversionUtil.typeParameterErasure(parameter)))) {
return MyResult.expected;
}
}
if (location.getCompletionType() != CompletionType.BASIC) return MyResult.normal;
if (item.getObject() instanceof PsiClass) return MyResult.normal;
ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location);
if (expectedInfos == null) return MyResult.normal;
PsiType itemType = JavaCompletionUtil.getPsiType(object);
PsiType itemType = JavaCompletionUtil.getLookupElementType(item);
if (itemType == null || !itemType.isValid()) return MyResult.normal;
final LookupItem lookupItem = item.as(LookupItem.class);
if (lookupItem != null) {
final PsiSubstitutor substitutor = (PsiSubstitutor)lookupItem.getAttribute(LookupItem.SUBSTITUTOR);
if (substitutor != null) {
itemType = substitutor.substitute(itemType);
}
}
if (object instanceof PsiClass) {
for (final ExpectedTypeInfo info : expectedInfos) {
if (TypeConversionUtil.erasure(info.getType().getDeepComponentType()).equals(TypeConversionUtil.erasure(itemType))) {
return SkipAbstractExpectedTypeWeigher.getSkippingStatus(item, location) != SkipAbstractExpectedTypeWeigher.Result.ACCEPT ? MyResult.expectedNoSelect : MyResult.expected;
}
}
}
for (final ExpectedTypeInfo expectedInfo : expectedInfos) {
final PsiType defaultType = expectedInfo.getDefaultType();
final PsiType expectedType = expectedInfo.getType();
@@ -82,23 +38,11 @@ public class PreferExpectedTypeWeigher extends CompletionWeigher {
return MyResult.normal;
}
if (defaultType != expectedType) {
if (defaultType.equals(itemType)) {
return MyResult.exactlyDefault;
}
if (defaultType.isAssignableFrom(itemType)) {
return MyResult.ofDefaultType;
}
if (defaultType != expectedType && defaultType.isAssignableFrom(itemType)) {
return MyResult.ofDefaultType;
}
if ((location.getCompletionType() == CompletionType.BASIC || PsiType.VOID.equals(expectedType))) {
if (expectedType.equals(itemType)) {
return MyResult.exactlyExpected;
}
if (expectedType.isAssignableFrom(itemType)) {
return MyResult.expected;
}
if (expectedType.isAssignableFrom(itemType)) {
return MyResult.expected;
}
}
@@ -54,7 +54,7 @@ public class RecursionWeigher extends CompletionWeigher {
if (expression != null) {
final ExpectedTypeInfo[] expectedInfos = JavaCompletionUtil.EXPECTED_TYPES.getValue(location);
if (expectedInfos != null) {
final PsiType itemType = JavaCompletionUtil.getPsiType(object);
final PsiType itemType = JavaCompletionUtil.getLookupElementType(element);
if (itemType != null) {
for (final ExpectedTypeInfo expectedInfo : expectedInfos) {
if (positionMethod.equals(expectedInfo.getCalledMethod()) && expectedInfo.getType().isAssignableFrom(itemType)) {