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