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.descriptors.impl.NamespaceDescriptorParent;
028    import org.jetbrains.jet.lang.psi.JetElement;
029    import org.jetbrains.jet.lang.psi.JetFunction;
030    import org.jetbrains.jet.lang.psi.JetParameter;
031    import org.jetbrains.jet.lang.psi.JetProperty;
032    import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
033    import org.jetbrains.jet.lang.resolve.name.FqName;
034    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
035    import org.jetbrains.jet.lang.resolve.name.Name;
036    import org.jetbrains.jet.lang.resolve.scopes.FilteringScope;
037    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
038    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
039    import org.jetbrains.jet.lang.types.*;
040    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
041    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
042    import org.jetbrains.jet.renderer.DescriptorRenderer;
043    
044    import java.util.*;
045    
046    import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_RECEIVER_PARAMETER;
047    import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.DONT_CARE;
048    
049    public 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(@Nullable 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    }