001    /*
002     * Copyright 2010-2015 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.kotlin.resolve.lazy;
018    
019    import com.intellij.psi.PsiElement;
020    import com.intellij.psi.util.PsiTreeUtil;
021    import org.jetbrains.annotations.NotNull;
022    import org.jetbrains.kotlin.context.GlobalContext;
023    import org.jetbrains.kotlin.descriptors.*;
024    import org.jetbrains.kotlin.incremental.KotlinLookupLocation;
025    import org.jetbrains.kotlin.incremental.components.LookupLocation;
026    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
027    import org.jetbrains.kotlin.name.FqName;
028    import org.jetbrains.kotlin.name.Name;
029    import org.jetbrains.kotlin.psi.*;
030    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
031    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
032    import org.jetbrains.kotlin.resolve.BindingContext;
033    import org.jetbrains.kotlin.resolve.BindingTrace;
034    import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor;
035    import org.jetbrains.kotlin.resolve.scopes.MemberScope;
036    import org.jetbrains.kotlin.storage.LockBasedLazyResolveStorageManager;
037    
038    import javax.inject.Inject;
039    import java.util.List;
040    
041    public class LazyDeclarationResolver {
042    
043        @NotNull private final TopLevelDescriptorProvider topLevelDescriptorProvider;
044        @NotNull private final BindingTrace trace;
045    
046        protected DeclarationScopeProvider scopeProvider;
047    
048        // component dependency cycle
049        @Inject
050        public void setDeclarationScopeProvider(@NotNull DeclarationScopeProviderImpl scopeProvider) {
051            this.scopeProvider = scopeProvider;
052        }
053    
054        @Deprecated
055        public LazyDeclarationResolver(
056                @NotNull GlobalContext globalContext,
057                @NotNull BindingTrace delegationTrace,
058                @NotNull TopLevelDescriptorProvider topLevelDescriptorProvider
059        ) {
060            this.topLevelDescriptorProvider = topLevelDescriptorProvider;
061            LockBasedLazyResolveStorageManager lockBasedLazyResolveStorageManager =
062                    new LockBasedLazyResolveStorageManager(globalContext.getStorageManager());
063    
064            this.trace = lockBasedLazyResolveStorageManager.createSafeTrace(delegationTrace);
065        }
066    
067        @NotNull
068        public ClassDescriptor getClassDescriptor(@NotNull KtClassOrObject classOrObject, @NotNull LookupLocation location) {
069            return findClassDescriptor(classOrObject, location);
070        }
071    
072        @NotNull
073        public ScriptDescriptor getScriptDescriptor(@NotNull KtScript script, @NotNull LookupLocation location) {
074            return (ScriptDescriptor) findClassDescriptor(script, location);
075        }
076    
077        @NotNull
078        private ClassDescriptor findClassDescriptor(
079                @NotNull KtNamedDeclaration classObjectOrScript,
080                @NotNull LookupLocation location
081        ) {
082            MemberScope scope = getMemberScopeDeclaredIn(classObjectOrScript, location);
083    
084            // Why not use the result here. Because it may be that there is a redeclaration:
085            //     class A {} class A { fun foo(): A<completion here>}
086            // and if we find the class by name only, we may b-not get the right one.
087            // This call is only needed to make sure the classes are written to trace
088            ClassifierDescriptor scopeDescriptor = scope.getContributedClassifier(classObjectOrScript.getNameAsSafeName(), location);
089            DeclarationDescriptor descriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classObjectOrScript);
090    
091            if (descriptor == null) {
092                throw new IllegalArgumentException(
093                        String.format("Could not find a classifier for %s.\n" +
094                                      "Found descriptor: %s (%s).\n",
095                                      PsiUtilsKt.getElementTextWithContext(classObjectOrScript),
096                                      scopeDescriptor != null ? DescriptorRenderer.DEBUG_TEXT.render(scopeDescriptor) : "null",
097                                      scopeDescriptor != null ? (scopeDescriptor.getContainingDeclaration().getClass()) : null));
098            }
099    
100            return (ClassDescriptor) descriptor;
101        }
102    
103        @NotNull
104        private BindingContext getBindingContext() {
105            return trace.getBindingContext();
106        }
107    
108        @NotNull
109        public DeclarationDescriptor resolveToDescriptor(@NotNull KtDeclaration declaration) {
110            return resolveToDescriptor(declaration, /*track =*/true);
111        }
112    
113        @NotNull
114        private DeclarationDescriptor resolveToDescriptor(@NotNull KtDeclaration declaration, final boolean track) {
115            DeclarationDescriptor result = declaration.accept(new KtVisitor<DeclarationDescriptor, Void>() {
116                @NotNull
117                private LookupLocation lookupLocationFor(@NotNull KtDeclaration declaration, boolean isTopLevel) {
118                    return isTopLevel && track ? new KotlinLookupLocation(declaration) : NoLookupLocation.WHEN_RESOLVE_DECLARATION;
119                }
120    
121                @Override
122                public DeclarationDescriptor visitClass(@NotNull KtClass klass, Void data) {
123                    return getClassDescriptor(klass, lookupLocationFor(klass, klass.isTopLevel()));
124                }
125    
126                @Override
127                public DeclarationDescriptor visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, Void data) {
128                    return getClassDescriptor(declaration, lookupLocationFor(declaration, declaration.isTopLevel()));
129                }
130    
131                @Override
132                public DeclarationDescriptor visitTypeParameter(@NotNull KtTypeParameter parameter, Void data) {
133                    KtTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, KtTypeParameterListOwner.class);
134                    assert ownerElement != null : "Owner not found for type parameter: " + parameter.getText();
135                    DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false);
136    
137                    List<TypeParameterDescriptor> typeParameters;
138                    if (ownerDescriptor instanceof CallableDescriptor) {
139                        CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
140                        typeParameters = callableDescriptor.getTypeParameters();
141                    }
142                    else if (ownerDescriptor instanceof ClassDescriptor) {
143                        ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
144                        typeParameters = classDescriptor.getTypeConstructor().getParameters();
145                    }
146                    else {
147                        throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
148                    }
149    
150                    Name name = parameter.getNameAsSafeName();
151                    for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
152                        if (typeParameterDescriptor.getName().equals(name)) {
153                            return typeParameterDescriptor;
154                        }
155                    }
156    
157                    throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
158                }
159    
160                @Override
161                public DeclarationDescriptor visitNamedFunction(@NotNull KtNamedFunction function, Void data) {
162                    LookupLocation location = lookupLocationFor(function, function.isTopLevel());
163                    MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(function, location);
164                    scopeForDeclaration.getContributedFunctions(function.getNameAsSafeName(), location);
165                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
166                }
167    
168                @Override
169                public DeclarationDescriptor visitParameter(@NotNull KtParameter parameter, Void data) {
170                    PsiElement grandFather = parameter.getParent().getParent();
171                    if (grandFather instanceof KtPrimaryConstructor) {
172                        KtClassOrObject jetClass = ((KtPrimaryConstructor) grandFather).getContainingClassOrObject();
173                        // This is a primary constructor parameter
174                        ClassDescriptor classDescriptor = getClassDescriptor(jetClass, lookupLocationFor(jetClass, false));
175                        if (parameter.hasValOrVar()) {
176                            classDescriptor.getDefaultType().getMemberScope().getContributedVariables(parameter.getNameAsSafeName(), lookupLocationFor(parameter, false));
177                            return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
178                        }
179                        else {
180                            ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
181                            assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
182                            constructor.getValueParameters();
183                            return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
184                        }
185                    }
186                    else if (grandFather instanceof KtNamedFunction) {
187                        FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((KtNamedFunction) grandFather, data);
188                        function.getValueParameters();
189                        return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
190                    }
191                    else if (grandFather instanceof KtSecondaryConstructor) {
192                        ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) visitSecondaryConstructor(
193                                (KtSecondaryConstructor) grandFather, data
194                        );
195                        constructorDescriptor.getValueParameters();
196                        return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
197                    }
198                    else {
199                        //TODO: support parameters in accessors and other places(?)
200                        return super.visitParameter(parameter, data);
201                    }
202                }
203    
204                @Override
205                public DeclarationDescriptor visitSecondaryConstructor(@NotNull KtSecondaryConstructor constructor, Void data) {
206                    getClassDescriptor((KtClassOrObject) constructor.getParent().getParent(), lookupLocationFor(constructor, false)).getConstructors();
207                    return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
208                }
209    
210                @Override
211                public DeclarationDescriptor visitPrimaryConstructor(@NotNull KtPrimaryConstructor constructor, Void data) {
212                    getClassDescriptor(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false)).getConstructors();
213                    return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
214                }
215    
216                @Override
217                public DeclarationDescriptor visitProperty(@NotNull KtProperty property, Void data) {
218                    LookupLocation location = lookupLocationFor(property, property.isTopLevel());
219                    MemberScope scopeForDeclaration = getMemberScopeDeclaredIn(property, location);
220                    scopeForDeclaration.getContributedVariables(property.getNameAsSafeName(), location);
221                    return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
222                }
223    
224                @Override
225                public DeclarationDescriptor visitScript(@NotNull KtScript script, Void data) {
226                    return getScriptDescriptor(script, lookupLocationFor(script, true));
227                }
228    
229                @Override
230                public DeclarationDescriptor visitKtElement(@NotNull KtElement element, Void data) {
231                    throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
232                                                       PsiUtilsKt.getElementTextWithContext(element));
233                }
234            }, null);
235            if (result == null) {
236                throw new NoDescriptorForDeclarationException(declaration);
237            }
238            return result;
239        }
240    
241        @NotNull
242        /*package*/ MemberScope getMemberScopeDeclaredIn(@NotNull KtDeclaration declaration, @NotNull LookupLocation location) {
243            KtDeclaration parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(declaration);
244            boolean isTopLevel = parentDeclaration == null;
245            if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
246                KtFile ktFile = (KtFile) declaration.getContainingFile();
247                FqName fqName = ktFile.getPackageFqName();
248                LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
249                if (packageDescriptor == null) {
250                    if (topLevelDescriptorProvider instanceof LazyClassContext) {
251                        ((LazyClassContext) topLevelDescriptorProvider).getDeclarationProviderFactory().diagnoseMissingPackageFragment(ktFile);
252                    }
253                    else {
254                        throw new IllegalStateException("Cannot find package fragment for file " + ktFile.getName() + " with package " + fqName);
255                    }
256                }
257                return packageDescriptor.getMemberScope();
258            }
259            else {
260                if (parentDeclaration instanceof KtClassOrObject) {
261                    return getClassDescriptor((KtClassOrObject) parentDeclaration, location).getUnsubstitutedMemberScope();
262                }
263                else if (parentDeclaration instanceof KtScript) {
264                    return getScriptDescriptor((KtScript) parentDeclaration, location).getUnsubstitutedMemberScope();
265                }
266                else {
267                    throw new IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
268                                                    PsiUtilsKt.getElementTextWithContext(declaration));
269                }
270            }
271        }
272    }