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