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