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.HashMultimap;
021 import com.google.common.collect.Multimap;
022 import com.google.common.collect.Sets;
023 import com.intellij.psi.PsiElement;
024 import kotlin.Function1;
025 import kotlin.KotlinPackage;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.context.GlobalContext;
029 import org.jetbrains.jet.context.GlobalContextImpl;
030 import org.jetbrains.jet.di.InjectorForLazyResolve;
031 import org.jetbrains.jet.di.InjectorForTopDownAnalyzerBasic;
032 import org.jetbrains.jet.lang.PlatformToKotlinClassMap;
033 import org.jetbrains.jet.lang.descriptors.*;
034 import org.jetbrains.jet.lang.descriptors.impl.*;
035 import org.jetbrains.jet.lang.psi.*;
036 import org.jetbrains.jet.lang.resolve.lazy.ForceResolveUtil;
037 import org.jetbrains.jet.lang.resolve.lazy.LazyImportScope;
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.name.Name;
042 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
044 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext;
045 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
046 import org.jetbrains.jet.storage.LockBasedStorageManager;
047
048 import javax.inject.Inject;
049 import java.util.*;
050
051 import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_CLASS_OBJECTS;
052
053 public class TopDownAnalyzer {
054
055 public static boolean LAZY;
056
057 static {
058 LAZY = "true".equals(System.getProperty("lazy.tda"));
059 }
060
061 @NotNull
062 private BindingTrace trace;
063 @NotNull
064 private DeclarationResolver declarationResolver;
065 @NotNull
066 private TypeHierarchyResolver typeHierarchyResolver;
067 @NotNull
068 private OverrideResolver overrideResolver;
069 @NotNull
070 private OverloadResolver overloadResolver;
071 @NotNull
072 private ModuleDescriptor moduleDescriptor;
073 @NotNull
074 private MutablePackageFragmentProvider packageFragmentProvider;
075 @NotNull
076 private BodyResolver bodyResolver;
077 @NotNull
078 private ScriptHeaderResolver scriptHeaderResolver;
079
080 @Inject
081 public void setTrace(@NotNull BindingTrace trace) {
082 this.trace = trace;
083 }
084
085 @Inject
086 public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
087 this.declarationResolver = declarationResolver;
088 }
089
090 @Inject
091 public void setTypeHierarchyResolver(@NotNull TypeHierarchyResolver typeHierarchyResolver) {
092 this.typeHierarchyResolver = typeHierarchyResolver;
093 }
094
095 @Inject
096 public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
097 this.overrideResolver = overrideResolver;
098 }
099
100 @Inject
101 public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
102 this.overloadResolver = overloadResolver;
103 }
104
105 @Inject
106 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
107 this.moduleDescriptor = moduleDescriptor;
108 }
109
110 @Inject
111 public void setPackageFragmentProvider(@NotNull MutablePackageFragmentProvider packageFragmentProvider) {
112 this.packageFragmentProvider = packageFragmentProvider;
113 }
114
115 @Inject
116 public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
117 this.bodyResolver = bodyResolver;
118 }
119
120 @Inject
121 public void setScriptHeaderResolver(@NotNull ScriptHeaderResolver scriptHeaderResolver) {
122 this.scriptHeaderResolver = scriptHeaderResolver;
123 }
124
125 public void doProcess(
126 @NotNull final TopDownAnalysisContext c,
127 @NotNull JetScope outerScope,
128 @NotNull PackageLikeBuilder owner,
129 @NotNull Collection<? extends PsiElement> declarations
130 ) {
131 // c.enableDebugOutput();
132 c.debug("Enter");
133
134 if (LAZY && !c.getTopDownAnalysisParameters().isDeclaredLocally()) {
135 final ResolveSession resolveSession = new InjectorForLazyResolve(
136 declarations.iterator().next().getProject(), // TODO
137 new GlobalContextImpl((LockBasedStorageManager) c.getStorageManager(), c.getExceptionTracker()), // TODO
138 (ModuleDescriptorImpl) moduleDescriptor, // TODO
139 new FileBasedDeclarationProviderFactory(c.getStorageManager(), getFiles(declarations)),
140 trace
141 ).getResolveSession();
142
143 final Multimap<FqName, JetElement> topLevelFqNames = HashMultimap.create();
144
145 // fill in the context
146 for (PsiElement declaration : declarations) {
147 declaration.accept(
148 new JetVisitorVoid() {
149 private void registerDeclarations(@NotNull List<JetDeclaration> declarations) {
150 for (JetDeclaration jetDeclaration : declarations) {
151 jetDeclaration.accept(this);
152 }
153 }
154
155 private void registerTopLevelFqName(@NotNull JetNamedDeclaration declaration, @NotNull DeclarationDescriptor descriptor) {
156 if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
157 FqName fqName = JetPsiUtil.getFQName(declaration);
158 if (fqName != null) {
159 topLevelFqNames.put(fqName, declaration);
160 }
161 }
162 }
163
164 private void registerScope(@Nullable JetDeclaration declaration, @NotNull JetDeclaration anchorForScope) {
165 if (declaration == null) return;
166 c.registerDeclaringScope(
167 declaration,
168 resolveSession.getScopeProvider().getResolutionScopeForDeclaration(anchorForScope)
169 );
170 }
171
172 @Override
173 public void visitDeclaration(@NotNull JetDeclaration dcl) {
174 throw new IllegalArgumentException("Unsupported declaration: " + dcl + " " + dcl.getText());
175 }
176
177 @Override
178 public void visitJetFile(@NotNull JetFile file) {
179 if (file.isScript()) {
180 JetScript script = file.getScript();
181 assert script != null;
182 scriptHeaderResolver.processScriptHierarchy(c, script, resolveSession.getScopeProvider().getFileScope(file));
183 }
184 else {
185 JetPackageDirective packageDirective = file.getPackageDirective();
186 assert packageDirective != null : "No package in a non-script file: " + file;
187
188 c.addFile(file);
189
190 DescriptorResolver.resolvePackageHeader(packageDirective, moduleDescriptor, trace);
191 registerDeclarations(file.getDeclarations());
192
193 topLevelFqNames.put(JetPsiUtil.getFQName(file), packageDirective);
194 }
195 resolveAndCheckImports(file, resolveSession);
196 }
197
198 private void resolveAndCheckImports(@NotNull JetFile file, @NotNull ResolveSession resolveSession) {
199 LazyImportScope fileScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(file);
200 fileScope.forceResolveAllContents();
201 }
202
203 private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) {
204 ClassDescriptorWithResolutionScopes descriptor = ForceResolveUtil.forceResolveAllContents(
205 (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject)
206 );
207
208 c.getClasses().put(classOrObject, descriptor);
209 registerDeclarations(classOrObject.getDeclarations());
210 registerTopLevelFqName(classOrObject, descriptor);
211
212 checkManyClassObjects(classOrObject);
213 }
214
215 private void checkManyClassObjects(JetClassOrObject classOrObject) {
216 boolean classObjectAlreadyFound = false;
217 for (JetDeclaration jetDeclaration : classOrObject.getDeclarations()) {
218 jetDeclaration.accept(this);
219
220 if (jetDeclaration instanceof JetClassObject) {
221 if (classObjectAlreadyFound) {
222 trace.report(MANY_CLASS_OBJECTS.on((JetClassObject) jetDeclaration));
223 }
224 classObjectAlreadyFound = true;
225 }
226 }
227 }
228
229 @Override
230 public void visitClass(@NotNull JetClass klass) {
231 visitClassOrObject(klass);
232
233 registerPrimaryConstructorParameters(klass);
234 }
235
236 private void registerPrimaryConstructorParameters(@NotNull JetClass klass) {
237 for (JetParameter jetParameter : klass.getPrimaryConstructorParameters()) {
238 if (jetParameter.getValOrVarNode() != null) {
239 c.getPrimaryConstructorParameterProperties().put(
240 jetParameter,
241 (PropertyDescriptor) resolveSession.resolveToDescriptor(jetParameter)
242 );
243 }
244 }
245 }
246
247 @Override
248 public void visitClassObject(@NotNull JetClassObject classObject) {
249 visitClassOrObject(classObject.getObjectDeclaration());
250 }
251
252 @Override
253 public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) {
254 visitClassOrObject(enumEntry);
255 }
256
257 @Override
258 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
259 visitClassOrObject(declaration);
260 }
261
262 @Override
263 public void visitAnonymousInitializer(@NotNull JetClassInitializer initializer) {
264 registerScope(initializer, initializer);
265 }
266
267 @Override
268 public void visitNamedFunction(@NotNull JetNamedFunction function) {
269 c.getFunctions().put(
270 function,
271 ForceResolveUtil.forceResolveAllContents(
272 (SimpleFunctionDescriptor) resolveSession.resolveToDescriptor(function)
273 )
274 );
275 registerScope(function, function);
276 }
277
278 @Override
279 public void visitProperty(@NotNull JetProperty property) {
280 PropertyDescriptor descriptor = ForceResolveUtil.forceResolveAllContents(
281 (PropertyDescriptor) resolveSession.resolveToDescriptor(property)
282 );
283
284 c.getProperties().put(property, descriptor);
285 registerTopLevelFqName(property, descriptor);
286
287 registerScope(property, property);
288 registerScope(property.getGetter(), property);
289 registerScope(property.getSetter(), property);
290 }
291 }
292 );
293 }
294
295 declarationResolver.checkRedeclarationsInPackages(resolveSession, topLevelFqNames);
296 declarationResolver.checkRedeclarationsInInnerClassNames(c);
297 overrideResolver.check(c);
298 }
299 else {
300 typeHierarchyResolver.process(c, outerScope, owner, declarations);
301 declarationResolver.process(c);
302 overrideResolver.process(c);
303 lockScopes(c);
304 }
305
306 overloadResolver.process(c);
307
308 if (!c.getTopDownAnalysisParameters().isAnalyzingBootstrapLibrary()) {
309 bodyResolver.resolveBodies(c);
310 }
311
312 c.debug("Exit");
313 c.printDebugOutput(System.out);
314 }
315
316 private static Collection<JetFile> getFiles(Collection<? extends PsiElement> declarations) {
317 return new LinkedHashSet<JetFile>(KotlinPackage.map(declarations, new Function1<PsiElement, JetFile>() {
318 @Nullable
319 @Override
320 public JetFile invoke(PsiElement element) {
321 return (JetFile) element.getContainingFile();
322 }
323 }));
324 }
325
326 private void lockScopes(@NotNull TopDownAnalysisContext c) {
327 for (ClassDescriptorWithResolutionScopes mutableClassDescriptor : c.getClasses().values()) {
328 ((MutableClassDescriptor) mutableClassDescriptor).lockScopes();
329 }
330 Set<FqName> scriptFqNames = Sets.newHashSet();
331 for (JetFile file : c.getFileScopes().keySet()) {
332 if (file.isScript()) {
333 scriptFqNames.add(JetPsiUtil.getFQName(file));
334 }
335 }
336 for (MutablePackageFragmentDescriptor fragment : packageFragmentProvider.getAllFragments()) {
337 // todo: this is hack in favor of REPL
338 if (!scriptFqNames.contains(fragment.getFqName())) {
339 fragment.getMemberScope().changeLockLevel(WritableScope.LockLevel.READING);
340 }
341 }
342 }
343
344 public static void processClassOrObject(
345 @NotNull GlobalContext globalContext,
346 @Nullable final WritableScope scope,
347 @NotNull ExpressionTypingContext context,
348 @NotNull final DeclarationDescriptor containingDeclaration,
349 @NotNull JetClassOrObject object
350 ) {
351 ModuleDescriptorImpl moduleDescriptor = new ModuleDescriptorImpl(Name.special("<dummy for object>"),
352 Collections.<ImportPath>emptyList(),
353 PlatformToKotlinClassMap.EMPTY);
354
355 TopDownAnalysisParameters topDownAnalysisParameters =
356 new TopDownAnalysisParameters(
357 globalContext.getStorageManager(),
358 globalContext.getExceptionTracker(),
359 Predicates.equalTo(object.getContainingFile()),
360 false,
361 true,
362 Collections.<AnalyzerScriptParameter>emptyList()
363 );
364
365 InjectorForTopDownAnalyzerBasic injector = new InjectorForTopDownAnalyzerBasic(
366 object.getProject(), topDownAnalysisParameters, context.trace, moduleDescriptor
367 );
368
369 TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
370 c.setOuterDataFlowInfo(context.dataFlowInfo);
371
372 injector.getTopDownAnalyzer().doProcess(
373 c,
374 context.scope,
375 new PackageLikeBuilder() {
376
377 @NotNull
378 @Override
379 public DeclarationDescriptor getOwnerForChildren() {
380 return containingDeclaration;
381 }
382
383 @Override
384 public void addClassifierDescriptor(@NotNull MutableClassDescriptorLite classDescriptor) {
385 if (scope != null) {
386 scope.addClassifierDescriptor(classDescriptor);
387 }
388 }
389
390 @Override
391 public void addFunctionDescriptor(@NotNull SimpleFunctionDescriptor functionDescriptor) {
392 throw new UnsupportedOperationException();
393 }
394
395 @Override
396 public void addPropertyDescriptor(@NotNull PropertyDescriptor propertyDescriptor) {
397
398 }
399
400 @Override
401 public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptorLite classObjectDescriptor) {
402 return ClassObjectStatus.NOT_ALLOWED;
403 }
404 },
405 Collections.<PsiElement>singletonList(object)
406 );
407 }
408
409 @NotNull
410 public TopDownAnalysisContext analyzeFiles(
411 @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
412 @NotNull Collection<JetFile> files
413 ) {
414 ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
415
416 // "depend on" builtins module
417 ((ModuleDescriptorImpl) moduleDescriptor).addFragmentProvider(DependencyKind.BUILT_INS, KotlinBuiltIns.getInstance().getBuiltInsModule().getPackageFragmentProvider());
418
419 // dummy builder is used because "root" is module descriptor,
420 // packages added to module explicitly in
421
422 TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
423 doProcess(c, JetModuleUtil.getSubpackagesOfRootScope(moduleDescriptor), new PackageLikeBuilderDummy(), files);
424 return c;
425 }
426
427
428 public void prepareForTheNextReplLine(@NotNull TopDownAnalysisContext c) {
429 c.getScriptScopes().clear();
430 c.getScripts().clear();
431 }
432
433
434 @NotNull
435 public MutablePackageFragmentProvider getPackageFragmentProvider() {
436 return packageFragmentProvider;
437 }
438 }
439
440