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.base.Predicates;
020    import com.google.common.collect.HashMultimap;
021    import com.google.common.collect.Multimap;
022    import com.google.common.collect.Sets;
023    import com.intellij.psi.PsiElement;
024    import kotlin.Function1;
025    import kotlin.KotlinPackage;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.jet.context.GlobalContext;
029    import org.jetbrains.jet.context.GlobalContextImpl;
030    import org.jetbrains.jet.di.InjectorForLazyResolve;
031    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
032    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
033    import org.jetbrains.jet.lang.descriptors.*;
034    import org.jetbrains.jet.lang.descriptors.impl.*;
035    import org.jetbrains.jet.lang.psi.*;
036    import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
037    import org.jetbrains.jet.lang.resolve.lazy.LazyImportScope;
038    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
039    import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
040    import org.jetbrains.jet.lang.resolve.name.FqName;
041    import org.jetbrains.jet.lang.resolve.name.Name;
042    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
044    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
045    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
046    import org.jetbrains.jet.storage.LockBasedStorageManager;
047    
048    import javax.inject.Inject;
049    import java.util.*;
050    
051    import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_CLASS_OBJECTS;
052    
053    public class TopDownAnalyzer {
054    
055        public static boolean LAZY;
056    
057        static {
058            LAZY = "true".equals(System.getProperty("lazy.tda"));
059        }
060    
061        @NotNull
062        private BindingTrace trace;
063        @NotNull
064        private DeclarationResolver declarationResolver;
065        @NotNull
066        private TypeHierarchyResolver typeHierarchyResolver;
067        @NotNull
068        private OverrideResolver overrideResolver;
069        @NotNull
070        private OverloadResolver overloadResolver;
071        @NotNull
072        private ModuleDescriptor moduleDescriptor;
073        @NotNull
074        private MutablePackageFragmentProvider packageFragmentProvider;
075        @NotNull
076        private BodyResolver bodyResolver;
077        @NotNull
078        private ScriptHeaderResolver scriptHeaderResolver;
079    
080        @Inject
081        public void setTrace(@NotNull BindingTrace trace) {
082            this.trace = trace;
083        }
084    
085        @Inject
086        public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
087            this.declarationResolver = declarationResolver;
088        }
089    
090        @Inject
091        public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
092            this.typeHierarchyResolver = typeHierarchyResolver;
093        }
094    
095        @Inject
096        public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
097            this.overrideResolver = overrideResolver;
098        }
099    
100        @Inject
101        public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
102            this.overloadResolver = overloadResolver;
103        }
104    
105        @Inject
106        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
107            this.moduleDescriptor = moduleDescriptor;
108        }
109    
110        @Inject
111        public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
112            this.packageFragmentProvider = packageFragmentProvider;
113        }
114    
115        @Inject
116        public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
117            this.bodyResolver = bodyResolver;
118        }
119    
120        @Inject
121        public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
122            this.scriptHeaderResolver = scriptHeaderResolver;
123        }
124    
125        public void doProcess(
126                @NotNull final TopDownAnalysisContext c,
127                @NotNull JetScope outerScope,
128                @NotNull PackageLikeBuilder owner,
129                @NotNull Collection<? extends PsiElement> declarations
130        ) {
131    //        c.enableDebugOutput();
132            c.debug("Enter");
133    
134            if (LAZY && !c.getTopDownAnalysisParameters().isDeclaredLocally()) {
135                final ResolveSession resolveSession = new InjectorForLazyResolve(
136                        declarations.iterator().next().getProject(), // TODO
137                        new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
138                        (ModuleDescriptorImpl) moduleDescriptor, // TODO
139                        new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
140                        trace
141                ).getResolveSession();
142    
143                final Multimap<FqName, JetElement> topLevelFqNames = HashMultimap.create();
144    
145                // fill in the context
146                for (PsiElement declaration : declarations) {
147                    declaration.accept(
148                            new JetVisitorVoid() {
149                                private void registerDeclarations(@NotNull List<JetDeclaration> declarations) {
150                                    for (JetDeclaration jetDeclaration : declarations) {
151                                        jetDeclaration.accept(this);
152                                    }
153                                }
154    
155                                private void registerTopLevelFqName(@NotNull JetNamedDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
156                                    if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
157                                        FqName fqName = JetPsiUtil.getFQName(declaration);
158                                        if (fqName != null) {
159                                            topLevelFqNames.put(fqName, declaration);
160                                        }
161                                    }
162                                }
163    
164                                private void registerScope(@Nullable JetDeclaration declaration, @NotNull JetDeclaration anchorForScope) {
165                                    if (declaration == null) return;
166                                    c.registerDeclaringScope(
167                                            declaration,
168                                            resolveSession.getScopeProvider().getResolutionScopeForDeclaration(anchorForScope)
169                                    );
170                                }
171    
172                                @Override
173                                public void visitDeclaration(@NotNull JetDeclaration dcl) {
174                                    throw new IllegalArgumentException("Unsupported declaration: " + dcl + " " + dcl.getText());
175                                }
176    
177                                @Override
178                                public void visitJetFile(@NotNull JetFile file) {
179                                    if (file.isScript()) {
180                                        JetScript script = file.getScript();
181                                        assert script != null;
182                                        scriptHeaderResolver.processScriptHierarchy(c, script, resolveSession.getScopeProvider().getFileScope(file));
183                                    }
184                                    else {
185                                        JetPackageDirective packageDirective = file.getPackageDirective();
186                                        assert packageDirective != null : "No package in a non-script file: " + file;
187    
188                                        c.addFile(file);
189    
190                                        DescriptorResolver.resolvePackageHeader(packageDirective, moduleDescriptor, trace);
191                                        registerDeclarations(file.getDeclarations());
192    
193                                        topLevelFqNames.put(JetPsiUtil.getFQName(file), packageDirective);
194                                    }
195                                    resolveAndCheckImports(file, resolveSession);
196                                }
197    
198                                private void resolveAndCheckImports(@NotNull JetFile file, @NotNull ResolveSession resolveSession) {
199                                   LazyImportScope fileScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(file);
200                                   fileScope.forceResolveAllContents();
201                               }
202    
203                                private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) {
204                                    ClassDescriptorWithResolutionScopes descriptor = ForceResolveUtil.forceResolveAllContents(
205                                            (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject)
206                                    );
207    
208                                    c.getClasses().put(classOrObject, descriptor);
209                                    registerDeclarations(classOrObject.getDeclarations());
210                                    registerTopLevelFqName(classOrObject, descriptor);
211    
212                                    checkManyClassObjects(classOrObject);
213                                }
214    
215                                private void checkManyClassObjects(JetClassOrObject classOrObject) {
216                                    boolean classObjectAlreadyFound = false;
217                                    for (JetDeclaration jetDeclaration : classOrObject.getDeclarations()) {
218                                        jetDeclaration.accept(this);
219    
220                                        if (jetDeclaration instanceof JetClassObject) {
221                                            if (classObjectAlreadyFound) {
222                                                trace.report(MANY_CLASS_OBJECTS.on((JetClassObject) jetDeclaration));
223                                            }
224                                            classObjectAlreadyFound = true;
225                                        }
226                                    }
227                                }
228    
229                                @Override
230                                public void visitClass(@NotNull JetClass klass) {
231                                    visitClassOrObject(klass);
232    
233                                    registerPrimaryConstructorParameters(klass);
234                                }
235    
236                                private void registerPrimaryConstructorParameters(@NotNull JetClass klass) {
237                                    for (JetParameter jetParameter : klass.getPrimaryConstructorParameters()) {
238                                        if (jetParameter.getValOrVarNode() != null) {
239                                            c.getPrimaryConstructorParameterProperties().put(
240                                                    jetParameter,
241                                                    (PropertyDescriptor) resolveSession.resolveToDescriptor(jetParameter)
242                                            );
243                                        }
244                                    }
245                                }
246    
247                                @Override
248                                public void visitClassObject(@NotNull JetClassObject classObject) {
249                                    visitClassOrObject(classObject.getObjectDeclaration());
250                                }
251    
252                                @Override
253                                public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) {
254                                    visitClassOrObject(enumEntry);
255                                }
256    
257                                @Override
258                                public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
259                                    visitClassOrObject(declaration);
260                                }
261    
262                                @Override
263                                public void visitAnonymousInitializer(@NotNull JetClassInitializer initializer) {
264                                    registerScope(initializer, initializer);
265                                }
266    
267                                @Override
268                                public void visitNamedFunction(@NotNull JetNamedFunction function) {
269                                    c.getFunctions().put(
270                                            function,
271                                            ForceResolveUtil.forceResolveAllContents(
272                                                    (SimpleFunctionDescriptor) resolveSession.resolveToDescriptor(function)
273                                            )
274                                    );
275                                    registerScope(function, function);
276                                }
277    
278                                @Override
279                                public void visitProperty(@NotNull JetProperty property) {
280                                    PropertyDescriptor descriptor = ForceResolveUtil.forceResolveAllContents(
281                                            (PropertyDescriptor) resolveSession.resolveToDescriptor(property)
282                                    );
283    
284                                    c.getProperties().put(property, descriptor);
285                                    registerTopLevelFqName(property, descriptor);
286    
287                                    registerScope(property, property);
288                                    registerScope(property.getGetter(), property);
289                                    registerScope(property.getSetter(), property);
290                                }
291                            }
292                    );
293                }
294    
295                declarationResolver.checkRedeclarationsInPackages(resolveSession, topLevelFqNames);
296                declarationResolver.checkRedeclarationsInInnerClassNames(c);
297                overrideResolver.check(c);
298            }
299            else {
300                typeHierarchyResolver.process(c, outerScope, owner, declarations);
301                declarationResolver.process(c);
302                overrideResolver.process(c);
303                lockScopes(c);
304            }
305    
306            overloadResolver.process(c);
307    
308            if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
309                bodyResolver.resolveBodies(c);
310            }
311    
312            c.debug("Exit");
313            c.printDebugOutput(System.out);
314        }
315    
316        private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
317            return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
318                @Nullable
319                @Override
320                public JetFile invoke(PsiElement element) {
321                    return (JetFile) element.getContainingFile();
322                }
323            }));
324        }
325    
326        private void lockScopes(@NotNull TopDownAnalysisContext c) {
327            for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getClasses().values()) {
328                ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
329            }
330            Set<FqName> scriptFqNames = Sets.newHashSet();
331            for (JetFile file : c.getFileScopes().keySet()) {
332                if (file.isScript()) {
333                    scriptFqNames.add(JetPsiUtil.getFQName(file));
334                }
335            }
336            for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
337                // todo: this is hack in favor of REPL
338                if (!scriptFqNames.contains(fragment.getFqName())) {
339                    fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
340                }
341            }
342        }
343    
344        public static void processClassOrObject(
345                @NotNull GlobalContext globalContext,
346                @Nullable final WritableScope scope,
347                @NotNull ExpressionTypingContext context,
348                @NotNull final DeclarationDescriptor containingDeclaration,
349                @NotNull JetClassOrObject object
350        ) {
351            ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<dummy for object>"),
352                                                                             Collections.<ImportPath>emptyList(),
353                                                                             PlatformToKotlinClassMap.EMPTY);
354    
355            TopDownAnalysisParameters topDownAnalysisParameters =
356                    new TopDownAnalysisParameters(
357                            globalContext.getStorageManager(),
358                            globalContext.getExceptionTracker(),
359                            Predicates.equalTo(object.getContainingFile()),
360                            false,
361                            true,
362                            Collections.<AnalyzerScriptParameter>emptyList()
363                    );
364    
365            InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
366                    object.getProject(), topDownAnalysisParameters, context.trace, moduleDescriptor
367            );
368    
369            TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
370            c.setOuterDataFlowInfo(context.dataFlowInfo);
371    
372            injector.getTopDownAnalyzer().doProcess(
373                   c,
374                   context.scope,
375                   new PackageLikeBuilder() {
376    
377                       @NotNull
378                       @Override
379                       public DeclarationDescriptor getOwnerForChildren() {
380                           return containingDeclaration;
381                       }
382    
383                       @Override
384                       public void addClassifierDescriptor(@NotNull MutableClassDescriptorLite classDescriptor) {
385                           if (scope != null) {
386                               scope.addClassifierDescriptor(classDescriptor);
387                           }
388                       }
389    
390                       @Override
391                       public void addFunctionDescriptor(@NotNull SimpleFunctionDescriptor functionDescriptor) {
392                           throw new UnsupportedOperationException();
393                       }
394    
395                       @Override
396                       public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) {
397    
398                       }
399    
400                       @Override
401                       public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptorLite classObjectDescriptor) {
402                           return ClassObjectStatus.NOT_ALLOWED;
403                       }
404                   },
405                   Collections.<PsiElement>singletonList(object)
406            );
407        }
408    
409        @NotNull
410        public TopDownAnalysisContext analyzeFiles(
411                @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
412                @NotNull Collection<JetFile> files
413        ) {
414            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
415    
416            // "depend on" builtins module
417            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
418    
419            // dummy builder is used because "root" is module descriptor,
420            // packages added to module explicitly in
421    
422            TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
423            doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
424            return c;
425        }
426    
427    
428        public void prepareForTheNextReplLine(@NotNull TopDownAnalysisContext c) {
429            c.getScriptScopes().clear();
430            c.getScripts().clear();
431        }
432    
433    
434        @NotNull
435        public MutablePackageFragmentProvider getPackageFragmentProvider() {
436            return packageFragmentProvider;
437        }
438    }
439    
440