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 ClassDescriptor) {
146                        ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
147                        typeParameters = classDescriptor.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 visitScript(@NotNull KtScript script, Void data) {
229                    return getScriptDescriptor(script, lookupLocationFor(script, true));
230                }
231    
232                @Override
233                public DeclarationDescriptor visitKtElement(@NotNull KtElement element, Void data) {
234                    throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
235                                                       PsiUtilsKt.getElementTextWithContext(element));
236                }
237            }, null);
238            if (result == null) {
239                return absentDescriptorHandler.diagnoseDescriptorNotFound(declaration);
240            }
241            return result;
242        }
243    
244        @NotNull
245        /*package*/ MemberScope getMemberScopeDeclaredIn(@NotNull KtDeclaration declaration, @NotNull LookupLocation location) {
246            KtDeclaration parentDeclaration = KtStubbedPsiUtil.getContainingDeclaration(declaration);
247            boolean isTopLevel = parentDeclaration == null;
248            if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
249                KtFile ktFile = (KtFile) declaration.getContainingFile();
250                FqName fqName = ktFile.getPackageFqName();
251                LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
252                if (packageDescriptor == null) {
253                    if (topLevelDescriptorProvider instanceof LazyClassContext) {
254                        ((LazyClassContext) topLevelDescriptorProvider).getDeclarationProviderFactory().diagnoseMissingPackageFragment(ktFile);
255                    }
256                    else {
257                        throw new IllegalStateException("Cannot find package fragment for file " + ktFile.getName() + " with package " + fqName);
258                    }
259                }
260                return packageDescriptor.getMemberScope();
261            }
262            else {
263                if (parentDeclaration instanceof KtClassOrObject) {
264                    return getClassDescriptor((KtClassOrObject) parentDeclaration, location).getUnsubstitutedMemberScope();
265                }
266                else if (parentDeclaration instanceof KtScript) {
267                    return getScriptDescriptor((KtScript) parentDeclaration, location).getUnsubstitutedMemberScope();
268                }
269                else {
270                    throw new IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
271                                                    PsiUtilsKt.getElementTextWithContext(declaration));
272                }
273            }
274        }
275    }