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