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.Sets;
021    import com.intellij.openapi.project.Project;
022    import com.intellij.psi.PsiElement;
023    import kotlin.Function1;
024    import kotlin.KotlinPackage;
025    import org.jetbrains.annotations.NotNull;
026    import org.jetbrains.annotations.Nullable;
027    import org.jetbrains.jet.context.GlobalContext;
028    import org.jetbrains.jet.context.GlobalContextImpl;
029    import org.jetbrains.jet.di.InjectorForLazyResolve;
030    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
031    import org.jetbrains.jet.lang.descriptors.*;
032    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
033    import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
034    import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder;
035    import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilderDummy;
036    import org.jetbrains.jet.lang.psi.JetClassOrObject;
037    import org.jetbrains.jet.lang.psi.JetFile;
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.scopes.JetScope;
042    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
043    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
044    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
045    import org.jetbrains.jet.storage.LockBasedStorageManager;
046    
047    import javax.inject.Inject;
048    import java.util.Collection;
049    import java.util.Collections;
050    import java.util.LinkedHashSet;
051    import java.util.Set;
052    
053    public class TopDownAnalyzer {
054    
055        @NotNull
056        private BindingTrace trace;
057        @NotNull
058        private DeclarationResolver declarationResolver;
059        @NotNull
060        private TypeHierarchyResolver typeHierarchyResolver;
061        @NotNull
062        private OverrideResolver overrideResolver;
063        @NotNull
064        private OverloadResolver overloadResolver;
065        @NotNull
066        private ModuleDescriptor moduleDescriptor;
067        @NotNull
068        private MutablePackageFragmentProvider packageFragmentProvider;
069        @NotNull
070        private BodyResolver bodyResolver;
071        @NotNull
072        private Project project;
073    
074        @NotNull
075        private LazyTopDownAnalyzer lazyTopDownAnalyzer;
076    
077        @Inject
078        public void setTrace(@NotNull BindingTrace trace) {
079            this.trace = trace;
080        }
081    
082        @Inject
083        public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
084            this.declarationResolver = declarationResolver;
085        }
086    
087        @Inject
088        public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
089            this.typeHierarchyResolver = typeHierarchyResolver;
090        }
091    
092        @Inject
093        public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
094            this.overrideResolver = overrideResolver;
095        }
096    
097        @Inject
098        public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
099            this.overloadResolver = overloadResolver;
100        }
101    
102        @Inject
103        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
104            this.moduleDescriptor = moduleDescriptor;
105        }
106    
107        @Inject
108        public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
109            this.packageFragmentProvider = packageFragmentProvider;
110        }
111    
112        @Inject
113        public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
114            this.bodyResolver = bodyResolver;
115        }
116    
117        @Inject
118        public void setProject(@NotNull Project project) {
119            this.project = project;
120        }
121    
122        @Inject
123        public void setLazyTopDownAnalyzer(@NotNull LazyTopDownAnalyzer lazyTopDownAnalyzer) {
124            this.lazyTopDownAnalyzer = lazyTopDownAnalyzer;
125        }
126    
127        public void doProcess(
128                @NotNull TopDownAnalysisContext c,
129                @NotNull JetScope outerScope,
130                @NotNull PackageLikeBuilder owner,
131                @NotNull Collection<? extends PsiElement> declarations
132        ) {
133    //        c.enableDebugOutput();
134            c.debug("Enter");
135    
136            if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
137                ResolveSession resolveSession = new InjectorForLazyResolve(
138                        project,
139                        new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
140                        (ModuleDescriptorImpl) moduleDescriptor, // TODO
141                        new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
142                        trace
143                ).getResolveSession();
144    
145                lazyTopDownAnalyzer.analyzeDeclarations(
146                        resolveSession,
147                        c.getTopDownAnalysisParameters(),
148                        declarations
149                );
150                return;
151            }
152    
153            typeHierarchyResolver.process(c, outerScope, owner, declarations);
154            declarationResolver.process(c);
155            overrideResolver.process(c);
156            lockScopes(c);
157    
158            overloadResolver.process(c);
159    
160            if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
161                bodyResolver.resolveBodies(c);
162            }
163    
164            c.debug("Exit");
165            c.printDebugOutput(System.out);
166        }
167    
168        private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
169            return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
170                @Nullable
171                @Override
172                public JetFile invoke(PsiElement element) {
173                    return (JetFile) element.getContainingFile();
174                }
175            }));
176        }
177    
178        private void lockScopes(@NotNull TopDownAnalysisContext c) {
179            for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getDeclaredClasses().values()) {
180                ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
181            }
182    
183            // SCRIPT: extra code for scripts
184            Set<FqName> scriptFqNames = Sets.newHashSet();
185            for (JetFile file : c.getFileScopes().keySet()) {
186                if (file.isScript()) {
187                    scriptFqNames.add(file.getPackageFqName());
188                }
189            }
190            for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
191                // todo: this is hack in favor of REPL
192                if (!scriptFqNames.contains(fragment.getFqName())) {
193                    fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
194                }
195            }
196        }
197    
198        public static void processClassOrObject(
199                @NotNull GlobalContext globalContext,
200                @Nullable final WritableScope scope,
201                @NotNull ExpressionTypingContext context,
202                @NotNull final DeclarationDescriptor containingDeclaration,
203                @NotNull JetClassOrObject object
204        ) {
205            TopDownAnalysisParameters topDownAnalysisParameters =
206                    TopDownAnalysisParameters.createForLocalDeclarations(
207                            globalContext.getStorageManager(),
208                            globalContext.getExceptionTracker(),
209                            Predicates.equalTo(object.getContainingFile())
210                    );
211    
212            InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
213                    object.getProject(), topDownAnalysisParameters, context.trace, DescriptorUtils.getContainingModule(containingDeclaration)
214            );
215    
216            TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
217            c.setOuterDataFlowInfo(context.dataFlowInfo);
218    
219            injector.getTopDownAnalyzer().doProcess(
220                   c,
221                   context.scope,
222                   new PackageLikeBuilder() {
223    
224                       @NotNull
225                       @Override
226                       public DeclarationDescriptor getOwnerForChildren() {
227                           return containingDeclaration;
228                       }
229    
230                       @Override
231                       public void addClassifierDescriptor(@NotNull MutableClassDescriptor classDescriptor) {
232                           if (scope != null) {
233                               scope.addClassifierDescriptor(classDescriptor);
234                           }
235                       }
236    
237                       @Override
238                       public void addFunctionDescriptor(@NotNull SimpleFunctionDescriptor functionDescriptor) {
239                           throw new UnsupportedOperationException();
240                       }
241    
242                       @Override
243                       public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) {
244    
245                       }
246    
247                       @Override
248                       public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptor classObjectDescriptor) {
249                           return ClassObjectStatus.NOT_ALLOWED;
250                       }
251                   },
252                   Collections.<PsiElement>singletonList(object)
253            );
254        }
255    
256        @NotNull
257        public TopDownAnalysisContext analyzeFiles(
258                @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
259                @NotNull Collection<JetFile> files
260        ) {
261            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
262    
263            // "depend on" builtins module
264            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
265    
266            // dummy builder is used because "root" is module descriptor,
267            // packages added to module explicitly in
268    
269            TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
270            doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
271            return c;
272        }
273    
274    
275        @NotNull
276        public MutablePackageFragmentProvider getPackageFragmentProvider() {
277            return packageFragmentProvider;
278        }
279    
280    }
281    
282