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.name.FqName;
025 import org.jetbrains.kotlin.name.Name;
026 import org.jetbrains.kotlin.psi.*;
027 import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage;
028 import org.jetbrains.kotlin.renderer.DescriptorRenderer;
029 import org.jetbrains.kotlin.resolve.AnnotationResolver;
030 import org.jetbrains.kotlin.resolve.BindingContext;
031 import org.jetbrains.kotlin.resolve.BindingTrace;
032 import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor;
033 import org.jetbrains.kotlin.resolve.scopes.JetScope;
034 import org.jetbrains.kotlin.storage.LockBasedLazyResolveStorageManager;
035
036 import javax.inject.Inject;
037 import java.util.List;
038
039 public class LazyDeclarationResolver {
040
041 private final BindingTrace trace;
042
043 protected DeclarationScopeProvider scopeProvider;
044 private TopLevelDescriptorProvider topLevelDescriptorProvider;
045
046 @Inject
047 public void setDeclarationScopeProvider(@NotNull DeclarationScopeProviderImpl scopeProvider) {
048 this.scopeProvider = scopeProvider;
049 }
050
051 @Inject
052 public void setTopLevelDescriptorProvider(@NotNull TopLevelDescriptorProvider topLevelDescriptorProvider) {
053 this.topLevelDescriptorProvider = topLevelDescriptorProvider;
054 }
055
056 @Deprecated
057 public LazyDeclarationResolver(
058 @NotNull GlobalContext globalContext,
059 @NotNull BindingTrace delegationTrace
060 ) {
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) {
069 JetScope resolutionScope = resolutionScopeToResolveDeclaration(classOrObject);
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 = resolutionScope.getClassifier(classOrObject.getNameAsSafeName());
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 DeclarationDescriptor result = declaration.accept(new JetVisitor<DeclarationDescriptor, Void>() {
098 @Override
099 public DeclarationDescriptor visitClass(@NotNull JetClass klass, Void data) {
100 return getClassDescriptor(klass);
101 }
102
103 @Override
104 public DeclarationDescriptor visitObjectDeclaration(@NotNull JetObjectDeclaration declaration, Void data) {
105 return getClassDescriptor(declaration);
106 }
107
108 @Override
109 public DeclarationDescriptor visitTypeParameter(@NotNull JetTypeParameter parameter, Void data) {
110 JetTypeParameterListOwner ownerElement = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class);
111 DeclarationDescriptor ownerDescriptor = resolveToDescriptor(ownerElement);
112
113 List<TypeParameterDescriptor> typeParameters;
114 if (ownerDescriptor instanceof CallableDescriptor) {
115 CallableDescriptor callableDescriptor = (CallableDescriptor) ownerDescriptor;
116 typeParameters = callableDescriptor.getTypeParameters();
117 }
118 else if (ownerDescriptor instanceof ClassDescriptor) {
119 ClassDescriptor classDescriptor = (ClassDescriptor) ownerDescriptor;
120 typeParameters = classDescriptor.getTypeConstructor().getParameters();
121 }
122 else {
123 throw new IllegalStateException("Unknown owner kind for a type parameter: " + ownerDescriptor);
124 }
125
126 Name name = parameter.getNameAsSafeName();
127 for (TypeParameterDescriptor typeParameterDescriptor : typeParameters) {
128 if (typeParameterDescriptor.getName().equals(name)) {
129 return typeParameterDescriptor;
130 }
131 }
132
133 throw new IllegalStateException("Type parameter " + name + " not found for " + ownerDescriptor);
134 }
135
136 @Override
137 public DeclarationDescriptor visitNamedFunction(@NotNull JetNamedFunction function, Void data) {
138 JetScope scopeForDeclaration = resolutionScopeToResolveDeclaration(function);
139 scopeForDeclaration.getFunctions(function.getNameAsSafeName());
140 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
141 }
142
143 @Override
144 public DeclarationDescriptor visitParameter(@NotNull JetParameter parameter, Void data) {
145 PsiElement grandFather = parameter.getParent().getParent();
146 if (grandFather instanceof JetPrimaryConstructor) {
147 JetClassOrObject jetClass = ((JetPrimaryConstructor) grandFather).getContainingClassOrObject();
148 // This is a primary constructor parameter
149 ClassDescriptor classDescriptor = getClassDescriptor(jetClass);
150 if (parameter.hasValOrVarNode()) {
151 classDescriptor.getDefaultType().getMemberScope().getProperties(parameter.getNameAsSafeName());
152 return getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, parameter);
153 }
154 else {
155 ConstructorDescriptor constructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
156 assert constructor != null: "There are constructor parameters found, so a constructor should also exist";
157 constructor.getValueParameters();
158 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
159 }
160 }
161 else if (grandFather instanceof JetNamedFunction) {
162 FunctionDescriptor function = (FunctionDescriptor) visitNamedFunction((JetNamedFunction) grandFather, data);
163 function.getValueParameters();
164 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
165 }
166 else if (grandFather instanceof JetSecondaryConstructor) {
167 ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) visitSecondaryConstructor(
168 (JetSecondaryConstructor) grandFather, data
169 );
170 constructorDescriptor.getValueParameters();
171 return getBindingContext().get(BindingContext.VALUE_PARAMETER, parameter);
172 }
173 else {
174 //TODO: support parameters in accessors and other places(?)
175 return super.visitParameter(parameter, data);
176 }
177 }
178
179 @Override
180 public DeclarationDescriptor visitSecondaryConstructor(@NotNull JetSecondaryConstructor constructor, Void data) {
181 getClassDescriptor((JetClassOrObject) constructor.getParent().getParent()).getConstructors();
182 return getBindingContext().get(BindingContext.CONSTRUCTOR, constructor);
183 }
184
185 @Override
186 public DeclarationDescriptor visitPrimaryConstructor(@NotNull JetPrimaryConstructor constructor, Void data) {
187 JetClassOrObject klass = constructor.getContainingClassOrObject();
188 getClassDescriptor(klass).getConstructors();
189 return getBindingContext().get(BindingContext.CONSTRUCTOR, klass);
190 }
191
192 @Override
193 public DeclarationDescriptor visitProperty(@NotNull JetProperty property, Void data) {
194 JetScope scopeForDeclaration = resolutionScopeToResolveDeclaration(property);
195 scopeForDeclaration.getProperties(property.getNameAsSafeName());
196 return getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, property);
197 }
198
199 @Override
200 public DeclarationDescriptor visitScript(@NotNull JetScript script, Void data) {
201 return topLevelDescriptorProvider.getScriptDescriptor(script);
202 }
203
204 @Override
205 public DeclarationDescriptor visitJetElement(@NotNull JetElement element, Void data) {
206 throw new IllegalArgumentException("Unsupported declaration type: " + element + " " +
207 PsiUtilPackage.getElementTextWithContext(element));
208 }
209 }, null);
210 if (result == null) {
211 throw new IllegalStateException("No descriptor resolved for " + declaration + ":\n" +
212 PsiUtilPackage.getElementTextWithContext(declaration));
213 }
214 AnnotationResolver.resolveAnnotationsArguments(result.getAnnotations());
215 return result;
216 }
217
218 @NotNull
219 /*package*/ JetScope resolutionScopeToResolveDeclaration(@NotNull JetDeclaration declaration) {
220 boolean isTopLevel = JetStubbedPsiUtil.getContainingDeclaration(declaration) == null;
221 if (isTopLevel) { // for top level declarations we search directly in package because of possible conflicts with imports
222 FqName fqName = ((JetFile) declaration.getContainingFile()).getPackageFqName();
223 LazyPackageDescriptor packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName);
224 assert packageDescriptor != null;
225 return packageDescriptor.getMemberScope();
226 }
227 else {
228 return scopeProvider.getResolutionScopeForDeclaration(declaration);
229 }
230 }
231 }