Implement JavaTypeSubstitutor without PSI
This commit is contained in:
committed by
Alexander Udalov
parent
97b7768890
commit
0355b1bd53
+27
-4
@@ -16,10 +16,8 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiCompiledElement;
|
||||
import com.intellij.psi.PsiTypeParameter;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiSubstitutorImpl;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -30,7 +28,9 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.*;
|
||||
|
||||
@@ -181,4 +181,27 @@ public class JavaClassImpl extends JavaClassifierImpl<PsiClass> implements JavaC
|
||||
return OriginKind.SOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaType createImmediateType(@NotNull JavaTypeSubstitutor substitutor) {
|
||||
return new JavaClassifierTypeImpl(
|
||||
JavaPsiFacade.getElementFactory(getPsi().getProject()).createType(getPsi(), createPsiSubstitutor(substitutor)));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static PsiSubstitutor createPsiSubstitutor(@NotNull JavaTypeSubstitutor substitutor) {
|
||||
Map<PsiTypeParameter, PsiType> substMap = new HashMap<PsiTypeParameter, PsiType>();
|
||||
for (Map.Entry<JavaTypeParameter, JavaType> entry : substitutor.getSubstitutionMap().entrySet()) {
|
||||
PsiTypeParameter key = ((JavaTypeParameterImpl) entry.getKey()).getPsi();
|
||||
if (entry.getValue() == null) {
|
||||
substMap.put(key, null);
|
||||
}
|
||||
else {
|
||||
substMap.put(key, ((JavaTypeImpl) entry.getValue()).getPsi());
|
||||
}
|
||||
}
|
||||
|
||||
return PsiSubstitutorImpl.createSubstitutor(substMap);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-12
@@ -16,20 +16,12 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifier;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaClassifierType;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeSubstitutor;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.types;
|
||||
|
||||
@@ -68,13 +60,25 @@ public class JavaClassifierTypeImpl extends JavaTypeImpl<PsiClassType> implement
|
||||
if (resolutionResult == null) {
|
||||
PsiClassType.ClassResolveResult result = getPsi().resolveGenerics();
|
||||
PsiClass psiClass = result.getElement();
|
||||
PsiSubstitutor substitutor = result.getSubstitutor();
|
||||
resolutionResult = new ResolutionResult(
|
||||
psiClass == null ? null : JavaClassifierImpl.create(psiClass),
|
||||
new JavaTypeSubstitutorImpl(result.getSubstitutor())
|
||||
new JavaTypeSubstitutorImpl(convertSubstitutionMap(substitutor.getSubstitutionMap()))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Map<JavaTypeParameter, JavaType> convertSubstitutionMap(@NotNull Map<PsiTypeParameter, PsiType> psiMap) {
|
||||
Map<JavaTypeParameter, JavaType> substitutionMap = new HashMap<JavaTypeParameter, JavaType>();
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : psiMap.entrySet()) {
|
||||
PsiType value = entry.getValue();
|
||||
substitutionMap.put(new JavaTypeParameterImpl(entry.getKey()), value == null ? null : JavaTypeImpl.create(value));
|
||||
}
|
||||
|
||||
return substitutionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Collection<JavaClassifierType> getSupertypes() {
|
||||
|
||||
+5
-5
@@ -39,31 +39,31 @@ public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType {
|
||||
return psiType.accept(new PsiTypeVisitor<JavaTypeImpl<?>>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaTypeImpl<?> visitType(PsiType type) {
|
||||
public JavaTypeImpl<?> visitType(@NotNull PsiType type) {
|
||||
throw new UnsupportedOperationException("Unsupported PsiType: " + type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaTypeImpl<?> visitPrimitiveType(PsiPrimitiveType primitiveType) {
|
||||
public JavaTypeImpl<?> visitPrimitiveType(@NotNull PsiPrimitiveType primitiveType) {
|
||||
return new JavaPrimitiveTypeImpl(primitiveType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaTypeImpl<?> visitArrayType(PsiArrayType arrayType) {
|
||||
public JavaTypeImpl<?> visitArrayType(@NotNull PsiArrayType arrayType) {
|
||||
return new JavaArrayTypeImpl(arrayType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaTypeImpl<?> visitClassType(PsiClassType classType) {
|
||||
public JavaTypeImpl<?> visitClassType(@NotNull PsiClassType classType) {
|
||||
return new JavaClassifierTypeImpl(classType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JavaTypeImpl<?> visitWildcardType(PsiWildcardType wildcardType) {
|
||||
public JavaTypeImpl<?> visitWildcardType(@NotNull PsiWildcardType wildcardType) {
|
||||
return new JavaWildcardTypeImpl(wildcardType);
|
||||
}
|
||||
});
|
||||
|
||||
+20
@@ -18,10 +18,12 @@ package org.jetbrains.jet.lang.resolve.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiWildcardType;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeProvider;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaWildcardType;
|
||||
|
||||
public class JavaTypeProviderImpl implements JavaTypeProvider {
|
||||
private final PsiManager manager;
|
||||
@@ -35,4 +37,22 @@ public class JavaTypeProviderImpl implements JavaTypeProvider {
|
||||
public JavaType createJavaLangObjectType() {
|
||||
return JavaTypeImpl.create(PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject())));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaWildcardType createUpperBoundWildcard(@NotNull JavaType bound) {
|
||||
return new JavaWildcardTypeImpl(PsiWildcardType.createExtends(manager, ((JavaTypeImpl) bound).getPsi()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaWildcardType createLowerBoundWildcard(@NotNull JavaType bound) {
|
||||
return new JavaWildcardTypeImpl(PsiWildcardType.createSuper(manager, ((JavaTypeImpl) bound).getPsi()));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JavaWildcardType createUnboundedWildcard() {
|
||||
return new JavaWildcardTypeImpl(PsiWildcardType.createUnbounded(manager));
|
||||
}
|
||||
}
|
||||
|
||||
+128
-41
@@ -16,83 +16,170 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.java.structure.impl;
|
||||
|
||||
import com.intellij.psi.PsiSubstitutor;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.PsiTypeParameter;
|
||||
import com.intellij.psi.impl.PsiSubstitutorImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaType;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeParameter;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaTypeSubstitutor;
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class JavaTypeSubstitutorImpl implements JavaTypeSubstitutor {
|
||||
private final PsiSubstitutor psiSubstitutor;
|
||||
private Map<JavaTypeParameter, JavaType> substitutionMap;
|
||||
private final Map<JavaTypeParameter, JavaType> substitutionMap;
|
||||
|
||||
public JavaTypeSubstitutorImpl(@NotNull PsiSubstitutor psiSubstitutor) {
|
||||
this.psiSubstitutor = psiSubstitutor;
|
||||
}
|
||||
|
||||
public JavaTypeSubstitutorImpl(@NotNull PsiSubstitutor psiSubstitutor, @NotNull Map<JavaTypeParameter, JavaType> substitutionMap) {
|
||||
this(psiSubstitutor);
|
||||
public JavaTypeSubstitutorImpl(@NotNull Map<JavaTypeParameter, JavaType> substitutionMap) {
|
||||
this.substitutionMap = substitutionMap;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JavaTypeSubstitutor create(@NotNull Map<JavaTypeParameter, JavaType> substitutionMap) {
|
||||
Map<PsiTypeParameter, PsiType> psiMap = new HashMap<PsiTypeParameter, PsiType>();
|
||||
for (Map.Entry<JavaTypeParameter, JavaType> entry : substitutionMap.entrySet()) {
|
||||
JavaTypeImpl value = ((JavaTypeImpl) entry.getValue());
|
||||
psiMap.put(((JavaTypeParameterImpl) entry.getKey()).getPsi(), value == null ? null : value.getPsi());
|
||||
}
|
||||
PsiSubstitutor psiSubstitutor = PsiSubstitutorImpl.createSubstitutor(psiMap);
|
||||
return new JavaTypeSubstitutorImpl(psiSubstitutor, substitutionMap);
|
||||
@Override
|
||||
public JavaType substitute(@NotNull JavaType type) {
|
||||
JavaType substitutedType = substituteInternal(type);
|
||||
return substitutedType != null ? substitutedType : correctSubstitutionForRawType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public JavaType substitute(@NotNull JavaType type) {
|
||||
return JavaTypeImpl.create(psiSubstitutor.substitute(((JavaTypeImpl) type).getPsi()));
|
||||
// In case of raw type we get substition map like T -> null,
|
||||
// in this case we should substitute upper bound of T or,
|
||||
// if it does not exist, return java.lang.Object
|
||||
private JavaType correctSubstitutionForRawType(@NotNull JavaType original) {
|
||||
if (original instanceof JavaClassifierType) {
|
||||
JavaClassifier classifier = ((JavaClassifierType) original).getClassifier();
|
||||
if (classifier instanceof JavaTypeParameter) {
|
||||
return rawTypeForTypeParameter((JavaTypeParameter) classifier);
|
||||
}
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JavaType substituteInternal(@NotNull JavaType type) {
|
||||
if (type instanceof JavaClassifierType) {
|
||||
JavaClassifierType classifierType = (JavaClassifierType) type;
|
||||
JavaClassifier classifier = classifierType.getClassifier();
|
||||
|
||||
if (classifier instanceof JavaTypeParameter) {
|
||||
return substitute((JavaTypeParameter) classifier);
|
||||
}
|
||||
else if (classifier instanceof JavaClass) {
|
||||
JavaClass javaClass = (JavaClass) classifier;
|
||||
Map<JavaTypeParameter, JavaType> substMap = new HashMap<JavaTypeParameter, JavaType>();
|
||||
processClass(javaClass, classifierType.getSubstitutor(), substMap);
|
||||
|
||||
return javaClass.createImmediateType(new JavaTypeSubstitutorImpl(substMap));
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
else if (type instanceof JavaPrimitiveType) {
|
||||
return type;
|
||||
}
|
||||
else if (type instanceof JavaArrayType) {
|
||||
JavaType componentType = ((JavaArrayType) type).getComponentType();
|
||||
JavaType substitutedComponentType = substitute(componentType);
|
||||
if (substitutedComponentType == componentType) return type;
|
||||
|
||||
return substitutedComponentType.createArrayType();
|
||||
}
|
||||
else if (type instanceof JavaWildcardType) {
|
||||
return substituteWildcardType((JavaWildcardType) type);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
private void processClass(@NotNull JavaClass javaClass, @NotNull JavaTypeSubstitutor substitutor, @NotNull Map<JavaTypeParameter, JavaType> substMap) {
|
||||
List<JavaTypeParameter> typeParameters = javaClass.getTypeParameters();
|
||||
for (JavaTypeParameter typeParameter : typeParameters) {
|
||||
JavaType substitutedParam = substitutor.substitute(typeParameter);
|
||||
if (substitutedParam == null) {
|
||||
substMap.put(typeParameter, null);
|
||||
}
|
||||
else {
|
||||
substMap.put(typeParameter, substituteInternal(substitutedParam));
|
||||
}
|
||||
}
|
||||
|
||||
if (javaClass.isStatic()) {
|
||||
return;
|
||||
}
|
||||
|
||||
JavaClass outerClass = javaClass.getOuterClass();
|
||||
if (outerClass != null) {
|
||||
processClass(outerClass, substitutor, substMap);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private JavaType substituteWildcardType(@NotNull JavaWildcardType wildcardType) {
|
||||
JavaType bound = wildcardType.getBound();
|
||||
if (bound == null) {
|
||||
return wildcardType;
|
||||
}
|
||||
|
||||
JavaType newBound = substituteInternal(bound);
|
||||
if (newBound == null) {
|
||||
// This can be in case of substitution wildcard to raw type
|
||||
return null;
|
||||
}
|
||||
|
||||
return rebound(wildcardType, newBound);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JavaWildcardType rebound(@NotNull JavaWildcardType type, @NotNull JavaType newBound) {
|
||||
if (type.getTypeProvider().createJavaLangObjectType().equals(newBound)) {
|
||||
return type.getTypeProvider().createUnboundedWildcard();
|
||||
}
|
||||
|
||||
if (type.isExtends()) {
|
||||
return type.getTypeProvider().createUpperBoundWildcard(newBound);
|
||||
}
|
||||
else {
|
||||
return type.getTypeProvider().createLowerBoundWildcard(newBound);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JavaType rawTypeForTypeParameter(@NotNull JavaTypeParameter typeParameter) {
|
||||
Collection<JavaClassifierType> bounds = typeParameter.getUpperBounds();
|
||||
if (!bounds.isEmpty()) {
|
||||
return substitute(bounds.iterator().next());
|
||||
}
|
||||
|
||||
return typeParameter.getTypeProvider().createJavaLangObjectType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JavaType substitute(@NotNull JavaTypeParameter typeParameter) {
|
||||
PsiType psiType = psiSubstitutor.substitute(((JavaTypeParameterImpl) typeParameter).getPsi());
|
||||
return psiType == null ? null : JavaTypeImpl.create(psiType);
|
||||
if (substitutionMap.containsKey(typeParameter)) {
|
||||
return substitutionMap.get(typeParameter);
|
||||
}
|
||||
|
||||
return typeParameter.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<JavaTypeParameter, JavaType> getSubstitutionMap() {
|
||||
if (substitutionMap == null) {
|
||||
Map<PsiTypeParameter, PsiType> psiMap = psiSubstitutor.getSubstitutionMap();
|
||||
substitutionMap = new HashMap<JavaTypeParameter, JavaType>();
|
||||
for (Map.Entry<PsiTypeParameter, PsiType> entry : psiMap.entrySet()) {
|
||||
PsiType value = entry.getValue();
|
||||
substitutionMap.put(new JavaTypeParameterImpl(entry.getKey()), value == null ? null : JavaTypeImpl.create(value));
|
||||
}
|
||||
}
|
||||
|
||||
return substitutionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return psiSubstitutor.hashCode();
|
||||
return substitutionMap.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof JavaTypeSubstitutorImpl && psiSubstitutor.equals(((JavaTypeSubstitutorImpl) obj).psiSubstitutor);
|
||||
return obj instanceof JavaTypeSubstitutorImpl && substitutionMap.equals(((JavaTypeSubstitutorImpl) obj).substitutionMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": " + psiSubstitutor;
|
||||
return getClass().getSimpleName() + ": " + substitutionMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user