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.intellij.openapi.project.Project;
021    import com.intellij.psi.PsiElement;
022    import com.intellij.psi.PsiFile;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
025    import org.jetbrains.jet.lang.ModuleConfiguration;
026    import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
027    import org.jetbrains.jet.lang.descriptors.*;
028    import org.jetbrains.jet.lang.descriptors.impl.*;
029    import org.jetbrains.jet.lang.psi.JetClassOrObject;
030    import org.jetbrains.jet.lang.psi.JetDeclaration;
031    import org.jetbrains.jet.lang.psi.JetFile;
032    import org.jetbrains.jet.lang.resolve.name.FqName;
033    import org.jetbrains.jet.lang.resolve.name.Name;
034    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
036    import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
037    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
038    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
039    
040    import javax.inject.Inject;
041    import java.util.*;
042    
043    public class TopDownAnalyzer {
044    
045        @NotNull
046        private DeclarationResolver declarationResolver;
047        @NotNull
048        private TypeHierarchyResolver typeHierarchyResolver;
049        @NotNull
050        private OverrideResolver overrideResolver;
051        @NotNull
052        private OverloadResolver overloadResolver;
053        @NotNull
054        private TopDownAnalysisParameters topDownAnalysisParameters;
055        @NotNull
056        private TopDownAnalysisContext context;
057        @NotNull
058        private BindingTrace trace;
059        @NotNull
060        private ModuleDescriptor moduleDescriptor;
061        @NotNull
062        private NamespaceFactoryImpl namespaceFactory;
063        @NotNull
064        private BodyResolver bodyResolver;
065    
066        @Inject
067        public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
068            this.declarationResolver = declarationResolver;
069        }
070    
071        @Inject
072        public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
073            this.typeHierarchyResolver = typeHierarchyResolver;
074        }
075    
076        @Inject
077        public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
078            this.overrideResolver = overrideResolver;
079        }
080    
081        @Inject
082        public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
083            this.overloadResolver = overloadResolver;
084        }
085    
086        @Inject
087        public void setTopDownAnalysisParameters(@NotNull TopDownAnalysisParameters topDownAnalysisParameters) {
088            this.topDownAnalysisParameters = topDownAnalysisParameters;
089        }
090    
091        @Inject
092        public void setTrace(@NotNull BindingTrace trace) {
093            this.trace = trace;
094        }
095    
096        @Inject
097        public void setContext(@NotNull TopDownAnalysisContext context) {
098            this.context = context;
099        }
100    
101        @Inject
102        public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
103            this.moduleDescriptor = moduleDescriptor;
104        }
105    
106        @Inject
107        public void setNamespaceFactory(@NotNull NamespaceFactoryImpl namespaceFactory) {
108            this.namespaceFactory = namespaceFactory;
109        }
110    
111        @Inject
112        public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
113            this.bodyResolver = bodyResolver;
114        }
115    
116    
117    
118        public void doProcess(
119                JetScope outerScope,
120                NamespaceLikeBuilder owner,
121                Collection<? extends PsiElement> declarations) {
122    //        context.enableDebugOutput();
123            context.debug("Enter");
124    
125            typeHierarchyResolver.process(outerScope, owner, declarations);
126            declarationResolver.process(outerScope);
127            overrideResolver.process();
128    
129            lockScopes();
130    
131            overloadResolver.process();
132    
133            if (!topDownAnalysisParameters.isAnalyzingBootstrapLibrary()) {
134                bodyResolver.resolveBodies();
135            }
136    
137            context.debug("Exit");
138            context.printDebugOutput(System.out);
139        }
140    
141        private void lockScopes() {
142            for (MutableClassDescriptor mutableClassDescriptor : context.getClasses().values()) {
143                mutableClassDescriptor.lockScopes();
144            }
145            for (Map.Entry<JetFile, WritableScope> namespaceScope : context.getNamespaceScopes().entrySet()) {
146                // todo: this is hack in favor of REPL
147                if(!namespaceScope.getKey().isScript())
148                    namespaceScope.getValue().changeLockLevel(WritableScope.LockLevel.READING);
149            }
150        }
151    
152        public static void processStandardLibraryNamespace(
153                @NotNull Project project,
154                @NotNull BindingTrace trace,
155                @NotNull WritableScope outerScope,
156                @NotNull NamespaceDescriptorImpl standardLibraryNamespace,
157                @NotNull List<JetFile> files) {
158    
159            TopDownAnalysisParameters topDownAnalysisParameters = new TopDownAnalysisParameters(
160                    Predicates.<PsiFile>alwaysFalse(), true, false, Collections.<AnalyzerScriptParameter>emptyList());
161            InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
162                    project, topDownAnalysisParameters, new ObservableBindingTrace(trace),       
163                    KotlinBuiltIns.getInstance().getBuiltInsModule(), PlatformToKotlinClassMap.EMPTY);
164    
165            injector.getTopDownAnalyzer().doProcessStandardLibraryNamespace(outerScope, standardLibraryNamespace, files);
166        }
167    
168        private void doProcessStandardLibraryNamespace(
169                WritableScope outerScope, NamespaceDescriptorImpl standardLibraryNamespace, List<JetFile> files) {
170            ArrayList<JetDeclaration> toAnalyze = new ArrayList<JetDeclaration>();
171            for(JetFile file : files) {
172                context.getNamespaceDescriptors().put(file, standardLibraryNamespace);
173                context.getNamespaceScopes().put(file, standardLibraryNamespace.getMemberScope());
174                toAnalyze.addAll(file.getDeclarations());
175            }
176    //        context.getDeclaringScopes().put(file, outerScope);
177    
178            doProcess(outerScope, standardLibraryNamespace.getBuilder(), toAnalyze);
179        }
180    
181        public static void processClassOrObject(
182                @NotNull ExpressionTypingContext context,
183                @NotNull final DeclarationDescriptor containingDeclaration,
184                @NotNull JetClassOrObject object
185        ) {
186            ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<dummy for object>"),
187                                                                             Collections.<ImportPath>emptyList(),
188                                                                             PlatformToKotlinClassMap.EMPTY);
189            moduleDescriptor.setModuleConfiguration(ModuleConfiguration.EMPTY);
190    
191            TopDownAnalysisParameters topDownAnalysisParameters =
192                    new TopDownAnalysisParameters(Predicates.equalTo(object.getContainingFile()),
193                    false, true, Collections.<AnalyzerScriptParameter>emptyList());
194    
195            InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
196                    object.getProject(), topDownAnalysisParameters, new ObservableBindingTrace(context.trace),
197                    moduleDescriptor, context.expressionTypingServices.getPlatformToKotlinClassMap());
198    
199            injector.getTopDownAnalysisContext().setOuterDataFlowInfo(context.dataFlowInfo);
200    
201            injector.getTopDownAnalyzer().doProcess(context.scope, new NamespaceLikeBuilder() {
202    
203                @NotNull
204                @Override
205                public DeclarationDescriptor getOwnerForChildren() {
206                    return containingDeclaration;
207                }
208    
209                @Override
210                public void addClassifierDescriptor(@NotNull MutableClassDescriptorLite classDescriptor) {
211    
212                }
213    
214                @Override
215                public void addFunctionDescriptor(@NotNull SimpleFunctionDescriptor functionDescriptor) {
216                    throw new UnsupportedOperationException();
217                }
218    
219                @Override
220                public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) {
221    
222                }
223    
224                @Override
225                public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptorLite classObjectDescriptor) {
226                    return ClassObjectStatus.NOT_ALLOWED;
227                }
228            }, Collections.<PsiElement>singletonList(object));
229        }
230    
231        public void analyzeFiles(
232                @NotNull Collection<JetFile> files,
233                @NotNull List<AnalyzerScriptParameter> scriptParameters) {
234            WritableScope scope = new WritableScopeImpl(
235                    JetScope.EMPTY, moduleDescriptor,
236                    new TraceBasedRedeclarationHandler(trace), "Root scope in analyzeNamespace");
237    
238            scope.changeLockLevel(WritableScope.LockLevel.BOTH);
239    
240            NamespaceDescriptorImpl rootNs = namespaceFactory.createNamespaceDescriptorPathIfNeeded(FqName.ROOT);
241    
242            // map "jet" namespace into KotlinBuiltIns
243            // @see DefaultModuleConfiguraiton#extendNamespaceScope
244            namespaceFactory.createNamespaceDescriptorPathIfNeeded(KotlinBuiltIns.getInstance().getBuiltInsPackageFqName());
245    
246            // Import a scope that contains all top-level namespaces that come from dependencies
247            // This makes the namespaces visible at all, does not import themselves
248            scope.importScope(rootNs.getMemberScope());
249            
250            scope.changeLockLevel(WritableScope.LockLevel.READING);
251    
252            // dummy builder is used because "root" is module descriptor,
253            // namespaces added to module explicitly in
254            doProcess(scope, new NamespaceLikeBuilderDummy(), files);
255        }
256    
257    
258        public void prepareForTheNextReplLine() {
259            context.getScriptScopes().clear();
260            context.getScripts().clear();
261        }
262    
263    
264    }
265    
266