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