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