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.ModifiersChecker.getDefaultClassVisibility;
049    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
050    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
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 (JetClass jetClass : context.getClasses().keySet()) {
399                for (JetDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
400                    checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
401                }
402    
403                for (JetTypeParameter jetTypeParameter : jetClass.getTypeParameters()) {
404                    checkBoundsForTypeInClassHeader(jetTypeParameter.getExtendsBound());
405                }
406    
407                for (JetTypeConstraint constraint : jetClass.getTypeConstraints()) {
408                    checkBoundsForTypeInClassHeader(constraint.getBoundTypeReference());
409                }
410            }
411    
412            for (JetObjectDeclaration object : context.getObjects().keySet()) {
413                for (JetDelegationSpecifier delegationSpecifier : object.getDelegationSpecifiers()) {
414                    checkBoundsForTypeInClassHeader(delegationSpecifier.getTypeReference());
415                }
416            }
417        }
418    
419        private void checkBoundsForTypeInClassHeader(@Nullable JetTypeReference typeReference) {
420            if (typeReference != null) {
421                JetType type = trace.getBindingContext().get(TYPE, typeReference);
422                if (type != null) {
423                    DescriptorResolver.checkBounds(typeReference, type, trace);
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(@NotNull 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 in file " + file.getName());
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(@NotNull JetClass klass) {
462                MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
463    
464                owner.addClassifierDescriptor(mutableClassDescriptor);
465            }
466    
467            @Override
468            public void visitObjectDeclaration(@NotNull 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(@NotNull 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(@NotNull JetTypedef typedef) {
488                trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
489            }
490    
491            @Override
492            public void visitClassObject(@NotNull 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(@NotNull MutableClassDescriptor mutableClassDescriptor) {
517                if (mutableClassDescriptor.getKind() == ClassKind.ENUM_CLASS) {
518                    MutableClassDescriptor classObject = createSyntheticClassObject(mutableClassDescriptor);
519                    mutableClassDescriptor.getBuilder().setClassObjectDescriptor(classObject);
520                    classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValuesMethod(classObject, trace));
521                    classObject.getBuilder().addFunctionDescriptor(DescriptorResolver.createEnumClassObjectValueOfMethod(classObject, trace));
522                }
523            }
524    
525            @NotNull
526            private MutableClassDescriptor createSyntheticClassObject(@NotNull ClassDescriptor classDescriptor) {
527                MutableClassDescriptor classObject = new MutableClassDescriptor(classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false,
528                                                                                getClassObjectName(classDescriptor.getName()));
529                classObject.setModality(Modality.FINAL);
530                classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
531                classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
532                createPrimaryConstructorForObject(null, classObject);
533                classObject.createTypeConstructor();
534                return classObject;
535            }
536    
537            @NotNull
538            private MutableClassDescriptor createClassDescriptorForClass(
539                    @NotNull JetClass klass,
540                    @NotNull DeclarationDescriptor containingDeclaration
541            ) {
542                ClassKind kind = getClassKind(klass);
543                // Kind check is needed in order to not consider enums as inner in any case
544                // (otherwise it would be impossible to create a class object in the enum)
545                boolean isInner = kind == ClassKind.CLASS && klass.isInner();
546                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
547                        containingDeclaration, outerScope, kind, isInner, JetPsiUtil.safeName(klass.getName()));
548                context.getClasses().put(klass, mutableClassDescriptor);
549                trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetPsiUtil.getFQName(klass), mutableClassDescriptor);
550    
551                createClassObjectForEnumClass(mutableClassDescriptor);
552    
553                JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
554    
555                prepareForDeferredCall(classScope, mutableClassDescriptor, klass);
556    
557                return mutableClassDescriptor;
558            }
559    
560            @NotNull
561            private MutableClassDescriptor createClassDescriptorForObject(
562                    @NotNull JetObjectDeclaration declaration, @NotNull NamespaceLikeBuilder owner,
563                    @NotNull JetScope scope, @NotNull Name name, @NotNull ClassKind kind
564            ) {
565                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
566                        owner.getOwnerForChildren(), scope, kind, false, name);
567    
568                context.getObjects().put(declaration, mutableClassDescriptor);
569    
570                JetScope classScope = mutableClassDescriptor.getScopeForMemberResolution();
571    
572                prepareForDeferredCall(classScope, mutableClassDescriptor, declaration);
573    
574                createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
575                trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
576                return mutableClassDescriptor;
577            }
578    
579            private MutableClassDescriptor createClassDescriptorForEnumEntry(
580                    @NotNull JetEnumEntry declaration,
581                    @NotNull MutableClassDescriptorLite classObjectDescriptor
582            ) {
583                NamespaceLikeBuilder owner = classObjectDescriptor.getBuilder();
584                MutableClassDescriptor mutableClassObjectDescriptor = (MutableClassDescriptor) classObjectDescriptor;
585    
586                MutableClassDescriptor mutableClassDescriptor = new MutableClassDescriptor(
587                        owner.getOwnerForChildren(), mutableClassObjectDescriptor.getScopeForMemberResolution(), ClassKind.ENUM_ENTRY,
588                        false, JetPsiUtil.safeName(declaration.getName()));
589                context.getClasses().put(declaration, mutableClassDescriptor);
590    
591                prepareForDeferredCall(mutableClassDescriptor.getScopeForMemberResolution(), mutableClassDescriptor, declaration);
592    
593                // ??? - is enum entry object?
594                createPrimaryConstructorForObject(declaration, mutableClassDescriptor);
595                owner.addObjectDescriptor(mutableClassDescriptor);
596                trace.record(BindingContext.CLASS, declaration, mutableClassDescriptor);
597                return mutableClassDescriptor;
598            }
599    
600            private ConstructorDescriptorImpl createPrimaryConstructorForObject(
601                    @Nullable PsiElement object,
602                    MutableClassDescriptor mutableClassDescriptor
603            ) {
604                ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
605                        .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
606                mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
607                return constructorDescriptor;
608            }
609    
610            private void prepareForDeferredCall(
611                    @NotNull JetScope outerScope,
612                    @NotNull DeclarationDescriptor descriptorForDeferredResolve,
613                    @NotNull JetDeclarationContainer container
614            ) {
615                forDeferredResolve.add(container);
616                context.normalScope.put(container, outerScope);
617                context.forDeferredResolver.put(container, descriptorForDeferredResolve);
618            }
619        }
620    }