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.Predicate;
020 import com.google.common.base.Predicates;
021 import com.intellij.openapi.project.Project;
022 import com.intellij.psi.PsiElement;
023 import com.intellij.psi.util.PsiTreeUtil;
024 import com.intellij.util.Function;
025 import jet.Function0;
026 import org.jetbrains.annotations.NotNull;
027 import org.jetbrains.annotations.Nullable;
028 import org.jetbrains.jet.di.InjectorForLazyResolve;
029 import org.jetbrains.jet.lang.descriptors.*;
030 import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies;
031 import org.jetbrains.jet.lang.psi.*;
032 import org.jetbrains.jet.lang.resolve.BindingContext;
033 import org.jetbrains.jet.lang.resolve.BindingTrace;
034 import org.jetbrains.jet.lang.resolve.BindingTraceContext;
035 import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
036 import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
037 import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider;
038 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
039 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
040 import org.jetbrains.jet.lang.resolve.lazy.storage.LazyResolveStorageManager;
041 import org.jetbrains.jet.lang.resolve.name.FqName;
042 import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
043 import org.jetbrains.jet.lang.resolve.name.Name;
044 import org.jetbrains.jet.lang.resolve.name.SpecialNames;
045 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
046
047 import java.util.List;
048
049 import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
050
051 public class ResolveSession implements KotlinCodeAnalyzer {
052 public static final Function<FqName, Name> NO_ALIASES = new Function<FqName, Name>() {
053
054 @Override
055 public Name fun(FqName name) {
056 return null;
057 }
058 };
059
060 private final LazyResolveStorageManager storageManager;
061
062 private final ModuleDescriptor module;
063 private final LazyPackageDescriptor rootPackage;
064
065 private final BindingTrace trace;
066 private final DeclarationProviderFactory declarationProviderFactory;
067
068 private final Predicate<FqNameUnsafe> specialClasses;
069
070
071 private final InjectorForLazyResolve injector;
072
073 private final Function<FqName, Name> classifierAliases;
074
075 public ResolveSession(
076 @NotNull Project project,
077 @NotNull LazyResolveStorageManager storageManager,
078 @NotNull ModuleDescriptorImpl rootDescriptor,
079 @NotNull DeclarationProviderFactory declarationProviderFactory
080 ) {
081 this(project, storageManager, rootDescriptor, declarationProviderFactory, NO_ALIASES,
082 Predicates.<FqNameUnsafe>alwaysFalse(),
083 new BindingTraceContext());
084 }
085
086 public ResolveSession(
087 @NotNull Project project,
088 @NotNull LazyResolveStorageManager storageManager,
089 @NotNull ModuleDescriptorImpl rootDescriptor,
090 @NotNull DeclarationProviderFactory declarationProviderFactory,
091 @NotNull BindingTrace delegationTrace
092 ) {
093 this(project,
094 storageManager,
095 rootDescriptor,
096 declarationProviderFactory,
097 NO_ALIASES,
098 Predicates.<FqNameUnsafe>alwaysFalse(),
099 delegationTrace);
100 }
101
102 @Deprecated // Internal use only
103 public ResolveSession(
104 @NotNull Project project,
105 @NotNull LazyResolveStorageManager storageManager,
106 @NotNull ModuleDescriptorImpl rootDescriptor,
107 @NotNull DeclarationProviderFactory declarationProviderFactory,
108 @NotNull Function<FqName, Name> classifierAliases,
109 @NotNull Predicate<FqNameUnsafe> specialClasses,
110 @NotNull BindingTrace delegationTrace
111 ) {
112 this.storageManager = storageManager;
113 this.classifierAliases = classifierAliases;
114 this.specialClasses = specialClasses;
115 this.trace = storageManager.createSafeTrace(delegationTrace);
116 this.injector = new InjectorForLazyResolve(project, this, rootDescriptor);
117 this.module = rootDescriptor;
118 PackageMemberDeclarationProvider provider = declarationProviderFactory.getPackageMemberDeclarationProvider(FqName.ROOT);
119 assert provider != null : "No declaration provider for root package in " + rootDescriptor;
120 this.rootPackage = new LazyPackageDescriptor(rootDescriptor, FqNameUnsafe.ROOT_NAME, this, provider);
121 rootDescriptor.setRootNamespace(rootPackage);
122
123 this.declarationProviderFactory = declarationProviderFactory;
124 }
125
126 @NotNull
127 public InjectorForLazyResolve getInjector() {
128 return injector;
129 }
130
131 public boolean isClassSpecial(@NotNull FqNameUnsafe fqName) {
132 return specialClasses.apply(fqName);
133 }
134
135 @Override
136 public ModuleDescriptor getRootModuleDescriptor() {
137 return module;
138 }
139
140 @NotNull
141 public LazyResolveStorageManager getStorageManager() {
142 return storageManager;
143 }
144
145 @Override
146 @Nullable
147 public NamespaceDescriptor getPackageDescriptor(@NotNull Name shortName) {
148 return rootPackage.getMemberScope().getNamespace(shortName);
149 }
150
151 @Override
152 @Nullable
153 public NamespaceDescriptor getPackageDescriptorByFqName(FqName fqName) {
154 if (fqName.isRoot()) {
155 return rootPackage;
156 }
157 List<Name> names = fqName.pathSegments();
158 NamespaceDescriptor current = getPackageDescriptor(names.get(0));
159 if (current == null) return null;
160 for (Name name : names.subList(1, names.size())) {
161 current = current.getMemberScope().getNamespace(name);
162 if (current == null) return null;
163 }
164 return current;
165 }
166
167 @Override
168 @NotNull
169 public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) {
170 if (classOrObject.getParent() instanceof JetClassObject) {
171 return getClassObjectDescriptor((JetClassObject) classOrObject.getParent());
172 }
173 JetScope resolutionScope = getInjector().getScopeProvider().getResolutionScopeForDeclaration(classOrObject);
174 Name name = safeNameForLazyResolve(classOrObject.getNameAsName());
175
176 // Why not use the result here. Because it may be that there is a redeclaration:
177 // class A {} class A { fun foo(): A<completion here>}
178 // and if we find the class by name only, we may b-not get the right one.
179 // This call is only needed to make sure the classes are written to trace
180 resolutionScope.getClassifier(name);
181 DeclarationDescriptor declaration = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
182
183 if (declaration == null) {
184 throw new IllegalArgumentException("Could not find a classifier for " + classOrObject + " " + classOrObject.getText());
185 }
186 return (ClassDescriptor) declaration;
187 }
188
189 /*package*/ LazyClassDescriptor getClassObjectDescriptor(JetClassObject classObject) {
190 JetClass aClass = PsiTreeUtil.getParentOfType(classObject, JetClass.class);
191
192 final LazyClassDescriptor parentClassDescriptor;
193
194 if (aClass != null) {
195 parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(aClass);
196 }
197 else {
198 // Class object in object is an error but we want to find descriptors even for this case
199 JetObjectDeclaration objectDeclaration = PsiTreeUtil.getParentOfType(classObject, JetObjectDeclaration.class);
200 assert objectDeclaration != null : String.format("Class object %s can be in class or object in file %s", classObject, classObject.getContainingFile().getText());
201 parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(objectDeclaration);
202 }
203
204 // Activate resolution and writing to trace
205 parentClassDescriptor.getClassObjectDescriptor();
206 DeclarationDescriptor declaration = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObject.getObjectDeclaration());
207
208 if (declaration == null) {
209 // It's possible that there are several class objects and another class object is taking part in lazy resolve. We still want to
210 // build descriptors for such class objects.
211 final JetClassLikeInfo classObjectInfo = parentClassDescriptor.getClassObjectInfo(classObject);
212 if (classObjectInfo != null) {
213 final Name name = SpecialNames.getClassObjectName(parentClassDescriptor.getName());
214 return storageManager.compute(new Function0<LazyClassDescriptor>() {
215 @Override
216 public LazyClassDescriptor invoke() {
217 // Create under lock to avoid premature access to published 'this'
218 return new LazyClassDescriptor(ResolveSession.this, parentClassDescriptor, name, classObjectInfo);
219 }
220 });
221 }
222 }
223
224 return (LazyClassDescriptor) declaration;
225 }
226
227 @Override
228 @NotNull
229 public BindingContext getBindingContext() {
230 return trace.getBindingContext();
231 }
232
233 @NotNull
234 public BindingTrace getTrace() {
235 return trace;
236 }
237
238 @NotNull
239 public DeclarationProviderFactory getDeclarationProviderFactory() {
240 return declarationProviderFactory;
241 }
242
243 @Override
244 @NotNull
245 public DeclarationDescriptor resolveToDescriptor(JetDeclaration declaration) {
246 DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
247 @Override
248 public DeclarationDescriptor visitClass(@NotNull JetClass klass, Void data) {
249 return getClassDescriptor(klass);
250 }
251
252 @Override
253 public DeclarationDescriptor visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
254 PsiElement parent = declaration.getParent();
255 if (parent instanceof JetClassObject) {
256 JetClassObject jetClassObject = (JetClassObject) parent;
257 return resolveToDescriptor(jetClassObject);
258 }
259 return getClassDescriptor(declaration);
260 }
261
262 @Override
263 public DeclarationDescriptor visitClassObject(@NotNull JetClassObject classObject, Void data) {
264 return getClassObjectDescriptor(classObject);
265 }
266
267 @Override
268 public DeclarationDescriptor visitTypeParameter(@NotNull JetTypeParameter parameter, Void data) {
269 JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
270 DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement);
271
272 List<TypeParameterDescriptor> typeParameters;
273 if (ownerDescriptor instanceof CallableDescriptor) {
274 CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
275 typeParameters = callableDescriptor.getTypeParameters();
276 }
277 else if (ownerDescriptor instanceof ClassDescriptor) {
278 ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
279 typeParameters = classDescriptor.getTypeConstructor().getParameters();
280 }
281 else {
282 throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
283 }
284
285 Name name = ResolveSessionUtils.safeNameForLazyResolve(parameter.getNameAsName());
286 for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
287 if (typeParameterDescriptor.getName().equals(name)) {
288 return typeParameterDescriptor;
289 }
290 }
291
292 throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
293 }
294
295 @Override
296 public DeclarationDescriptor visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
297 JetScope scopeForDeclaration = getInjector().getScopeProvider().getResolutionScopeForDeclaration(function);
298 scopeForDeclaration.getFunctions(safeNameForLazyResolve(function));
299 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
300 }
301
302 @Override
303 public DeclarationDescriptor visitParameter(@NotNull JetParameter parameter, Void data) {
304 PsiElement grandFather = parameter.getParent().getParent();
305 if (grandFather instanceof JetClass) {
306 JetClass jetClass = (JetClass) grandFather;
307 // This is a primary constructor parameter
308 ClassDescriptor classDescriptor = getClassDescriptor(jetClass);
309 if (parameter.getValOrVarNode() != null) {
310 classDescriptor.getDefaultType().getMemberScope().getProperties(safeNameForLazyResolve(parameter));
311 return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
312 }
313 else {
314 ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
315 assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
316 constructor.getValueParameters();
317 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
318 }
319 }
320 return super.visitParameter(parameter, data);
321 }
322
323 @Override
324 public DeclarationDescriptor visitProperty(@NotNull JetProperty property, Void data) {
325 JetScope scopeForDeclaration = getInjector().getScopeProvider().getResolutionScopeForDeclaration(property);
326 scopeForDeclaration.getProperties(safeNameForLazyResolve(property));
327 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
328 }
329
330 @Override
331 public DeclarationDescriptor visitJetElement(@NotNull JetElement element, Void data) {
332 throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
333 JetPsiUtil.getElementTextWithContext(element));
334 }
335 }, null);
336 if (result == null) {
337 throw new IllegalStateException("No descriptor resolved for " + declaration + " " + declaration.getText());
338 }
339 return result;
340 }
341
342 @NotNull
343 public Name resolveClassifierAlias(@NotNull FqName packageName, @NotNull Name alias) {
344 // TODO: creating a new FqName object every time...
345 Name actualName = classifierAliases.fun(packageName.child(alias));
346 if (actualName == null) {
347 return alias;
348 }
349 return actualName;
350 }
351
352 @Override
353 public void forceResolveAll() {
354 rootPackage.acceptVoid(new DeclarationDescriptorVisitorEmptyBodies<Void, Void>() {
355
356 @Override
357 public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, Void data) {
358 ForceResolveUtil.forceResolveAllContents(descriptor);
359 return null;
360 }
361
362 @Override
363 public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, Void data) {
364 ForceResolveUtil.forceResolveAllContents(descriptor);
365 return null;
366 }
367
368 @Override
369 public Void visitClassDescriptor(ClassDescriptor descriptor, Void data) {
370 ForceResolveUtil.forceResolveAllContents(descriptor);
371 return null;
372 }
373
374 @Override
375 public Void visitModuleDeclaration(ModuleDescriptor descriptor, Void data) {
376 ForceResolveUtil.forceResolveAllContents(descriptor);
377 return null;
378 }
379
380 @Override
381 public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, Void data) {
382 ForceResolveUtil.forceResolveAllContents(scriptDescriptor);
383 return null;
384 }
385 });
386 }
387 }