mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Java] IDEA-375132 refactoring: move type parameters substitution to the PsiUtil to make API more consistent
GitOrigin-RevId: 85463e3c3093aec168fb1871de3dd306dc270351
This commit is contained in:
committed by
intellij-monorepo-bot
parent
233f2c8bd5
commit
877c7ad663
-53
@@ -6,7 +6,6 @@ import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -321,58 +320,6 @@ public final class JavaGenericsUtil {
|
||||
return getCollectionItemType(expression.getType(), expression.getResolveScope());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Substitutes all values for type parameters of the {@code baseType} from the {@code derivedType}.
|
||||
*
|
||||
* @return null if the calculation wasn't successful, list of substituted types otherwise.
|
||||
*
|
||||
* @see JavaGenericsUtil#getCollectionItemType(PsiExpression)
|
||||
*/
|
||||
public static @Nullable List<@NotNull PsiType> getParentParameterTypeListFromDerivedType(@Nullable PsiType baseType, @Nullable PsiType derivedType) {
|
||||
if (derivedType instanceof PsiClassType) {
|
||||
PsiClass baseClass = PsiTypesUtil.getPsiClass(baseType);
|
||||
if (baseClass == null) return null;
|
||||
final PsiClassType.ClassResolveResult resolveResult = getDerivedClassTypeResolveResult((PsiClassType)derivedType);
|
||||
PsiClass derivedClass = resolveResult.getElement();
|
||||
if (derivedClass == null) return null;
|
||||
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
PsiTypeParameter[] parameters = baseClass.getTypeParameters();
|
||||
PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getClassSubstitutor(baseClass, derivedClass, substitutor);
|
||||
if (superClassSubstitutor == null) return null;
|
||||
return ContainerUtil.map(
|
||||
parameters, typeParameter -> {
|
||||
PsiType substitutedType = superClassSubstitutor.substitute(typeParameter);
|
||||
return substitutedType == null ? PsiType.getJavaLangObject(derivedClass.getManager(), derivedClass.getResolveScope()) : substitutedType;
|
||||
}
|
||||
);
|
||||
} else if (derivedType instanceof PsiIntersectionType) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)derivedType).getConjuncts()) {
|
||||
List<@NotNull PsiType> candidates = getParentParameterTypeListFromDerivedType(baseType, conjunct);
|
||||
if (candidates != null) return candidates;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the resolve result corresponding to the given {@code derivedType}. If the initial resolved
|
||||
* result is a type parameter with an upper bound, then the upper bound is returned, otherwise the initial resolve result.
|
||||
*/
|
||||
private static @NotNull PsiClassType.ClassResolveResult getDerivedClassTypeResolveResult(PsiClassType derivedType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = derivedType.resolveGenerics();
|
||||
PsiClass derivedClass = resolveResult.getElement();
|
||||
if (derivedClass instanceof PsiTypeParameter) {
|
||||
PsiTypeParameter typeParameter = (PsiTypeParameter)derivedClass;
|
||||
PsiClassType[] types = typeParameter.getExtendsListTypes();
|
||||
if (types.length > 1) return PsiClassType.ClassResolveResult.EMPTY;
|
||||
else if (types.length == 1) {
|
||||
return types[0].resolveGenerics();
|
||||
}
|
||||
}
|
||||
return resolveResult;
|
||||
}
|
||||
|
||||
public static @Nullable PsiType getCollectionItemType(@Nullable PsiType type, @NotNull GlobalSearchScope scope) {
|
||||
if (type instanceof PsiArrayType) {
|
||||
return ((PsiArrayType)type).getComponentType();
|
||||
|
||||
@@ -1207,6 +1207,49 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
return type != null ? type : substituteTypeParameter(psiType, CommonClassNames.JAVA_UTIL_COLLECTION, 0, eraseTypeParameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes all values for type parameters of the {@code superClass} from the {@code derivedType}.
|
||||
*
|
||||
* @return null if the calculation wasn't successful, list of substituted types otherwise.
|
||||
*/
|
||||
@Contract("null, _, _-> null")
|
||||
public static @Nullable List<@NotNull PsiType> substituteTypeParameters(@Nullable PsiType derivedType, @NotNull PsiClass superClass, boolean eraseTypeParameter) {
|
||||
if (derivedType == null) return null;
|
||||
PsiClassType.ClassResolveResult resolveResult = getDerivedClassTypeResolveResult(derivedType);
|
||||
if (resolveResult == null) return null;
|
||||
PsiClass derivedClass = resolveResult.getElement();
|
||||
if (derivedClass == null) return null;
|
||||
PsiSubstitutor substitutor = resolveResult.getSubstitutor();
|
||||
PsiTypeParameter[] parameters = superClass.getTypeParameters();
|
||||
PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getClassSubstitutor(superClass, derivedClass, substitutor);
|
||||
List<@NotNull PsiType> typeParameterList = ContainerUtil.mapNotNull(
|
||||
parameters, typeParameter -> {
|
||||
return substituteType(typeParameter, superClassSubstitutor, eraseTypeParameter);
|
||||
}
|
||||
);
|
||||
if (typeParameterList.size() != parameters.length) return null;
|
||||
return typeParameterList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the resolve result corresponding to the given {@code derivedType}. If the initial resolved
|
||||
* result is a type parameter with an upper bound, then the upper bound is returned, otherwise the initial resolve result.
|
||||
*/
|
||||
private static @Nullable PsiClassType.ClassResolveResult getDerivedClassTypeResolveResult(@Nullable PsiType derivedType) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = resolveClass(derivedType);
|
||||
if (resolveResult == PsiClassType.ClassResolveResult.EMPTY) return null;
|
||||
PsiClass derivedClass = resolveResult.getElement();
|
||||
if (derivedClass instanceof PsiTypeParameter) {
|
||||
PsiTypeParameter typeParameter = (PsiTypeParameter)derivedClass;
|
||||
PsiClassType[] types = typeParameter.getExtendsListTypes();
|
||||
if (types.length > 1) return PsiClassType.ClassResolveResult.EMPTY;
|
||||
else if (types.length == 1) {
|
||||
return types[0].resolveGenerics();
|
||||
}
|
||||
}
|
||||
return resolveResult;
|
||||
}
|
||||
|
||||
@Contract("null, _, _, _ -> null")
|
||||
public static @Nullable PsiType substituteTypeParameter(@Nullable PsiType psiType, @NotNull String superClass, int typeParamIndex, boolean eraseTypeParameter) {
|
||||
PsiClassType.ClassResolveResult classResolveResult = resolveClass(psiType);
|
||||
@@ -1242,9 +1285,16 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
if (parameters.length <= typeParamIndex) return PsiType.getJavaLangObject(psiClass.getManager(), psiClass.getResolveScope());
|
||||
|
||||
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, psiClass, classResolveResult.getSubstitutor());
|
||||
PsiType type = substitutor.substitute(parameters[typeParamIndex]);
|
||||
return substituteType(parameters[typeParamIndex], substitutor, eraseTypeParameter);
|
||||
}
|
||||
|
||||
private static @Nullable PsiType substituteType(@NotNull PsiTypeParameter typeParameter,
|
||||
@Nullable PsiSubstitutor substitutor,
|
||||
boolean eraseTypeParameter) {
|
||||
if (substitutor == null) return null;
|
||||
PsiType type = substitutor.substitute(typeParameter);
|
||||
if (type == null && eraseTypeParameter) {
|
||||
return TypeConversionUtil.typeParameterErasure(parameters[typeParamIndex]);
|
||||
return TypeConversionUtil.typeParameterErasure(typeParameter);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
package com.intellij.util;
|
||||
|
||||
import com.intellij.codeInsight.*;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -166,8 +167,10 @@ public final class JavaTypeNullabilityUtil {
|
||||
private static @NotNull NullabilityConflict getNullabilityConflictInTypeArguments(@NotNull PsiType leftType,
|
||||
@NotNull PsiType rightType,
|
||||
boolean checkNotNullToNull) {
|
||||
List<PsiType> leftParameterTypeList = JavaGenericsUtil.getParentParameterTypeListFromDerivedType(leftType, leftType);
|
||||
List<PsiType> rightParameterTypeList = JavaGenericsUtil.getParentParameterTypeListFromDerivedType(leftType, rightType);
|
||||
PsiClass leftClass = PsiTypesUtil.getPsiClass(leftType);
|
||||
if (leftClass == null) return NullabilityConflict.UNKNOWN;
|
||||
List<PsiType> leftParameterTypeList = getParentParameterTypeListFromDerivedType(leftType, leftClass);
|
||||
List<PsiType> rightParameterTypeList = getParentParameterTypeListFromDerivedType(rightType, leftClass);
|
||||
if (leftParameterTypeList == null ||
|
||||
rightParameterTypeList == null ||
|
||||
leftParameterTypeList.size() != rightParameterTypeList.size()) {
|
||||
@@ -190,6 +193,18 @@ public final class JavaTypeNullabilityUtil {
|
||||
return NullabilityConflict.UNKNOWN;
|
||||
}
|
||||
|
||||
private static @Nullable List<@NotNull PsiType> getParentParameterTypeListFromDerivedType(@NotNull PsiType derivedType,
|
||||
@NotNull PsiClass superClass) {
|
||||
if (derivedType instanceof PsiIntersectionType) {
|
||||
for (PsiType conjunct : ((PsiIntersectionType)derivedType).getConjuncts()) {
|
||||
List<@NotNull PsiType> candidates = getParentParameterTypeListFromDerivedType(conjunct, superClass);
|
||||
if (candidates != null) return candidates;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return PsiUtil.substituteTypeParameters(derivedType, superClass, true);
|
||||
}
|
||||
|
||||
private static boolean isAllowedNullabilityConflictType(boolean checkNotNullToNull, @NotNull NullabilityConflict nullabilityConflict) {
|
||||
return nullabilityConflict != NullabilityConflict.UNKNOWN &&
|
||||
(checkNotNullToNull || nullabilityConflict != NullabilityConflict.NOT_NULL_TO_NULL);
|
||||
|
||||
Reference in New Issue
Block a user