001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.resolve.jvm; 018 019 import org.jetbrains.annotations.NotNull; 020 import org.jetbrains.annotations.Nullable; 021 import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; 022 import org.jetbrains.kotlin.descriptors.SourceElement; 023 import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; 024 import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl; 025 import org.jetbrains.kotlin.load.java.structure.*; 026 import org.jetbrains.kotlin.types.TypeConstructor; 027 import org.jetbrains.kotlin.types.TypeProjection; 028 import org.jetbrains.kotlin.types.TypeProjectionImpl; 029 import org.jetbrains.kotlin.types.TypeSubstitutor; 030 031 import java.util.*; 032 033 public class JavaResolverUtils { 034 private JavaResolverUtils() { 035 } 036 037 /** 038 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType) 039 */ 040 @Nullable 041 public static JavaType erasure(@NotNull JavaType type) { 042 return erasure(type, JavaTypeSubstitutor.EMPTY); 043 } 044 045 /** 046 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType, com.intellij.psi.PsiSubstitutor) 047 */ 048 @Nullable 049 public static JavaType erasure(@NotNull JavaType type, @NotNull JavaTypeSubstitutor substitutor) { 050 if (type instanceof JavaClassifierType) { 051 JavaClassifier classifier = ((JavaClassifierType) type).getClassifier(); 052 if (classifier instanceof JavaClass) { 053 return ((JavaClass) classifier).getDefaultType(); 054 } 055 else if (classifier instanceof JavaTypeParameter) { 056 JavaTypeParameter typeParameter = (JavaTypeParameter) classifier; 057 return typeParameterErasure(typeParameter, new HashSet<JavaTypeParameter>(), substitutor); 058 } 059 else { 060 return null; 061 } 062 } 063 else if (type instanceof JavaPrimitiveType) { 064 return type; 065 } 066 else if (type instanceof JavaArrayType) { 067 JavaType erasure = erasure(((JavaArrayType) type).getComponentType(), substitutor); 068 return erasure == null ? null : erasure.createArrayType(); 069 } 070 else if (type instanceof JavaWildcardType) { 071 JavaWildcardType wildcardType = (JavaWildcardType) type; 072 JavaType bound = wildcardType.getBound(); 073 if (bound != null && wildcardType.isExtends()) { 074 return erasure(bound, substitutor); 075 } 076 return wildcardType.getTypeProvider().createJavaLangObjectType(); 077 } 078 else { 079 throw new IllegalStateException("Unsupported type: " + type); 080 } 081 } 082 083 /** 084 * @see com.intellij.psi.util.TypeConversionUtil#typeParameterErasure(com.intellij.psi.PsiTypeParameter) 085 */ 086 @Nullable 087 private static JavaType typeParameterErasure( 088 @NotNull JavaTypeParameter typeParameter, 089 @NotNull HashSet<JavaTypeParameter> visited, 090 @NotNull JavaTypeSubstitutor substitutor 091 ) { 092 Collection<JavaClassifierType> upperBounds = typeParameter.getUpperBounds(); 093 if (!upperBounds.isEmpty()) { 094 JavaClassifier classifier = upperBounds.iterator().next().getClassifier(); 095 if (classifier instanceof JavaTypeParameter && !visited.contains(classifier)) { 096 JavaTypeParameter typeParameterBound = (JavaTypeParameter) classifier; 097 visited.add(typeParameterBound); 098 JavaType substitutedType = substitutor.substitute(typeParameterBound); 099 if (substitutedType != null) { 100 return erasure(substitutedType); 101 } 102 return typeParameterErasure(typeParameterBound, visited, substitutor); 103 } 104 else if (classifier instanceof JavaClass) { 105 return ((JavaClass) classifier).getDefaultType(); 106 } 107 } 108 return typeParameter.getTypeProvider().createJavaLangObjectType(); 109 } 110 111 @NotNull 112 public static Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> recreateTypeParametersAndReturnMapping( 113 @NotNull List<TypeParameterDescriptor> originalParameters, 114 @Nullable DeclarationDescriptor newOwner 115 ) { 116 // LinkedHashMap to save the order of type parameters 117 Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> result = 118 new LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>(); 119 for (TypeParameterDescriptor typeParameter : originalParameters) { 120 result.put(typeParameter, 121 TypeParameterDescriptorImpl.createForFurtherModification( 122 newOwner == null ? typeParameter.getContainingDeclaration() : newOwner, 123 typeParameter.getAnnotations(), 124 typeParameter.isReified(), 125 typeParameter.getVariance(), 126 typeParameter.getName(), 127 typeParameter.getIndex(), 128 SourceElement.NO_SOURCE 129 ) 130 ); 131 } 132 return result; 133 } 134 135 @NotNull 136 public static TypeSubstitutor createSubstitutorForTypeParameters( 137 @NotNull Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters 138 ) { 139 Map<TypeConstructor, TypeProjection> typeSubstitutionContext = new HashMap<TypeConstructor, TypeProjection>(); 140 for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameter : originalToAltTypeParameters.entrySet()) { 141 typeSubstitutionContext.put(originalToAltTypeParameter.getKey().getTypeConstructor(), 142 new TypeProjectionImpl(originalToAltTypeParameter.getValue().getDefaultType())); 143 } 144 return TypeSubstitutor.create(typeSubstitutionContext); 145 } 146 }