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;
018
019 import com.google.common.base.Predicate;
020 import com.google.common.collect.Lists;
021 import com.google.common.collect.Sets;
022 import org.jetbrains.annotations.NotNull;
023 import org.jetbrains.annotations.Nullable;
024 import org.jetbrains.jet.lang.descriptors.*;
025 import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
026 import org.jetbrains.jet.lang.resolve.name.FqName;
027 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
028 import org.jetbrains.jet.lang.resolve.name.Name;
029 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
030 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
031 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
032 import org.jetbrains.jet.lang.types.*;
033 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
034 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
035
036 import java.util.ArrayList;
037 import java.util.Collection;
038 import java.util.List;
039 import java.util.Set;
040
041 import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
042
043 public class DescriptorUtils {
044 private DescriptorUtils() {
045 }
046
047 @NotNull
048 public static <D extends CallableDescriptor> D substituteBounds(@NotNull D functionDescriptor) {
049 List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
050 if (typeParameters.isEmpty()) return functionDescriptor;
051
052 // TODO: this does not handle any recursion in the bounds
053 @SuppressWarnings("unchecked")
054 D substitutedFunction = (D) functionDescriptor.substitute(DescriptorSubstitutor.createUpperBoundsSubstitutor(typeParameters));
055 assert substitutedFunction != null : "Substituting upper bounds should always be legal";
056
057 return substitutedFunction;
058 }
059
060 @NotNull
061 public static Modality convertModality(@NotNull Modality modality, boolean makeNonAbstract) {
062 if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
063 return modality;
064 }
065
066 @Nullable
067 public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
068 if (containingDeclaration instanceof ClassDescriptor) {
069 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
070 return classDescriptor.getThisAsReceiverParameter();
071 }
072 else if (containingDeclaration instanceof ScriptDescriptor) {
073 ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration;
074 return scriptDescriptor.getThisAsReceiverParameter();
075 }
076 return NO_RECEIVER_PARAMETER;
077 }
078
079 /**
080 * The primary case for local extensions is the following:
081 *
082 * I had a locally declared extension function or a local variable of function type called foo
083 * And I called it on my x
084 * Now, someone added function foo() to the class of x
085 * My code should not change
086 *
087 * thus
088 *
089 * local extension prevail over members (and members prevail over all non-local extensions)
090 */
091 public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
092 if (candidate instanceof ValueParameterDescriptor) {
093 return true;
094 }
095 DeclarationDescriptor parent = candidate.getContainingDeclaration();
096 if (!(parent instanceof FunctionDescriptor)) {
097 return false;
098 }
099 FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
100 DeclarationDescriptor current = containerOfTheCurrentLocality;
101 while (current != null) {
102 if (current == functionDescriptor) {
103 return true;
104 }
105 current = current.getContainingDeclaration();
106 }
107 return false;
108 }
109
110 @NotNull
111 public static FqNameUnsafe getFqName(@NotNull DeclarationDescriptor descriptor) {
112 FqName safe = getFqNameSafeIfPossible(descriptor);
113 return safe != null ? safe.toUnsafe() : getFqNameUnsafe(descriptor);
114 }
115
116 @NotNull
117 public static FqName getFqNameSafe(@NotNull DeclarationDescriptor descriptor) {
118 FqName safe = getFqNameSafeIfPossible(descriptor);
119 return safe != null ? safe : getFqNameUnsafe(descriptor).toSafe();
120 }
121
122
123 @Nullable
124 private static FqName getFqNameSafeIfPossible(@NotNull DeclarationDescriptor descriptor) {
125 if (descriptor instanceof ModuleDescriptor || ErrorUtils.isError(descriptor)) {
126 return FqName.ROOT;
127 }
128
129 if (descriptor instanceof PackageViewDescriptor) {
130 return ((PackageViewDescriptor) descriptor).getFqName();
131 }
132 else if (descriptor instanceof PackageFragmentDescriptor) {
133 return ((PackageFragmentDescriptor) descriptor).getFqName();
134 }
135
136 return null;
137 }
138
139 @NotNull
140 private static FqNameUnsafe getFqNameUnsafe(@NotNull DeclarationDescriptor descriptor) {
141 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
142
143 if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) {
144 DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration();
145 assert classOfClassObject != null;
146 return getFqName(classOfClassObject).child(descriptor.getName());
147 }
148
149 return getFqName(containingDeclaration).child(descriptor.getName());
150 }
151
152 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
153 return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
154 }
155
156 public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
157 ModuleDescriptor parentModule = getParentOfType(first, ModuleDescriptor.class, false);
158 ModuleDescriptor fromModule = getParentOfType(second, ModuleDescriptor.class, false);
159 assert parentModule != null && fromModule != null;
160 return parentModule.equals(fromModule);
161 }
162
163 @Nullable
164 public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
165 DeclarationDescriptor descriptor = declarationDescriptor;
166 if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
167 descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
168 }
169 while (!(descriptor == null || isTopLevelDeclaration(descriptor))) {
170 descriptor = descriptor.getContainingDeclaration();
171 }
172 return descriptor;
173 }
174
175 @Nullable
176 public static <D extends DeclarationDescriptor> D getParentOfType(
177 @Nullable DeclarationDescriptor descriptor,
178 @NotNull Class<D> aClass
179 ) {
180 return getParentOfType(descriptor, aClass, true);
181 }
182
183 @Nullable
184 public static <D extends DeclarationDescriptor> D getParentOfType(
185 @Nullable DeclarationDescriptor descriptor,
186 @NotNull Class<D> aClass,
187 boolean strict
188 ) {
189 if (descriptor == null) return null;
190 if (strict) {
191 descriptor = descriptor.getContainingDeclaration();
192 }
193 while (descriptor != null) {
194 if (aClass.isInstance(descriptor)) {
195 //noinspection unchecked
196 return (D) descriptor;
197 }
198 descriptor = descriptor.getContainingDeclaration();
199 }
200 return null;
201 }
202
203 public static boolean isAncestor(
204 @Nullable DeclarationDescriptor ancestor,
205 @NotNull DeclarationDescriptor declarationDescriptor,
206 boolean strict
207 ) {
208 if (ancestor == null) return false;
209 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
210 while (descriptor != null) {
211 if (ancestor == descriptor) return true;
212 descriptor = descriptor.getContainingDeclaration();
213 }
214 return false;
215 }
216
217 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
218 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
219 }
220
221 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
222 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
223 if (descriptor != null && superClass == descriptor.getOriginal()) {
224 return true;
225 }
226 for (JetType superType : type.getConstructor().getSupertypes()) {
227 if (isSubtypeOfClass(superType, superClass)) {
228 return true;
229 }
230 }
231 return false;
232 }
233
234 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
235 return descriptor instanceof AnonymousFunctionDescriptor;
236 }
237
238 public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) {
239 return isKindOf(descriptor, ClassKind.CLASS_OBJECT);
240 }
241
242 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
243 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
244 }
245
246 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
247 return isKindOf(descriptor, ClassKind.OBJECT);
248 }
249
250 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) {
251 return isKindOf(descriptor, ClassKind.ENUM_ENTRY);
252 }
253
254 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) {
255 if (classifier instanceof ClassDescriptor) {
256 ClassDescriptor clazz = (ClassDescriptor) classifier;
257 return clazz.getKind().isSingleton();
258 }
259 return false;
260 }
261
262 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) {
263 return isKindOf(descriptor, ClassKind.ENUM_CLASS);
264 }
265
266 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
267 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
268 }
269
270 public static boolean isTrait(@NotNull DeclarationDescriptor descriptor) {
271 return isKindOf(descriptor, ClassKind.TRAIT);
272 }
273
274 public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
275 return isKindOf(descriptor, ClassKind.CLASS);
276 }
277
278 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
279 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind;
280 }
281
282 @NotNull
283 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
284 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
285 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
286 for (JetType type : superclassTypes) {
287 ClassDescriptor result = getClassDescriptorForType(type);
288 if (!isAny(result)) {
289 superClassDescriptors.add(result);
290 }
291 }
292 return superClassDescriptors;
293 }
294
295 @NotNull
296 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
297 return getClassDescriptorForTypeConstructor(type.getConstructor());
298 }
299
300 @NotNull
301 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) {
302 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
303 assert descriptor instanceof ClassDescriptor
304 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor;
305 return (ClassDescriptor) descriptor;
306 }
307
308 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) {
309 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
310 }
311
312 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) {
313 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) {
314 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
315 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) {
316 return true;
317 }
318 }
319 return false;
320 }
321
322 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
323 if (isClassObject(descriptor)) {
324 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
325 if (containing != null) {
326 return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing);
327 }
328 }
329 return false;
330 }
331
332 @NotNull
333 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
334 ClassKind classKind = classDescriptor.getKind();
335 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) {
336 return Visibilities.PRIVATE;
337 }
338 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
339 return Visibilities.PUBLIC;
340 }
341
342 @NotNull
343 public static Visibility getSyntheticClassObjectVisibility() {
344 return Visibilities.PUBLIC;
345 }
346
347 @Nullable
348 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
349 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
350 assert classifier instanceof ClassDescriptor :
351 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
352 + (classifier == null ? "null" : classifier.getClass());
353 return (ClassDescriptor) classifier;
354 }
355
356 @NotNull
357 public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) {
358 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
359 assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors();
360 return descriptor;
361 }
362
363 @NotNull
364 public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) {
365 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
366 assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors();
367 return descriptor;
368 }
369
370 @Nullable
371 private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) {
372 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
373 return constructors.size() != 1 ? null : constructors.iterator().next();
374 }
375
376 @Nullable
377 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
378 if (receiverParameterDescriptor == null) {
379 return null;
380 }
381 return receiverParameterDescriptor.getType();
382 }
383
384 @NotNull
385 public static JetType getVarargParameterType(@NotNull JetType elementType) {
386 JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType);
387 return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType);
388 }
389
390 @NotNull
391 public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
392 List<JetType> parameterTypes = Lists.newArrayList();
393 for (ValueParameterDescriptor parameter : valueParameters) {
394 parameterTypes.add(parameter.getType());
395 }
396 return parameterTypes;
397 }
398
399 public static boolean isInsideOuterClassOrItsSubclass(@Nullable DeclarationDescriptor nested, @NotNull ClassDescriptor outer) {
400 if (nested == null) return false;
401
402 if (nested instanceof ClassDescriptor && isSubclass((ClassDescriptor) nested, outer)) return true;
403
404 return isInsideOuterClassOrItsSubclass(nested.getContainingDeclaration(), outer);
405 }
406
407 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) {
408 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration());
409 }
410
411 /**
412 * @return true if descriptor is a class inside another class and does not have access to the outer class
413 */
414 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
415 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
416 return descriptor instanceof ClassDescriptor &&
417 containing instanceof ClassDescriptor &&
418 !((ClassDescriptor) descriptor).isInner();
419 }
420
421 @Nullable
422 public static ClassDescriptor getContainingClass(@NotNull JetScope scope) {
423 DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration();
424 return getParentOfType(containingDeclaration, ClassDescriptor.class, false);
425 }
426
427 @NotNull
428 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
429 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
430 return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
431 @Override
432 public boolean apply(@Nullable DeclarationDescriptor descriptor) {
433 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
434 }
435 });
436 }
437
438 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
439 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
440 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
441 return "valueOf".equals(functionDescriptor.getName().asString())
442 && methodTypeParameters.size() == 1
443 && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
444 }
445
446 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
447 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
448 return "values".equals(functionDescriptor.getName().asString())
449 && methodTypeParameters.isEmpty();
450 }
451
452 @NotNull
453 public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) {
454 Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType());
455 Set<ClassDescriptor> allSuperclasses = Sets.newHashSet();
456 for (JetType supertype : allSupertypes) {
457 ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype);
458 assert superclass != null;
459 allSuperclasses.add(superclass);
460 }
461 return allSuperclasses;
462 }
463
464 /**
465 * @return true iff {@code descriptor}'s first non-class container is a package
466 */
467 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
468 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
469 return isTopLevelDeclaration(descriptor) ||
470 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
471 }
472 }