001 /* 002 * Copyright 2010-2013 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.jet.lang.resolve.java; 018 019 import com.intellij.psi.PsiClass; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 023 import org.jetbrains.jet.lang.descriptors.SourceElement; 024 import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; 025 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl; 026 import org.jetbrains.jet.lang.resolve.java.structure.*; 027 import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl; 028 import org.jetbrains.jet.lang.types.TypeConstructor; 029 import org.jetbrains.jet.lang.types.TypeProjection; 030 import org.jetbrains.jet.lang.types.TypeProjectionImpl; 031 import org.jetbrains.jet.lang.types.TypeSubstitutor; 032 033 import java.util.*; 034 035 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_CLASS; 036 import static org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames.KOTLIN_PACKAGE; 037 038 public class JavaResolverUtils { 039 private JavaResolverUtils() { 040 } 041 042 public static boolean isCompiledKotlinClass(@NotNull PsiClass psiClass) { 043 JavaClass javaClass = new JavaClassImpl(psiClass); 044 return javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED && javaClass.findAnnotation(KOTLIN_CLASS) != null; 045 } 046 047 public static boolean isCompiledKotlinPackageClass(@NotNull PsiClass psiClass) { 048 JavaClass javaClass = new JavaClassImpl(psiClass); 049 return javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED && javaClass.findAnnotation(KOTLIN_PACKAGE) != null; 050 } 051 052 public static boolean isCompiledKotlinClassOrPackageClass(@NotNull PsiClass psiClass) { 053 return isCompiledKotlinClass(psiClass) || isCompiledKotlinPackageClass(psiClass); 054 } 055 056 /** 057 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType) 058 */ 059 @Nullable 060 public static JavaType erasure(@NotNull JavaType type) { 061 return erasure(type, JavaTypeSubstitutor.EMPTY); 062 } 063 064 /** 065 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType, com.intellij.psi.PsiSubstitutor) 066 */ 067 @Nullable 068 public static JavaType erasure(@NotNull JavaType type, @NotNull JavaTypeSubstitutor substitutor) { 069 if (type instanceof JavaClassifierType) { 070 JavaClassifier classifier = ((JavaClassifierType) type).getClassifier(); 071 if (classifier instanceof JavaClass) { 072 return ((JavaClass) classifier).getDefaultType(); 073 } 074 else if (classifier instanceof JavaTypeParameter) { 075 JavaTypeParameter typeParameter = (JavaTypeParameter) classifier; 076 return typeParameterErasure(typeParameter, new HashSet<JavaTypeParameter>(), substitutor); 077 } 078 else { 079 return null; 080 } 081 } 082 else if (type instanceof JavaPrimitiveType) { 083 return type; 084 } 085 else if (type instanceof JavaArrayType) { 086 JavaType erasure = erasure(((JavaArrayType) type).getComponentType(), substitutor); 087 return erasure == null ? null : erasure.createArrayType(); 088 } 089 else if (type instanceof JavaWildcardType) { 090 JavaWildcardType wildcardType = (JavaWildcardType) type; 091 JavaType bound = wildcardType.getBound(); 092 if (bound != null && wildcardType.isExtends()) { 093 return erasure(bound, substitutor); 094 } 095 return wildcardType.getTypeProvider().createJavaLangObjectType(); 096 } 097 else { 098 throw new IllegalStateException("Unsupported type: " + type); 099 } 100 } 101 102 /** 103 * @see com.intellij.psi.util.TypeConversionUtil#typeParameterErasure(com.intellij.psi.PsiTypeParameter) 104 */ 105 @Nullable 106 private static JavaType typeParameterErasure( 107 @NotNull JavaTypeParameter typeParameter, 108 @NotNull HashSet<JavaTypeParameter> visited, 109 @NotNull JavaTypeSubstitutor substitutor 110 ) { 111 Collection<JavaClassifierType> upperBounds = typeParameter.getUpperBounds(); 112 if (!upperBounds.isEmpty()) { 113 JavaClassifier classifier = upperBounds.iterator().next().getClassifier(); 114 if (classifier instanceof JavaTypeParameter && !visited.contains(classifier)) { 115 JavaTypeParameter typeParameterBound = (JavaTypeParameter) classifier; 116 visited.add(typeParameterBound); 117 JavaType substitutedType = substitutor.substitute(typeParameterBound); 118 if (substitutedType != null) { 119 return erasure(substitutedType); 120 } 121 return typeParameterErasure(typeParameterBound, visited, substitutor); 122 } 123 else if (classifier instanceof JavaClass) { 124 return ((JavaClass) classifier).getDefaultType(); 125 } 126 } 127 return typeParameter.getTypeProvider().createJavaLangObjectType(); 128 } 129 130 @NotNull 131 public static Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> recreateTypeParametersAndReturnMapping( 132 @NotNull List<TypeParameterDescriptor> originalParameters, 133 @Nullable DeclarationDescriptor newOwner 134 ) { 135 // LinkedHashMap to save the order of type parameters 136 Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> result = 137 new LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptorImpl>(); 138 for (TypeParameterDescriptor typeParameter : originalParameters) { 139 result.put(typeParameter, 140 TypeParameterDescriptorImpl.createForFurtherModification( 141 newOwner == null ? typeParameter.getContainingDeclaration() : newOwner, 142 typeParameter.getAnnotations(), 143 typeParameter.isReified(), 144 typeParameter.getVariance(), 145 typeParameter.getName(), 146 typeParameter.getIndex(), 147 SourceElement.NO_SOURCE 148 ) 149 ); 150 } 151 return result; 152 } 153 154 @NotNull 155 public static TypeSubstitutor createSubstitutorForTypeParameters( 156 @NotNull Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters 157 ) { 158 Map<TypeConstructor, TypeProjection> typeSubstitutionContext = new HashMap<TypeConstructor, TypeProjection>(); 159 for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameter : originalToAltTypeParameters.entrySet()) { 160 typeSubstitutionContext.put(originalToAltTypeParameter.getKey().getTypeConstructor(), 161 new TypeProjectionImpl(originalToAltTypeParameter.getValue().getDefaultType())); 162 } 163 return TypeSubstitutor.create(typeSubstitutionContext); 164 } 165 }