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.annotations.AnnotationDescriptor;
026 import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
027 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
028 import org.jetbrains.jet.lang.resolve.name.FqName;
029 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
030 import org.jetbrains.jet.lang.resolve.name.Name;
031 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
032 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
033 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
034 import org.jetbrains.jet.lang.types.*;
035 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
036 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
037 import org.jetbrains.jet.renderer.DescriptorRenderer;
038
039 import java.util.*;
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 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
113
114 if (descriptor instanceof ModuleDescriptor || containingDeclaration instanceof ModuleDescriptor) {
115 return FqName.ROOT.toUnsafe();
116 }
117
118 if (containingDeclaration == null) {
119 if (descriptor instanceof NamespaceDescriptor) {
120 // TODO: namespace must always have parent
121 if (descriptor.getName().equals(Name.identifier("jet"))) {
122 return FqNameUnsafe.topLevel(Name.identifier("jet"));
123 }
124 if (descriptor.getName().equals(Name.special("<java_root>"))) {
125 return FqName.ROOT.toUnsafe();
126 }
127 }
128 throw new IllegalStateException("descriptor is not module descriptor and has null containingDeclaration: " + descriptor);
129 }
130
131 if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) {
132 DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration();
133 assert classOfClassObject != null;
134 return getFQName(classOfClassObject).child(descriptor.getName());
135 }
136
137 return getFQName(containingDeclaration).child(descriptor.getName());
138 }
139
140 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
141 return descriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
142 }
143
144 public static boolean isInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
145 ModuleDescriptor parentModule = getParentOfType(first, ModuleDescriptorImpl.class, false);
146 ModuleDescriptor fromModule = getParentOfType(second, ModuleDescriptorImpl.class, false);
147 assert parentModule != null && fromModule != null;
148 return parentModule.equals(fromModule);
149 }
150
151 @Nullable
152 public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
153 DeclarationDescriptor descriptor = declarationDescriptor;
154 if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
155 descriptor = ((PropertyAccessorDescriptor) descriptor).getCorrespondingProperty();
156 }
157 while (!(descriptor == null || isTopLevelDeclaration(descriptor))) {
158 descriptor = descriptor.getContainingDeclaration();
159 }
160 return descriptor;
161 }
162
163 @Nullable
164 public static <D extends DeclarationDescriptor> D getParentOfType(
165 @Nullable DeclarationDescriptor descriptor,
166 @NotNull Class<D> aClass
167 ) {
168 return getParentOfType(descriptor, aClass, true);
169 }
170
171 @Nullable
172 public static <D extends DeclarationDescriptor> D getParentOfType(
173 @Nullable DeclarationDescriptor descriptor,
174 @NotNull Class<D> aClass,
175 boolean strict
176 ) {
177 if (descriptor == null) return null;
178 if (strict) {
179 descriptor = descriptor.getContainingDeclaration();
180 }
181 while (descriptor != null) {
182 if (aClass.isInstance(descriptor)) {
183 //noinspection unchecked
184 return (D) descriptor;
185 }
186 descriptor = descriptor.getContainingDeclaration();
187 }
188 return null;
189 }
190
191 public static boolean isAncestor(
192 @Nullable DeclarationDescriptor ancestor,
193 @NotNull DeclarationDescriptor declarationDescriptor,
194 boolean strict
195 ) {
196 if (ancestor == null) return false;
197 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
198 while (descriptor != null) {
199 if (ancestor == descriptor) return true;
200 descriptor = descriptor.getContainingDeclaration();
201 }
202 return false;
203 }
204
205 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
206 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
207 }
208
209 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
210 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
211 if (descriptor != null && superClass == descriptor.getOriginal()) {
212 return true;
213 }
214 for (JetType superType : type.getConstructor().getSupertypes()) {
215 if (isSubtypeOfClass(superType, superClass)) {
216 return true;
217 }
218 }
219 return false;
220 }
221
222 public static boolean isRootNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
223 return namespaceDescriptor.getContainingDeclaration() instanceof ModuleDescriptor;
224 }
225
226 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
227 return descriptor instanceof AnonymousFunctionDescriptor;
228 }
229
230 public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) {
231 return isKindOf(descriptor, ClassKind.CLASS_OBJECT);
232 }
233
234 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
235 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
236 }
237
238 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
239 return isKindOf(descriptor, ClassKind.OBJECT);
240 }
241
242 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) {
243 return isKindOf(descriptor, ClassKind.ENUM_ENTRY);
244 }
245
246 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) {
247 if (classifier instanceof ClassDescriptor) {
248 ClassDescriptor clazz = (ClassDescriptor) classifier;
249 return clazz.getKind().isSingleton();
250 }
251 return false;
252 }
253
254 public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) {
255 return isKindOf(descriptor, ClassKind.ENUM_CLASS);
256 }
257
258 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
259 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
260 }
261
262 public static boolean isTrait(@NotNull DeclarationDescriptor descriptor) {
263 return isKindOf(descriptor, ClassKind.TRAIT);
264 }
265
266 public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
267 return isKindOf(descriptor, ClassKind.CLASS);
268 }
269
270 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
271 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind;
272 }
273
274 @NotNull
275 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
276 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
277 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
278 for (JetType type : superclassTypes) {
279 ClassDescriptor result = getClassDescriptorForType(type);
280 if (!isAny(result)) {
281 superClassDescriptors.add(result);
282 }
283 }
284 return superClassDescriptors;
285 }
286
287 @NotNull
288 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
289 return getClassDescriptorForTypeConstructor(type.getConstructor());
290 }
291
292 @NotNull
293 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) {
294 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
295 assert descriptor instanceof ClassDescriptor
296 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor;
297 return (ClassDescriptor) descriptor;
298 }
299
300 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) {
301 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
302 }
303
304 public static boolean inStaticContext(@NotNull DeclarationDescriptor descriptor) {
305 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
306 if (containingDeclaration instanceof NamespaceDescriptor) {
307 return true;
308 }
309 if (containingDeclaration instanceof ClassDescriptor) {
310 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
311
312 if (classDescriptor.getKind().isSingleton()) {
313 return inStaticContext(classDescriptor.getContainingDeclaration());
314 }
315
316 }
317 return false;
318 }
319
320 public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) {
321 if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) {
322 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
323 if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) {
324 return true;
325 }
326 }
327 return false;
328 }
329
330 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
331 if (isClassObject(descriptor)) {
332 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
333 if (containing != null) {
334 return isEnumClass(containing) || isObject(containing) || isEnumEntry(containing);
335 }
336 }
337 return false;
338 }
339
340 @NotNull
341 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
342 ClassKind classKind = classDescriptor.getKind();
343 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton() || isAnonymousObject(classDescriptor)) {
344 return Visibilities.PRIVATE;
345 }
346 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
347 return Visibilities.PUBLIC;
348 }
349
350 @NotNull
351 public static Visibility getSyntheticClassObjectVisibility() {
352 return Visibilities.PUBLIC;
353 }
354
355 @NotNull
356 public static List<String> getSortedValueArguments(
357 @NotNull AnnotationDescriptor descriptor,
358 @Nullable DescriptorRenderer rendererForTypesIfNecessary
359 ) {
360 List<String> resultList = Lists.newArrayList();
361 for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) {
362 CompileTimeConstant<?> value = entry.getValue();
363 String typeSuffix = rendererForTypesIfNecessary == null
364 ? ""
365 : ": " + rendererForTypesIfNecessary.renderType(value.getType(KotlinBuiltIns.getInstance()));
366 resultList.add(entry.getKey().getName().asString() + " = " + value.toString() + typeSuffix);
367 }
368 Collections.sort(resultList);
369 return resultList;
370 }
371
372 @Nullable
373 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
374 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
375 assert classifier instanceof ClassDescriptor :
376 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
377 + (classifier == null ? "null" : classifier.getClass());
378 return (ClassDescriptor) classifier;
379 }
380
381 @NotNull
382 public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) {
383 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
384 assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors();
385 return descriptor;
386 }
387
388 @NotNull
389 public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) {
390 ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
391 assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors();
392 return descriptor;
393 }
394
395 @Nullable
396 private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) {
397 Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
398 return constructors.size() != 1 ? null : constructors.iterator().next();
399 }
400
401 @Nullable
402 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
403 if (receiverParameterDescriptor == null) {
404 return null;
405 }
406 return receiverParameterDescriptor.getType();
407 }
408
409 @NotNull
410 public static JetType getVarargParameterType(@NotNull JetType elementType) {
411 JetType primitiveArrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(elementType);
412 return primitiveArrayType != null ? primitiveArrayType : KotlinBuiltIns.getInstance().getArrayType(Variance.INVARIANT, elementType);
413 }
414
415 @NotNull
416 public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
417 List<JetType> parameterTypes = Lists.newArrayList();
418 for (ValueParameterDescriptor parameter : valueParameters) {
419 parameterTypes.add(parameter.getType());
420 }
421 return parameterTypes;
422 }
423
424 public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) {
425 return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration());
426 }
427
428 /**
429 * @return true if descriptor is a class inside another class and does not have access to the outer class
430 */
431 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
432 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
433 return descriptor instanceof ClassDescriptor &&
434 containing instanceof ClassDescriptor &&
435 !((ClassDescriptor) descriptor).isInner() &&
436 !((ClassDescriptor) containing).getKind().isSingleton();
437 }
438
439 @Nullable
440 public static ClassDescriptor getContainingClass(@NotNull JetScope scope) {
441 DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration();
442 return getParentOfType(containingDeclaration, ClassDescriptor.class, false);
443 }
444
445 @NotNull
446 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
447 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
448 return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
449 @Override
450 public boolean apply(@Nullable DeclarationDescriptor descriptor) {
451 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
452 }
453 });
454 }
455
456 public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
457 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
458 JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
459 return "valueOf".equals(functionDescriptor.getName().asString())
460 && methodTypeParameters.size() == 1
461 && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
462 }
463
464 public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
465 List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
466 return "values".equals(functionDescriptor.getName().asString())
467 && methodTypeParameters.isEmpty();
468 }
469
470 @NotNull
471 public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) {
472 Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType());
473 Set<ClassDescriptor> allSuperclasses = Sets.newHashSet();
474 for (JetType supertype : allSupertypes) {
475 ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype);
476 assert superclass != null;
477 allSuperclasses.add(superclass);
478 }
479 return allSuperclasses;
480 }
481
482 /**
483 * @return true iff {@code descriptor}'s first non-class container is a namespace
484 */
485 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
486 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
487 return isTopLevelDeclaration(descriptor) ||
488 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
489 }
490 }