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