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 FqName fqName = ((KtFile) declaration.getContainingFile()).getPackageFqName();
247 LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
248 assert packageDescriptor != null;
249 return packageDescriptor.getMemberScope();
250 }
251 else {
252 if (parentDeclaration instanceof KtClassOrObject) {
253 return getClassDescriptor((KtClassOrObject) parentDeclaration, location).getUnsubstitutedMemberScope();
254 }
255 else if (parentDeclaration instanceof KtScript) {
256 return getScriptDescriptor((KtScript) parentDeclaration, location).getUnsubstitutedMemberScope();
257 }
258 else {
259 throw new IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
260 PsiUtilsKt.getElementTextWithContext(declaration));
261 }
262 }
263 }
264 }