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