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.openapi.util.Computable;
023    import com.intellij.psi.PsiElement;
024    import com.intellij.psi.util.PsiTreeUtil;
025    import com.intellij.util.Function;
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.DescriptorUtils;
036    import org.jetbrains.jet.lang.resolve.lazy.data.JetClassLikeInfo;
037    import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
038    import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider;
039    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
040    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
041    import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
042    import org.jetbrains.jet.lang.resolve.name.FqName;
043    import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
044    import org.jetbrains.jet.lang.resolve.name.Name;
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 StorageManager 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 StorageManager 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 StorageManager 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 StorageManager 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 StorageManager 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                // Why not use the result here. See the comment
185                resolutionScope.getObjectDescriptor(name);
186                declaration = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
187            }
188            if (declaration == null) {
189                throw new IllegalArgumentException("Could not find a classifier for " + classOrObject + " " + classOrObject.getText());
190            }
191            return (ClassDescriptor) declaration;
192        }
193    
194        /*package*/ LazyClassDescriptor getClassObjectDescriptor(JetClassObject classObject) {
195            JetClass aClass = PsiTreeUtil.getParentOfType(classObject, JetClass.class);
196    
197            final LazyClassDescriptor parentClassDescriptor;
198    
199            if (aClass != null) {
200                parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(aClass);
201            }
202            else {
203                // Class object in object is an error but we want to find descriptors even for this case
204                JetObjectDeclaration objectDeclaration = PsiTreeUtil.getParentOfType(classObject, JetObjectDeclaration.class);
205                assert objectDeclaration != null : String.format("Class object %s can be in class or object in file %s", classObject, classObject.getContainingFile().getText());
206                parentClassDescriptor = (LazyClassDescriptor) getClassDescriptor(objectDeclaration);
207            }
208    
209            // Activate resolution and writing to trace
210            parentClassDescriptor.getClassObjectDescriptor();
211            DeclarationDescriptor declaration = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObject.getObjectDeclaration());
212    
213            if (declaration == null) {
214                // It's possible that there are several class objects and another class object is taking part in lazy resolve. We still want to
215                // build descriptors for such class objects.
216                final JetClassLikeInfo classObjectInfo = parentClassDescriptor.getClassObjectInfo(classObject);
217                if (classObjectInfo != null) {
218                    final Name name = DescriptorUtils.getClassObjectName(parentClassDescriptor.getName().asString());
219                    return storageManager.compute(new Computable<LazyClassDescriptor>() {
220                        @Override
221                        public LazyClassDescriptor compute() {
222                            // Create under lock to avoid premature access to published 'this'
223                            return new LazyClassDescriptor(ResolveSession.this, parentClassDescriptor, name, classObjectInfo);
224                        }
225                    });
226                }
227            }
228    
229            return (LazyClassDescriptor) declaration;
230        }
231    
232        @Override
233        @NotNull
234        public BindingContext getBindingContext() {
235            return trace.getBindingContext();
236        }
237    
238        @NotNull
239        public BindingTrace getTrace() {
240            return trace;
241        }
242    
243        @NotNull
244        public DeclarationProviderFactory getDeclarationProviderFactory() {
245            return declarationProviderFactory;
246        }
247    
248        @Override
249        @NotNull
250        public DeclarationDescriptor resolveToDescriptor(JetDeclaration declaration) {
251            DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
252                @Override
253                public DeclarationDescriptor visitClass(JetClass klass, Void data) {
254                    return getClassDescriptor(klass);
255                }
256    
257                @Override
258                public DeclarationDescriptor visitObjectDeclaration(JetObjectDeclaration declaration, Void data) {
259                    PsiElement parent = declaration.getParent();
260                    if (parent instanceof JetClassObject) {
261                        JetClassObject jetClassObject = (JetClassObject) parent;
262                        return resolveToDescriptor(jetClassObject);
263                    }
264                    return getClassDescriptor(declaration);
265                }
266    
267                @Override
268                public DeclarationDescriptor visitClassObject(JetClassObject classObject, Void data) {
269                    return getClassObjectDescriptor(classObject);
270                }
271    
272                @Override
273                public DeclarationDescriptor visitTypeParameter(JetTypeParameter parameter, Void data) {
274                    JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
275                    DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement);
276    
277                    List<TypeParameterDescriptor> typeParameters;
278                    if (ownerDescriptor instanceof CallableDescriptor) {
279                        CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
280                        typeParameters = callableDescriptor.getTypeParameters();
281                    }
282                    else if (ownerDescriptor instanceof ClassDescriptor) {
283                        ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
284                        typeParameters = classDescriptor.getTypeConstructor().getParameters();
285                    }
286                    else {
287                        throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
288                    }
289    
290                    Name name = ResolveSessionUtils.safeNameForLazyResolve(parameter.getNameAsName());
291                    for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
292                        if (typeParameterDescriptor.getName().equals(name)) {
293                            return typeParameterDescriptor;
294                        }
295                    }
296    
297                    throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
298                }
299    
300                @Override
301                public DeclarationDescriptor visitNamedFunction(JetNamedFunction function, Void data) {
302                    JetScope scopeForDeclaration = getInjector().getScopeProvider().getResolutionScopeForDeclaration(function);
303                    scopeForDeclaration.getFunctions(safeNameForLazyResolve(function));
304                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
305                }
306    
307                @Override
308                public DeclarationDescriptor visitParameter(JetParameter parameter, Void data) {
309                    PsiElement grandFather = parameter.getParent().getParent();
310                    if (grandFather instanceof JetClass) {
311                        JetClass jetClass = (JetClass) grandFather;
312                        // This is a primary constructor parameter
313                        ClassDescriptor classDescriptor = getClassDescriptor(jetClass);
314                        if (parameter.getValOrVarNode() != null) {
315                            classDescriptor.getDefaultType().getMemberScope().getProperties(safeNameForLazyResolve(parameter));
316                            return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
317                        }
318                        else {
319                            ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
320                            assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
321                            constructor.getValueParameters();
322                            return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
323                        }
324                    }
325                    return super.visitParameter(parameter, data);
326                }
327    
328                @Override
329                public DeclarationDescriptor visitProperty(JetProperty property, Void data) {
330                    JetScope scopeForDeclaration = getInjector().getScopeProvider().getResolutionScopeForDeclaration(property);
331                    scopeForDeclaration.getProperties(safeNameForLazyResolve(property));
332                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
333                }
334    
335                @Override
336                public DeclarationDescriptor visitObjectDeclarationName(JetObjectDeclarationName declarationName, Void data) {
337                    JetScope scopeForDeclaration = getInjector().getScopeProvider().getResolutionScopeForDeclaration(declarationName.getParent());
338                    scopeForDeclaration.getProperties(safeNameForLazyResolve(declarationName));
339                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, declarationName);
340                }
341    
342                @Override
343                public DeclarationDescriptor visitJetElement(JetElement element, Void data) {
344                    throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
345                                                       JetPsiUtil.getElementTextWithContext(element));
346                }
347            }, null);
348            if (result == null) {
349                throw new IllegalStateException("No descriptor resolved for " + declaration + " " + declaration.getText());
350            }
351            return result;
352        }
353    
354        @NotNull
355        public Name resolveClassifierAlias(@NotNull FqName packageName, @NotNull Name alias) {
356            // TODO: creating a new FqName object every time...
357            Name actualName = classifierAliases.fun(packageName.child(alias));
358            if (actualName == null) {
359                return alias;
360            }
361            return actualName;
362        }
363    
364        @Override
365        public void forceResolveAll() {
366            rootPackage.acceptVoid(new DeclarationDescriptorVisitorEmptyBodies<Void, Void>() {
367    
368                @Override
369                public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, Void data) {
370                    ForceResolveUtil.forceResolveAllContents(descriptor);
371                    return null;
372                }
373    
374                @Override
375                public Void visitNamespaceDescriptor(NamespaceDescriptor descriptor, Void data) {
376                    ForceResolveUtil.forceResolveAllContents(descriptor);
377                    return null;
378                }
379    
380                @Override
381                public Void visitClassDescriptor(ClassDescriptor descriptor, Void data) {
382                    ForceResolveUtil.forceResolveAllContents(descriptor);
383                    return null;
384                }
385    
386                @Override
387                public Void visitModuleDeclaration(ModuleDescriptor descriptor, Void data) {
388                    ForceResolveUtil.forceResolveAllContents(descriptor);
389                    return null;
390                }
391    
392                @Override
393                public Void visitScriptDescriptor(ScriptDescriptor scriptDescriptor, Void data) {
394                    ForceResolveUtil.forceResolveAllContents(scriptDescriptor);
395                    return null;
396                }
397            });
398        }
399    }