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