Implement JavaTypeSubstitutor without PSI

This commit is contained in:
zarechenskiy
2014-06-24 15:24:22 +04:00
committed by Alexander Udalov
parent 97b7768890
commit 0355b1bd53
54 changed files with 1000 additions and 62 deletions
@@ -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,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() {
@@ -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);
}
});
@@ -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));
}
}
@@ -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;
}
}
}