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.Function;
020    import com.google.common.base.Functions;
021    import com.google.common.base.Predicates;
022    import com.google.common.collect.Lists;
023    import com.intellij.psi.PsiElement;
024    import com.intellij.psi.PsiFile;
025    import com.intellij.psi.util.PsiTreeUtil;
026    import org.jetbrains.annotations.NotNull;
027    import org.jetbrains.annotations.Nullable;
028    import org.jetbrains.jet.di.InjectorForBodyResolve;
029    import org.jetbrains.jet.lang.descriptors.*;
030    import org.jetbrains.jet.lang.descriptors.impl.ClassDescriptorBase;
031    import org.jetbrains.jet.lang.descriptors.impl.MutableClassDescriptor;
032    import org.jetbrains.jet.lang.psi.*;
033    import org.jetbrains.jet.lang.resolve.*;
034    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyClassDescriptor;
035    import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyPackageDescriptor;
036    import org.jetbrains.jet.lang.resolve.name.FqName;
037    import org.jetbrains.jet.lang.resolve.name.Name;
038    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039    import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
040    import org.jetbrains.jet.util.QualifiedNamesUtil;
041    
042    import java.util.*;
043    
044    public class ResolveSessionUtils {
045    
046        // This name is used as a key for the case when something has no name _due to a syntactic error_
047        // Example: fun (x: Int) = 5
048        //          There's no name for this function in the PSI
049        // The name contains a GUID to avoid clashes, if a clash happens, it's not a big deal: the code does not compile anyway
050        public static final Name NO_NAME_FOR_LAZY_RESOLVE = Name.identifier("no_name_in_PSI_for_lazy_resolve_3d19d79d_1ba9_4cd0_b7f5_b46aa3cd5d40");
051    
052        private ResolveSessionUtils() {
053        }
054    
055        @SuppressWarnings("unchecked")
056        private static final BodyResolveContextForLazy EMPTY_CONTEXT = new BodyResolveContextForLazy((Function) Functions.constant(null));
057    
058        private static class BodyResolveContextForLazy implements BodiesResolveContext {
059    
060            private final Function<JetDeclaration, JetScope> declaringScopes;
061    
062            private BodyResolveContextForLazy(@NotNull Function<JetDeclaration, JetScope> declaringScopes) {
063                this.declaringScopes = declaringScopes;
064            }
065    
066            @Override
067            public Collection<JetFile> getFiles() {
068                return Collections.emptySet();
069            }
070    
071            @Override
072            public Map<JetClass, MutableClassDescriptor> getClasses() {
073                return Collections.emptyMap();
074            }
075    
076            @Override
077            public Map<JetObjectDeclaration, MutableClassDescriptor> getObjects() {
078                return Collections.emptyMap();
079            }
080    
081            @Override
082            public Map<JetProperty, PropertyDescriptor> getProperties() {
083                return Collections.emptyMap();
084            }
085    
086            @Override
087            public Map<JetNamedFunction, SimpleFunctionDescriptor> getFunctions() {
088                return Collections.emptyMap();
089            }
090    
091            @Override
092            public Function<JetDeclaration, JetScope> getDeclaringScopes() {
093                return declaringScopes;
094            }
095    
096            @Override
097            public Map<JetScript, ScriptDescriptor> getScripts() {
098                return Collections.emptyMap();
099            }
100    
101            @Override
102            public Map<JetScript, WritableScope> getScriptScopes() {
103                return Collections.emptyMap();
104            }
105    
106            @Override
107            public void setTopDownAnalysisParameters(TopDownAnalysisParameters parameters) {
108            }
109    
110            @Override
111            public boolean completeAnalysisNeeded(@NotNull PsiElement element) {
112                return true;
113            }
114        }
115    
116        public static @NotNull BindingContext resolveToExpression(
117                @NotNull ResolveSession resolveSession,
118                @NotNull JetElement expression
119        ) {
120            DelegatingBindingTrace trace = new DelegatingBindingTrace(
121                    resolveSession.getBindingContext(), "trace to resolve expression", expression);
122            JetFile file = (JetFile) expression.getContainingFile();
123    
124            @SuppressWarnings("unchecked")
125            PsiElement topmostCandidateForAdditionalResolve = JetPsiUtil.getTopmostParentOfTypes(expression,
126                    JetNamedFunction.class, JetClassInitializer.class, JetProperty.class, JetDelegationSpecifierList.class);
127    
128            if (topmostCandidateForAdditionalResolve != null) {
129                if (topmostCandidateForAdditionalResolve instanceof JetNamedFunction) {
130                    functionAdditionalResolve(resolveSession, (JetNamedFunction) topmostCandidateForAdditionalResolve, trace, file);
131                }
132                else if (topmostCandidateForAdditionalResolve instanceof JetClassInitializer) {
133                    initializerAdditionalResolve(resolveSession, (JetClassInitializer) topmostCandidateForAdditionalResolve, trace, file);
134                }
135                else if (topmostCandidateForAdditionalResolve instanceof JetProperty) {
136                    propertyAdditionalResolve(resolveSession, (JetProperty) topmostCandidateForAdditionalResolve, trace, file);
137                }
138                else if (topmostCandidateForAdditionalResolve instanceof JetDelegationSpecifierList) {
139                    delegationSpecifierAdditionalResolve(resolveSession, (JetDelegationSpecifierList) topmostCandidateForAdditionalResolve,
140                                                         trace, file);
141                }
142                else {
143                    assert false : "Invalid type of the topmost parent";
144                }
145    
146                return trace.getBindingContext();
147            }
148    
149            if (expression instanceof JetExpression) {
150                JetExpression jetExpression = (JetExpression) expression;
151                // Setup resolution scope explicitly
152                if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, jetExpression) == null) {
153                    JetScope scope = getExpressionMemberScope(resolveSession, jetExpression);
154                    if (scope != null) {
155                        trace.record(BindingContext.RESOLUTION_SCOPE, jetExpression, scope);
156                    }
157                }
158            }
159    
160            return trace.getBindingContext();
161        }
162    
163        private static void delegationSpecifierAdditionalResolve(
164                KotlinCodeAnalyzer analyzer,
165                JetDelegationSpecifierList specifier, DelegatingBindingTrace trace, JetFile file) {
166            BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, analyzer.getRootModuleDescriptor());
167    
168            JetClassOrObject classOrObject = (JetClassOrObject) specifier.getParent();
169            LazyClassDescriptor descriptor = (LazyClassDescriptor) analyzer.resolveToDescriptor(classOrObject);
170    
171            // Activate resolving of supertypes
172            descriptor.getTypeConstructor().getSupertypes();
173    
174            bodyResolver.resolveDelegationSpecifierList(classOrObject, descriptor,
175                                                        descriptor.getUnsubstitutedPrimaryConstructor(),
176                                                        descriptor.getScopeForClassHeaderResolution(),
177                                                        descriptor.getScopeForMemberDeclarationResolution());
178        }
179    
180        private static void propertyAdditionalResolve(ResolveSession resolveSession, final JetProperty jetProperty, DelegatingBindingTrace trace, JetFile file) {
181            final JetScope propertyResolutionScope = resolveSession.getInjector().getScopeProvider().getResolutionScopeForDeclaration(
182                    jetProperty);
183    
184            BodyResolveContextForLazy bodyResolveContext = new BodyResolveContextForLazy(new Function<JetDeclaration, JetScope>() {
185                @Override
186                public JetScope apply(JetDeclaration declaration) {
187                    assert declaration.getParent() == jetProperty : "Must be called only for property accessors, but called for " + declaration;
188                    return propertyResolutionScope;
189                }
190            });
191            BodyResolver bodyResolver = createBodyResolver(trace, file, bodyResolveContext, resolveSession.getRootModuleDescriptor());
192            PropertyDescriptor descriptor = (PropertyDescriptor) resolveSession.resolveToDescriptor(jetProperty);
193    
194            JetExpression propertyInitializer = jetProperty.getInitializer();
195            if (propertyInitializer != null) {
196                bodyResolver.resolvePropertyInitializer(jetProperty, descriptor, propertyInitializer, propertyResolutionScope);
197            }
198    
199            JetExpression propertyDelegate = jetProperty.getDelegateExpression();
200            if (propertyDelegate != null) {
201                bodyResolver.resolvePropertyDelegate(jetProperty, descriptor, propertyDelegate, propertyResolutionScope, propertyResolutionScope);
202            }
203    
204            bodyResolver.resolvePropertyAccessors(jetProperty, descriptor);
205        }
206    
207        private static void functionAdditionalResolve(
208                ResolveSession resolveSession,
209                JetNamedFunction namedFunction,
210                DelegatingBindingTrace trace,
211                JetFile file
212        ) {
213            BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, resolveSession.getRootModuleDescriptor());
214            JetScope scope = resolveSession.getInjector().getScopeProvider().getResolutionScopeForDeclaration(namedFunction);
215            FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction);
216            bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope);
217        }
218    
219        private static boolean initializerAdditionalResolve(
220                KotlinCodeAnalyzer analyzer,
221                JetClassInitializer classInitializer,
222                DelegatingBindingTrace trace,
223                JetFile file
224        ) {
225            BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, analyzer.getRootModuleDescriptor());
226            JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class);
227            LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) analyzer.resolveToDescriptor(classOrObject);
228            bodyResolver.resolveAnonymousInitializers(classOrObject, classOrObjectDescriptor.getUnsubstitutedPrimaryConstructor(),
229                    classOrObjectDescriptor.getScopeForPropertyInitializerResolution());
230    
231            return true;
232        }
233    
234        private static BodyResolver createBodyResolver(DelegatingBindingTrace trace, JetFile file, BodyResolveContextForLazy bodyResolveContext,
235                ModuleDescriptor module) {
236            TopDownAnalysisParameters parameters = new TopDownAnalysisParameters(
237                    Predicates.<PsiFile>alwaysTrue(), false, true, Collections.<AnalyzerScriptParameter>emptyList());
238            InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(file.getProject(), parameters, trace, bodyResolveContext, module);
239            return bodyResolve.getBodyResolver();
240        }
241    
242        private static BodyResolver createBodyResolverWithEmptyContext(
243                DelegatingBindingTrace trace,
244                JetFile file,
245                ModuleDescriptor module
246        ) {
247            return createBodyResolver(trace, file, EMPTY_CONTEXT, module);
248        }
249    
250        private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
251            ScopeProvider provider = resolveSession.getInjector().getScopeProvider();
252            JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class);
253            if (parentDeclaration == null) {
254                return provider.getFileScope((JetFile) expression.getContainingFile());
255            }
256            return provider.getResolutionScopeForDeclaration(parentDeclaration);
257        }
258    
259        public static JetScope getExpressionMemberScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) {
260            DelegatingBindingTrace trace = new DelegatingBindingTrace(
261                    resolveSession.getBindingContext(), "trace to resolve a member scope of expression", expression);
262    
263            if (BindingContextUtils.isExpressionWithValidReference(expression, resolveSession.getBindingContext())) {
264                QualifiedExpressionResolver qualifiedExpressionResolver = resolveSession.getInjector().getQualifiedExpressionResolver();
265    
266                // In some type declaration
267                if (expression.getParent() instanceof JetUserType) {
268                    JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier();
269                    if (qualifier != null) {
270                        Collection<? extends DeclarationDescriptor> descriptors = qualifiedExpressionResolver
271                                .lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace);
272    
273                        for (DeclarationDescriptor descriptor : descriptors) {
274                            if (descriptor instanceof LazyPackageDescriptor) {
275                                return ((LazyPackageDescriptor) descriptor).getMemberScope();
276                            }
277                        }
278                    }
279                }
280    
281                // Inside import
282                if (PsiTreeUtil.getParentOfType(expression, JetImportDirective.class, false) != null) {
283                    NamespaceDescriptor rootPackage = resolveSession.getPackageDescriptorByFqName(FqName.ROOT);
284                    assert rootPackage != null;
285    
286                    if (expression.getParent() instanceof JetDotQualifiedExpression) {
287                        JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression();
288                        String name = ((JetFile) expression.getContainingFile()).getPackageName();
289    
290                        NamespaceDescriptor filePackage =
291                                name != null ? resolveSession.getPackageDescriptorByFqName(new FqName(name)) : rootPackage;
292                        assert filePackage != null : "File package should be already resolved and be found";
293    
294                        JetScope scope = filePackage.getMemberScope();
295                        Collection<? extends DeclarationDescriptor> descriptors;
296    
297                        if (element instanceof JetDotQualifiedExpression) {
298                            descriptors = qualifiedExpressionResolver.lookupDescriptorsForQualifiedExpression(
299                                    (JetDotQualifiedExpression) element, rootPackage.getMemberScope(), scope, trace,
300                                    QualifiedExpressionResolver.LookupMode.EVERYTHING, false);
301                        }
302                        else {
303                            descriptors = qualifiedExpressionResolver.lookupDescriptorsForSimpleNameReference(
304                                    (JetSimpleNameExpression) element, rootPackage.getMemberScope(), scope, trace,
305                                    QualifiedExpressionResolver.LookupMode.EVERYTHING, false, false);
306                        }
307    
308                        for (DeclarationDescriptor descriptor : descriptors) {
309                            if (descriptor instanceof NamespaceDescriptor) {
310                                return ((NamespaceDescriptor) descriptor).getMemberScope();
311                            }
312                        }
313                    }
314                    else {
315                        return rootPackage.getMemberScope();
316                    }
317                }
318    
319                // Inside package declaration
320                JetNamespaceHeader namespaceHeader = PsiTreeUtil.getParentOfType(expression, JetNamespaceHeader.class, false);
321                if (namespaceHeader != null) {
322                    NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName(
323                            namespaceHeader.getParentFqName((JetReferenceExpression) expression));
324                    if (packageDescriptor != null) {
325                        return packageDescriptor.getMemberScope();
326                    }
327                }
328            }
329    
330            return null;
331        }
332    
333        @NotNull
334        public static Collection<ClassDescriptor> getClassDescriptorsByFqName(
335                    @NotNull KotlinCodeAnalyzer analyzer,
336                    @NotNull FqName fqName
337        ) {
338            return getClassOrObjectDescriptorsByFqName(analyzer, fqName, false);
339        }
340    
341        @NotNull
342        public static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
343                @NotNull KotlinCodeAnalyzer analyzer,
344                @NotNull FqName fqName,
345                boolean includeObjectDeclarations
346        ) {
347            if (fqName.isRoot()) {
348                return Collections.emptyList();
349            }
350    
351            Collection<ClassDescriptor> classDescriptors = Lists.newArrayList();
352    
353            FqName packageFqName = fqName.parent();
354            while (true) {
355                NamespaceDescriptor packageDescriptor = analyzer.getPackageDescriptorByFqName(packageFqName);
356                if (packageDescriptor != null) {
357                    FqName classInPackagePath = new FqName(QualifiedNamesUtil.tail(packageFqName, fqName));
358                    Collection<ClassDescriptor> descriptors = getClassOrObjectDescriptorsByFqName(packageDescriptor, classInPackagePath,
359                                                                                                  includeObjectDeclarations);
360                    classDescriptors.addAll(descriptors);
361                }
362    
363                if (packageFqName.isRoot()) {
364                    break;
365                }
366                else {
367                    packageFqName = packageFqName.parent();
368                }
369            }
370    
371            return classDescriptors;
372        }
373    
374        private static Collection<ClassDescriptor> getClassOrObjectDescriptorsByFqName(
375                NamespaceDescriptor packageDescriptor,
376                FqName path,
377                boolean includeObjectDeclarations
378        ) {
379            if (path.isRoot()) {
380                return Collections.emptyList();
381            }
382    
383            Collection<JetScope> scopes = Arrays.asList(packageDescriptor.getMemberScope());
384    
385            List<Name> names = path.pathSegments();
386            if (names.size() > 1) {
387                for (Name subName : path.pathSegments().subList(0, names.size() - 1)) {
388                    Collection<JetScope> tempScopes = Lists.newArrayList();
389                    for (JetScope scope : scopes) {
390                        ClassifierDescriptor classifier = scope.getClassifier(subName);
391                        if (classifier instanceof ClassDescriptorBase) {
392                            ClassDescriptorBase classDescriptor = (ClassDescriptorBase) classifier;
393                            tempScopes.add(classDescriptor.getUnsubstitutedInnerClassesScope());
394                        }
395                    }
396                    scopes = tempScopes;
397                }
398            }
399    
400            Name shortName = path.shortName();
401            Collection<ClassDescriptor> resultClassifierDescriptors = Lists.newArrayList();
402            for (JetScope scope : scopes) {
403                ClassifierDescriptor classifier = scope.getClassifier(shortName);
404                if (classifier instanceof ClassDescriptor) {
405                    resultClassifierDescriptors.add((ClassDescriptor) classifier);
406                }
407                if (includeObjectDeclarations) {
408                    ClassDescriptor objectDescriptor = scope.getObjectDescriptor(shortName);
409                    if (objectDescriptor != null) {
410                        resultClassifierDescriptors.add(objectDescriptor);
411                    }
412                }
413            }
414    
415            return resultClassifierDescriptors;
416        }
417    
418        @NotNull
419        public static Name safeNameForLazyResolve(@NotNull JetNamed named) {
420            Name name = named.getNameAsName();
421            return safeNameForLazyResolve(name);
422        }
423    
424        @NotNull
425        public static Name safeNameForLazyResolve(@Nullable Name name) {
426            return name != null ? name : NO_NAME_FOR_LAZY_RESOLVE;
427        }
428    }