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