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    }