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    }