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.lazy;
018
019 import com.google.common.base.Function;
020 import com.google.common.base.Functions;
021 import com.google.common.base.Predicates;
022 import com.google.common.collect.Lists;
023 import com.intellij.psi.PsiElement;
024 import com.intellij.psi.PsiFile;
025 import com.intellij.psi.util.PsiTreeUtil;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.di.InjectorForBodyResolve;
029 import org.jetbrains.jet.lang.descriptors.*;
030 import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
031 import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
032 import org.jetbrains.jet.lang.psi.*;
033 import org.jetbrains.jet.lang.resolve.*;
034 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
035 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
036 import org.jetbrains.jet.lang.resolve.name.FqName;
037 import org.jetbrains.jet.lang.resolve.name.Name;
038 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039 import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
040 import org.jetbrains.jet.util.QualifiedNamesUtil;
041
042 import java.util.*;
043
044 public class ResolveSessionUtils {
045
046 // This name is used as a key for the case when something has no name _due to a syntactic error_
047 // Example: fun (x: Int) = 5
048 // There's no name for this function in the PSI
049 // The name contains a GUID to avoid clashes, if a clash happens, it's not a big deal: the code does not compile anyway
050 public static final Name NO_NAME_FOR_LAZY_RESOLVE = Name.identifier("no_name_in_PSI_for_lazy_resolve_3d19d79d_1ba9_4cd0_b7f5_b46aa3cd5d40");
051
052 private ResolveSessionUtils() {
053 }
054
055 @SuppressWarnings("unchecked")
056 private static final BodyResolveContextForLazy EMPTY_CONTEXT = new BodyResolveContextForLazy((Function) Functions.constant(null));
057
058 private static class BodyResolveContextForLazy implements BodiesResolveContext {
059
060 private final Function<JetDeclaration, JetScope> declaringScopes;
061
062 private BodyResolveContextForLazy(@NotNull Function<JetDeclaration, JetScope> declaringScopes) {
063 this.declaringScopes = declaringScopes;
064 }
065
066 @Override
067 public Collection<JetFile> getFiles() {
068 return Collections.emptySet();
069 }
070
071 @Override
072 public Map<JetClass, MutableClassDescriptor> getClasses() {
073 return Collections.emptyMap();
074 }
075
076 @Override
077 public Map<JetObjectDeclaration, MutableClassDescriptor> getObjects() {
078 return Collections.emptyMap();
079 }
080
081 @Override
082 public Map<JetProperty, PropertyDescriptor> getProperties() {
083 return Collections.emptyMap();
084 }
085
086 @Override
087 public Map<JetNamedFunction, SimpleFunctionDescriptor> getFunctions() {
088 return Collections.emptyMap();
089 }
090
091 @Override
092 public Function<JetDeclaration, JetScope> getDeclaringScopes() {
093 return declaringScopes;
094 }
095
096 @Override
097 public Map<JetScript, ScriptDescriptor> getScripts() {
098 return Collections.emptyMap();
099 }
100
101 @Override
102 public Map<JetScript, WritableScope> getScriptScopes() {
103 return Collections.emptyMap();
104 }
105
106 @Override
107 public void setTopDownAnalysisParameters(TopDownAnalysisParameters parameters) {
108 }
109
110 @Override
111 public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
112 return true;
113 }
114 }
115
116 public static @NotNull BindingContext resolveToExpression(
117 @NotNull ResolveSession resolveSession,
118 @NotNull JetElement expression
119 ) {
120 DelegatingBindingTrace trace = new DelegatingBindingTrace(
121 resolveSession.getBindingContext(), "trace to resolve expression", expression);
122 JetFile file = (JetFile) expression.getContainingFile();
123
124 @SuppressWarnings("unchecked")
125 PsiElement topmostCandidateForAdditionalResolve = JetPsiUtil.getTopmostParentOfTypes(expression,
126 JetNamedFunction.class, JetClassInitializer.class, JetProperty.class, JetDelegationSpecifierList.class);
127
128 if (topmostCandidateForAdditionalResolve != null) {
129 if (topmostCandidateForAdditionalResolve instanceof JetNamedFunction) {
130 functionAdditionalResolve(resolveSession, (JetNamedFunction) topmostCandidateForAdditionalResolve, trace, file);
131 }
132 else if (topmostCandidateForAdditionalResolve instanceof JetClassInitializer) {
133 initializerAdditionalResolve(resolveSession, (JetClassInitializer) topmostCandidateForAdditionalResolve, trace, file);
134 }
135 else if (topmostCandidateForAdditionalResolve instanceof JetProperty) {
136 propertyAdditionalResolve(resolveSession, (JetProperty) topmostCandidateForAdditionalResolve, trace, file);
137 }
138 else if (topmostCandidateForAdditionalResolve instanceof JetDelegationSpecifierList) {
139 delegationSpecifierAdditionalResolve(resolveSession, (JetDelegationSpecifierList) topmostCandidateForAdditionalResolve,
140 trace, file);
141 }
142 else {
143 assert false : "Invalid type of the topmost parent";
144 }
145
146 return trace.getBindingContext();
147 }
148
149 if (expression instanceof JetExpression) {
150 JetExpression jetExpression = (JetExpression) expression;
151 // Setup resolution scope explicitly
152 if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, jetExpression) == null) {
153 JetScope scope = getExpressionMemberScope(resolveSession, jetExpression);
154 if (scope != null) {
155 trace.record(BindingContext.RESOLUTION_SCOPE, jetExpression, scope);
156 }
157 }
158 }
159
160 return trace.getBindingContext();
161 }
162
163 private static void delegationSpecifierAdditionalResolve(
164 KotlinCodeAnalyzer analyzer,
165 JetDelegationSpecifierList specifier, DelegatingBindingTrace trace, JetFile file) {
166 BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, analyzer.getRootModuleDescriptor());
167
168 JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent();
169 LazyClassDescriptor descriptor = (LazyClassDescriptor) analyzer.resolveToDescriptor(classOrObject);
170
171 // Activate resolving of supertypes
172 descriptor.getTypeConstructor().getSupertypes();
173
174 bodyResolver.resolveDelegationSpecifierList(classOrObject, descriptor,
175 descriptor.getUnsubstitutedPrimaryConstructor(),
176 descriptor.getScopeForClassHeaderResolution(),
177 descriptor.getScopeForMemberDeclarationResolution());
178 }
179
180 private static void propertyAdditionalResolve(ResolveSession resolveSession, final JetProperty jetProperty, DelegatingBindingTrace trace, JetFile file) {
181 final JetScope propertyResolutionScope = resolveSession.getInjector().getScopeProvider().getResolutionScopeForDeclaration(
182 jetProperty);
183
184 BodyResolveContextForLazy bodyResolveContext = new BodyResolveContextForLazy(new Function<JetDeclaration, JetScope>() {
185 @Override
186 public JetScope apply(JetDeclaration declaration) {
187 assert declaration.getParent() == jetProperty : "Must be called only for property accessors, but called for " + declaration;
188 return propertyResolutionScope;
189 }
190 });
191 BodyResolver bodyResolver = createBodyResolver(trace, file, bodyResolveContext, resolveSession.getRootModuleDescriptor());
192 PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty);
193
194 JetExpression propertyInitializer = jetProperty.getInitializer();
195 if (propertyInitializer != null) {
196 bodyResolver.resolvePropertyInitializer(jetProperty, descriptor, propertyInitializer, propertyResolutionScope);
197 }
198
199 JetExpression propertyDelegate = jetProperty.getDelegateExpression();
200 if (propertyDelegate != null) {
201 bodyResolver.resolvePropertyDelegate(jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope);
202 }
203
204 bodyResolver.resolvePropertyAccessors(jetProperty, descriptor);
205 }
206
207 private static void functionAdditionalResolve(
208 ResolveSession resolveSession,
209 JetNamedFunction namedFunction,
210 DelegatingBindingTrace trace,
211 JetFile file
212 ) {
213 BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, resolveSession.getRootModuleDescriptor());
214 JetScope scope = resolveSession.getInjector().getScopeProvider().getResolutionScopeForDeclaration(namedFunction);
215 FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction);
216 bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope);
217 }
218
219 private static boolean initializerAdditionalResolve(
220 KotlinCodeAnalyzer analyzer,
221 JetClassInitializer classInitializer,
222 DelegatingBindingTrace trace,
223 JetFile file
224 ) {
225 BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, analyzer.getRootModuleDescriptor());
226 JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class);
227 LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) analyzer.resolveToDescriptor(classOrObject);
228 bodyResolver.resolveAnonymousInitializers(classOrObject, classOrObjectDescriptor.getUnsubstitutedPrimaryConstructor(),
229 classOrObjectDescriptor.getScopeForPropertyInitializerResolution());
230
231 return true;
232 }
233
234 private static BodyResolver createBodyResolver(DelegatingBindingTrace trace, JetFile file, BodyResolveContextForLazy bodyResolveContext,
235 ModuleDescriptor module) {
236 TopDownAnalysisParameters parameters = new TopDownAnalysisParameters(
237 Predicates.<PsiFile>alwaysTrue(), false, true, Collections.<AnalyzerScriptParameter>emptyList());
238 InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(file.getProject(), parameters, trace, bodyResolveContext, module);
239 return bodyResolve.getBodyResolver();
240 }
241
242 private static BodyResolver createBodyResolverWithEmptyContext(
243 DelegatingBindingTrace trace,
244 JetFile file,
245 ModuleDescriptor module
246 ) {
247 return createBodyResolver(trace, file, EMPTY_CONTEXT, module);
248 }
249
250 private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
251 ScopeProvider provider = resolveSession.getInjector().getScopeProvider();
252 JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
253 if (parentDeclaration == null) {
254 return provider.getFileScope((JetFile) expression.getContainingFile());
255 }
256 return provider.getResolutionScopeForDeclaration(parentDeclaration);
257 }
258
259 public static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
260 DelegatingBindingTrace trace = new DelegatingBindingTrace(
261 resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression);
262
263 if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) {
264 QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getInjector().getQualifiedExpressionResolver();
265
266 // In some type declaration
267 if (expression.getParent() instanceof JetUserType) {
268 JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier();
269 if (qualifier != null) {
270 Collection<? extends DeclarationDescriptor> descriptors = qualifiedExpressionResolver
271 .lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace);
272
273 for (DeclarationDescriptor descriptor : descriptors) {
274 if (descriptor instanceof LazyPackageDescriptor) {
275 return ((LazyPackageDescriptor) descriptor).getMemberScope();
276 }
277 }
278 }
279 }
280
281 // Inside import
282 if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) {
283 NamespaceDescriptor rootPackage = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
284 assert rootPackage != null;
285
286 if (expression.getParent() instanceof JetDotQualifiedExpression) {
287 JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression();
288 String name = ((JetFile) expression.getContainingFile()).getPackageName();
289
290 NamespaceDescriptor filePackage =
291 name != null ? resolveSession.getPackageDescriptorByFqName(new FqName(name)) : rootPackage;
292 assert filePackage != null : "File package should be already resolved and be found";
293
294 JetScope scope = filePackage.getMemberScope();
295 Collection<? extends DeclarationDescriptor> descriptors;
296
297 if (element instanceof JetDotQualifiedExpression) {
298 descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression(
299 (JetDotQualifiedExpression) element, rootPackage.getMemberScope(), scope, trace,
300 QualifiedExpressionResolver.LookupMode.EVERYTHING, false);
301 }
302 else {
303 descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
304 (JetSimpleNameExpression) element, rootPackage.getMemberScope(), scope, trace,
305 QualifiedExpressionResolver.LookupMode.EVERYTHING, false, false);
306 }
307
308 for (DeclarationDescriptor descriptor : descriptors) {
309 if (descriptor instanceof NamespaceDescriptor) {
310 return ((NamespaceDescriptor) descriptor).getMemberScope();
311 }
312 }
313 }
314 else {
315 return rootPackage.getMemberScope();
316 }
317 }
318
319 // Inside package declaration
320 JetNamespaceHeader namespaceHeader = PsiTreeUtil.getParentOfType(expression, JetNamespaceHeader.class, false);
321 if (namespaceHeader != null) {
322 NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(
323 namespaceHeader.getParentFqName((JetReferenceExpression) expression));
324 if (packageDescriptor != null) {
325 return packageDescriptor.getMemberScope();
326 }
327 }
328 }
329
330 return null;
331 }
332
333 @NotNull
334 public static Collection<ClassDescriptor> getClassDescriptorsByFqName(
335 @NotNull KotlinCodeAnalyzer analyzer,
336 @NotNull FqName fqName
337 ) {
338 return getClassOrObjectDescriptorsByFqName(analyzer, fqName, false);
339 }
340
341 @NotNull
342 public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
343 @NotNull KotlinCodeAnalyzer analyzer,
344 @NotNull FqName fqName,
345 boolean includeObjectDeclarations
346 ) {
347 if (fqName.isRoot()) {
348 return Collections.emptyList();
349 }
350
351 Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();
352
353 FqName packageFqName = fqName.parent();
354 while (true) {
355 NamespaceDescriptor packageDescriptor = analyzer.getPackageDescriptorByFqName(packageFqName);
356 if (packageDescriptor != null) {
357 FqName classInPackagePath = new FqName(QualifiedNamesUtil.tail(packageFqName, fqName));
358 Collection<ClassDescriptor> descriptors = getClassOrObjectDescriptorsByFqName(packageDescriptor, classInPackagePath,
359 includeObjectDeclarations);
360 classDescriptors.addAll(descriptors);
361 }
362
363 if (packageFqName.isRoot()) {
364 break;
365 }
366 else {
367 packageFqName = packageFqName.parent();
368 }
369 }
370
371 return classDescriptors;
372 }
373
374 private static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
375 NamespaceDescriptor packageDescriptor,
376 FqName path,
377 boolean includeObjectDeclarations
378 ) {
379 if (path.isRoot()) {
380 return Collections.emptyList();
381 }
382
383 Collection<JetScope> scopes = Arrays.asList(packageDescriptor.getMemberScope());
384
385 List<Name> names = path.pathSegments();
386 if (names.size() > 1) {
387 for (Name subName : path.pathSegments().subList(0, names.size() - 1)) {
388 Collection<JetScope> tempScopes = Lists.newArrayList();
389 for (JetScope scope : scopes) {
390 ClassifierDescriptor classifier = scope.getClassifier(subName);
391 if (classifier instanceof ClassDescriptorBase) {
392 ClassDescriptorBase classDescriptor = (ClassDescriptorBase) classifier;
393 tempScopes.add(classDescriptor.getUnsubstitutedInnerClassesScope());
394 }
395 }
396 scopes = tempScopes;
397 }
398 }
399
400 Name shortName = path.shortName();
401 Collection<ClassDescriptor> resultClassifierDescriptors = Lists.newArrayList();
402 for (JetScope scope : scopes) {
403 ClassifierDescriptor classifier = scope.getClassifier(shortName);
404 if (classifier instanceof ClassDescriptor) {
405 resultClassifierDescriptors.add((ClassDescriptor) classifier);
406 }
407 if (includeObjectDeclarations) {
408 ClassDescriptor objectDescriptor = scope.getObjectDescriptor(shortName);
409 if (objectDescriptor != null) {
410 resultClassifierDescriptors.add(objectDescriptor);
411 }
412 }
413 }
414
415 return resultClassifierDescriptors;
416 }
417
418 @NotNull
419 public static Name safeNameForLazyResolve(@NotNull JetNamed named) {
420 Name name = named.getNameAsName();
421 return safeNameForLazyResolve(name);
422 }
423
424 @NotNull
425 public static Name safeNameForLazyResolve(@Nullable Name name) {
426 return name != null ? name : NO_NAME_FOR_LAZY_RESOLVE;
427 }
428 }