mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
TypeConversionUtil#erasurePreservingIntersection; used in DfaPsiType#normalizeType
This commit is contained in:
+2
-8
@@ -17,10 +17,9 @@ package com.intellij.codeInspection.dataFlow.value;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.TypeConstraint;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiCapturedWildcardType;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiWildcardType;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
@@ -78,15 +77,10 @@ public class DfaPsiType {
|
||||
public static PsiType normalizeType(@NotNull PsiType psiType) {
|
||||
int dimensions = psiType.getArrayDimensions();
|
||||
psiType = psiType.getDeepComponentType();
|
||||
if (psiType instanceof PsiCapturedWildcardType) {
|
||||
psiType = ((PsiCapturedWildcardType)psiType).getUpperBound();
|
||||
}
|
||||
if (psiType instanceof PsiWildcardType) {
|
||||
psiType = ((PsiWildcardType)psiType).getExtendsBound();
|
||||
}
|
||||
if (psiType instanceof PsiClassType) {
|
||||
psiType = ((PsiClassType)psiType).rawType();
|
||||
}
|
||||
psiType = TypeConversionUtil.erasurePreservingIntersection(psiType);
|
||||
while (dimensions-- > 0) {
|
||||
psiType = psiType.createArrayType();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TypeConversionUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.TypeConversionUtil");
|
||||
@@ -1191,49 +1192,43 @@ public class TypeConversionUtil {
|
||||
}
|
||||
|
||||
public static PsiType typeParameterErasure(@NotNull PsiTypeParameter typeParameter) {
|
||||
return typeParameterErasure(typeParameter, PsiSubstitutor.EMPTY);
|
||||
return typeParameterErasure(typeParameter, new THashSet<>(), PsiSubstitutor.EMPTY, false);
|
||||
}
|
||||
|
||||
private static PsiType typeParameterErasure(@NotNull PsiTypeParameter typeParameter, @NotNull PsiSubstitutor beforeSubstitutor) {
|
||||
private static PsiType typeParameterErasure(PsiTypeParameter typeParameter,
|
||||
Set<? super PsiClass> visited,
|
||||
PsiSubstitutor beforeSubstitutor, boolean preserveIntersection) {
|
||||
final PsiClassType[] extendsList = typeParameter.getExtendsList().getReferencedTypes();
|
||||
if (extendsList.length > 0) {
|
||||
final PsiClass psiClass = extendsList[0].resolve();
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
Set<PsiClass> visited = new THashSet<>();
|
||||
visited.add(psiClass);
|
||||
final PsiTypeParameter boundTypeParameter = (PsiTypeParameter)psiClass;
|
||||
if (preserveIntersection) {
|
||||
PsiType[] types = Stream.of(extendsList).map(PsiClassType::resolve).filter(Objects::nonNull)
|
||||
.map(psiClass -> getClassErasedType(psiClass, visited, beforeSubstitutor, typeParameter, true))
|
||||
.toArray(PsiType[]::new);
|
||||
return PsiIntersectionType.createIntersection(true, types);
|
||||
}
|
||||
return getClassErasedType(extendsList[0].resolve(), visited, beforeSubstitutor, typeParameter, false);
|
||||
}
|
||||
return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiType getClassErasedType(PsiClass psiClass,
|
||||
Set<? super PsiClass> visited,
|
||||
PsiSubstitutor beforeSubstitutor,
|
||||
PsiElement context, boolean preserveIntersection) {
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
if (visited.add(psiClass)) {
|
||||
PsiTypeParameter boundTypeParameter = (PsiTypeParameter)psiClass;
|
||||
if (beforeSubstitutor.getSubstitutionMap().containsKey(boundTypeParameter)) {
|
||||
return erasure(beforeSubstitutor.substitute(boundTypeParameter));
|
||||
return erasure(Objects.requireNonNull(beforeSubstitutor.substitute(boundTypeParameter)));
|
||||
}
|
||||
return typeParameterErasureInner(boundTypeParameter, visited, beforeSubstitutor);
|
||||
}
|
||||
else if (psiClass != null) {
|
||||
return JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(psiClass);
|
||||
return typeParameterErasure(boundTypeParameter, visited, beforeSubstitutor, preserveIntersection);
|
||||
}
|
||||
}
|
||||
return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
|
||||
}
|
||||
|
||||
private static PsiClassType typeParameterErasureInner(PsiTypeParameter typeParameter,
|
||||
Set<? super PsiClass> visited,
|
||||
PsiSubstitutor beforeSubstitutor) {
|
||||
final PsiClassType[] extendsList = typeParameter.getExtendsList().getReferencedTypes();
|
||||
if (extendsList.length > 0) {
|
||||
final PsiClass psiClass = extendsList[0].resolve();
|
||||
if (psiClass instanceof PsiTypeParameter) {
|
||||
if (!visited.contains(psiClass)) {
|
||||
visited.add(psiClass);
|
||||
if (beforeSubstitutor.getSubstitutionMap().containsKey(psiClass)) {
|
||||
return (PsiClassType)erasure(beforeSubstitutor.substitute((PsiTypeParameter)psiClass));
|
||||
}
|
||||
return typeParameterErasureInner((PsiTypeParameter)psiClass, visited, beforeSubstitutor);
|
||||
}
|
||||
}
|
||||
else if (psiClass != null) {
|
||||
return JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(psiClass);
|
||||
}
|
||||
else if (psiClass != null) {
|
||||
return JavaPsiFacade.getInstance(context.getProject()).getElementFactory().createType(psiClass);
|
||||
}
|
||||
return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
|
||||
return PsiType.getJavaLangObject(context.getManager(), context.getResolveScope());
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@@ -1241,8 +1236,25 @@ public class TypeConversionUtil {
|
||||
return erasure(type, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase type, but preserve intersections
|
||||
*
|
||||
* @param type type to erase
|
||||
* @return erased type (probably a {@link PsiIntersectionType})
|
||||
*/
|
||||
public static PsiType erasurePreservingIntersection(@Nullable PsiType type) {
|
||||
return erasure(type, PsiSubstitutor.EMPTY, true);
|
||||
}
|
||||
|
||||
@Contract("null, _ -> null")
|
||||
public static PsiType erasure(@Nullable final PsiType type, @NotNull final PsiSubstitutor beforeSubstitutor) {
|
||||
return erasure(type, beforeSubstitutor, false);
|
||||
}
|
||||
|
||||
@Contract("null, _, _ -> null")
|
||||
private static PsiType erasure(@Nullable final PsiType type,
|
||||
@NotNull final PsiSubstitutor beforeSubstitutor,
|
||||
boolean preserveIntersection) {
|
||||
if (type == null) return null;
|
||||
return type.accept(new PsiTypeVisitor<PsiType>() {
|
||||
@Nullable
|
||||
@@ -1255,7 +1267,7 @@ public class TypeConversionUtil {
|
||||
public PsiType visitClassType(PsiClassType classType) {
|
||||
final PsiClass aClass = classType.resolve();
|
||||
if (aClass instanceof PsiTypeParameter && !isFreshVariable((PsiTypeParameter)aClass)) {
|
||||
return typeParameterErasure((PsiTypeParameter)aClass, beforeSubstitutor);
|
||||
return typeParameterErasure((PsiTypeParameter)aClass, new THashSet<>(), beforeSubstitutor, preserveIntersection);
|
||||
}
|
||||
return classType.rawType();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ class Main {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
<T> T test() {
|
||||
return (T)new One();
|
||||
}
|
||||
}
|
||||
|
||||
class One { }
|
||||
|
||||
Reference in New Issue
Block a user