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