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.PsiUtilPackage;
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.JetScope;
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 JetClassOrObject classOrObject, @NotNull LookupLocation location) {
069 JetScope scope = getMemberScopeDeclaredIn(classOrObject, location);
070
071 // Why not use the result here. Because it may be that there is a redeclaration:
072 // class A {} class A { fun foo(): A<completion here>}
073 // and if we find the class by name only, we may b-not get the right one.
074 // This call is only needed to make sure the classes are written to trace
075 ClassifierDescriptor scopeDescriptor = scope.getClassifier(classOrObject.getNameAsSafeName(), location);
076 DeclarationDescriptor descriptor = getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, classOrObject);
077
078 if (descriptor == null) {
079 throw new IllegalArgumentException(
080 String.format("Could not find a classifier for %s.\n" +
081 "Found descriptor: %s (%s).\n",
082 PsiUtilPackage.getElementTextWithContext(classOrObject),
083 scopeDescriptor != null ? DescriptorRenderer.DEBUG_TEXT.render(scopeDescriptor) : "null",
084 scopeDescriptor != null ? (scopeDescriptor.getContainingDeclaration().getClass()) : null));
085 }
086
087 return (ClassDescriptor) descriptor;
088 }
089
090 @NotNull
091 private BindingContext getBindingContext() {
092 return trace.getBindingContext();
093 }
094
095 @NotNull
096 public DeclarationDescriptor resolveToDescriptor(@NotNull JetDeclaration declaration) {
097 return resolveToDescriptor(declaration, /*track =*/true);
098 }
099
100 @NotNull
101 private DeclarationDescriptor resolveToDescriptor(@NotNull JetDeclaration declaration, final boolean track) {
102 DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
103 @NotNull
104 private LookupLocation lookupLocationFor(@NotNull JetDeclaration declaration, boolean isTopLevel) {
105 return isTopLevel && track ? new KotlinLookupLocation(declaration) : NoLookupLocation.WHEN_RESOLVE_DECLARATION;
106 }
107
108 @Override
109 public DeclarationDescriptor visitClass(@NotNull JetClass klass, Void data) {
110 return getClassDescriptor(klass, lookupLocationFor(klass, klass.isTopLevel()));
111 }
112
113 @Override
114 public DeclarationDescriptor visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
115 return getClassDescriptor(declaration, lookupLocationFor(declaration, declaration.isTopLevel()));
116 }
117
118 @Override
119 public DeclarationDescriptor visitTypeParameter(@NotNull JetTypeParameter parameter, Void data) {
120 JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
121 assert ownerElement != null : "Owner not found for type parameter: " + parameter.getText();
122 DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement, /*track =*/false);
123
124 List<TypeParameterDescriptor> typeParameters;
125 if (ownerDescriptor instanceof CallableDescriptor) {
126 CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
127 typeParameters = callableDescriptor.getTypeParameters();
128 }
129 else if (ownerDescriptor instanceof ClassDescriptor) {
130 ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
131 typeParameters = classDescriptor.getTypeConstructor().getParameters();
132 }
133 else {
134 throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
135 }
136
137 Name name = parameter.getNameAsSafeName();
138 for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
139 if (typeParameterDescriptor.getName().equals(name)) {
140 return typeParameterDescriptor;
141 }
142 }
143
144 throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
145 }
146
147 @Override
148 public DeclarationDescriptor visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
149 LookupLocation location = lookupLocationFor(function, function.isTopLevel());
150 JetScope scopeForDeclaration = getMemberScopeDeclaredIn(function, location);
151 scopeForDeclaration.getFunctions(function.getNameAsSafeName(), location);
152 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
153 }
154
155 @Override
156 public DeclarationDescriptor visitParameter(@NotNull JetParameter parameter, Void data) {
157 PsiElement grandFather = parameter.getParent().getParent();
158 if (grandFather instanceof JetPrimaryConstructor) {
159 JetClassOrObject jetClass = ((JetPrimaryConstructor) grandFather).getContainingClassOrObject();
160 // This is a primary constructor parameter
161 ClassDescriptor classDescriptor = getClassDescriptor(jetClass, lookupLocationFor(jetClass, false));
162 if (parameter.hasValOrVar()) {
163 classDescriptor.getDefaultType().getMemberScope().getProperties(parameter.getNameAsSafeName(), lookupLocationFor(parameter, false));
164 return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
165 }
166 else {
167 ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
168 assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
169 constructor.getValueParameters();
170 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
171 }
172 }
173 else if (grandFather instanceof JetNamedFunction) {
174 FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((JetNamedFunction) grandFather, data);
175 function.getValueParameters();
176 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
177 }
178 else if (grandFather instanceof JetSecondaryConstructor) {
179 ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) visitSecondaryConstructor(
180 (JetSecondaryConstructor) grandFather, data
181 );
182 constructorDescriptor.getValueParameters();
183 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
184 }
185 else {
186 //TODO: support parameters in accessors and other places(?)
187 return super.visitParameter(parameter, data);
188 }
189 }
190
191 @Override
192 public DeclarationDescriptor visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, Void data) {
193 getClassDescriptor((JetClassOrObject) constructor.getParent().getParent(), lookupLocationFor(constructor, false)).getConstructors();
194 return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
195 }
196
197 @Override
198 public DeclarationDescriptor visitPrimaryConstructor(@NotNull JetPrimaryConstructor constructor, Void data) {
199 getClassDescriptor(constructor.getContainingClassOrObject(), lookupLocationFor(constructor, false)).getConstructors();
200 return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
201 }
202
203 @Override
204 public DeclarationDescriptor visitProperty(@NotNull JetProperty property, Void data) {
205 LookupLocation location = lookupLocationFor(property, property.isTopLevel());
206 JetScope scopeForDeclaration = getMemberScopeDeclaredIn(property, location);
207 scopeForDeclaration.getProperties(property.getNameAsSafeName(), location);
208 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
209 }
210
211 @Override
212 public DeclarationDescriptor visitScript(@NotNull JetScript script, Void data) {
213 return topLevelDescriptorProvider.getScriptDescriptor(script);
214 }
215
216 @Override
217 public DeclarationDescriptor visitJetElement(@NotNull JetElement element, Void data) {
218 throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
219 PsiUtilPackage.getElementTextWithContext(element));
220 }
221 }, null);
222 if (result == null) {
223 throw new NoDescriptorForDeclarationException(declaration);
224 }
225 return result;
226 }
227
228 @NotNull
229 /*package*/ JetScope getMemberScopeDeclaredIn(@NotNull JetDeclaration declaration, @NotNull LookupLocation location) {
230 JetDeclaration parentDeclaration = JetStubbedPsiUtil.getContainingDeclaration(declaration);
231 boolean isTopLevel = parentDeclaration == null;
232 if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
233 FqName fqName = ((JetFile) declaration.getContainingFile()).getPackageFqName();
234 LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
235 assert packageDescriptor != null;
236 return packageDescriptor.getMemberScope();
237 }
238 else {
239 if (parentDeclaration instanceof JetClassOrObject) {
240 return getClassDescriptor((JetClassOrObject) parentDeclaration, location).getUnsubstitutedMemberScope();
241 } else {
242 throw new IllegalStateException("Don't call this method for local declarations: " + declaration + "\n" +
243 PsiUtilPackage.getElementTextWithContext(declaration));
244 }
245 }
246 }
247 }