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