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.collect.Lists;
020    import com.google.common.collect.Multimap;
021    import com.google.common.collect.Sets;
022    import com.intellij.psi.PsiElement;
023    import com.intellij.psi.PsiNameIdentifierOwner;
024    import com.intellij.util.containers.ContainerUtil;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.jet.lang.descriptors.*;
028    import org.jetbrains.jet.lang.descriptors.impl.*;
029    import org.jetbrains.jet.lang.psi.*;
030    import org.jetbrains.jet.lang.resolve.name.Name;
031    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
032    import org.jetbrains.jet.lang.resolve.scopes.RedeclarationHandler;
033    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
034    import org.jetbrains.jet.lang.resolve.scopes.WriteThroughScope;
035    import org.jetbrains.jet.lang.types.JetType;
036    import org.jetbrains.jet.lang.types.SubstitutionUtils;
037    import org.jetbrains.jet.lang.types.TypeConstructor;
038    import org.jetbrains.jet.lang.types.TypeProjection;
039    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
040    import org.jetbrains.jet.utils.DFS;
041    
042    import javax.inject.Inject;
043    import java.util.*;
044    
045    import static org.jetbrains.jet.lang.diagnostics.Errors.*;
046    import static org.jetbrains.jet.lang.resolve.BindingContext.FQNAME_TO_CLASS_DESCRIPTOR;
047    import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
048    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getClassObjectName;
049    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.getDefaultClassVisibility;
050    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
051    
052    public class TypeHierarchyResolver {
053        @NotNull
054        private TopDownAnalysisContext context;
055        @NotNull
056        private ImportsResolver importsResolver;
057        @NotNull
058        private DescriptorResolver descriptorResolver;
059        @NotNull
060        private ScriptHeaderResolver scriptHeaderResolver;
061        @NotNull
062        private NamespaceFactoryImpl namespaceFactory;
063        @NotNull
064        private BindingTrace trace;
065    
066        @Inject
067        public void setContext(@NotNull TopDownAnalysisContext context) {
068            this.context = context;
069        }
070    
071        @Inject
072        public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
073            this.importsResolver = importsResolver;
074        }
075    
076        @Inject
077        public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
078            this.descriptorResolver = descriptorResolver;
079        }
080    
081        @Inject
082        public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
083            this.scriptHeaderResolver = scriptHeaderResolver;
084        }
085    
086        @Inject
087        public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
088            this.namespaceFactory = namespaceFactory;
089        }
090    
091        @Inject
092        public void setTrace(@NotNull BindingTrace trace) {
093            this.trace = trace;
094        }
095    
096        public void process(
097                @NotNull JetScope outerScope, @NotNull NamespaceLikeBuilder owner,
098                @NotNull Collection<? extends PsiElement> declarations
099        ) {
100    
101            {
102                // TODO: Very temp code - main goal is to remove recursion from collectNamespacesAndClassifiers
103                Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
104                forDeferredResolve.addAll(collectNamespacesAndClassifiers(outerScope, owner, declarations));
105    
106                while (!forDeferredResolve.isEmpty()) {
107                    JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
108                    assert declarationContainer != null;
109    
110                    DeclarationDescriptor descriptorForDeferredResolve = context.forDeferredResolver.get(declarationContainer);
111                    JetScope scope = context.normalScope.get(declarationContainer);
112    
113                    // Even more temp code
114                    if (descriptorForDeferredResolve instanceof MutableClassDescriptorLite) {
115                        forDeferredResolve.addAll(
116                                collectNamespacesAndClassifiers(
117                                        scope,
118                                        ((MutableClassDescriptorLite) descriptorForDeferredResolve).getBuilder(),
119                                        declarationContainer.getDeclarations()));
120                    }
121                    else if (descriptorForDeferredResolve instanceof NamespaceDescriptorImpl) {
122                        forDeferredResolve.addAll(
123                                collectNamespacesAndClassifiers(
124                                        scope,
125                                        ((NamespaceDescriptorImpl) descriptorForDeferredResolve).getBuilder(),
126                                        declarationContainer.getDeclarations()));
127                    }
128                    else {
129                        assert false;
130                    }
131                }
132            }
133    
134            importsResolver.processTypeImports(outerScope);
135    
136            createTypeConstructors(); // create type constructors for classes and generic parameters, supertypes are not filled in
137            resolveTypesInClassHeaders(); // Generic bounds and types in supertype lists (no expressions or constructor resolution)
138    
139            context.setClassesTopologicalOrder(topologicallySortClassesAndObjects());
140    
141            // Detect and disconnect all loops in the hierarchy
142            detectAndDisconnectLoops();
143    
144            // At this point, there are no loops in the type hierarchy
145    
146            checkSupertypesForConsistency();
147            //        computeSuperclasses();
148    
149            checkTypesInClassHeaders(); // Check bounds in the types used in generic bounds and supertype lists
150        }
151    
152        @Nullable
153        private Collection<JetDeclarationContainer> collectNamespacesAndClassifiers(
154                @NotNull JetScope outerScope,
155                @NotNull NamespaceLikeBuilder owner,
156                @NotNull Iterable<? extends PsiElement> declarations
157        ) {
158            Collection<JetDeclarationContainer> forDeferredResolve = new ArrayList<JetDeclarationContainer>();
159    
160            ClassifierCollector collector = new ClassifierCollector(outerScope, owner, forDeferredResolve);
161    
162            for (PsiElement declaration : declarations) {
163                declaration.accept(collector);
164            }
165    
166            return forDeferredResolve;
167        }
168    
169    
170        @NotNull
171        private static ClassKind getClassKind(@NotNull JetClass jetClass) {
172            if (jetClass.isTrait()) return ClassKind.TRAIT;
173            if (jetClass.isAnnotation()) return ClassKind.ANNOTATION_CLASS;
174            if (jetClass.isEnum()) return ClassKind.ENUM_CLASS;
175            return ClassKind.CLASS;
176        }
177    
178        private void createTypeConstructors() {
179            for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
180                JetClass jetClass = entry.getKey();
181                MutableClassDescriptor descriptor = entry.getValue();
182                descriptorResolver.resolveMutableClassDescriptor(jetClass, descriptor, trace);
183                descriptor.createTypeConstructor();
184            }
185            for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
186                JetObjectDeclaration objectDeclaration = entry.getKey();
187                MutableClassDescriptor descriptor = entry.getValue();
188                descriptor.setModality(Modality.FINAL);
189                descriptor.setVisibility(resolveVisibilityFromModifiers(objectDeclaration, getDefaultClassVisibility(descriptor)));
190                descriptor.setTypeParameterDescriptors(new ArrayList<TypeParameterDescriptor>(0));
191                descriptor.createTypeConstructor();
192            }
193        }
194    
195        private void resolveTypesInClassHeaders() {
196            for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
197                JetClass jetClass = entry.getKey();
198                MutableClassDescriptor descriptor = entry.getValue();
199                descriptorResolver.resolveGenericBounds(jetClass, descriptor.getScopeForSupertypeResolution(),
200                                                        (List) descriptor.getTypeConstructor().getParameters(), trace);
201                descriptorResolver.resolveSupertypesForMutableClassDescriptor(jetClass, descriptor, trace);
202            }
203            for (Map.Entry<JetObjectDeclaration, MutableClassDescriptor> entry : context.getObjects().entrySet()) {
204                JetClassOrObject jetClass = entry.getKey();
205                MutableClassDescriptor descriptor = entry.getValue();
206                descriptorResolver.resolveSupertypesForMutableClassDescriptor(jetClass, descriptor, trace);
207            }
208        }
209    
210        private List<MutableClassDescriptorLite> topologicallySortClassesAndObjects() {
211            // A topsort is needed only for better diagnostics:
212            //    edges that get removed to disconnect loops are more reasonable in this case
213            return DFS.topologicalOrder(
214                    ContainerUtil.<MutableClassDescriptorLite>concat(context.getClasses().values(), context.getObjects().values()),
215                    new DFS.Neighbors<MutableClassDescriptorLite>() {
216                        @NotNull
217                        @Override
218                        public Iterable<MutableClassDescriptorLite> getNeighbors(MutableClassDescriptorLite current) {
219                            List<MutableClassDescriptorLite> result = Lists.newArrayList();
220                            for (JetType supertype : current.getSupertypes()) {
221                                DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
222                                if (declarationDescriptor instanceof MutableClassDescriptorLite) {
223                                    MutableClassDescriptorLite classDescriptor = (MutableClassDescriptorLite) declarationDescriptor;
224                                    result.add(classDescriptor);
225                                }
226                            }
227                            return result;
228                        }
229                    });
230    
231        }
232    
233        private void detectAndDisconnectLoops() {
234            // Loop detection and disconnection
235            Set<ClassDescriptor> visited = Sets.newHashSet();
236            Set<ClassDescriptor> beingProcessed = Sets.newHashSet();
237            List<ClassDescriptor> currentPath = Lists.newArrayList();
238            for (MutableClassDescriptorLite klass : context.getClassesTopologicalOrder()) {
239                traverseTypeHierarchy(klass, visited, beingProcessed, currentPath);
240            }
241        }
242    
243        private void traverseTypeHierarchy(
244                MutableClassDescriptorLite currentClass,
245                Set<ClassDescriptor> visited,
246                Set<ClassDescriptor> beingProcessed,
247                List<ClassDescriptor> currentPath
248        ) {
249            if (!visited.add(currentClass)) {
250                if (beingProcessed.contains(currentClass)) {
251                    markCycleErrors(currentPath, currentClass);
252                    assert !currentPath.isEmpty() : "Cycle cannot be found on an empty currentPath";
253                    ClassDescriptor subclassOfCurrent = currentPath.get(currentPath.size() - 1);
254                    assert subclassOfCurrent instanceof MutableClassDescriptor;
255                    // Disconnect the loop
256                    for (Iterator<JetType> iterator = ((MutableClassDescriptor) subclassOfCurrent).getSupertypes().iterator();
257                         iterator.hasNext(); ) {
258                        JetType type = iterator.next();
259                        if (type.getConstructor() == currentClass.getTypeConstructor()) {
260                            iterator.remove();
261                            break;
262                        }
263                    }
264                }
265                return;
266            }
267    
268            beingProcessed.add(currentClass);
269            currentPath.add(currentClass);
270            for (JetType supertype : Lists.newArrayList(currentClass.getSupertypes())) {
271                DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
272                if (declarationDescriptor instanceof MutableClassDescriptor) {
273                    MutableClassDescriptor mutableClassDescriptor = (MutableClassDescriptor) declarationDescriptor;
274                    traverseTypeHierarchy(mutableClassDescriptor, visited, beingProcessed, currentPath);
275                }
276            }
277            beingProcessed.remove(currentClass);
278            currentPath.remove(currentPath.size() - 1);
279        }
280    
281        private void markCycleErrors(List<ClassDescriptor> currentPath, @NotNull ClassDescriptor current) {
282            int size = currentPath.size();
283            for (int i = size - 1; i >= 0; i--) {
284                ClassDescriptor classDescriptor = currentPath.get(i);
285    
286                ClassDescriptor superclass = (i < size - 1) ? currentPath.get(i + 1) : current;
287                PsiElement psiElement = BindingContextUtils.classDescriptorToDeclaration(trace.getBindingContext(), classDescriptor);
288    
289                PsiElement elementToMark = null;
290                if (psiElement instanceof JetClassOrObject) {
291                    JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
292                    for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
293                        JetTypeReference typeReference = delegationSpecifier.getTypeReference();
294                        if (typeReference == null) continue;
295                        JetType supertype = trace.get(TYPE, typeReference);
296                        if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
297                            elementToMark = typeReference;
298                        }
299                    }
300                }
301                if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
302                    PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
303                    PsiElement nameIdentifier = namedElement.getNameIdentifier();
304                    if (nameIdentifier != null) {
305                        elementToMark = nameIdentifier;
306                    }
307                }
308                if (elementToMark != null) {
309                    trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
310                }
311    
312                if (classDescriptor == current) {
313                    // Beginning of cycle is found
314                    break;
315                }
316            }
317        }
318    
319        private void checkSupertypesForConsistency() {
320            for (MutableClassDescriptorLite mutableClassDescriptor : context.getClassesTopologicalOrder()) {
321                Multimap<TypeConstructor, TypeProjection> multimap = SubstitutionUtils
322                        .buildDeepSubstitutionMultimap(mutableClassDescriptor.getDefaultType());
323                for (Map.Entry<TypeConstructor, Collection<TypeProjection>> entry : multimap.asMap().entrySet()) {
324                    Collection<TypeProjection> projections = entry.getValue();
325                    if (projections.size() > 1) {
326                        TypeConstructor typeConstructor = entry.getKey();
327                        DeclarationDescriptor declarationDescriptor = typeConstructor.getDeclarationDescriptor();
328                        assert declarationDescriptor instanceof TypeParameterDescriptor : declarationDescriptor;
329                        TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) declarationDescriptor;
330    
331                        // Immediate arguments of supertypes cannot be projected
332                        Set<JetType> conflictingTypes = Sets.newLinkedHashSet();
333                        for (TypeProjection projection : projections) {
334                            conflictingTypes.add(projection.getType());
335                        }
336                        switch (typeParameterDescriptor.getVariance()) {
337                            case INVARIANT:
338                                // Leave conflicting types as is
339                                break;
340                            case IN_VARIANCE:
341                                // Filter out those who have supertypes in this set (common supertype)
342                                Filter.REMOVE_IF_SUPERTYPE_IN_THE_SET.proceed(conflictingTypes);
343                                break;
344                            case OUT_VARIANCE:
345                                // Filter out those who have subtypes in this set (common subtype)
346                                Filter.REMOVE_IF_SUBTYPE_IN_THE_SET.proceed(conflictingTypes);
347                                break;
348                        }
349    
350                        if (conflictingTypes.size() > 1) {
351                            DeclarationDescriptor containingDeclaration = typeParameterDescriptor.getContainingDeclaration();
352                            assert containingDeclaration instanceof ClassDescriptor : containingDeclaration;
353                            JetClassOrObject psiElement = (JetClassOrObject) BindingContextUtils
354                                    .classDescriptorToDeclaration(trace.getBindingContext(), mutableClassDescriptor);
355                            JetDelegationSpecifierList delegationSpecifierList = psiElement.getDelegationSpecifierList();
356                            assert delegationSpecifierList != null;
357                            //                        trace.getErrorHandler().genericError(delegationSpecifierList.getNode(), "Type parameter " + typeParameterDescriptor.getName() + " of " + containingDeclaration.getName() + " has inconsistent values: " + conflictingTypes);
358                            trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES
359                                                 .on(delegationSpecifierList, typeParameterDescriptor, (ClassDescriptor) containingDeclaration,
360                                                     conflictingTypes));
361                        }
362                    }
363                }
364            }
365        }
366    
367        private enum Filter {
368            REMOVE_IF_SUBTYPE_IN_THE_SET {
369                @Override
370                public boolean removeNeeded(JetType subject, JetType other) {
371                    return JetTypeChecker.INSTANCE.isSubtypeOf(other, subject);
372                }
373            },
374            REMOVE_IF_SUPERTYPE_IN_THE_SET {
375                @Override
376                public boolean removeNeeded(JetType subject, JetType other) {
377                    return JetTypeChecker.INSTANCE.isSubtypeOf(subject, other);
378                }
379            };
380    
381            private void proceed(Set<JetType> conflictingTypes) {
382                for (Iterator<JetType> iterator = conflictingTypes.iterator(); iterator.hasNext(); ) {
383                    JetType type = iterator.next();
384                    for (JetType otherType : conflictingTypes) {
385                        boolean subtypeOf = removeNeeded(type, otherType);
386                        if (type != otherType && subtypeOf) {
387                            iterator.remove();
388                            break;
389                        }
390                    }
391                }
392            }
393    
394            public abstract boolean removeNeeded(JetType subject, JetType other);
395        }
396    
397        private void checkTypesInClassHeaders() {
398            for (Map.Entry<JetClass, MutableClassDescriptor> entry : context.getClasses().entrySet()) {
399                JetClass jetClass = entry.getKey();
400    
401                for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
402                    JetTypeReference typeReference = delegationSpecifier.getTypeReference();
403                    if (typeReference != null) {
404                        JetType type = trace.getBindingContext().get(TYPE, typeReference);
405                        if (type != null) {
406                            descriptorResolver.checkBounds(typeReference, type, trace);
407                        }
408                    }
409                }
410    
411                for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
412                    JetTypeReference extendsBound = jetTypeParameter.getExtendsBound();
413                    if (extendsBound != null) {
414                        JetType type = trace.getBindingContext().get(TYPE, extendsBound);
415                        if (type != null) {
416                            descriptorResolver.checkBounds(extendsBound, type, trace);
417                        }
418                    }
419                }
420    
421                for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
422                    JetTypeReference extendsBound = constraint.getBoundTypeReference();
423                    if (extendsBound != null) {
424                        JetType type = trace.getBindingContext().get(TYPE, extendsBound);
425                        if (type != null) {
426                            descriptorResolver.checkBounds(extendsBound, type, trace);
427                        }
428                    }
429                }
430            }
431        }
432    
433        private class ClassifierCollector extends JetVisitorVoid {
434            private final JetScope outerScope;
435            private final NamespaceLikeBuilder owner;
436            private final Collection<JetDeclarationContainer> forDeferredResolve;
437    
438            public ClassifierCollector(@NotNull JetScope outerScope,
439                    @NotNull NamespaceLikeBuilder owner,
440                    @NotNull Collection<JetDeclarationContainer> forDeferredResolve
441            ) {
442                this.outerScope = outerScope;
443                this.owner = owner;
444                this.forDeferredResolve = forDeferredResolve;
445            }
446    
447            @Override
448            public void visitJetFile(JetFile file) {
449                NamespaceDescriptorImpl namespaceDescriptor = namespaceFactory.createNamespaceDescriptorPathIfNeeded(
450                        file, outerScope, RedeclarationHandler.DO_NOTHING);
451                context.getNamespaceDescriptors().put(file, namespaceDescriptor);
452    
453                WriteThroughScope namespaceScope = new WriteThroughScope(outerScope, namespaceDescriptor.getMemberScope(),
454                                                                         new TraceBasedRedeclarationHandler(trace), "namespace");
455                namespaceScope.changeLockLevel(WritableScope.LockLevel.BOTH);
456                context.getNamespaceScopes().put(file, namespaceScope);
457    
458                if (file.isScript()) {
459                    scriptHeaderResolver.processScriptHierarchy(file.getScript(), namespaceScope);
460                }
461    
462                prepareForDeferredCall(namespaceScope, namespaceDescriptor, file);
463            }
464    
465            @Override
466            public void visitClass(JetClass klass) {
467                MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
468    
469                owner.addClassifierDescriptor(mutableClassDescriptor);
470            }
471    
472            @Override
473            public void visitObjectDeclaration(JetObjectDeclaration declaration) {
474                MutableClassDescriptor objectDescriptor =
475                        createClassDescriptorForObject(declaration, owner, outerScope, JetPsiUtil.safeName(declaration.getName()),
476                                                       ClassKind.OBJECT);
477                owner.addObjectDescriptor(objectDescriptor);
478                trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(declaration), objectDescriptor);
479            }
480    
481            @Override
482            public void visitEnumEntry(JetEnumEntry enumEntry) {
483                // TODO: Bad casting
484                MutableClassDescriptorLite ownerClassDescriptor = (MutableClassDescriptorLite) owner.getOwnerForChildren();
485                MutableClassDescriptorLite classObjectDescriptor = ownerClassDescriptor.getClassObjectDescriptor();
486    
487                assert classObjectDescriptor != null : enumEntry.getParent().getText();
488                createClassDescriptorForEnumEntry(enumEntry, classObjectDescriptor);
489            }
490    
491            @Override
492            public void visitTypedef(JetTypedef typedef) {
493                trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
494            }
495    
496            @Override
497            public void visitClassObject(JetClassObject classObject) {
498                JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
499                if (objectDeclaration != null) {
500                    Name classObjectName = getClassObjectName(owner.getOwnerForChildren().getName());
501    
502                    MutableClassDescriptor classObjectDescriptor = createClassDescriptorForObject(
503                            objectDeclaration, owner, outerScope,
504                            classObjectName, ClassKind.CLASS_OBJECT);
505    
506                    NamespaceLikeBuilder.ClassObjectStatus status = owner.setClassObjectDescriptor(classObjectDescriptor);
507                    switch (status) {
508                        case DUPLICATE:
509                            trace.report(MANY_CLASS_OBJECTS.on(classObject));
510                            break;
511                        case NOT_ALLOWED:
512                            trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
513                            break;
514                        case OK:
515                            // Everything is OK so no errors to trace.
516                            break;
517                    }
518                }
519            }
520    
521            private void createClassObjectForEnumClass(JetClass klass, MutableClassDescriptor mutableClassDescriptor) {
522                if (mutableClassDescriptor.getKind() == ClassKind.ENUM_CLASS) {
523                    MutableClassDescriptor classObjectDescriptor =
524                            createClassObjectDescriptor(mutableClassDescriptor, resolveVisibilityFromModifiers(klass));
525                    mutableClassDescriptor.getBuilder().setClassObjectDescriptor(classObjectDescriptor);
526                    classObjectDescriptor.getBuilder().addFunctionDescriptor(
527                            DescriptorResolver.createEnumClassObjectValuesMethod(classObjectDescriptor, trace));
528                    classObjectDescriptor.getBuilder().addFunctionDescriptor(
529                            DescriptorResolver.createEnumClassObjectValueOfMethod(classObjectDescriptor, trace));
530                }
531            }
532    
533            @NotNull
534            private MutableClassDescriptor createClassObjectDescriptor(
535                    @NotNull ClassDescriptor classDescriptor,
536                    @NotNull Visibility visibility
537            ) {
538                MutableClassDescriptor classObjectDescriptor = new MutableClassDescriptor(
539                        classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false, getClassObjectName(classDescriptor.getName()));
540                classObjectDescriptor.setModality(Modality.FINAL);
541                classObjectDescriptor.setVisibility(visibility);
542                classObjectDescriptor.setTypeParameterDescriptors(new ArrayList<TypeParameterDescriptor>(0));
543                classObjectDescriptor.createTypeConstructor();
544                ConstructorDescriptorImpl primaryConstructorForObject = createPrimaryConstructorForObject(null, classObjectDescriptor);
545                primaryConstructorForObject.setReturnType(classObjectDescriptor.getDefaultType());
546                return classObjectDescriptor;
547            }
548    
549            @NotNull
550            private MutableClassDescriptor createClassDescriptorForClass(
551                    @NotNull JetClass klass,
552                    @NotNull DeclarationDescriptor containingDeclaration
553            ) {
554                ClassKind kind = getClassKind(klass);
555                // Kind check is needed in order to not consider enums as inner in any case
556                // (otherwise it would be impossible to create a class object in the enum)
557                boolean isInner = kind == ClassKind.CLASS && klass.isInner();
558                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
559                        containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName()));
560                context.getClasses().put(klass, mutableClassDescriptor);
561                trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(klass), mutableClassDescriptor);
562    
563                createClassObjectForEnumClass(klass, mutableClassDescriptor);
564    
565                JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
566    
567                prepareForDeferredCall(classScope, mutableClassDescriptor, klass);
568    
569                return mutableClassDescriptor;
570            }
571    
572            @NotNull
573            private MutableClassDescriptor createClassDescriptorForObject(
574                    @NotNull JetObjectDeclaration declaration, @NotNull NamespaceLikeBuilder owner,
575                    @NotNull JetScope scope, @NotNull Name name, @NotNull ClassKind kind
576            ) {
577                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
578                        owner.getOwnerForChildren(), scope, kind, false, name);
579    
580                context.getObjects().put(declaration, mutableClassDescriptor);
581    
582                JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
583    
584                prepareForDeferredCall(classScope, mutableClassDescriptor, declaration);
585    
586                createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
587                trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
588                return mutableClassDescriptor;
589            }
590    
591            private MutableClassDescriptor createClassDescriptorForEnumEntry(
592                    @NotNull JetEnumEntry declaration,
593                    @NotNull MutableClassDescriptorLite classObjectDescriptor
594            ) {
595                NamespaceLikeBuilder owner = classObjectDescriptor.getBuilder();
596                MutableClassDescriptor mutableClassObjectDescriptor = (MutableClassDescriptor) classObjectDescriptor;
597    
598                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
599                        owner.getOwnerForChildren(), mutableClassObjectDescriptor.getScopeForMemberResolution(), ClassKind.ENUM_ENTRY,
600                        false, JetPsiUtil.safeName(declaration.getName()));
601                context.getClasses().put(declaration, mutableClassDescriptor);
602    
603                prepareForDeferredCall(mutableClassDescriptor.getScopeForMemberResolution(), mutableClassDescriptor, declaration);
604    
605                // ??? - is enum entry object?
606                createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
607                owner.addObjectDescriptor(mutableClassDescriptor);
608                trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
609                return mutableClassDescriptor;
610            }
611    
612            private ConstructorDescriptorImpl createPrimaryConstructorForObject(
613                    @Nullable PsiElement object,
614                    MutableClassDescriptor mutableClassDescriptor
615            ) {
616                ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
617                        .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
618                mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
619                return constructorDescriptor;
620            }
621    
622            private void prepareForDeferredCall(
623                    @NotNull JetScope outerScope,
624                    @NotNull DeclarationDescriptor descriptorForDeferredResolve,
625                    @NotNull JetDeclarationContainer container
626            ) {
627                forDeferredResolve.add(container);
628                context.normalScope.put(container, outerScope);
629                context.forDeferredResolver.put(container, descriptorForDeferredResolve);
630            }
631        }
632    }