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.intellij.psi.PsiElement;
020    import com.intellij.psi.PsiNameIdentifierOwner;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.annotations.Nullable;
023    import org.jetbrains.jet.lang.descriptors.*;
024    import org.jetbrains.jet.lang.descriptors.impl.ConstructorDescriptorImpl;
025    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
026    import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
027    import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder;
028    import org.jetbrains.jet.lang.psi.*;
029    import org.jetbrains.jet.lang.resolve.name.Name;
030    import org.jetbrains.jet.lang.resolve.name.SpecialNames;
031    import org.jetbrains.jet.lang.resolve.scopes.ChainedScope;
032    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
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.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.FQNAME_TO_CLASS_DESCRIPTOR;
043    import static org.jetbrains.jet.lang.resolve.BindingContext.TYPE;
044    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
045    import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isObject;
046    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.getDefaultClassVisibility;
047    import static org.jetbrains.jet.lang.resolve.ModifiersChecker.resolveVisibilityFromModifiers;
048    import static org.jetbrains.jet.lang.resolve.name.SpecialNames.getClassObjectName;
049    import static org.jetbrains.jet.lang.resolve.source.SourcePackage.toSourceElement;
050    
051    public class TypeHierarchyResolver {
052        private static final DFS.Neighbors<ClassDescriptor> CLASS_INHERITANCE_EDGES = new DFS.Neighbors<ClassDescriptor>() {
053            @NotNull
054            @Override
055            public Iterable<ClassDescriptor> getNeighbors(ClassDescriptor current) {
056                List<ClassDescriptor> result = new ArrayList<ClassDescriptor>();
057                for (JetType supertype : current.getDefaultType().getConstructor().getSupertypes()) {
058                    DeclarationDescriptor descriptor = supertype.getConstructor().getDeclarationDescriptor();
059                    if (descriptor instanceof ClassDescriptor) {
060                        result.add((ClassDescriptor) descriptor);
061                    }
062                }
063                DeclarationDescriptor container = current.getContainingDeclaration();
064                if (container instanceof ClassDescriptor) {
065                    result.add((ClassDescriptor) container);
066                }
067                return result;
068            }
069        };
070    
071        @NotNull
072        private ImportsResolver importsResolver;
073        @NotNull
074        private DescriptorResolver descriptorResolver;
075        @NotNull
076        private ScriptHeaderResolver scriptHeaderResolver;
077        @NotNull
078        private MutablePackageFragmentProvider packageFragmentProvider;
079        @NotNull
080        private BindingTrace trace;
081    
082        @Inject
083        public void setImportsResolver(@NotNull ImportsResolver importsResolver) {
084            this.importsResolver = importsResolver;
085        }
086    
087        @Inject
088        public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
089            this.descriptorResolver = descriptorResolver;
090        }
091    
092        // SCRIPT: inject script header resolver
093        @Inject
094        public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
095            this.scriptHeaderResolver = scriptHeaderResolver;
096        }
097    
098        @Inject
099        public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
100            this.packageFragmentProvider = packageFragmentProvider;
101        }
102    
103        @Inject
104        public void setTrace(@NotNull BindingTrace trace) {
105            this.trace = trace;
106        }
107    
108        public void process(
109                @NotNull TopDownAnalysisContext c,
110                @NotNull JetScope outerScope,
111                @NotNull PackageLikeBuilder owner,
112                @NotNull Collection<? extends PsiElement> declarations
113        ) {
114    
115            {
116                // TODO: Very temp code - main goal is to remove recursion from collectPackageFragmentsAndClassifiers
117                Queue<JetDeclarationContainer> forDeferredResolve = new LinkedList<JetDeclarationContainer>();
118                forDeferredResolve.addAll(collectPackageFragmentsAndClassifiers(c, outerScope, owner, declarations));
119    
120                while (!forDeferredResolve.isEmpty()) {
121                    JetDeclarationContainer declarationContainer = forDeferredResolve.poll();
122                    assert declarationContainer != null;
123    
124                    DeclarationDescriptor descriptorForDeferredResolve = c.forDeferredResolver.get(declarationContainer);
125                    JetScope scope = c.normalScope.get(declarationContainer);
126    
127                    // Even more temp code
128                    if (descriptorForDeferredResolve instanceof MutableClassDescriptor) {
129                        forDeferredResolve.addAll(
130                                collectPackageFragmentsAndClassifiers(
131                                        c,
132                                        scope,
133                                        ((MutableClassDescriptor) descriptorForDeferredResolve).getBuilder(),
134                                        declarationContainer.getDeclarations()));
135                    }
136                    else if (descriptorForDeferredResolve instanceof MutablePackageFragmentDescriptor) {
137                        forDeferredResolve.addAll(
138                                collectPackageFragmentsAndClassifiers(
139                                        c,
140                                        scope,
141                                        ((MutablePackageFragmentDescriptor) descriptorForDeferredResolve).getBuilder(),
142                                        declarationContainer.getDeclarations()));
143                    }
144                    else {
145                        assert false;
146                    }
147                }
148            }
149    
150            importsResolver.processTypeImports(c);
151    
152            createTypeConstructors(c); // create type constructors for classes and generic parameters, supertypes are not filled in
153            resolveTypesInClassHeaders(c); // Generic bounds and types in supertype lists (no expressions or constructor resolution)
154    
155            c.setClassesTopologicalOrder(topologicallySortClassesAndObjects(c));
156    
157            // Detect and disconnect all loops in the hierarchy
158            detectAndDisconnectLoops(c);
159        }
160    
161        @NotNull
162        private Collection<JetDeclarationContainer> collectPackageFragmentsAndClassifiers(
163                @NotNull TopDownAnalysisContext c,
164                @NotNull JetScope outerScope,
165                @NotNull PackageLikeBuilder owner,
166                @NotNull Iterable<? extends PsiElement> declarations
167        ) {
168            Collection<JetDeclarationContainer> forDeferredResolve = new ArrayList<JetDeclarationContainer>();
169    
170            ClassifierCollector collector = new ClassifierCollector(c, outerScope, owner, forDeferredResolve);
171    
172            for (PsiElement declaration : declarations) {
173                declaration.accept(collector);
174            }
175    
176            return forDeferredResolve;
177        }
178    
179    
180        @NotNull
181        private static ClassKind getClassKind(@NotNull JetClass jetClass) {
182            if (jetClass.isTrait()) return ClassKind.TRAIT;
183            if (jetClass.isAnnotation()) return ClassKind.ANNOTATION_CLASS;
184            if (jetClass.isEnum()) return ClassKind.ENUM_CLASS;
185            return ClassKind.CLASS;
186        }
187    
188        private void createTypeConstructors(@NotNull TopDownAnalysisContext c) {
189            for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
190                JetClassOrObject classOrObject = entry.getKey();
191                MutableClassDescriptor descriptor = (MutableClassDescriptor) entry.getValue();
192                if (classOrObject instanceof JetClass) {
193                    descriptorResolver.resolveMutableClassDescriptor(
194                            c.getTopDownAnalysisParameters(),
195                            (JetClass) classOrObject, descriptor, trace);
196                }
197                else if (classOrObject instanceof JetObjectDeclaration) {
198                    descriptor.setModality(Modality.FINAL);
199                    descriptor.setVisibility(resolveVisibilityFromModifiers(classOrObject, getDefaultClassVisibility(descriptor)));
200                    descriptor.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
201                }
202    
203                descriptor.createTypeConstructor();
204    
205                ClassKind kind = descriptor.getKind();
206                if (kind == ClassKind.ENUM_ENTRY || kind == ClassKind.OBJECT) {
207                    MutableClassDescriptor classObject = descriptor.getClassObjectDescriptor();
208                    assert classObject != null : "Enum entries and named objects should have class objects: " + classOrObject.getText();
209    
210                    // This is a clever hack: each enum entry and object declaration (i.e. singleton) has a synthetic class object.
211                    // We make this class object inherit from the singleton here, thus allowing to use the singleton's class object where
212                    // the instance of the singleton is applicable. Effectively all members of the singleton would be present in its class
213                    // object as fake overrides, so you can access them via standard class object notation: ObjectName.memberName()
214                    classObject.setSupertypes(Collections.singleton(descriptor.getDefaultType()));
215    
216                    classObject.createTypeConstructor();
217                }
218            }
219        }
220    
221        private void resolveTypesInClassHeaders(@NotNull TopDownAnalysisContext c) {
222            for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
223                JetClassOrObject classOrObject = entry.getKey();
224                if (classOrObject instanceof JetClass) {
225                    ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
226                    //noinspection unchecked
227                    descriptorResolver.resolveGenericBounds((JetClass) classOrObject, descriptor, descriptor.getScopeForClassHeaderResolution(),
228                                                            (List) descriptor.getTypeConstructor().getParameters(), trace);
229                }
230            }
231    
232            for (Map.Entry<JetClassOrObject, ClassDescriptorWithResolutionScopes> entry : c.getDeclaredClasses().entrySet()) {
233                descriptorResolver.resolveSupertypesForMutableClassDescriptor(entry.getKey(), (MutableClassDescriptor) entry.getValue(), trace);
234            }
235        }
236    
237        @NotNull
238        @SuppressWarnings("unchecked")
239        private static List<MutableClassDescriptor> topologicallySortClassesAndObjects(@NotNull TopDownAnalysisContext c) {
240            Collection<ClassDescriptor> sourceClasses = (Collection) c.getAllClasses();
241            List<ClassDescriptor> allClassesOrdered = DFS.topologicalOrder(sourceClasses, CLASS_INHERITANCE_EDGES);
242            allClassesOrdered.retainAll(sourceClasses);
243            return (List) allClassesOrdered;
244        }
245    
246        private void detectAndDisconnectLoops(@NotNull TopDownAnalysisContext c) {
247            List<Runnable> tasks = new ArrayList<Runnable>();
248            for (final MutableClassDescriptor klass : c.getClassesTopologicalOrder()) {
249                for (final JetType supertype : klass.getSupertypes()) {
250                    ClassifierDescriptor supertypeDescriptor = supertype.getConstructor().getDeclarationDescriptor();
251                    if (supertypeDescriptor instanceof ClassDescriptor) {
252                        ClassDescriptor superclass = (ClassDescriptor) supertypeDescriptor;
253                        if (isReachable(superclass, klass, new HashSet<ClassDescriptor>())) {
254                            tasks.add(new Runnable() {
255                                @Override
256                                public void run() {
257                                    klass.getSupertypes().remove(supertype);
258                                }
259                            });
260                            reportCyclicInheritanceHierarchyError(trace, klass, superclass);
261                        }
262                    }
263                }
264            }
265    
266            for (Runnable task : tasks) {
267                task.run();
268            }
269        }
270    
271        // TODO: use DFS and copy to LazyClassTypeConstructor.isReachable
272        private static boolean isReachable(
273                @NotNull ClassDescriptor from,
274                @NotNull MutableClassDescriptor to,
275                @NotNull Set<ClassDescriptor> visited
276        ) {
277            if (!visited.add(from)) return false;
278            for (ClassDescriptor superclass : CLASS_INHERITANCE_EDGES.getNeighbors(from)) {
279                if (superclass == to || isReachable(superclass, to, visited)) return true;
280            }
281            return false;
282        }
283    
284        public static void reportCyclicInheritanceHierarchyError(
285                @NotNull BindingTrace trace,
286                @NotNull ClassDescriptor classDescriptor,
287                @NotNull ClassDescriptor superclass
288        ) {
289            PsiElement psiElement = DescriptorToSourceUtils.classDescriptorToDeclaration(classDescriptor);
290    
291            PsiElement elementToMark = null;
292            if (psiElement instanceof JetClassOrObject) {
293                JetClassOrObject classOrObject = (JetClassOrObject) psiElement;
294                for (JetDelegationSpecifier delegationSpecifier : classOrObject.getDelegationSpecifiers()) {
295                    JetTypeReference typeReference = delegationSpecifier.getTypeReference();
296                    if (typeReference == null) continue;
297                    JetType supertype = trace.get(TYPE, typeReference);
298                    if (supertype != null && supertype.getConstructor() == superclass.getTypeConstructor()) {
299                        elementToMark = typeReference;
300                    }
301                }
302            }
303            if (elementToMark == null && psiElement instanceof PsiNameIdentifierOwner) {
304                PsiNameIdentifierOwner namedElement = (PsiNameIdentifierOwner) psiElement;
305                PsiElement nameIdentifier = namedElement.getNameIdentifier();
306                if (nameIdentifier != null) {
307                    elementToMark = nameIdentifier;
308                }
309            }
310            if (elementToMark != null) {
311                trace.report(CYCLIC_INHERITANCE_HIERARCHY.on(elementToMark));
312            }
313        }
314    
315        private class ClassifierCollector extends JetVisitorVoid {
316            private final TopDownAnalysisContext c;
317            private final JetScope outerScope;
318            private final PackageLikeBuilder owner;
319            private final Collection<JetDeclarationContainer> forDeferredResolve;
320    
321            public ClassifierCollector(
322                    @NotNull TopDownAnalysisContext c,
323                    @NotNull JetScope outerScope,
324                    @NotNull PackageLikeBuilder owner,
325                    @NotNull Collection<JetDeclarationContainer> forDeferredResolve
326            ) {
327                this.c = c;
328                this.outerScope = outerScope;
329                this.owner = owner;
330                this.forDeferredResolve = forDeferredResolve;
331            }
332    
333            @Override
334            public void visitJetFile(@NotNull JetFile file) {
335                MutablePackageFragmentDescriptor packageFragment = getOrCreatePackageFragmentForFile(file);
336                c.getPackageFragments().put(file, packageFragment);
337                c.addFile(file);
338    
339                PackageViewDescriptor packageView = packageFragment.getContainingDeclaration().getPackage(packageFragment.getFqName());
340                ChainedScope rootPlusPackageScope = new ChainedScope(packageView, "Root scope for " + file, packageView.getMemberScope(), outerScope);
341                WriteThroughScope packageScope = new WriteThroughScope(rootPlusPackageScope, packageFragment.getMemberScope(),
342                                                                         new TraceBasedRedeclarationHandler(trace), "package in file " + file.getName());
343                packageScope.changeLockLevel(WritableScope.LockLevel.BOTH);
344                c.getFileScopes().put(file, packageScope);
345    
346                if (file.isScript()) {
347                    // SCRIPT: process script hierarchy
348                    scriptHeaderResolver.processScriptHierarchy(c, file.getScript(), packageScope);
349                }
350    
351                prepareForDeferredCall(packageScope, packageFragment, file);
352            }
353    
354            @Override
355            public void visitClass(@NotNull JetClass klass) {
356                MutableClassDescriptor mutableClassDescriptor = createClassDescriptorForClass(klass, owner.getOwnerForChildren());
357    
358                owner.addClassifierDescriptor(mutableClassDescriptor);
359            }
360    
361            @Override
362            public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
363                if (declaration.isObjectLiteral()) {
364                    createClassDescriptorForSingleton(declaration, SpecialNames.NO_NAME_PROVIDED, ClassKind.CLASS);
365                    return;
366                }
367    
368                MutableClassDescriptor descriptor =
369                        createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.OBJECT);
370    
371                owner.addClassifierDescriptor(descriptor);
372                trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(declaration), descriptor);
373    
374                descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObjectForSingleton(descriptor));
375            }
376    
377            @Override
378            public void visitEnumEntry(@NotNull JetEnumEntry declaration) {
379                MutableClassDescriptor descriptor =
380                        createClassDescriptorForSingleton(declaration, JetPsiUtil.safeName(declaration.getName()), ClassKind.ENUM_ENTRY);
381    
382                owner.addClassifierDescriptor(descriptor);
383    
384                descriptor.getBuilder().setClassObjectDescriptor(createSyntheticClassObjectForSingleton(descriptor));
385            }
386    
387            @Override
388            public void visitTypedef(@NotNull JetTypedef typedef) {
389                trace.report(UNSUPPORTED.on(typedef, "TypeHierarchyResolver"));
390            }
391    
392            @Override
393            public void visitClassObject(@NotNull JetClassObject classObject) {
394                JetObjectDeclaration objectDeclaration = classObject.getObjectDeclaration();
395    
396                DeclarationDescriptor container = owner.getOwnerForChildren();
397    
398                MutableClassDescriptor classObjectDescriptor =
399                        createClassDescriptorForSingleton(objectDeclaration, getClassObjectName(container.getName()), ClassKind.CLASS_OBJECT);
400    
401                PackageLikeBuilder.ClassObjectStatus status =
402                        isEnumEntry(container) || isObject(container) || c.getTopDownAnalysisParameters().isDeclaredLocally() ?
403                        PackageLikeBuilder.ClassObjectStatus.NOT_ALLOWED :
404                        owner.setClassObjectDescriptor(classObjectDescriptor);
405    
406                switch (status) {
407                    case DUPLICATE:
408                        trace.report(MANY_CLASS_OBJECTS.on(classObject));
409                        break;
410                    case NOT_ALLOWED:
411                        trace.report(CLASS_OBJECT_NOT_ALLOWED.on(classObject));
412                        break;
413                    case OK:
414                        // Everything is OK so no errors to trace.
415                        break;
416                }
417            }
418    
419            @NotNull
420            private MutablePackageFragmentDescriptor getOrCreatePackageFragmentForFile(@NotNull JetFile file) {
421                JetPackageDirective packageDirective = file.getPackageDirective();
422                assert packageDirective != null : "scripts are not supported";
423    
424                MutablePackageFragmentDescriptor fragment = packageFragmentProvider.getOrCreateFragment(packageDirective.getFqName());
425    
426                ModuleDescriptor module = packageFragmentProvider.getModule();
427                DescriptorResolver.resolvePackageHeader(packageDirective, module, trace);
428                DescriptorResolver.registerFileInPackage(trace, file);
429                trace.record(BindingContext.FILE_TO_PACKAGE_FRAGMENT, file, fragment);
430    
431                return fragment;
432            }
433    
434    
435            @NotNull
436            private MutableClassDescriptor createSyntheticClassObjectForSingleton(@NotNull ClassDescriptor classDescriptor) {
437                MutableClassDescriptor classObject =
438                        new MutableClassDescriptor(classDescriptor, outerScope, ClassKind.CLASS_OBJECT, false,
439                                                   getClassObjectName(classDescriptor.getName()), SourceElement.NO_SOURCE);
440    
441                classObject.setModality(Modality.FINAL);
442                classObject.setVisibility(DescriptorUtils.getSyntheticClassObjectVisibility());
443                classObject.setTypeParameterDescriptors(Collections.<TypeParameterDescriptor>emptyList());
444                createPrimaryConstructorForObject(null, classObject);
445                return classObject;
446            }
447    
448            @NotNull
449            private MutableClassDescriptor createClassDescriptorForClass(
450                    @NotNull JetClass klass,
451                    @NotNull DeclarationDescriptor containingDeclaration
452            ) {
453                MutableClassDescriptor descriptor = new MutableClassDescriptor(
454                        containingDeclaration, outerScope, getClassKind(klass), klass.isInner(), JetPsiUtil.safeName(klass.getName()),
455                        toSourceElement(klass)
456                );
457                c.getDeclaredClasses().put(klass, descriptor);
458                trace.record(FQNAME_TO_CLASS_DESCRIPTOR, JetNamedDeclarationUtil.getUnsafeFQName(klass), descriptor);
459    
460                prepareForDeferredCall(descriptor.getScopeForMemberDeclarationResolution(), descriptor, klass);
461    
462                return descriptor;
463            }
464    
465            @NotNull
466            private MutableClassDescriptor createClassDescriptorForSingleton(
467                    @NotNull JetClassOrObject declaration,
468                    @NotNull Name name,
469                    @NotNull ClassKind kind
470            ) {
471                MutableClassDescriptor descriptor = new MutableClassDescriptor(owner.getOwnerForChildren(), outerScope, kind, false, name,
472                                                                               toSourceElement(declaration));
473    
474                prepareForDeferredCall(descriptor.getScopeForMemberDeclarationResolution(), descriptor, declaration);
475    
476                createPrimaryConstructorForObject(declaration, descriptor);
477                trace.record(BindingContext.CLASS, declaration, descriptor);
478    
479                c.getDeclaredClasses().put(declaration, descriptor);
480    
481                return descriptor;
482            }
483    
484            @NotNull
485            private ConstructorDescriptorImpl createPrimaryConstructorForObject(
486                    @Nullable JetClassOrObject object,
487                    @NotNull MutableClassDescriptor mutableClassDescriptor
488            ) {
489                ConstructorDescriptorImpl constructorDescriptor = DescriptorResolver
490                        .createAndRecordPrimaryConstructorForObject(object, mutableClassDescriptor, trace);
491                mutableClassDescriptor.setPrimaryConstructor(constructorDescriptor);
492                return constructorDescriptor;
493            }
494    
495            private void prepareForDeferredCall(
496                    @NotNull JetScope outerScope,
497                    @NotNull DeclarationDescriptor descriptorForDeferredResolve,
498                    @NotNull JetDeclarationContainer container
499            ) {
500                forDeferredResolve.add(container);
501                c.normalScope.put(container, outerScope);
502                c.forDeferredResolver.put(container, descriptorForDeferredResolve);
503            }
504        }
505    }