From be5ba7fa0d480a61eb7211846c30ffaabd5946c8 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 2 Aug 2013 21:21:14 +0400 Subject: [PATCH] Migrate PropagationHeuristics from PSI to JavaElement Aside from refactorings, minor changes in logic are made: - to find out if a type of a value parameter is vararg ('ellipsis type'), we now check if the method is vararg and the parameter is its last parameter (instead of 'instanceof PsiEllipsisType') - 'visitedSuperclasses' is now a Set: this better reflects what it's supposed to represent. Also result check of the 'add()' method on a List was useless --- .../resolve/java/DescriptorResolverUtils.java | 20 +-- .../JavaToKotlinMethodMap.java | 23 +-- .../PropagationHeuristics.java | 135 +++++++++--------- .../SignaturesPropagationData.java | 43 +++--- .../java/sam/SingleAbstractMethodUtils.java | 2 +- .../lang/resolve/java/scope/MembersCache.java | 2 +- .../resolve/java/structure/JavaArrayType.java | 5 + .../java/structure/JavaTypeSubstitutor.java | 37 +++++ 8 files changed, 158 insertions(+), 109 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java index 8af72ca8755..28e1a11abda 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/DescriptorResolverUtils.java @@ -18,8 +18,6 @@ package org.jetbrains.jet.lang.resolve.java; import com.google.common.collect.ImmutableSet; import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiMember; -import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiSubstitutor; import com.intellij.psi.impl.compiled.ClsClassImpl; import com.intellij.psi.util.PsiFormatUtil; @@ -118,23 +116,19 @@ public final class DescriptorResolverUtils { return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member); } - public static boolean isObjectMethodInInterface(@NotNull PsiMember member) { - if (!(member instanceof PsiMethod)) { + public static boolean isObjectMethodInInterface(@NotNull JavaMember member) { + if (!(member instanceof JavaMethod)) { return false; } - PsiClass containingClass = member.getContainingClass(); - assert containingClass != null : "containing class is null for " + member; + JavaClass containingClass = member.getContainingClass(); + assert containingClass != null : "Containing class is null for member: " + member; - if (!containingClass.isInterface()) { - return false; - } - - return isObjectMethod((PsiMethod) member); + return containingClass.isInterface() && isObjectMethod((JavaMethod) member); } - public static boolean isObjectMethod(@NotNull PsiMethod method) { + public static boolean isObjectMethod(@NotNull JavaMethod method) { String formattedMethod = PsiFormatUtil.formatMethod( - method, PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES); + method.getPsi(), PsiSubstitutor.EMPTY, SHOW_NAME | SHOW_PARAMETERS, SHOW_TYPE | SHOW_FQ_CLASS_NAMES); return OBJECT_METHODS.contains(formattedMethod); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/JavaToKotlinMethodMap.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/JavaToKotlinMethodMap.java index 8ebc6aa2cf6..87e9c31b879 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/JavaToKotlinMethodMap.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/JavaToKotlinMethodMap.java @@ -16,7 +16,10 @@ package org.jetbrains.jet.lang.resolve.java.kotlinSignature; -import com.google.common.collect.*; +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Lists; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiMethod; import com.intellij.psi.PsiSubstitutor; @@ -25,6 +28,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; +import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; @@ -45,24 +50,26 @@ public class JavaToKotlinMethodMap { } @NotNull - public List getFunctions(@NotNull PsiMethod psiMethod, @NotNull ClassDescriptor containingClass) { - ImmutableCollection classDatas = mapContainer.map.get(psiMethod.getContainingClass().getQualifiedName()); + public List getFunctions( + @NotNull JavaMethod javaMethod, + @NotNull FqName classFqName, + @NotNull ClassDescriptor containingClass + ) { + ImmutableCollection classDatas = mapContainer.map.get(classFqName.asString()); List result = Lists.newArrayList(); Set allSuperClasses = DescriptorUtils.getAllSuperClasses(containingClass); - String serializedPsiMethod = serializePsiMethod(psiMethod); + String serializedMethod = serializePsiMethod(javaMethod.getPsi()); for (ClassData classData : classDatas) { - String expectedSerializedFunction = classData.method2Function.get(serializedPsiMethod); + String expectedSerializedFunction = classData.method2Function.get(serializedMethod); if (expectedSerializedFunction == null) continue; ClassDescriptor kotlinClass = classData.kotlinClass; if (!allSuperClasses.contains(kotlinClass)) continue; - - Collection functions = - kotlinClass.getDefaultType().getMemberScope().getFunctions(Name.identifier(psiMethod.getName())); + Collection functions = kotlinClass.getDefaultType().getMemberScope().getFunctions(javaMethod.getName()); for (FunctionDescriptor function : functions) { if (expectedSerializedFunction.equals(serializeFunction(function))) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java index 6a5db6423b7..734442caef1 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/PropagationHeuristics.java @@ -18,15 +18,18 @@ package org.jetbrains.jet.lang.resolve.java.kotlinSignature; import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.intellij.openapi.util.Comparing; +import com.google.common.collect.Sets; import com.intellij.openapi.util.Condition; -import com.intellij.psi.*; -import com.intellij.psi.impl.PsiSubstitutorImpl; +import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.Visibilities; +import org.jetbrains.jet.lang.resolve.java.resolver.JavaSupertypeResolver; +import org.jetbrains.jet.lang.resolve.java.structure.*; +import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetTypeImpl; @@ -36,12 +39,7 @@ import org.jetbrains.jet.lang.types.checker.JetTypeChecker; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.renderer.DescriptorRenderer; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.intellij.psi.util.TypeConversionUtil.erasure; +import java.util.*; // This class contains heuristics for processing corner cases in propagation class PropagationHeuristics { @@ -123,7 +121,7 @@ class PropagationHeuristics { } @NotNull - static List getSuperMethods(@NotNull PsiMethod method) { + static List getSuperMethods(@NotNull JavaMethod method) { return new SuperMethodCollector(method).collect(); } @@ -131,79 +129,83 @@ class PropagationHeuristics { } private static class SuperMethodCollector { - private final PsiMethod initialMethod; - private final String initialMethodName; - private final List initialParametersErasure; + private final JavaMethod initialMethod; + private final Name initialMethodName; + private final List initialParametersErasure; - private final List visitedSuperclasses = Lists.newArrayList(); - private final List collectedMethods = Lists.newArrayList(); + private final Set visitedSuperclasses = Sets.newHashSet(); + private final List collectedMethods = Lists.newArrayList(); - private SuperMethodCollector(@NotNull PsiMethod initialMethod) { + private SuperMethodCollector(@NotNull JavaMethod initialMethod) { this.initialMethod = initialMethod; initialMethodName = initialMethod.getName(); - PsiParameterList parameterList = initialMethod.getParameterList(); - initialParametersErasure = Lists.newArrayListWithExpectedSize(parameterList.getParametersCount()); - for (PsiParameter parameter : parameterList.getParameters()) { - initialParametersErasure.add(erasureNoEllipsis(parameter.getType())); + Collection valueParameters = initialMethod.getValueParameters(); + initialParametersErasure = Lists.newArrayListWithExpectedSize(valueParameters.size()); + for (Iterator iterator = valueParameters.iterator(); iterator.hasNext(); ) { + JavaType type = iterator.next().getType(); + boolean isVararg = initialMethod.isVararg() && !iterator.hasNext(); + initialParametersErasure.add(erasure(varargToArray(type, isVararg))); } } - public List collect() { + @NotNull + public List collect() { if (!canHaveSuperMethod(initialMethod)) { return Collections.emptyList(); } - PsiClass containingClass = initialMethod.getContainingClass(); + JavaClass containingClass = initialMethod.getContainingClass(); assert containingClass != null : " containing class is null for " + initialMethod; - for (PsiClassType superType : containingClass.getSuperTypes()) { - collectFromSupertype(superType); + for (JavaClassifierType supertype : containingClass.getSupertypes()) { + collectFromSupertype(supertype); } return collectedMethods; } - private void collectFromSupertype(PsiClassType type) { - PsiClass klass = type.resolve(); - if (klass == null) { - return; - } - if (!visitedSuperclasses.add(klass)) { - return; - } + private void collectFromSupertype(@NotNull JavaClassifierType type) { + JavaClassifier classifier = type.getClassifier(); + if (!(classifier instanceof JavaClass)) return; - PsiSubstitutor supertypeSubstitutor = getErasedSubstitutor(type); - for (PsiMethod methodFromSuper : klass.getMethods()) { + JavaClass klass = (JavaClass) classifier; + if (!visitedSuperclasses.add(klass)) return; + + JavaTypeSubstitutor supertypeSubstitutor = getErasedSubstitutor(type); + for (JavaMethod methodFromSuper : klass.getMethods()) { if (isSubMethodOf(methodFromSuper, supertypeSubstitutor)) { collectedMethods.add(methodFromSuper); return; } } - for (PsiType superType : type.getSuperTypes()) { - assert superType instanceof PsiClassType : "supertype is not a PsiClassType for " + type + ": " + superType; - collectFromSupertype((PsiClassType) superType); + for (JavaClassifierType supertype : type.getSupertypes()) { + collectFromSupertype(supertype); } } - private boolean isSubMethodOf(@NotNull PsiMethod methodFromSuper, @NotNull PsiSubstitutor supertypeSubstitutor) { + private boolean isSubMethodOf(@NotNull JavaMethod methodFromSuper, @NotNull JavaTypeSubstitutor supertypeSubstitutor) { if (!methodFromSuper.getName().equals(initialMethodName)) { return false; } - PsiParameterList fromSuperParameterList = methodFromSuper.getParameterList(); - - if (fromSuperParameterList.getParametersCount() != initialParametersErasure.size()) { + Collection fromSuperParameters = methodFromSuper.getValueParameters(); + if (fromSuperParameters.size() != initialParametersErasure.size()) { return false; } - for (int i = 0; i < initialParametersErasure.size(); i++) { - PsiType originalType = initialParametersErasure.get(i); - PsiType typeFromSuper = fromSuperParameterList.getParameters()[i].getType(); - PsiType typeFromSuperErased = erasureNoEllipsis(supertypeSubstitutor.substitute(typeFromSuper)); + Iterator originalIterator = initialParametersErasure.iterator(); + Iterator superIterator = fromSuperParameters.iterator(); + while (originalIterator.hasNext()) { + JavaType originalType = originalIterator.next(); + JavaType typeFromSuper = superIterator.next().getType(); - if (!Comparing.equal(originalType, typeFromSuperErased)) { + boolean isVarargType = methodFromSuper.isVararg() && !superIterator.hasNext(); + + JavaType typeFromSuperErased = erasure(varargToArray(supertypeSubstitutor.substitute(typeFromSuper), isVarargType)); + + if (!originalType.equals(typeFromSuperErased)) { return false; } } @@ -211,28 +213,33 @@ class PropagationHeuristics { return true; } - private static PsiType erasureNoEllipsis(PsiType type) { - if (type instanceof PsiEllipsisType) { - return erasureNoEllipsis(((PsiEllipsisType) type).toArrayType()); - } - return erasure(type); + @NotNull + private static JavaType varargToArray(@NotNull JavaType type, boolean isVararg) { + return isVararg ? JavaArrayType.create(((JavaArrayType) type).getComponentType()) : type; } - private static PsiSubstitutor getErasedSubstitutor(PsiClassType type) { - Map unerasedMap = type.resolveGenerics().getSubstitutor().getSubstitutionMap(); - Map erasedMap = Maps.newHashMapWithExpectedSize(unerasedMap.size()); - for (Map.Entry entry : unerasedMap.entrySet()) { - erasedMap.put(entry.getKey(), erasure(entry.getValue())); - } - return PsiSubstitutorImpl.createSubstitutor(erasedMap); + @NotNull + private static JavaType erasure(@NotNull JavaType type) { + return JavaType.create(TypeConversionUtil.erasure(type.getPsi())); } - private static boolean canHaveSuperMethod(PsiMethod method) { - if (method.isConstructor()) return false; - if (method.hasModifierProperty(PsiModifier.STATIC)) return false; - if (method.hasModifierProperty(PsiModifier.PRIVATE)) return false; - PsiClass containingClass = method.getContainingClass(); - return containingClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()); + @NotNull + private static JavaTypeSubstitutor getErasedSubstitutor(@NotNull JavaClassifierType type) { + Map unerasedMap = type.getSubstitutor().getSubstitutionMap(); + Map erasedMap = Maps.newHashMapWithExpectedSize(unerasedMap.size()); + for (Map.Entry entry : unerasedMap.entrySet()) { + JavaType value = entry.getValue(); + erasedMap.put(entry.getKey(), value == null ? null : erasure(value)); + } + return JavaTypeSubstitutor.create(erasedMap); + } + + private static boolean canHaveSuperMethod(@NotNull JavaMethod method) { + if (method.isConstructor() || method.isStatic() || method.getVisibility() == Visibilities.PRIVATE) { + return false; + } + JavaClass containingClass = method.getContainingClass(); + return containingClass != null && !JavaSupertypeResolver.OBJECT_FQ_NAME.equals(containingClass.getFqName()); } } } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java index edd1f0d0b3d..694feba829e 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/kotlinSignature/SignaturesPropagationData.java @@ -20,7 +20,6 @@ import com.google.common.collect.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; -import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiManager; import com.intellij.psi.PsiMethod; @@ -40,6 +39,7 @@ import org.jetbrains.jet.lang.resolve.java.TypeUsage; import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetClsMethod; import org.jetbrains.jet.lang.resolve.java.mapping.JavaToKotlinClassMap; import org.jetbrains.jet.lang.resolve.java.resolver.JavaValueParameterResolver; +import org.jetbrains.jet.lang.resolve.java.structure.JavaClass; import org.jetbrains.jet.lang.resolve.java.structure.JavaMethod; import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe; @@ -217,30 +217,29 @@ public class SignaturesPropagationData { Map superclassToSupertype = getSuperclassToSupertypeMap(containingClass); - Multimap> superclassToFunctions = + Multimap> superclassToFunctions = getSuperclassToFunctionsMultimap(method, trace.getBindingContext(), containingClass); - for (PsiMethod superMethod : PropagationHeuristics.getSuperMethods(method.getPsi())) { - PsiClass psiClass = superMethod.getContainingClass(); - assert psiClass != null; - String classFqNameString = psiClass.getQualifiedName(); - assert classFqNameString != null; - FqName classFqName = new FqName(classFqNameString); + for (JavaMethod superMethod : PropagationHeuristics.getSuperMethods(method)) { + JavaClass javaClass = superMethod.getContainingClass(); + assert javaClass != null : "Super method doesn't have a containing class: " + superMethod; + FqName classFqName = javaClass.getFqName(); + assert classFqName != null : "Class FQ name should not be null: " + javaClass; if (!JavaToKotlinClassMap.getInstance().mapPlatformClass(classFqName).isEmpty()) { - for (FunctionDescriptor superFun : JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, containingClass)) { + for (FunctionDescriptor superFun : JavaToKotlinMethodMap.INSTANCE.getFunctions(superMethod, classFqName, containingClass)) { superFunctions.add(substituteSuperFunction(superclassToSupertype, superFun)); } continue; } - DeclarationDescriptor superFun = superMethod instanceof JetClsMethod - ? trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ((JetClsMethod) superMethod).getOrigin()) + DeclarationDescriptor superFun = superMethod.getPsi() instanceof JetClsMethod + ? trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, ((JetClsMethod) superMethod.getPsi()).getOrigin()) : findSuperFunction(superclassToFunctions.get(classFqName), superMethod); if (superFun == null) { // Super methods which are Object methods in interfaces are not loaded by JDR. if (!DescriptorResolverUtils.isObjectMethodInInterface(superMethod)) { - reportCantFindSuperFunction(method.getPsi()); + reportCantFindSuperFunction(method); } continue; } @@ -264,12 +263,12 @@ public class SignaturesPropagationData { } @NotNull - private static Multimap> getSuperclassToFunctionsMultimap( + private static Multimap> getSuperclassToFunctionsMultimap( @NotNull JavaMethod method, @NotNull BindingContext bindingContext, @NotNull ClassDescriptor containingClass ) { - Multimap> result = HashMultimap.create(); + Multimap> result = HashMultimap.create(); Name functionName = method.getName(); int parameterCount = method.getValueParameters().size(); @@ -285,7 +284,7 @@ public class SignaturesPropagationData { fun.getValueParameters().size() + (fun.getReceiverParameter() != null ? 1 : 0) == parameterCount) { PsiElement declaration = BindingContextUtils.descriptorToDeclaration(bindingContext, fun); if (declaration instanceof PsiMethod) { - result.put(fqName, Pair.create(fun, (PsiMethod) declaration)); + result.put(fqName, Pair.create(fun, new JavaMethod((PsiMethod) declaration))); } // else declaration is null or JetNamedFunction: both cases are processed later } } @@ -295,12 +294,12 @@ public class SignaturesPropagationData { @Nullable private static DeclarationDescriptor findSuperFunction( - @NotNull Collection> superFunctionCandidates, - @NotNull PsiMethod superMethod + @NotNull Collection> superFunctionCandidates, + @NotNull JavaMethod superMethod ) { - PsiManager psiManager = PsiManager.getInstance(superMethod.getProject()); - for (Pair candidate : superFunctionCandidates) { - if (psiManager.areElementsEquivalent(candidate.second, superMethod)) { + PsiManager psiManager = PsiManager.getInstance(superMethod.getPsi().getProject()); + for (Pair candidate : superFunctionCandidates) { + if (psiManager.areElementsEquivalent(candidate.second.getPsi(), superMethod.getPsi())) { return candidate.first; } } @@ -693,8 +692,8 @@ public class SignaturesPropagationData { return builtIns.isArray(type) || builtIns.isPrimitiveArray(type); } - private static void reportCantFindSuperFunction(@NotNull PsiMethod psiMethod) { - String errorMessage = "Can't find super function for " + psiMethod + " defined in " + psiMethod.getContainingClass(); + private static void reportCantFindSuperFunction(@NotNull JavaMethod javaMethod) { + String errorMessage = "Can't find super function for " + javaMethod + " defined in " + javaMethod.getContainingClass(); if (SystemInfo.isMac) { LOG.error("Remove duplicates from your JDK definition\n" + errorMessage); } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index e4cfed65e39..f496d7aa360 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -375,7 +375,7 @@ public class SingleAbstractMethodUtils { return true; } for (JavaMethod method : javaClass.getMethods()) { - if (DescriptorResolverUtils.isObjectMethod(method.getPsi())) { // e.g., ignore toString() declared in interface + if (DescriptorResolverUtils.isObjectMethod(method)) { // e.g., ignore toString() declared in interface continue; } if (!method.getTypeParameters().isEmpty()) { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/MembersCache.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/MembersCache.java index 820a3da8012..fe416a7dc78 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/MembersCache.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/scope/MembersCache.java @@ -211,7 +211,7 @@ import java.util.Map; return false; } - if (DescriptorResolverUtils.isObjectMethodInInterface(member.getPsi())) { + if (DescriptorResolverUtils.isObjectMethodInInterface(member)) { return false; } diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaArrayType.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaArrayType.java index 3332002a87e..edf6c64b859 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaArrayType.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaArrayType.java @@ -30,6 +30,11 @@ public class JavaArrayType extends JavaType { return (PsiArrayType) super.getPsi(); } + @NotNull + public static JavaArrayType create(@NotNull JavaType elementType) { + return new JavaArrayType(elementType.getPsi().createArrayType()); + } + @NotNull public JavaType getComponentType() { return JavaType.create(getPsi().getComponentType()); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeSubstitutor.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeSubstitutor.java index 826f833c5cf..ee941e08dda 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeSubstitutor.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/structure/JavaTypeSubstitutor.java @@ -17,25 +17,62 @@ package org.jetbrains.jet.lang.resolve.java.structure; 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 java.util.HashMap; +import java.util.Map; + public class JavaTypeSubstitutor { private final PsiSubstitutor psiSubstitutor; + private Map substitutionMap; public JavaTypeSubstitutor(@NotNull PsiSubstitutor psiSubstitutor) { this.psiSubstitutor = psiSubstitutor; } + public JavaTypeSubstitutor(@NotNull PsiSubstitutor psiSubstitutor, @NotNull Map substitutionMap) { + this(psiSubstitutor); + this.substitutionMap = substitutionMap; + } + @NotNull public PsiSubstitutor getPsi() { return psiSubstitutor; } + @NotNull + public static JavaTypeSubstitutor create(@NotNull Map substitutionMap) { + Map psiMap = new HashMap(); + for (Map.Entry entry : substitutionMap.entrySet()) { + JavaType value = entry.getValue(); + psiMap.put(entry.getKey().getPsi(), value == null ? null : value.getPsi()); + } + PsiSubstitutor psiSubstitutor = PsiSubstitutorImpl.createSubstitutor(psiMap); + return new JavaTypeSubstitutor(psiSubstitutor, substitutionMap); + } + @NotNull public JavaType substitute(@NotNull JavaType type) { return JavaType.create(getPsi().substitute(type.getPsi())); } + @NotNull + public Map getSubstitutionMap() { + if (substitutionMap == null) { + Map psiMap = psiSubstitutor.getSubstitutionMap(); + substitutionMap = new HashMap(); + for (Map.Entry entry : psiMap.entrySet()) { + PsiType value = entry.getValue(); + substitutionMap.put(new JavaTypeParameter(entry.getKey()), value == null ? null : JavaType.create(value)); + } + } + + return substitutionMap; + } + @Override public int hashCode() { return getPsi().hashCode();