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 }