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 }