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.collect.HashMultimap;
020 import com.google.common.collect.Multimap;
021 import com.intellij.psi.PsiElement;
022 import com.intellij.psi.util.PsiTreeUtil;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.lazy.KotlinCodeAnalyzer;
028 import org.jetbrains.jet.lang.resolve.lazy.LazyImportScope;
029 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
030 import org.jetbrains.jet.lang.resolve.name.FqName;
031
032 import javax.inject.Inject;
033 import java.util.ArrayList;
034 import java.util.Collection;
035 import java.util.List;
036
037 import static org.jetbrains.jet.lang.diagnostics.Errors.MANY_CLASS_OBJECTS;
038 import static org.jetbrains.jet.lang.diagnostics.Errors.UNSUPPORTED;
039
040 public class LazyTopDownAnalyzer {
041
042 @NotNull
043 private BindingTrace trace;
044 @NotNull
045 private DeclarationResolver declarationResolver;
046 @NotNull
047 private OverrideResolver overrideResolver;
048 @NotNull
049 private OverloadResolver overloadResolver;
050 @NotNull
051 private ModuleDescriptor moduleDescriptor;
052 @NotNull
053 private BodyResolver bodyResolver;
054
055 @Inject
056 public void setTrace(@NotNull BindingTrace trace) {
057 this.trace = trace;
058 }
059
060 @Inject
061 public void setDeclarationResolver(@NotNull DeclarationResolver declarationResolver) {
062 this.declarationResolver = declarationResolver;
063 }
064
065 @Inject
066 public void setOverrideResolver(@NotNull OverrideResolver overrideResolver) {
067 this.overrideResolver = overrideResolver;
068 }
069
070 @Inject
071 public void setOverloadResolver(@NotNull OverloadResolver overloadResolver) {
072 this.overloadResolver = overloadResolver;
073 }
074
075 @Inject
076 public void setModuleDescriptor(@NotNull ModuleDescriptor moduleDescriptor) {
077 this.moduleDescriptor = moduleDescriptor;
078 }
079
080 @Inject
081 public void setBodyResolver(@NotNull BodyResolver bodyResolver) {
082 this.bodyResolver = bodyResolver;
083 }
084
085 @NotNull
086 public TopDownAnalysisContext analyzeDeclarations(
087 final KotlinCodeAnalyzer resolveSession,
088 @NotNull TopDownAnalysisParameters topDownAnalysisParameters,
089 @NotNull Collection<? extends PsiElement> declarations
090 ) {
091 assert topDownAnalysisParameters.isLazyTopDownAnalysis() : "Lazy analyzer is run in non-lazy mode";
092
093 final TopDownAnalysisContext c = new TopDownAnalysisContext(topDownAnalysisParameters);
094 final Multimap<FqName, JetElement> topLevelFqNames = HashMultimap.create();
095
096 final List<JetProperty> properties = new ArrayList<JetProperty>();
097 final List<JetNamedFunction> functions = new ArrayList<JetNamedFunction>();
098
099 // fill in the context
100 for (PsiElement declaration : declarations) {
101 declaration.accept(
102 new JetVisitorVoid() {
103
104 private void registerDeclarations(@NotNull List<JetDeclaration> declarations) {
105 for (JetDeclaration jetDeclaration : declarations) {
106 jetDeclaration.accept(this);
107 }
108 }
109
110 @Override
111 public void visitDeclaration(@NotNull JetDeclaration dcl) {
112 throw new IllegalArgumentException("Unsupported declaration: " + dcl + " " + dcl.getText());
113 }
114
115 @Override
116 public void visitJetFile(@NotNull JetFile file) {
117 if (file.isScript()) {
118 JetScript script = file.getScript();
119 assert script != null;
120
121 c.getScripts().put(script, resolveSession.getScriptDescriptor(script));
122 }
123 else {
124 JetPackageDirective packageDirective = file.getPackageDirective();
125 assert packageDirective != null : "No package in a non-script file: " + file;
126
127 c.addFile(file);
128
129 packageDirective.accept(this);
130 DescriptorResolver.registerFileInPackage(trace, file);
131
132 registerDeclarations(file.getDeclarations());
133
134 topLevelFqNames.put(file.getPackageFqName(), packageDirective);
135 }
136 }
137
138 @Override
139 public void visitPackageDirective(@NotNull JetPackageDirective directive) {
140 DescriptorResolver.resolvePackageHeader(directive, moduleDescriptor, trace);
141 }
142
143 @Override
144 public void visitImportDirective(@NotNull JetImportDirective importDirective) {
145 LazyImportScope importScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(importDirective.getContainingJetFile());
146 importScope.forceResolveImportDirective(importDirective);
147 }
148
149 private void visitClassOrObject(@NotNull JetClassOrObject classOrObject) {
150 ClassDescriptorWithResolutionScopes descriptor =
151 (ClassDescriptorWithResolutionScopes) resolveSession.getClassDescriptor(classOrObject);
152
153 c.getDeclaredClasses().put(classOrObject, descriptor);
154 registerDeclarations(classOrObject.getDeclarations());
155 registerTopLevelFqName(topLevelFqNames, classOrObject, descriptor);
156
157 checkManyClassObjects(classOrObject);
158 }
159
160 private void checkManyClassObjects(JetClassOrObject classOrObject) {
161 boolean classObjectAlreadyFound = false;
162 for (JetDeclaration jetDeclaration : classOrObject.getDeclarations()) {
163 jetDeclaration.accept(this);
164
165 if (jetDeclaration instanceof JetClassObject) {
166 if (classObjectAlreadyFound) {
167 trace.report(MANY_CLASS_OBJECTS.on((JetClassObject) jetDeclaration));
168 }
169 classObjectAlreadyFound = true;
170 }
171 }
172 }
173
174 @Override
175 public void visitClass(@NotNull JetClass klass) {
176 visitClassOrObject(klass);
177
178 registerPrimaryConstructorParameters(klass);
179 }
180
181 private void registerPrimaryConstructorParameters(@NotNull JetClass klass) {
182 for (JetParameter jetParameter : klass.getPrimaryConstructorParameters()) {
183 if (jetParameter.hasValOrVarNode()) {
184 c.getPrimaryConstructorParameterProperties().put(
185 jetParameter,
186 (PropertyDescriptor) resolveSession.resolveToDescriptor(jetParameter)
187 );
188 }
189 }
190 }
191
192 @Override
193 public void visitClassObject(@NotNull JetClassObject classObject) {
194 visitClassOrObject(classObject.getObjectDeclaration());
195 }
196
197 @Override
198 public void visitEnumEntry(@NotNull JetEnumEntry enumEntry) {
199 visitClassOrObject(enumEntry);
200 }
201
202 @Override
203 public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) {
204 visitClassOrObject(declaration);
205 }
206
207 @Override
208 public void visitAnonymousInitializer(@NotNull JetClassInitializer initializer) {
209 registerScope(c, resolveSession, initializer);
210 JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(initializer, JetClassOrObject.class);
211 c.getAnonymousInitializers().put(
212 initializer,
213 (ClassDescriptorWithResolutionScopes) resolveSession.resolveToDescriptor(classOrObject)
214 );
215 }
216
217 @Override
218 public void visitTypedef(@NotNull JetTypedef typedef) {
219 trace.report(UNSUPPORTED.on(typedef, "Typedefs are not supported"));
220 }
221
222 @Override
223 public void visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration) {
224 // Ignore: multi-declarations are only allowed locally
225 }
226
227 @Override
228 public void visitNamedFunction(@NotNull JetNamedFunction function) {
229 functions.add(function);
230 }
231
232 @Override
233 public void visitProperty(@NotNull JetProperty property) {
234 properties.add(property);
235 }
236 }
237 );
238 }
239
240 createFunctionDescriptors(c, resolveSession, functions);
241
242 createPropertyDescriptors(c, resolveSession, topLevelFqNames, properties);
243
244 resolveAllHeadersInClasses(c);
245
246 declarationResolver.checkRedeclarationsInPackages(resolveSession, topLevelFqNames);
247 declarationResolver.checkRedeclarationsInInnerClassNames(c);
248
249 overrideResolver.check(c);
250
251 resolveImportsInAllFiles(c, resolveSession);
252
253 overloadResolver.process(c);
254
255 bodyResolver.resolveBodies(c);
256
257
258 return c;
259 }
260
261 private static void resolveImportsInAllFiles(TopDownAnalysisContext c, KotlinCodeAnalyzer resolveSession) {
262 for (JetFile file : c.getFiles()) {
263 resolveAndCheckImports(file, resolveSession);
264 }
265
266 for (JetScript script : c.getScripts().keySet()) {
267 resolveAndCheckImports(script.getContainingJetFile(), resolveSession);
268 }
269 }
270
271 private static void resolveAllHeadersInClasses(TopDownAnalysisContext c) {
272 for (ClassDescriptorWithResolutionScopes classDescriptor : c.getAllClasses()) {
273 ((LazyClassDescriptor) classDescriptor).resolveMemberHeaders();
274 }
275 }
276
277 private static void createPropertyDescriptors(
278 TopDownAnalysisContext c,
279 KotlinCodeAnalyzer resolveSession,
280 Multimap<FqName, JetElement> topLevelFqNames,
281 List<JetProperty> properties
282 ) {
283 for (JetProperty property : properties) {
284 PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(property);
285
286 c.getProperties().put(property, descriptor);
287 registerTopLevelFqName(topLevelFqNames, property, descriptor);
288
289 registerScope(c, resolveSession, property);
290 registerScope(c, resolveSession, property.getGetter());
291 registerScope(c, resolveSession, property.getSetter());
292 }
293 }
294
295 private static void createFunctionDescriptors(
296 TopDownAnalysisContext c,
297 KotlinCodeAnalyzer resolveSession,
298 List<JetNamedFunction> functions
299 ) {
300 for (JetNamedFunction function : functions) {
301 c.getFunctions().put(
302 function,
303 (SimpleFunctionDescriptor) resolveSession.resolveToDescriptor(function)
304 );
305 registerScope(c, resolveSession, function);
306 }
307 }
308
309 private static void resolveAndCheckImports(@NotNull JetFile file, @NotNull KotlinCodeAnalyzer resolveSession) {
310 LazyImportScope fileScope = resolveSession.getScopeProvider().getExplicitImportsScopeForFile(file);
311 fileScope.forceResolveAllContents();
312 }
313
314 private static void registerScope(
315 @NotNull TopDownAnalysisContext c,
316 @NotNull KotlinCodeAnalyzer resolveSession,
317 @Nullable JetDeclaration declaration
318 ) {
319 if (declaration == null) return;
320 c.registerDeclaringScope(
321 declaration,
322 resolveSession.getScopeProvider().getResolutionScopeForDeclaration(declaration)
323 );
324 }
325
326 private static void registerTopLevelFqName(
327 @NotNull Multimap<FqName, JetElement> topLevelFqNames,
328 @NotNull JetNamedDeclaration declaration,
329 @NotNull DeclarationDescriptor descriptor
330 ) {
331 if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
332 FqName fqName = declaration.getFqName();
333 if (fqName != null) {
334 topLevelFqNames.put(fqName, declaration);
335 }
336 }
337 }
338
339 }
340
341