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
017package org.jetbrains.jet.lang.resolve;
018
019import com.google.common.base.Predicates;
020import com.intellij.openapi.project.Project;
021import com.intellij.psi.PsiElement;
022import com.intellij.psi.PsiFile;
023import org.jetbrains.annotations.NotNull;
024import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
025import org.jetbrains.jet.lang.ModuleConfiguration;
026import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
027import org.jetbrains.jet.lang.descriptors.*;
028import org.jetbrains.jet.lang.descriptors.impl.*;
029import org.jetbrains.jet.lang.psi.JetClassOrObject;
030import org.jetbrains.jet.lang.psi.JetDeclaration;
031import org.jetbrains.jet.lang.psi.JetFile;
032import org.jetbrains.jet.lang.resolve.name.FqName;
033import org.jetbrains.jet.lang.resolve.name.Name;
034import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
036import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
037import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
038
039import javax.inject.Inject;
040import java.util.*;
041
042public 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