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