001    /*
002     * Copyright 2010-2014 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.collect.Lists;
020    import com.intellij.openapi.project.Project;
021    import com.intellij.psi.PsiElement;
022    import com.intellij.psi.util.PsiTreeUtil;
023    import com.intellij.util.Function;
024    import com.intellij.util.containers.ContainerUtil;
025    import kotlin.Function1;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.annotations.ReadOnly;
029    import org.jetbrains.jet.context.GlobalContextImpl;
030    import org.jetbrains.jet.lang.descriptors.*;
031    import org.jetbrains.jet.lang.psi.*;
032    import org.jetbrains.jet.lang.resolve.*;
033    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
034    import org.jetbrains.jet.lang.resolve.lazy.data.JetScriptInfo;
035    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
036    import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider;
037    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
038    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
039    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyScriptDescriptor;
040    import org.jetbrains.jet.lang.resolve.name.FqName;
041    import org.jetbrains.jet.lang.resolve.name.Name;
042    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043    import org.jetbrains.jet.renderer.DescriptorRenderer;
044    import org.jetbrains.jet.storage.*;
045    
046    import javax.inject.Inject;
047    import java.util.Collection;
048    import java.util.Collections;
049    import java.util.List;
050    
051    public class ResolveSession implements KotlinCodeAnalyzer {
052        private final LazyResolveStorageManager storageManager;
053        private final ExceptionTracker exceptionTracker;
054    
055        private final ModuleDescriptor module;
056    
057        private final BindingTrace trace;
058        private final DeclarationProviderFactory declarationProviderFactory;
059    
060        private final MemoizedFunctionToNullable<FqName, LazyPackageDescriptor> packages;
061        private final PackageFragmentProvider packageFragmentProvider;
062    
063        private final MemoizedFunctionToNotNull<JetScript, LazyScriptDescriptor> scriptDescriptors;
064    
065        private ScopeProvider scopeProvider;
066    
067        private JetImportsFactory jetImportFactory;
068        private AnnotationResolver annotationResolve;
069        private DescriptorResolver descriptorResolver;
070        private TypeResolver typeResolver;
071        private QualifiedExpressionResolver qualifiedExpressionResolver;
072        private ScriptBodyResolver scriptBodyResolver;
073    
074        @Inject
075        public void setJetImportFactory(JetImportsFactory jetImportFactory) {
076            this.jetImportFactory = jetImportFactory;
077        }
078    
079        @Inject
080        public void setAnnotationResolve(AnnotationResolver annotationResolve) {
081            this.annotationResolve = annotationResolve;
082        }
083    
084        @Inject
085        public void setDescriptorResolver(DescriptorResolver descriptorResolver) {
086            this.descriptorResolver = descriptorResolver;
087        }
088    
089        @Inject
090        public void setTypeResolver(TypeResolver typeResolver) {
091            this.typeResolver = typeResolver;
092        }
093    
094        @Inject
095        public void setQualifiedExpressionResolver(QualifiedExpressionResolver qualifiedExpressionResolver) {
096            this.qualifiedExpressionResolver = qualifiedExpressionResolver;
097        }
098    
099        @Inject
100        public void setScopeProvider(ScopeProvider scopeProvider) {
101            this.scopeProvider = scopeProvider;
102        }
103    
104        @Inject
105        public void setScriptBodyResolver(ScriptBodyResolver scriptBodyResolver) {
106            this.scriptBodyResolver = scriptBodyResolver;
107        }
108    
109        // Only calls from injectors expected
110        @Deprecated
111        public ResolveSession(
112                @NotNull Project project,
113                @NotNull GlobalContextImpl globalContext,
114                @NotNull ModuleDescriptorImpl rootDescriptor,
115                @NotNull DeclarationProviderFactory declarationProviderFactory,
116                @NotNull BindingTrace delegationTrace
117        ) {
118            LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager = new LockBasedLazyResolveStorageManager(globalContext.getStorageManager());
119            this.storageManager = lockBasedLazyResolveStorageManager;
120            this.exceptionTracker = globalContext.getExceptionTracker();
121            this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace);
122            this.module = rootDescriptor;
123    
124            this.packages = storageManager.createMemoizedFunctionWithNullableValues(new MemoizedFunctionToNullable<FqName, LazyPackageDescriptor>() {
125                @Nullable
126                @Override
127                public LazyPackageDescriptor invoke(FqName fqName) {
128                    return createPackage(fqName);
129                }
130            });
131    
132            this.declarationProviderFactory = declarationProviderFactory;
133    
134            this.packageFragmentProvider = new PackageFragmentProvider() {
135                @NotNull
136                @Override
137                public List<PackageFragmentDescriptor> getPackageFragments(@NotNull FqName fqName) {
138                    return ContainerUtil.<PackageFragmentDescriptor>createMaybeSingletonList(getPackageFragment(fqName));
139                }
140    
141                @NotNull
142                @Override
143                public Collection<FqName> getSubPackagesOf(@NotNull FqName fqName) {
144                    LazyPackageDescriptor packageDescriptor = getPackageFragment(fqName);
145                    if (packageDescriptor == null) {
146                        return Collections.emptyList();
147                    }
148                    return packageDescriptor.getDeclarationProvider().getAllDeclaredSubPackages();
149                }
150            };
151    
152            // TODO: parameter modification
153            rootDescriptor.addFragmentProvider(DependencyKind.SOURCES, packageFragmentProvider);
154    
155            this.scriptDescriptors = storageManager.createMemoizedFunction(
156                    new Function1<JetScript, LazyScriptDescriptor>() {
157                        @Override
158                        public LazyScriptDescriptor invoke(JetScript script) {
159                            return new LazyScriptDescriptor(
160                                    ResolveSession.this,
161                                    scriptBodyResolver,
162                                    script,
163                                    ScriptHeaderResolver.getScriptPriority(script)
164                            );
165                        }
166                    }
167            );
168        }
169    
170        @NotNull
171        public PackageFragmentProvider getPackageFragmentProvider() {
172            return packageFragmentProvider;
173        }
174    
175        @Override
176        @Nullable
177        public LazyPackageDescriptor getPackageFragment(@NotNull FqName fqName) {
178            return packages.invoke(fqName);
179        }
180    
181        @Nullable
182        private LazyPackageDescriptor createPackage(FqName fqName) {
183            if (!fqName.isRoot() && getPackageFragment(fqName.parent()) == null) {
184                return null;
185            }
186            PackageMemberDeclarationProvider provider = declarationProviderFactory.getPackageMemberDeclarationProvider(fqName);
187            if (provider == null) {
188                return null;
189            }
190            return new LazyPackageDescriptor(module, fqName, this, provider);
191        }
192    
193        @NotNull
194        @Override
195        public ModuleDescriptor getModuleDescriptor() {
196            return module;
197        }
198    
199        @NotNull
200        //@Override
201        public LazyResolveStorageManager getStorageManager() {
202            return storageManager;
203        }
204    
205        @NotNull
206        //@Override
207        public ExceptionTracker getExceptionTracker() {
208            return exceptionTracker;
209        }
210    
211        @Override
212        @NotNull
213        @ReadOnly
214        public Collection<ClassDescriptor> getTopLevelClassDescriptors(@NotNull FqName fqName) {
215            if (fqName.isRoot()) return Collections.emptyList();
216    
217            PackageMemberDeclarationProvider provider = declarationProviderFactory.getPackageMemberDeclarationProvider(fqName.parent());
218            if (provider == null) return Collections.emptyList();
219    
220            return ContainerUtil.mapNotNull(
221                    provider.getClassOrObjectDeclarations(fqName.shortName()),
222                    new Function<JetClassLikeInfo, ClassDescriptor>() {
223                        @Override
224                        public ClassDescriptor fun(JetClassLikeInfo classLikeInfo) {
225                            if (classLikeInfo instanceof JetScriptInfo) {
226                                return getClassDescriptorForScript(((JetScriptInfo) classLikeInfo).getScript());
227                            }
228                            JetClassOrObject classOrObject = classLikeInfo.getCorrespondingClassOrObject();
229                            if (classOrObject == null) return null;
230                            return getClassDescriptor(classOrObject);
231                        }
232                    }
233            );
234        }
235    
236        @Override
237        @NotNull
238        public ClassDescriptor getClassDescriptor(@NotNull JetClassOrObject classOrObject) {
239            if (classOrObject instanceof JetObjectDeclaration) {
240                JetObjectDeclaration objectDeclaration = (JetObjectDeclaration) classOrObject;
241                JetClassObject classObjectElement = objectDeclaration.getClassObjectElement();
242                if (classObjectElement != null) {
243                    return getClassObjectDescriptor(classObjectElement);
244                }
245            }
246            JetScope resolutionScope = getScopeProvider().getResolutionScopeForDeclaration(classOrObject);
247            Name name = classOrObject.getNameAsSafeName();
248    
249            // Why not use the result here. Because it may be that there is a redeclaration:
250            //     class A {} class A { fun foo(): A<completion here>}
251            // and if we find the class by name only, we may b-not get the right one.
252            // This call is only needed to make sure the classes are written to trace
253            ClassifierDescriptor scopeDescriptor = resolutionScope.getClassifier(name);
254            DeclarationDescriptor descriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
255    
256            if (descriptor == null) {
257                throw new IllegalArgumentException(
258                       String.format("Could not find a classifier for %s.\n" +
259                                     "Found descriptor: %s (%s).\n",
260                                     JetPsiUtil.getElementTextWithContext(classOrObject),
261                                     scopeDescriptor != null ? DescriptorRenderer.DEBUG_TEXT.render(scopeDescriptor) : "null",
262                                     scopeDescriptor != null ? (scopeDescriptor.getContainingDeclaration().getClass()) : null));
263            }
264    
265            return (ClassDescriptor) descriptor;
266        }
267    
268        @NotNull
269        public ClassDescriptor getClassDescriptorForScript(@NotNull JetScript script) {
270            JetScope resolutionScope = getScopeProvider().getResolutionScopeForDeclaration(script);
271            FqName fqName = ScriptNameUtil.classNameForScript(script);
272            ClassifierDescriptor classifier = resolutionScope.getClassifier(fqName.shortName());
273            assert classifier != null : "No descriptor for " + fqName + " in file " + script.getContainingFile();
274            return (ClassDescriptor) classifier;
275        }
276    
277        @Override
278        @NotNull
279        public ScriptDescriptor getScriptDescriptor(@NotNull JetScript script) {
280            return scriptDescriptors.invoke(script);
281        }
282    
283        @NotNull
284        /*package*/ LazyClassDescriptor getClassObjectDescriptor(@NotNull JetClassObject classObject) {
285            JetClass aClass = JetStubbedPsiUtil.getContainingDeclaration(classObject, JetClass.class);
286    
287            LazyClassDescriptor parentClassDescriptor;
288    
289            if (aClass != null) {
290                parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(aClass);
291            }
292            else {
293                // Class object in object is an error but we want to find descriptors even for this case
294                JetObjectDeclaration objectDeclaration = PsiTreeUtil.getParentOfType(classObject, JetObjectDeclaration.class);
295                assert objectDeclaration != null : String.format("Class object %s can be in class or object in file %s", classObject, classObject.getContainingFile().getText());
296                parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(objectDeclaration);
297            }
298    
299            // Activate resolution and writing to trace
300            parentClassDescriptor.getClassObjectDescriptor();
301            parentClassDescriptor.getDescriptorsForExtraClassObjects();
302            DeclarationDescriptor classObjectDescriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObject.getObjectDeclaration());
303            assert classObjectDescriptor != null : "No descriptor found for " + JetPsiUtil.getElementTextWithContext(classObject);
304    
305            return (LazyClassDescriptor) classObjectDescriptor;
306        }
307    
308        @Override
309        @NotNull
310        public BindingContext getBindingContext() {
311            return trace.getBindingContext();
312        }
313    
314        @NotNull
315        public BindingTrace getTrace() {
316            return trace;
317        }
318    
319        @NotNull
320        public DeclarationProviderFactory getDeclarationProviderFactory() {
321            return declarationProviderFactory;
322        }
323    
324        @Override
325        @NotNull
326        public DeclarationDescriptor resolveToDescriptor(@NotNull JetDeclaration declaration) {
327            DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
328                @Override
329                public DeclarationDescriptor visitClass(@NotNull JetClass klass, Void data) {
330                    return getClassDescriptor(klass);
331                }
332    
333                @Override
334                public DeclarationDescriptor visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
335                    PsiElement parent = declaration.getParent();
336                    if (parent instanceof JetClassObject) {
337                        JetClassObject jetClassObject = (JetClassObject) parent;
338                        return resolveToDescriptor(jetClassObject);
339                    }
340                    return getClassDescriptor(declaration);
341                }
342    
343                @Override
344                public DeclarationDescriptor visitClassObject(@NotNull JetClassObject classObject, Void data) {
345                    return getClassObjectDescriptor(classObject);
346                }
347    
348                @Override
349                public DeclarationDescriptor visitTypeParameter(@NotNull JetTypeParameter parameter, Void data) {
350                    JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
351                    DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement);
352    
353                    List<TypeParameterDescriptor> typeParameters;
354                    if (ownerDescriptor instanceof CallableDescriptor) {
355                        CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
356                        typeParameters = callableDescriptor.getTypeParameters();
357                    }
358                    else if (ownerDescriptor instanceof ClassDescriptor) {
359                        ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
360                        typeParameters = classDescriptor.getTypeConstructor().getParameters();
361                    }
362                    else {
363                        throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
364                    }
365    
366                    Name name = parameter.getNameAsSafeName();
367                    for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
368                        if (typeParameterDescriptor.getName().equals(name)) {
369                            return typeParameterDescriptor;
370                        }
371                    }
372    
373                    throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
374                }
375    
376                @Override
377                public DeclarationDescriptor visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
378                    JetScope scopeForDeclaration = getScopeProvider().getResolutionScopeForDeclaration(function);
379                    scopeForDeclaration.getFunctions(function.getNameAsSafeName());
380                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
381                }
382    
383                @Override
384                public DeclarationDescriptor visitParameter(@NotNull JetParameter parameter, Void data) {
385                    PsiElement grandFather = parameter.getParent().getParent();
386                    if (grandFather instanceof JetClass) {
387                        JetClass jetClass = (JetClass) grandFather;
388                        // This is a primary constructor parameter
389                        ClassDescriptor classDescriptor = getClassDescriptor(jetClass);
390                        if (parameter.hasValOrVarNode()) {
391                            classDescriptor.getDefaultType().getMemberScope().getProperties(parameter.getNameAsSafeName());
392                            return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
393                        }
394                        else {
395                            ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
396                            assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
397                            constructor.getValueParameters();
398                            return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
399                        }
400                    }
401                    return super.visitParameter(parameter, data);
402                }
403    
404                @Override
405                public DeclarationDescriptor visitProperty(@NotNull JetProperty property, Void data) {
406                    JetScope scopeForDeclaration = getScopeProvider().getResolutionScopeForDeclaration(property);
407                    scopeForDeclaration.getProperties(property.getNameAsSafeName());
408                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
409                }
410    
411                @Override
412                public DeclarationDescriptor visitJetElement(@NotNull JetElement element, Void data) {
413                    throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
414                                                       JetPsiUtil.getElementTextWithContext(element));
415                }
416            }, null);
417            if (result == null) {
418                throw new IllegalStateException("No descriptor resolved for " + declaration + ":\n" +
419                                                JetPsiUtil.getElementTextWithContext(declaration));
420            }
421            return result;
422        }
423    
424        @NotNull
425        private List<LazyPackageDescriptor> getAllPackages() {
426            LazyPackageDescriptor rootPackage = getPackageFragment(FqName.ROOT);
427            assert rootPackage != null : "Root package must be initialized";
428    
429            return collectAllPackages(Lists.<LazyPackageDescriptor>newArrayList(), rootPackage);
430        }
431    
432        @NotNull
433        private List<LazyPackageDescriptor> collectAllPackages(
434                @NotNull List<LazyPackageDescriptor> result,
435                @NotNull LazyPackageDescriptor current
436        ) {
437            result.add(current);
438            for (FqName subPackage : packageFragmentProvider.getSubPackagesOf(current.getFqName())) {
439                LazyPackageDescriptor fragment = getPackageFragment(subPackage);
440                assert fragment != null : "Couldn't find fragment for " + subPackage;
441                collectAllPackages(result, fragment);
442            }
443            return result;
444        }
445    
446        @Override
447        public void forceResolveAll() {
448            for (LazyPackageDescriptor lazyPackage : getAllPackages()) {
449                ForceResolveUtil.forceResolveAllContents(lazyPackage);
450            }
451        }
452    
453        @Override
454        @NotNull
455        public ScopeProvider getScopeProvider() {
456            return scopeProvider;
457        }
458    
459        @NotNull
460        public JetImportsFactory getJetImportsFactory() {
461            return jetImportFactory;
462        }
463    
464        @NotNull
465        public AnnotationResolver getAnnotationResolver() {
466            return annotationResolve;
467        }
468    
469        @NotNull
470        public DescriptorResolver getDescriptorResolver() {
471            return descriptorResolver;
472        }
473    
474        @NotNull
475        public TypeResolver getTypeResolver() {
476            return typeResolver;
477        }
478    
479        @NotNull
480        public QualifiedExpressionResolver getQualifiedExpressionResolver() {
481            return qualifiedExpressionResolver;
482        }
483    }