001    /*
002     * Copyright 2010-2013 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.jet.lang.resolve;
018    
019    import com.google.common.base.Predicate;
020    import com.google.common.collect.Lists;
021    import com.google.common.collect.Sets;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.jet.lang.descriptors.*;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.AnonymousFunctionDescriptor;
027    import org.jetbrains.jet.lang.psi.JetElement;
028    import org.jetbrains.jet.lang.psi.JetFunction;
029    import org.jetbrains.jet.lang.psi.JetParameter;
030    import org.jetbrains.jet.lang.psi.JetProperty;
031    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
032    import org.jetbrains.jet.lang.resolve.name.FqName;
033    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
034    import org.jetbrains.jet.lang.resolve.name.Name;
035    import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
036    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
037    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
038    import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
039    import org.jetbrains.jet.lang.types.JetType;
040    import org.jetbrains.jet.lang.types.TypeUtils;
041    import org.jetbrains.jet.lang.types.Variance;
042    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
043    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044    import org.jetbrains.jet.renderer.DescriptorRenderer;
045    
046    import java.util.*;
047    
048    import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
049    
050    public class DescriptorUtils {
051    
052        @NotNull
053        public static <D extends CallableDescriptor> D substituteBounds(@NotNull D functionDescriptor) {
054            List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
055            if (typeParameters.isEmpty()) return functionDescriptor;
056    
057            // TODO: this does not handle any recursion in the bounds
058            @SuppressWarnings("unchecked")
059            D substitutedFunction = (D) functionDescriptor.substitute(DescriptorSubstitutor.createUpperBoundsSubstitutor(typeParameters));
060            assert substitutedFunction != null : "Substituting upper bounds should always be legal";
061    
062            return substitutedFunction;
063        }
064    
065        public static Modality convertModality(Modality modality, boolean makeNonAbstract) {
066            if (makeNonAbstract && modality == Modality.ABSTRACT) return Modality.OPEN;
067            return modality;
068        }
069    
070        @Nullable
071        public static ReceiverParameterDescriptor getExpectedThisObjectIfNeeded(@NotNull DeclarationDescriptor containingDeclaration) {
072            if (containingDeclaration instanceof ClassDescriptor) {
073                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
074                return classDescriptor.getThisAsReceiverParameter();
075            }
076            else if (containingDeclaration instanceof ScriptDescriptor) {
077                ScriptDescriptor scriptDescriptor = (ScriptDescriptor) containingDeclaration;
078                return scriptDescriptor.getThisAsReceiverParameter();
079            }
080            return NO_RECEIVER_PARAMETER;
081        }
082    
083        /**
084         * The primary case for local extensions is the following:
085         *
086         * I had a locally declared extension function or a local variable of function type called foo
087         * And I called it on my x
088         * Now, someone added function foo() to the class of x
089         * My code should not change
090         *
091         * thus
092         *
093         * local extension prevail over members (and members prevail over all non-local extensions)
094         */
095        public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
096            if (candidate instanceof ValueParameterDescriptor) {
097                return true;
098            }
099            DeclarationDescriptor parent = candidate.getContainingDeclaration();
100            if (!(parent instanceof FunctionDescriptor)) {
101                return false;
102            }
103            FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
104            DeclarationDescriptor current = containerOfTheCurrentLocality;
105            while (current != null) {
106                if (current == functionDescriptor) {
107                    return true;
108                }
109                current = current.getContainingDeclaration();
110            }
111            return false;
112        }
113    
114        @NotNull
115        public static FqNameUnsafe getFQName(@NotNull DeclarationDescriptor descriptor) {
116            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
117    
118            if (descriptor instanceof ModuleDescriptor || containingDeclaration instanceof ModuleDescriptor) {
119                return FqName.ROOT.toUnsafe();
120            }
121    
122            if (containingDeclaration == null) {
123                if (descriptor instanceof NamespaceDescriptor) {
124                    // TODO: namespace must always have parent
125                    if (descriptor.getName().equals(Name.identifier("jet"))) {
126                        return FqNameUnsafe.topLevel(Name.identifier("jet"));
127                    }
128                    if (descriptor.getName().equals(Name.special("<java_root>"))) {
129                        return FqName.ROOT.toUnsafe();
130                    }
131                }
132                throw new IllegalStateException("descriptor is not module descriptor and has null containingDeclaration: " + containingDeclaration);
133            }
134    
135            if (containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.CLASS_OBJECT) {
136                DeclarationDescriptor classOfClassObject = containingDeclaration.getContainingDeclaration();
137                assert classOfClassObject != null;
138                return getFQName(classOfClassObject).child(descriptor.getName());
139            }
140    
141            return getFQName(containingDeclaration).child(descriptor.getName());
142        }
143    
144        public static boolean isTopLevelDeclaration(@NotNull DeclarationDescriptor descriptor) {
145            return descriptor.getContainingDeclaration() instanceof NamespaceDescriptor;
146        }
147    
148        public static boolean isInSameModule(@NotNull DeclarationDescriptor first, @NotNull DeclarationDescriptor second) {
149            ModuleDescriptor parentModule = DescriptorUtils.getParentOfType(first, ModuleDescriptorImpl.class, false);
150            ModuleDescriptor fromModule = DescriptorUtils.getParentOfType(second, ModuleDescriptorImpl.class, false);
151            assert parentModule != null && fromModule != null;
152            return parentModule.equals(fromModule);
153        }
154    
155        @Nullable
156        public static DeclarationDescriptor findTopLevelParent(@NotNull DeclarationDescriptor declarationDescriptor) {
157            DeclarationDescriptor descriptor = declarationDescriptor;
158            if (declarationDescriptor instanceof PropertyAccessorDescriptor) {
159                descriptor = ((PropertyAccessorDescriptor)descriptor).getCorrespondingProperty();
160            }
161            while (!(descriptor == null || isTopLevelDeclaration(descriptor))) {
162                descriptor = descriptor.getContainingDeclaration();
163            }
164            return descriptor;
165        }
166    
167        @Nullable
168        public static <D extends DeclarationDescriptor> D getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class<D> aClass) {
169            return getParentOfType(descriptor, aClass, true);
170        }
171    
172        @Nullable
173        public static <D extends DeclarationDescriptor> D getParentOfType(@Nullable DeclarationDescriptor descriptor, @NotNull Class<D> aClass, boolean strict) {
174            if (descriptor == null) return null;
175            if (strict) {
176                descriptor = descriptor.getContainingDeclaration();
177            }
178            while (descriptor != null) {
179                if (aClass.isInstance(descriptor)) {
180                    //noinspection unchecked
181                    return (D) descriptor;
182                }
183                descriptor = descriptor.getContainingDeclaration();
184            }
185            return null;
186        }
187    
188        public static boolean isAncestor(@Nullable DeclarationDescriptor ancestor, @NotNull DeclarationDescriptor declarationDescriptor, boolean strict) {
189            if (ancestor == null) return false;
190            DeclarationDescriptor descriptor = strict ? declarationDescriptor.getContainingDeclaration() : declarationDescriptor;
191            while (descriptor != null) {
192                if (ancestor == descriptor) return true;
193                descriptor = descriptor.getContainingDeclaration();
194            }
195            return false;
196        }
197    
198        @NotNull
199        public static JetType getFunctionExpectedReturnType(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) {
200            JetType expectedType;
201            if (function instanceof JetFunction) {
202                if (((JetFunction) function).getReturnTypeRef() != null || ((JetFunction) function).hasBlockBody()) {
203                    expectedType = descriptor.getReturnType();
204                }
205                else {
206                    expectedType = TypeUtils.NO_EXPECTED_TYPE;
207                }
208            }
209            else {
210                expectedType = descriptor.getReturnType();
211            }
212            return expectedType != null ? expectedType : TypeUtils.NO_EXPECTED_TYPE;
213        }
214    
215        public static boolean isSubclass(@NotNull ClassDescriptor subClass, @NotNull ClassDescriptor superClass) {
216            return isSubtypeOfClass(subClass.getDefaultType(), superClass.getOriginal());
217        }
218    
219        private static boolean isSubtypeOfClass(@NotNull JetType type, @NotNull DeclarationDescriptor superClass) {
220            DeclarationDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
221            if (descriptor != null && superClass == descriptor.getOriginal()) {
222                return true;
223            }
224            for (JetType superType : type.getConstructor().getSupertypes()) {
225                if (isSubtypeOfClass(superType, superClass)) {
226                    return true;
227                }
228            }
229            return false;
230        }
231    
232        public static void addSuperTypes(JetType type, Set<JetType> set) {
233            set.add(type);
234    
235            for (JetType jetType : type.getConstructor().getSupertypes()) {
236                addSuperTypes(jetType, set);
237            }
238        }
239    
240        public static boolean isRootNamespace(@NotNull NamespaceDescriptor namespaceDescriptor) {
241            return namespaceDescriptor.getContainingDeclaration() instanceof ModuleDescriptor;
242        }
243    
244        @NotNull
245        public static List<DeclarationDescriptor> getPathWithoutRootNsAndModule(@NotNull DeclarationDescriptor descriptor) {
246            List<DeclarationDescriptor> path = Lists.newArrayList();
247            DeclarationDescriptor current = descriptor;
248            while (true) {
249                if (current instanceof NamespaceDescriptor && isRootNamespace((NamespaceDescriptor) current)) {
250                    return Lists.reverse(path);
251                }
252                path.add(current);
253                current = current.getContainingDeclaration();
254            }
255        }
256    
257        public static boolean isFunctionLiteral(@NotNull FunctionDescriptor descriptor) {
258            return descriptor instanceof AnonymousFunctionDescriptor;
259        }
260    
261        public static boolean isClassObject(@NotNull DeclarationDescriptor descriptor) {
262            return isKindOf(descriptor, ClassKind.CLASS_OBJECT);
263        }
264    
265        public static boolean isAnonymous(@Nullable ClassifierDescriptor descriptor) {
266            return isKindOf(descriptor, ClassKind.OBJECT) && descriptor.getName().isSpecial();
267        }
268    
269        public static boolean isEnumEntry(@NotNull DeclarationDescriptor descriptor) {
270            return isKindOf(descriptor, ClassKind.ENUM_ENTRY);
271        }
272    
273        public static boolean isEnumClass(@NotNull DeclarationDescriptor descriptor) {
274            return isKindOf(descriptor, ClassKind.ENUM_CLASS);
275        }
276    
277        public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
278            return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
279        }
280    
281        public static boolean isClass(@NotNull DeclarationDescriptor descriptor) {
282            return isKindOf(descriptor, ClassKind.CLASS);
283        }
284    
285        public static boolean isKindOf(@NotNull JetType jetType, @NotNull ClassKind classKind) {
286            ClassifierDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
287            return isKindOf(descriptor, classKind);
288        }
289    
290        public static boolean isKindOf(@Nullable DeclarationDescriptor descriptor, @NotNull ClassKind classKind) {
291            if (descriptor instanceof ClassDescriptor) {
292                return ((ClassDescriptor) descriptor).getKind() == classKind;
293            }
294            return false;
295        }
296    
297        @NotNull
298        public static List<ClassDescriptor> getSuperclassDescriptors(@NotNull ClassDescriptor classDescriptor) {
299            Collection<JetType> superclassTypes = classDescriptor.getTypeConstructor().getSupertypes();
300            List<ClassDescriptor> superClassDescriptors = new ArrayList<ClassDescriptor>();
301            for (JetType type : superclassTypes) {
302                ClassDescriptor result = getClassDescriptorForType(type);
303                if (isNotAny(result)) {
304                    superClassDescriptors.add(result);
305                }
306            }
307            return superClassDescriptors;
308        }
309    
310        @NotNull
311        public static ClassDescriptor getClassDescriptorForType(@NotNull JetType type) {
312            DeclarationDescriptor superClassDescriptor =
313                type.getConstructor().getDeclarationDescriptor();
314            assert superClassDescriptor instanceof ClassDescriptor
315                : "Superclass descriptor of a type should be of type ClassDescriptor";
316            return (ClassDescriptor)superClassDescriptor;
317        }
318    
319        public static boolean isNotAny(@NotNull DeclarationDescriptor superClassDescriptor) {
320            return !superClassDescriptor.equals(KotlinBuiltIns.getInstance().getAny());
321        }
322    
323        public static boolean inStaticContext(@NotNull DeclarationDescriptor descriptor) {
324            DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
325            if (containingDeclaration instanceof NamespaceDescriptor) {
326                return true;
327            }
328            if (containingDeclaration instanceof ClassDescriptor) {
329                ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration;
330    
331                if (classDescriptor.getKind().isObject()) {
332                    return inStaticContext(classDescriptor.getContainingDeclaration());
333                }
334    
335            }
336            return false;
337        }
338    
339        public static boolean isIteratorWithoutRemoveImpl(@NotNull ClassDescriptor classDescriptor) {
340            ClassDescriptor iteratorOfT = KotlinBuiltIns.getInstance().getIterator();
341            JetType iteratorOfAny = TypeUtils.substituteParameters(iteratorOfT, Collections.singletonList(KotlinBuiltIns.getInstance().getAnyType()));
342            boolean isIterator = JetTypeChecker.INSTANCE.isSubtypeOf(classDescriptor.getDefaultType(), iteratorOfAny);
343            boolean hasRemove = hasMethod(classDescriptor, Name.identifier("remove"));
344            return isIterator && !hasRemove;
345        }
346    
347        private static boolean hasMethod(ClassDescriptor classDescriptor, Name name) {
348            Collection<FunctionDescriptor> removeFunctions = classDescriptor.getDefaultType().getMemberScope().getFunctions(name);
349            for (FunctionDescriptor function : removeFunctions) {
350                if (function.getValueParameters().isEmpty() && function.getTypeParameters().isEmpty()) {
351                    return true;
352                }
353            }
354            return false;
355        }
356    
357        @NotNull
358        public static Name getClassObjectName(@NotNull Name className) {
359            return Name.special("<class-object-for-" + className.asString() + ">");
360        }
361    
362        public static boolean isEnumClassObject(@NotNull DeclarationDescriptor descriptor) {
363            if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.CLASS_OBJECT) {
364                DeclarationDescriptor containing = descriptor.getContainingDeclaration();
365                if ((containing instanceof ClassDescriptor) && ((ClassDescriptor) containing).getKind() == ClassKind.ENUM_CLASS) {
366                    return true;
367                }
368            }
369            return false;
370        }
371    
372        @NotNull
373        public static Visibility getDefaultConstructorVisibility(@NotNull ClassDescriptor classDescriptor) {
374            ClassKind classKind = classDescriptor.getKind();
375            if (classKind == ClassKind.ENUM_CLASS) {
376                return Visibilities.PRIVATE;
377            }
378            if (classKind.isObject()) {
379                return Visibilities.PRIVATE;
380            }
381            assert classKind == ClassKind.CLASS || classKind == ClassKind.TRAIT || classKind == ClassKind.ANNOTATION_CLASS;
382            return Visibilities.PUBLIC;
383        }
384    
385        @NotNull
386        public static List<String> getSortedValueArguments(
387                @NotNull AnnotationDescriptor descriptor,
388                @Nullable DescriptorRenderer rendererForTypesIfNecessary
389        ) {
390            List<String> resultList = Lists.newArrayList();
391            for (Map.Entry<ValueParameterDescriptor, CompileTimeConstant<?>> entry : descriptor.getAllValueArguments().entrySet()) {
392                CompileTimeConstant<?> value = entry.getValue();
393                String typeSuffix = rendererForTypesIfNecessary == null
394                                    ? ""
395                                    : ": " + rendererForTypesIfNecessary.renderType(value.getType(KotlinBuiltIns.getInstance()));
396                resultList.add(entry.getKey().getName().asString() + " = " + value.toString() + typeSuffix);
397            }
398            Collections.sort(resultList);
399            return resultList;
400        }
401    
402        @Nullable
403        public static ClassDescriptor getInnerClassByName(@NotNull ClassDescriptor classDescriptor, @NotNull String innerClassName) {
404            ClassifierDescriptor classifier = classDescriptor.getDefaultType().getMemberScope().getClassifier(Name.identifier(innerClassName));
405            assert classifier instanceof ClassDescriptor :
406                    "Inner class " + innerClassName + " in " + classDescriptor + " should be instance of ClassDescriptor, but was: "
407                    + (classifier == null ? "null" : classifier.getClass());
408            return (ClassDescriptor) classifier;
409        }
410    
411        @NotNull
412        public static ConstructorDescriptor getConstructorOfDataClass(ClassDescriptor classDescriptor) {
413            ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
414            assert descriptor != null : "Data class must have only one constructor: " + classDescriptor.getConstructors();
415            return descriptor;
416        }
417    
418        @NotNull
419        public static ConstructorDescriptor getConstructorOfSingletonObject(ClassDescriptor classDescriptor) {
420            ConstructorDescriptor descriptor = getConstructorDescriptorIfOnlyOne(classDescriptor);
421            assert descriptor != null : "Class of singleton object must have only one constructor: " + classDescriptor.getConstructors();
422            return descriptor;
423        }
424    
425        @Nullable
426        private static ConstructorDescriptor getConstructorDescriptorIfOnlyOne(ClassDescriptor classDescriptor) {
427            Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
428            return constructors.size() != 1 ? null : constructors.iterator().next();
429        }
430    
431        @Nullable
432        public static JetType getReceiverParameterType(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
433            if (receiverParameterDescriptor == null) {
434                return null;
435            }
436            return receiverParameterDescriptor.getType();
437        }
438    
439        @NotNull
440        public static ReceiverValue safeGetValue(@Nullable ReceiverParameterDescriptor receiverParameterDescriptor) {
441            if (receiverParameterDescriptor == null) {
442                return ReceiverValue.NO_RECEIVER;
443            }
444            return receiverParameterDescriptor.getValue();
445        }
446    
447    
448        public static boolean isExternallyAccessible(PropertyDescriptor propertyDescriptor) {
449            return propertyDescriptor.getVisibility() != Visibilities.PRIVATE || isClassObject(propertyDescriptor.getContainingDeclaration())
450                   || isTopLevelDeclaration(propertyDescriptor);
451        }
452    
453        @NotNull
454        public static JetType getVarargParameterType(@NotNull JetType elementType) {
455            return getVarargParameterType(elementType, Variance.INVARIANT);
456        }
457    
458        @NotNull
459        public static JetType getVarargParameterType(@NotNull JetType elementType, @NotNull Variance projectionKind) {
460            KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
461            JetType primitiveArrayType = builtIns.getPrimitiveArrayJetTypeByPrimitiveJetType(elementType);
462            if (primitiveArrayType != null) {
463                return primitiveArrayType;
464            }
465            else {
466                return builtIns.getArrayType(projectionKind, elementType);
467            }
468        }
469    
470        @NotNull
471        public static List<JetType> getValueParametersTypes(@NotNull List<ValueParameterDescriptor> valueParameters) {
472            List<JetType> parameterTypes = Lists.newArrayList();
473            for (ValueParameterDescriptor parameter : valueParameters) {
474                parameterTypes.add(parameter.getType());
475            }
476            return parameterTypes;
477        }
478    
479        public static boolean isConstructorOfStaticNestedClass(@Nullable CallableDescriptor descriptor) {
480            return descriptor instanceof ConstructorDescriptor && isStaticNestedClass(descriptor.getContainingDeclaration());
481        }
482    
483        /**
484         * @return true if descriptor is a class inside another class and does not have access to the outer class
485         */
486        public static boolean isStaticNestedClass(@NotNull DeclarationDescriptor descriptor) {
487            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
488            return descriptor instanceof ClassDescriptor &&
489                   containing instanceof ClassDescriptor &&
490                   !((ClassDescriptor) descriptor).isInner() &&
491                   !((ClassDescriptor) containing).getKind().isObject();
492        }
493    
494        @Nullable
495        public static ClassDescriptor getContainingClass(@NotNull JetScope scope) {
496            DeclarationDescriptor containingDeclaration = scope.getContainingDeclaration();
497            return getParentOfType(containingDeclaration, ClassDescriptor.class, false);
498        }
499    
500        @NotNull
501        public static JetScope getStaticNestedClassesScope(@NotNull ClassDescriptor descriptor) {
502            JetScope innerClassesScope = descriptor.getUnsubstitutedInnerClassesScope();
503            return new FilteringScope(innerClassesScope, new Predicate<DeclarationDescriptor>() {
504                @Override
505                public boolean apply(@Nullable DeclarationDescriptor descriptor) {
506                    return descriptor instanceof ClassDescriptor && !((ClassDescriptor) descriptor).isInner();
507                }
508            });
509        }
510    
511        public static boolean isEnumValueOfMethod(@NotNull FunctionDescriptor functionDescriptor) {
512            List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
513            JetType nullableString = TypeUtils.makeNullable(KotlinBuiltIns.getInstance().getStringType());
514            return "valueOf".equals(functionDescriptor.getName().asString())
515                   && methodTypeParameters.size() == 1
516                   && JetTypeChecker.INSTANCE.isSubtypeOf(methodTypeParameters.get(0).getType(), nullableString);
517        }
518    
519        public static boolean isEnumValuesMethod(@NotNull FunctionDescriptor functionDescriptor) {
520            List<ValueParameterDescriptor> methodTypeParameters = functionDescriptor.getValueParameters();
521            return "values".equals(functionDescriptor.getName().asString())
522                   && methodTypeParameters.isEmpty();
523        }
524    
525        @NotNull
526        public static Set<ClassDescriptor> getAllSuperClasses(@NotNull ClassDescriptor klass) {
527            Set<JetType> allSupertypes = TypeUtils.getAllSupertypes(klass.getDefaultType());
528            Set<ClassDescriptor> allSuperclasses = Sets.newHashSet();
529            for (JetType supertype : allSupertypes) {
530                ClassDescriptor superclass = TypeUtils.getClassDescriptor(supertype);
531                assert superclass != null;
532                allSuperclasses.add(superclass);
533            }
534            return allSuperclasses;
535        }
536    
537        @NotNull
538        public static PropertyDescriptor getPropertyDescriptor(@NotNull JetProperty property, @NotNull BindingContext bindingContext) {
539            VariableDescriptor descriptor = bindingContext.get(BindingContext.VARIABLE, property);
540            if (!(descriptor instanceof PropertyDescriptor)) {
541                throw new UnsupportedOperationException("expect a property to have a property descriptor");
542            }
543            return (PropertyDescriptor) descriptor;
544        }
545    
546    
547        @NotNull
548        public static PropertyDescriptor getPropertyDescriptor(@NotNull JetParameter constructorParameter, @NotNull BindingContext bindingContext) {
549            assert constructorParameter.getValOrVarNode() != null;
550            PropertyDescriptor descriptor = bindingContext.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, constructorParameter);
551            assert descriptor != null;
552            return descriptor;
553        }
554    
555        /**
556         * @return true iff {@code descriptor}'s first non-class container is a namespace
557         */
558        public static boolean isTopLevelOrInnerClass(@NotNull ClassDescriptor descriptor) {
559            DeclarationDescriptor containing = descriptor.getContainingDeclaration();
560            return isTopLevelDeclaration(descriptor) ||
561                   containing instanceof ClassDescriptor && isTopLevelOrInnerClass((ClassDescriptor) containing);
562        }
563    
564        @NotNull
565        public static JetScope getEnumEntriesScope(@NotNull ClassDescriptor enumClass) {
566            assert enumClass.getKind() == ClassKind.ENUM_CLASS : "Only enum classes have enum entries: " + enumClass;
567            ClassDescriptor classObject = enumClass.getClassObjectDescriptor();
568            assert classObject != null : "Enum class should have a class object: " + enumClass;
569            return classObject.getDefaultType().getMemberScope();
570        }
571    }