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