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.resolver;
018
019 import com.google.common.collect.Maps;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.impl.TypeParameterDescriptorImpl;
024 import org.jetbrains.jet.lang.resolve.OverrideResolver;
025 import org.jetbrains.jet.lang.resolve.java.JvmAnnotationNames;
026 import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
027 import org.jetbrains.jet.lang.resolve.java.structure.*;
028 import org.jetbrains.jet.lang.resolve.name.FqName;
029 import org.jetbrains.jet.lang.resolve.name.Name;
030 import org.jetbrains.jet.lang.types.TypeConstructor;
031 import org.jetbrains.jet.lang.types.TypeProjection;
032 import org.jetbrains.jet.lang.types.TypeSubstitutor;
033
034 import java.util.*;
035
036 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClassObject;
037
038 public final class DescriptorResolverUtils {
039 private DescriptorResolverUtils() {
040 }
041
042 public static boolean isCompiledKotlinPackageClass(@NotNull JavaClass javaClass) {
043 if (javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED) {
044 FqName fqName = javaClass.getFqName();
045 if (fqName != null && PackageClassUtils.isPackageClassFqName(fqName)) {
046 return javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_PACKAGE.getFqName()) != null;
047 }
048 }
049 return false;
050 }
051
052 public static boolean isCompiledKotlinClass(@NotNull JavaClass javaClass) {
053 if (javaClass.getOriginKind() == JavaClass.OriginKind.COMPILED) {
054 return javaClass.findAnnotation(JvmAnnotationNames.KOTLIN_CLASS.getFqName()) != null;
055 }
056 return false;
057 }
058
059 public static boolean isCompiledKotlinClassOrPackageClass(@NotNull JavaClass javaClass) {
060 return isCompiledKotlinClass(javaClass) || isCompiledKotlinPackageClass(javaClass);
061 }
062
063 @NotNull
064 public static <D extends CallableMemberDescriptor> Collection<D> resolveOverrides(
065 @NotNull Name name,
066 @NotNull Collection<D> membersFromSupertypes,
067 @NotNull Collection<D> membersFromCurrent,
068 @NotNull ClassDescriptor classDescriptor,
069 @NotNull final FakeOverrideVisibilityResolver visibilityResolver
070 ) {
071 final Set<D> result = new HashSet<D>();
072
073 OverrideResolver.generateOverridesInFunctionGroup(
074 name, membersFromSupertypes, membersFromCurrent, classDescriptor,
075 new OverrideResolver.DescriptorSink() {
076 @Override
077 @SuppressWarnings("unchecked")
078 public void addToScope(@NotNull CallableMemberDescriptor fakeOverride) {
079 visibilityResolver.resolveUnknownVisibilityForMember(fakeOverride);
080 result.add((D) fakeOverride);
081 }
082
083 @Override
084 public void conflict(@NotNull CallableMemberDescriptor fromSuper, @NotNull CallableMemberDescriptor fromCurrent) {
085 // nop
086 }
087 }
088 );
089
090 return result;
091 }
092
093 @Nullable
094 public static ValueParameterDescriptor getAnnotationParameterByName(@NotNull Name name, @NotNull ClassDescriptor annotationClass) {
095 Collection<ConstructorDescriptor> constructors = annotationClass.getConstructors();
096 assert constructors.size() == 1 : "Annotation class descriptor must have only one constructor";
097
098 for (ValueParameterDescriptor parameter : constructors.iterator().next().getValueParameters()) {
099 if (parameter.getName().equals(name)) {
100 return parameter;
101 }
102 }
103
104 return null;
105 }
106
107 /**
108 * @return true if {@code member} is a static member of enum class, which is to be put into its class object (and not into the
109 * corresponding package). This applies to enum entries, values() and valueOf(String) methods
110 */
111 public static boolean shouldBeInEnumClassObject(@NotNull JavaMember member) {
112 if (!member.getContainingClass().isEnum()) return false;
113
114 if (member instanceof JavaField && ((JavaField) member).isEnumEntry()) return true;
115
116 if (!(member instanceof JavaMethod)) return false;
117 String signature = JavaSignatureFormatter.getInstance().formatMethod((JavaMethod) member);
118
119 return "values()".equals(signature) ||
120 "valueOf(java.lang.String)".equals(signature);
121 }
122
123 public static boolean isCorrectOwnerForEnumMember(@NotNull ClassOrNamespaceDescriptor ownerDescriptor, @NotNull JavaMember member) {
124 return isEnumClassObject(ownerDescriptor) == shouldBeInEnumClassObject(member);
125 }
126
127 public static boolean isObjectMethodInInterface(@NotNull JavaMember member) {
128 return member.getContainingClass().isInterface() && member instanceof JavaMethod && isObjectMethod((JavaMethod) member);
129 }
130
131 public static boolean isObjectMethod(@NotNull JavaMethod method) {
132 String signature = JavaSignatureFormatter.getInstance().formatMethod(method);
133 return "hashCode()".equals(signature) ||
134 "equals(java.lang.Object)".equals(signature) ||
135 "toString()".equals(signature);
136 }
137
138 @NotNull
139 public static Collection<JavaClass> getClassesInPackage(@NotNull JavaPackage javaPackage) {
140 Collection<JavaClass> classes = javaPackage.getClasses();
141 Set<FqName> addedQualifiedNames = new HashSet<FqName>(classes.size());
142 List<JavaClass> result = new ArrayList<JavaClass>(classes.size());
143
144 for (JavaClass javaClass : classes) {
145 FqName fqName = javaClass.getFqName();
146 if (fqName != null && addedQualifiedNames.add(fqName)) {
147 result.add(javaClass);
148 }
149 }
150
151 return result;
152 }
153
154 /**
155 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType)
156 */
157 @Nullable
158 public static JavaType erasure(@NotNull JavaType type) {
159 return erasure(type, JavaTypeSubstitutor.EMPTY);
160 }
161
162 /**
163 * @see com.intellij.psi.util.TypeConversionUtil#erasure(com.intellij.psi.PsiType, com.intellij.psi.PsiSubstitutor)
164 */
165 @Nullable
166 public static JavaType erasure(@NotNull JavaType type, @NotNull JavaTypeSubstitutor substitutor) {
167 if (type instanceof JavaClassifierType) {
168 JavaClassifier classifier = ((JavaClassifierType) type).getClassifier();
169 if (classifier instanceof JavaClass) {
170 return ((JavaClass) classifier).getDefaultType();
171 }
172 else if (classifier instanceof JavaTypeParameter) {
173 JavaTypeParameter typeParameter = (JavaTypeParameter) classifier;
174 return typeParameterErasure(typeParameter, new HashSet<JavaTypeParameter>(), substitutor);
175 }
176 else {
177 return null;
178 }
179 }
180 else if (type instanceof JavaPrimitiveType) {
181 return type;
182 }
183 else if (type instanceof JavaArrayType) {
184 JavaType erasure = erasure(((JavaArrayType) type).getComponentType(), substitutor);
185 return erasure == null ? null : JavaElementFactory.getInstance().createArrayType(erasure);
186 }
187 else if (type instanceof JavaWildcardType) {
188 JavaWildcardType wildcardType = (JavaWildcardType) type;
189 JavaType bound = wildcardType.getBound();
190 if (bound != null && wildcardType.isExtends()) {
191 return erasure(bound, substitutor);
192 }
193 return wildcardType.getTypeProvider().createJavaLangObjectType();
194 }
195 else {
196 throw new IllegalStateException("Unsupported type: " + type);
197 }
198 }
199
200 /**
201 * @see com.intellij.psi.util.TypeConversionUtil#typeParameterErasure(com.intellij.psi.PsiTypeParameter)
202 */
203 @Nullable
204 private static JavaType typeParameterErasure(
205 @NotNull JavaTypeParameter typeParameter,
206 @NotNull HashSet<JavaTypeParameter> visited,
207 @NotNull JavaTypeSubstitutor substitutor
208 ) {
209 Collection<JavaClassifierType> upperBounds = typeParameter.getUpperBounds();
210 if (!upperBounds.isEmpty()) {
211 JavaClassifier classifier = upperBounds.iterator().next().getClassifier();
212 if (classifier instanceof JavaTypeParameter && !visited.contains(classifier)) {
213 JavaTypeParameter typeParameterBound = (JavaTypeParameter) classifier;
214 visited.add(typeParameterBound);
215 JavaType substitutedType = substitutor.substitute(typeParameterBound);
216 if (substitutedType != null) {
217 return erasure(substitutedType);
218 }
219 return typeParameterErasure(typeParameterBound, visited, substitutor);
220 }
221 else if (classifier instanceof JavaClass) {
222 return ((JavaClass) classifier).getDefaultType();
223 }
224 }
225 return typeParameter.getTypeProvider().createJavaLangObjectType();
226 }
227
228 @NotNull
229 public static Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> recreateTypeParametersAndReturnMapping(
230 @NotNull List<TypeParameterDescriptor> originalParameters,
231 @Nullable DeclarationDescriptor newOwner
232 ) {
233 Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> result = Maps.newLinkedHashMap(); // save order of type parameters
234 for (TypeParameterDescriptor typeParameter : originalParameters) {
235 result.put(typeParameter,
236 TypeParameterDescriptorImpl.createForFurtherModification(
237 newOwner == null ? typeParameter.getContainingDeclaration() : newOwner,
238 typeParameter.getAnnotations(),
239 typeParameter.isReified(),
240 typeParameter.getVariance(),
241 typeParameter.getName(),
242 typeParameter.getIndex()));
243 }
244 return result;
245 }
246
247 @NotNull
248 public static TypeSubstitutor createSubstitutorForTypeParameters(
249 @NotNull Map<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameters
250 ) {
251 Map<TypeConstructor, TypeProjection> typeSubstitutionContext = Maps.newHashMap();
252 for (Map.Entry<TypeParameterDescriptor, TypeParameterDescriptorImpl> originalToAltTypeParameter : originalToAltTypeParameters
253 .entrySet()) {
254 typeSubstitutionContext.put(originalToAltTypeParameter.getKey().getTypeConstructor(),
255 new TypeProjection(originalToAltTypeParameter.getValue().getDefaultType()));
256 }
257 return TypeSubstitutor.create(typeSubstitutionContext);
258 }
259 }