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 017package org.jetbrains.jet.lang.resolve.lazy; 018 019import com.google.common.base.Function; 020import com.google.common.base.Functions; 021import com.google.common.base.Predicates; 022import com.google.common.collect.Lists; 023import com.intellij.psi.PsiElement; 024import com.intellij.psi.PsiFile; 025import com.intellij.psi.util.PsiTreeUtil; 026import org.jetbrains.annotations.NotNull; 027import org.jetbrains.annotations.Nullable; 028import org.jetbrains.jet.di.InjectorForBodyResolve; 029import org.jetbrains.jet.lang.descriptors.*; 030import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase; 031import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor; 032import org.jetbrains.jet.lang.psi.*; 033import org.jetbrains.jet.lang.resolve.*; 034import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor; 035import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor; 036import org.jetbrains.jet.lang.resolve.name.FqName; 037import org.jetbrains.jet.lang.resolve.name.Name; 038import org.jetbrains.jet.lang.resolve.scopes.JetScope; 039import org.jetbrains.jet.lang.resolve.scopes.WritableScope; 040import org.jetbrains.jet.util.QualifiedNamesUtil; 041 042import java.util.*; 043 044public 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}