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