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.PlatformToKotlinClassMap;
032    import org.jetbrains.jet.lang.descriptors.*;
033    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
034    import org.jetbrains.jet.lang.descriptors.impl.MutablePackageFragmentDescriptor;
035    import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilder;
036    import org.jetbrains.jet.lang.descriptors.impl.PackageLikeBuilderDummy;
037    import org.jetbrains.jet.lang.psi.JetClassOrObject;
038    import org.jetbrains.jet.lang.psi.JetFile;
039    import org.jetbrains.jet.lang.resolve.lazy.ResolveSession;
040    import org.jetbrains.jet.lang.resolve.lazy.declarations.FileBasedDeclarationProviderFactory;
041    import org.jetbrains.jet.lang.resolve.name.FqName;
042    import org.jetbrains.jet.lang.resolve.name.Name;
043    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
044    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
045    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
046    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
047    import org.jetbrains.jet.storage.LockBasedStorageManager;
048    
049    import javax.inject.Inject;
050    import java.util.Collection;
051    import java.util.Collections;
052    import java.util.LinkedHashSet;
053    import java.util.Set;
054    
055    public class TopDownAnalyzer {
056    
057        @NotNull
058        private BindingTrace trace;
059        @NotNull
060        private DeclarationResolver declarationResolver;
061        @NotNull
062        private TypeHierarchyResolver typeHierarchyResolver;
063        @NotNull
064        private OverrideResolver overrideResolver;
065        @NotNull
066        private OverloadResolver overloadResolver;
067        @NotNull
068        private ModuleDescriptor moduleDescriptor;
069        @NotNull
070        private MutablePackageFragmentProvider packageFragmentProvider;
071        @NotNull
072        private BodyResolver bodyResolver;
073        @NotNull
074        private Project project;
075    
076        @NotNull
077        private LazyTopDownAnalyzer lazyTopDownAnalyzer;
078    
079        @Inject
080        public void setTrace(@NotNull BindingTrace trace) {
081            this.trace = trace;
082        }
083    
084        @Inject
085        public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
086            this.declarationResolver = declarationResolver;
087        }
088    
089        @Inject
090        public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
091            this.typeHierarchyResolver = typeHierarchyResolver;
092        }
093    
094        @Inject
095        public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
096            this.overrideResolver = overrideResolver;
097        }
098    
099        @Inject
100        public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
101            this.overloadResolver = overloadResolver;
102        }
103    
104        @Inject
105        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
106            this.moduleDescriptor = moduleDescriptor;
107        }
108    
109        @Inject
110        public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
111            this.packageFragmentProvider = packageFragmentProvider;
112        }
113    
114        @Inject
115        public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
116            this.bodyResolver = bodyResolver;
117        }
118    
119        @Inject
120        public void setProject(@NotNull Project project) {
121            this.project = project;
122        }
123    
124        @Inject
125        public void setLazyTopDownAnalyzer(@NotNull LazyTopDownAnalyzer lazyTopDownAnalyzer) {
126            this.lazyTopDownAnalyzer = lazyTopDownAnalyzer;
127        }
128    
129        public void doProcess(
130                @NotNull TopDownAnalysisContext c,
131                @NotNull JetScope outerScope,
132                @NotNull PackageLikeBuilder owner,
133                @NotNull Collection<? extends PsiElement> declarations
134        ) {
135    //        c.enableDebugOutput();
136            c.debug("Enter");
137    
138            if (c.getTopDownAnalysisParameters().isLazyTopDownAnalysis()) {
139                ResolveSession resolveSession = new InjectorForLazyResolve(
140                        project,
141                        new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
142                        (ModuleDescriptorImpl) moduleDescriptor, // TODO
143                        new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
144                        trace
145                ).getResolveSession();
146    
147                lazyTopDownAnalyzer.analyzeDeclarations(
148                        resolveSession,
149                        c.getTopDownAnalysisParameters(),
150                        declarations
151                );
152                return;
153            }
154    
155            typeHierarchyResolver.process(c, outerScope, owner, declarations);
156            declarationResolver.process(c);
157            overrideResolver.process(c);
158            lockScopes(c);
159    
160            overloadResolver.process(c);
161    
162            if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
163                bodyResolver.resolveBodies(c);
164            }
165    
166            c.debug("Exit");
167            c.printDebugOutput(System.out);
168        }
169    
170        private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
171            return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
172                @Nullable
173                @Override
174                public JetFile invoke(PsiElement element) {
175                    return (JetFile) element.getContainingFile();
176                }
177            }));
178        }
179    
180        private void lockScopes(@NotNull TopDownAnalysisContext c) {
181            for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getDeclaredClasses().values()) {
182                ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
183            }
184    
185            // SCRIPT: extra code for scripts
186            Set<FqName> scriptFqNames = Sets.newHashSet();
187            for (JetFile file : c.getFileScopes().keySet()) {
188                if (file.isScript()) {
189                    scriptFqNames.add(file.getPackageFqName());
190                }
191            }
192            for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
193                // todo: this is hack in favor of REPL
194                if (!scriptFqNames.contains(fragment.getFqName())) {
195                    fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
196                }
197            }
198        }
199    
200        public static void processClassOrObject(
201                @NotNull GlobalContext globalContext,
202                @Nullable final WritableScope scope,
203                @NotNull ExpressionTypingContext context,
204                @NotNull final DeclarationDescriptor containingDeclaration,
205                @NotNull JetClassOrObject object
206        ) {
207            ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<dummy for object>"),
208                                                                             Collections.<ImportPath>emptyList(),
209                                                                             PlatformToKotlinClassMap.EMPTY);
210    
211            TopDownAnalysisParameters topDownAnalysisParameters =
212                    TopDownAnalysisParameters.createForLocalDeclarations(
213                            globalContext.getStorageManager(),
214                            globalContext.getExceptionTracker(),
215                            Predicates.equalTo(object.getContainingFile())
216                    );
217    
218            InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
219                    object.getProject(), topDownAnalysisParameters, context.trace, moduleDescriptor
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        ) {
267            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
268    
269            // "depend on" builtins module
270            ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
271    
272            // dummy builder is used because "root" is module descriptor,
273            // packages added to module explicitly in
274    
275            TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
276            doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
277            return c;
278        }
279    
280    
281        @NotNull
282        public MutablePackageFragmentProvider getPackageFragmentProvider() {
283            return packageFragmentProvider;
284        }
285    
286    }
287    
288