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 kotlin.Function1;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
024 import org.jetbrains.jet.lang.resolve.name.FqName;
025 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
026 import org.jetbrains.jet.lang.resolve.name.Name;
027 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
028 import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
029 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
030 import org.jetbrains.jet.lang.types.ErrorUtils;
031 import org.jetbrains.jet.lang.types.JetType;
032 import org.jetbrains.jet.lang.types.LazyType;
033 import org.jetbrains.jet.lang.types.TypeConstructor;
034 import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
035 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
036
037 import java.util.*;
038
039 import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.*;
040 import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
041
042 public class DescriptorUtils {
043 public static final Name ENUM_VALUES = Name.identifier("values");
044 public static final Name ENUM_VALUE_OF = Name.identifier("valueOf");
045
046 private DescriptorUtils() {
047 }
048
049 @Nullable
050 public static ReceiverParameterDescriptor getDispatchReceiverParameterIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
051 if (containingDeclaration instanceof ClassDescriptor) {
052 ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
053 return classDescriptor.getThisAsReceiverParameter();
054 }
055 else if (containingDeclaration instanceof ScriptDescriptor) {
056 ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration;
057 return scriptDescriptor.getThisAsReceiverParameter();
058 }
059 return NO_RECEIVER_PARAMETER;
060 }
061
062 /**
063 * Descriptor may be local itself or have a local ancestor
064 */
065 public static boolean isLocal(@NotNull DeclarationDescriptor descriptor) {
066 DeclarationDescriptor current = descriptor;
067 while (current instanceof MemberDescriptor) {
068 if (isAnonymousObject(current) || ((DeclarationDescriptorWithVisibility) current).getVisibility() == Visibilities.LOCAL) {
069 return true;
070 }
071 current = current.getContainingDeclaration();
072 }
073 return false;
074 }
075
076 @NotNull
077 public static FqNameUnsafe getFqName(@NotNull DeclarationDescriptor descriptor) {
078 FqName safe = getFqNameSafeIfPossible(descriptor);
079 return safe != null ? safe.toUnsafe() : getFqNameUnsafe(descriptor);
080 }
081
082 @NotNull
083 public static FqName getFqNameSafe(@NotNull DeclarationDescriptor descriptor) {
084 FqName safe = getFqNameSafeIfPossible(descriptor);
085 return safe != null ? safe : getFqNameUnsafe(descriptor).toSafe();
086 }
087
088
089 @Nullable
090 private static FqName getFqNameSafeIfPossible(@NotNull DeclarationDescriptor descriptor) {
091 if (descriptor instanceof ModuleDescriptor || ErrorUtils.isError(descriptor)) {
092 return FqName.ROOT;
093 }
094
095 if (descriptor instanceof PackageViewDescriptor) {
096 return ((PackageViewDescriptor) descriptor).getFqName();
097 }
098 else if (descriptor instanceof PackageFragmentDescriptor) {
099 return ((PackageFragmentDescriptor) descriptor).getFqName();
100 }
101
102 return null;
103 }
104
105 @NotNull
106 private static FqNameUnsafe getFqNameUnsafe(@NotNull DeclarationDescriptor descriptor) {
107 DeclarationDescriptor containingDeclaration = getContainingDeclarationSkippingClassObjects(descriptor);
108 assert containingDeclaration != null : "Not package/module descriptor doesn't have containing declaration: " + descriptor;
109 return getFqName(containingDeclaration).child(descriptor.getName());
110 }
111
112 @Nullable
113 private static DeclarationDescriptor getContainingDeclarationSkippingClassObjects(@NotNull DeclarationDescriptor descriptor) {
114 DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
115 return isClassObject(containingDeclaration) ? containingDeclaration.getContainingDeclaration() : containingDeclaration;
116 }
117
118 @NotNull
119 public static FqName getFqNameFromTopLevelClass(@NotNull DeclarationDescriptor descriptor) {
120 DeclarationDescriptor containingDeclaration = getContainingDeclarationSkippingClassObjects(descriptor);
121 Name name = descriptor.getName();
122 if (!(containingDeclaration instanceof ClassDescriptor)) {
123 return FqName.topLevel(name);
124 }
125 return getFqNameFromTopLevelClass(containingDeclaration).child(name);
126 }
127
128 public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
129 return descriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor;
130 }
131
132 /**
133 * @return true iff this is a top-level declaration or a class member with no expected "this" object (e.g. static members in Java,
134 * values() and valueOf() methods of enum classes, etc.)
135 */
136 public static boolean isStaticDeclaration(@NotNull CallableDescriptor descriptor) {
137 if (descriptor instanceof ConstructorDescriptor) return false;
138
139 DeclarationDescriptor container = descriptor.getContainingDeclaration();
140 return container instanceof PackageFragmentDescriptor ||
141 (container instanceof ClassDescriptor && descriptor.getDispatchReceiverParameter() == null);
142 }
143
144 // WARNING! Don't use this method in JVM backend, use JvmCodegenUtil.isCallInsideSameModuleAsDeclared() instead.
145 // The latter handles compilation against compiled part of our module correctly.
146 public static boolean areInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
147 return getContainingModule(first).equals(getContainingModule(second));
148 }
149
150 @Nullable
151 public static <D extends DeclarationDescriptor> D getParentOfType(
152 @Nullable DeclarationDescriptor descriptor,
153 @NotNull Class<D> aClass
154 ) {
155 return getParentOfType(descriptor, aClass, true);
156 }
157
158 @Nullable
159 public static <D extends DeclarationDescriptor> D getParentOfType(
160 @Nullable DeclarationDescriptor descriptor,
161 @NotNull Class<D> aClass,
162 boolean strict
163 ) {
164 if (descriptor == null) return null;
165 if (strict) {
166 descriptor = descriptor.getContainingDeclaration();
167 }
168 while (descriptor != null) {
169 if (aClass.isInstance(descriptor)) {
170 //noinspection unchecked
171 return (D) descriptor;
172 }
173 descriptor = descriptor.getContainingDeclaration();
174 }
175 return null;
176 }
177
178 @NotNull
179 public static ModuleDescriptor getContainingModule(@NotNull DeclarationDescriptor descriptor) {
180 if (descriptor instanceof PackageViewDescriptor) {
181 return ((PackageViewDescriptor) descriptor).getModule();
182 }
183 ModuleDescriptor module = getParentOfType(descriptor, ModuleDescriptor.class, false);
184 assert module != null : "Descriptor without a containing module: " + descriptor;
185 return module;
186 }
187
188 public static boolean isAncestor(
189 @Nullable DeclarationDescriptor ancestor,
190 @NotNull DeclarationDescriptor declarationDescriptor,
191 boolean strict
192 ) {
193 if (ancestor == null) return false;
194 DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
195 while (descriptor != null) {
196 if (ancestor == descriptor) return true;
197 descriptor = descriptor.getContainingDeclaration();
198 }
199 return false;
200 }
201
202 public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
203 return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
204 }
205
206 private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
207 DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
208 if (descriptor != null) {
209 DeclarationDescriptor originalDescriptor = descriptor.getOriginal();
210 if (originalDescriptor instanceof ClassifierDescriptor
211 && superClass instanceof ClassifierDescriptor
212 && ((ClassifierDescriptor) superClass).getTypeConstructor().equals(((ClassifierDescriptor) originalDescriptor).getTypeConstructor())) {
213 return true;
214 }
215 }
216
217 for (JetType superType : type.getConstructor().getSupertypes()) {
218 if (isSubtypeOfClass(superType, superClass)) {
219 return true;
220 }
221 }
222 return false;
223 }
224
225 public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
226 return descriptor instanceof AnonymousFunctionDescriptor;
227 }
228
229 public static boolean isClassObject(@Nullable DeclarationDescriptor descriptor) {
230 return isKindOf(descriptor, ClassKind.CLASS_OBJECT);
231 }
232
233 public static boolean isAnonymousObject(@NotNull DeclarationDescriptor descriptor) {
234 return isClass(descriptor) && descriptor.getName().equals(SpecialNames.NO_NAME_PROVIDED);
235 }
236
237 public static boolean isObject(@NotNull DeclarationDescriptor descriptor) {
238 return isKindOf(descriptor, ClassKind.OBJECT);
239 }
240
241 public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) {
242 return isKindOf(descriptor, ClassKind.ENUM_ENTRY);
243 }
244
245 public static boolean isSingleton(@Nullable DeclarationDescriptor classifier) {
246 if (classifier instanceof ClassDescriptor) {
247 ClassDescriptor clazz = (ClassDescriptor) classifier;
248 return clazz.getKind().isSingleton();
249 }
250 return false;
251 }
252
253 public static boolean isEnumClass(@Nullable DeclarationDescriptor descriptor) {
254 return isKindOf(descriptor, ClassKind.ENUM_CLASS);
255 }
256
257 public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
258 return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
259 }
260
261 public static boolean isTrait(@Nullable DeclarationDescriptor descriptor) {
262 return isKindOf(descriptor, ClassKind.TRAIT);
263 }
264
265 public static boolean isClass(@Nullable DeclarationDescriptor descriptor) {
266 return isKindOf(descriptor, ClassKind.CLASS);
267 }
268
269 public static boolean containerKindIs(@NotNull DeclarationDescriptor descriptor, @NotNull ClassKind kind) {
270 DeclarationDescriptor parentDeclaration = descriptor.getContainingDeclaration();
271 return parentDeclaration != null && isKindOf(parentDeclaration, kind);
272 }
273
274 public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
275 return descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == classKind;
276 }
277
278 @NotNull
279 public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
280 Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
281 List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
282 for (JetType type : superclassTypes) {
283 ClassDescriptor result = getClassDescriptorForType(type);
284 if (!isAny(result)) {
285 superClassDescriptors.add(result);
286 }
287 }
288 return superClassDescriptors;
289 }
290
291 @NotNull
292 public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
293 return getClassDescriptorForTypeConstructor(type.getConstructor());
294 }
295
296 @NotNull
297 public static ClassDescriptor getClassDescriptorForTypeConstructor(@NotNull TypeConstructor typeConstructor) {
298 ClassifierDescriptor descriptor = typeConstructor.getDeclarationDescriptor();
299 assert descriptor instanceof ClassDescriptor
300 : "Classifier descriptor of a type should be of type ClassDescriptor: " + typeConstructor;
301 return (ClassDescriptor) descriptor;
302 }
303
304 public static boolean isAny(@NotNull DeclarationDescriptor superClassDescriptor) {
305 return superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
306 }
307
308 public static boolean isSyntheticClassObject(@NotNull DeclarationDescriptor descriptor) {
309 return isClassObject(descriptor) && isSingleton(descriptor.getContainingDeclaration());
310 }
311
312 @NotNull
313 public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
314 ClassKind classKind = classDescriptor.getKind();
315 if (classKind == ClassKind.ENUM_CLASS || classKind.isSingleton()) {
316 return Visibilities.PRIVATE;
317 }
318 if (isAnonymousObject(classDescriptor)) {
319 return Visibilities.INTERNAL;
320 }
321 assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
322 return Visibilities.PUBLIC;
323 }
324
325 @NotNull
326 public static Visibility getSyntheticClassObjectVisibility() {
327 return Visibilities.PUBLIC;
328 }
329
330 @Nullable
331 public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
332 ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
333 assert classifier instanceof ClassDescriptor :
334 "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
335 + (classifier == null ? "null" : classifier.getClass());
336 return (ClassDescriptor) classifier;
337 }
338
339 @Nullable
340 public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
341 return receiverParameterDescriptor == null ? null : receiverParameterDescriptor.getType();
342 }
343
344 /**
345 * @return true if descriptor is a class inside another class and does not have access to the outer class
346 */
347 public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
348 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
349 return descriptor instanceof ClassDescriptor &&
350 containing instanceof ClassDescriptor &&
351 !((ClassDescriptor) descriptor).isInner();
352 }
353
354 @NotNull
355 public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
356 JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
357 return new FilteringScope(innerClassesScope, new Function1<DeclarationDescriptor, Boolean>() {
358 @Override
359 public Boolean invoke(DeclarationDescriptor descriptor) {
360 return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
361 }
362 });
363 }
364
365 /**
366 * @return true iff {@code descriptor}'s first non-class container is a package
367 */
368 public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
369 DeclarationDescriptor containing = descriptor.getContainingDeclaration();
370 return isTopLevelDeclaration(descriptor) ||
371 containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
372 }
373
374 /**
375 * Given a fake override, finds any declaration of it in the overridden descriptors. Keep in mind that there may be many declarations
376 * of the fake override in the supertypes, this method finds just the only one.
377 * TODO: probably all call-sites of this method are wrong, they should handle all super-declarations
378 */
379 @NotNull
380 public static <D extends CallableMemberDescriptor> D unwrapFakeOverride(@NotNull D descriptor) {
381 while (descriptor.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
382 Set<? extends CallableMemberDescriptor> overridden = descriptor.getOverriddenDescriptors();
383 if (overridden.isEmpty()) {
384 throw new IllegalStateException("Fake override should have at least one overridden descriptor: " + descriptor);
385 }
386 //noinspection unchecked
387 descriptor = (D) overridden.iterator().next();
388 }
389 return descriptor;
390 }
391
392 public static boolean shouldRecordInitializerForProperty(@NotNull VariableDescriptor variable, @NotNull JetType type) {
393 if (variable.isVar() || type.isError()) return false;
394
395 if (type instanceof LazyType || type.isNullable()) return true;
396
397 KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
398 return builtIns.isPrimitiveType(type) ||
399 JetTypeChecker.DEFAULT.equalTypes(builtIns.getStringType(), type) ||
400 JetTypeChecker.DEFAULT.equalTypes(builtIns.getNumber().getDefaultType(), type) ||
401 JetTypeChecker.DEFAULT.equalTypes(builtIns.getAnyType(), type);
402 }
403
404 public static boolean classCanHaveAbstractMembers(@NotNull ClassDescriptor classDescriptor) {
405 return classDescriptor.getModality() == Modality.ABSTRACT || classDescriptor.getKind() == ClassKind.ENUM_CLASS;
406 }
407
408 public static boolean classCanHaveOpenMembers(@NotNull ClassDescriptor classDescriptor) {
409 return classDescriptor.getModality() != Modality.FINAL || classDescriptor.getKind() == ClassKind.ENUM_CLASS;
410 }
411
412 @NotNull
413 @SuppressWarnings("unchecked")
414 public static <D extends CallableDescriptor> Set<D> getAllOverriddenDescriptors(@NotNull D f) {
415 Set<D> result = new LinkedHashSet<D>();
416 collectAllOverriddenDescriptors((D) f.getOriginal(), result);
417 return result;
418 }
419
420 private static <D extends CallableDescriptor> void collectAllOverriddenDescriptors(@NotNull D current, @NotNull Set<D> result) {
421 if (result.contains(current)) return;
422 for (CallableDescriptor callableDescriptor : current.getOriginal().getOverriddenDescriptors()) {
423 @SuppressWarnings("unchecked")
424 D descriptor = (D) callableDescriptor;
425 collectAllOverriddenDescriptors(descriptor, result);
426 result.add(descriptor);
427 }
428 }
429
430 @NotNull
431 public static <D extends CallableMemberDescriptor> Set<D> getAllOverriddenDeclarations(@NotNull D memberDescriptor) {
432 Set<D> result = new HashSet<D>();
433 for (CallableMemberDescriptor overriddenDeclaration : memberDescriptor.getOverriddenDescriptors()) {
434 CallableMemberDescriptor.Kind kind = overriddenDeclaration.getKind();
435 if (kind == DECLARATION) {
436 //noinspection unchecked
437 result.add((D) overriddenDeclaration);
438 }
439 else if (kind == DELEGATION || kind == FAKE_OVERRIDE || kind == SYNTHESIZED) {
440 //do nothing
441 }
442 else {
443 throw new AssertionError("Unexpected callable kind " + kind);
444 }
445 //noinspection unchecked
446 result.addAll(getAllOverriddenDeclarations((D) overriddenDeclaration));
447 }
448 return result;
449 }
450 }