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