IDEA-175517 Generic Map Autocomplete Always uses "Object" as type instead of the actual type

This commit is contained in:
peter
2017-07-07 18:49:25 +02:00
parent c7c2399460
commit 0e351d518b
8 changed files with 85 additions and 91 deletions
@@ -15,10 +15,7 @@
*/
package com.intellij.codeInsight;
import com.intellij.codeInsight.completion.AllClassesGetter;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.completion.PrefixMatcher;
import com.intellij.codeInsight.completion.*;
import com.intellij.lang.Language;
import com.intellij.lang.StdLanguages;
import com.intellij.openapi.diagnostic.Logger;
@@ -340,11 +337,12 @@ public class CodeInsightUtil {
PsiManager manager = context.getManager();
JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
PsiResolveHelper resolveHelper = facade.getResolveHelper();
PsiElementFactory factory = facade.getElementFactory();
return inheritor -> {
ProgressManager.checkCanceled();
if (!facade.getResolveHelper().isAccessible(inheritor, context, null)) {
if (!resolveHelper.isAccessible(inheritor, context, null)) {
return true;
}
@@ -357,57 +355,71 @@ public class CodeInsightUtil {
PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, inheritor, PsiSubstitutor.EMPTY);
if (superSubstitutor == null) return true;
if (getRawSubtypes) {
result.consume(createType(inheritor, facade.getElementFactory().createRawSubstitutor(inheritor), arrayDim));
return true;
}
PsiSubstitutor inheritorSubstitutor = PsiSubstitutor.EMPTY;
for (PsiTypeParameter inheritorParameter : PsiUtil.typeParametersIterable(inheritor)) {
for (PsiTypeParameter baseParameter : PsiUtil.typeParametersIterable(baseClass)) {
final PsiType substituted = superSubstitutor.substitute(baseParameter);
PsiClass inheritorCandidateParameter = PsiUtil.resolveClassInType(substituted);
if (inheritorCandidateParameter instanceof PsiTypeParameter &&
((PsiTypeParameter)inheritorCandidateParameter).getOwner() == inheritor &&
inheritorCandidateParameter != inheritorParameter) {
continue;
}
PsiType arg = baseSubstitutor.substitute(baseParameter);
if (arg instanceof PsiWildcardType) {
PsiType bound = ((PsiWildcardType)arg).getBound();
arg = bound != null ? bound : ((PsiWildcardType)arg).getExtendsBound();
}
PsiType substitution = resolveHelper.getSubstitutionForTypeParameter(inheritorParameter,
substituted,
arg,
true,
PsiUtil.getLanguageLevel(context));
if (PsiType.NULL.equals(substitution) || substitution instanceof PsiWildcardType) continue;
if (substitution == null) {
result.consume(createType(inheritor, facade.getElementFactory().createRawSubstitutor(inheritor), arrayDim));
return true;
}
inheritorSubstitutor = inheritorSubstitutor.put(inheritorParameter, substitution);
break;
}
}
PsiType toAdd = createType(inheritor, inheritorSubstitutor, arrayDim);
List<PsiType> typeArgs = getRawSubtypes ? null : getExpectedTypeArgs(context, inheritor, Arrays.asList(inheritor.getTypeParameters()), baseType);
PsiClassType inheritorType = typeArgs == null || typeArgs.contains(null)
? factory.createType(inheritor, factory.createRawSubstitutor(inheritor))
: factory.createType(inheritor, typeArgs.toArray(PsiType.EMPTY_ARRAY));
PsiType toAdd = addArrayDimensions(arrayDim, inheritorType);
if (baseType.isAssignableFrom(toAdd)) {
result.consume(toAdd);
}
return true;
};
}
private static PsiType createType(PsiClass cls,
PsiSubstitutor currentSubstitutor,
int arrayDim) {
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(cls.getProject()).getElementFactory();
PsiType newType = elementFactory.createType(cls, currentSubstitutor);
private static PsiType addArrayDimensions(int arrayDim, PsiType newType) {
for(int i = 0; i < arrayDim; i++){
newType = newType.createArrayType();
}
return newType;
}
@NotNull
public static List<PsiType> getExpectedTypeArgs(PsiElement context,
PsiTypeParameterListOwner paramOwner,
Iterable<PsiTypeParameter> typeParams, PsiClassType expectedType) {
if (paramOwner instanceof PsiClass) {
PsiClassType.ClassResolveResult resolve = expectedType.resolveGenerics();
PsiClass expectedClass = resolve.getElement();
if (!InheritanceUtil.isInheritorOrSelf((PsiClass)paramOwner, expectedClass, true)) {
return ContainerUtil.map(typeParams, p -> (PsiType)null);
}
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(expectedClass, (PsiClass)paramOwner, PsiSubstitutor.EMPTY);
assert substitutor != null;
return ContainerUtil.map(typeParams, p -> getExpectedTypeArg(context, resolve, substitutor, p));
}
PsiSubstitutor substitutor = SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor((PsiMethod)paramOwner, expectedType);
return ContainerUtil.map(typeParams, substitutor::substitute);
}
@Nullable
private static PsiType getExpectedTypeArg(PsiElement context,
PsiClassType.ClassResolveResult expectedType,
PsiSubstitutor superClassSubstitutor, PsiTypeParameter typeParam) {
PsiClass expectedClass = expectedType.getElement();
assert expectedClass != null;
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) {
PsiType paramSubstitution = superClassSubstitutor.substitute(parameter);
PsiClass inheritorCandidateParameter = PsiUtil.resolveClassInType(paramSubstitution);
if (inheritorCandidateParameter instanceof PsiTypeParameter &&
((PsiTypeParameter)inheritorCandidateParameter).getOwner() == typeParam.getOwner() &&
inheritorCandidateParameter != typeParam) {
continue;
}
PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter);
PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper()
.getSubstitutionForTypeParameter(typeParam, paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context));
if (substitution != null && substitution != PsiType.NULL) {
return substitution;
}
}
return null;
}
}
@@ -15,10 +15,7 @@
*/
package com.intellij.codeInsight.completion;
import com.intellij.codeInsight.CharTailType;
import com.intellij.codeInsight.ExpectedTypeInfo;
import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.TailType;
import com.intellij.codeInsight.*;
import com.intellij.codeInsight.completion.util.ParenthesesInsertHandler;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementPresentation;
@@ -29,7 +26,6 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -87,35 +83,13 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
PsiType type = info.getType();
if (type instanceof PsiClassType && !type.equals(expression.getType())) {
JBIterable<PsiTypeParameter> remainingParams = JBIterable.of(paramOwner.getTypeParameters()).skip(index);
List<PsiType> expectedArgs = getExpectedTypeArgs(context, paramOwner, remainingParams, (PsiClassType)type);
List<PsiType> expectedArgs = CodeInsightUtil.getExpectedTypeArgs(context, paramOwner, remainingParams, (PsiClassType)type);
createLookupItems(result, context, info, expectedArgs, paramOwner);
}
}
return true;
}
@NotNull
private static List<PsiType> getExpectedTypeArgs(PsiElement context,
PsiTypeParameterListOwner paramOwner,
JBIterable<PsiTypeParameter> typeParams, PsiClassType expectedType) {
if (paramOwner instanceof PsiClass) {
PsiClassType.ClassResolveResult resolve = expectedType.resolveGenerics();
final PsiClass expectedClass = resolve.getElement();
if (!InheritanceUtil.isInheritorOrSelf((PsiClass)paramOwner, expectedClass, true)) {
return typeParams.map(p -> (PsiType)null).toList();
}
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(expectedClass, (PsiClass)paramOwner, PsiSubstitutor.EMPTY);
assert substitutor != null;
return typeParams.map(p -> getExpectedTypeArg(context, resolve, substitutor, p)).toList();
}
PsiSubstitutor substitutor = SmartCompletionDecorator.calculateMethodReturnTypeSubstitutor((PsiMethod)paramOwner, expectedType);
return typeParams.map(substitutor::substitute).toList();
}
private void createLookupItems(Consumer<LookupElement> result,
PsiElement context,
ExpectedTypeInfo info,
@@ -146,24 +120,6 @@ class TypeArgumentCompletionProvider extends CompletionProvider<CompletionParame
return paramOwner instanceof PsiClass && ConstructorInsertHandler.hasConstructorParameters((PsiClass)paramOwner, context);
}
@Nullable
private static PsiType getExpectedTypeArg(PsiElement context,
PsiClassType.ClassResolveResult expectedType,
PsiSubstitutor currentSubstitutor, PsiTypeParameter typeParam) {
PsiClass expectedClass = expectedType.getElement();
assert expectedClass != null;
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(expectedClass)) {
final PsiType argSubstitution = expectedType.getSubstitutor().substitute(parameter);
final PsiType paramSubstitution = currentSubstitutor.substitute(parameter);
final PsiType substitution = JavaPsiFacade.getInstance(context.getProject()).getResolveHelper()
.getSubstitutionForTypeParameter(typeParam, paramSubstitution, argSubstitution, false, PsiUtil.getLanguageLevel(context));
if (substitution != null && substitution != PsiType.NULL) {
return substitution;
}
}
return null;
}
private static void addInheritors(CompletionParameters parameters,
Consumer<LookupElement> resultSet,
PsiClass referencedClass,