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
017package org.jetbrains.jet.lang.resolve.lazy;
018
019import com.google.common.base.Predicate;
020import com.google.common.base.Predicates;
021import com.intellij.openapi.project.Project;
022import com.intellij.psi.PsiElement;
023import com.intellij.psi.util.PsiTreeUtil;
024import com.intellij.util.Function;
025import org.jetbrains.annotations.NotNull;
026import org.jetbrains.annotations.Nullable;
027import org.jetbrains.jet.di.InjectorForLazyResolve;
028import org.jetbrains.jet.lang.descriptors.*;
029import org.jetbrains.jet.lang.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies;
030import org.jetbrains.jet.lang.psi.*;
031import org.jetbrains.jet.lang.resolve.BindingContext;
032import org.jetbrains.jet.lang.resolve.BindingTrace;
033import org.jetbrains.jet.lang.resolve.BindingTraceContext;
034import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactory;
035import org.jetbrains.jet.lang.resolve.lazy.declarations.PackageMemberDeclarationProvider;
036import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
037import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
038import org.jetbrains.jet.lang.resolve.lazy.storage.StorageManager;
039import org.jetbrains.jet.lang.resolve.name.FqName;
040import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
041import org.jetbrains.jet.lang.resolve.name.Name;
042import org.jetbrains.jet.lang.resolve.scopes.JetScope;
043
044import java.util.List;
045
046import static org.jetbrains.jet.lang.resolve.lazy.ResolveSessionUtils.safeNameForLazyResolve;
047
048public 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}