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