001 /*
002 * Copyright 2010-2013 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.jet.lang.resolve;
018
019 import com.google.common.collect.Lists;
020 import org.jetbrains.annotations.NotNull;
021 import org.jetbrains.annotations.Nullable;
022 import org.jetbrains.jet.lang.descriptors.*;
023 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
024 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.psi.*;
027 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
028 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
029 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
030 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
031 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
032 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
033 import org.jetbrains.jet.lang.resolve.constants.*;
034 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
035 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
036 import org.jetbrains.jet.lang.types.ErrorUtils;
037 import org.jetbrains.jet.lang.types.JetType;
038 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
039 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
040
041 import javax.inject.Inject;
042 import java.util.Collections;
043 import java.util.List;
044 import java.util.Map;
045
046 import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
047 import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER;
048 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
049
050 public class AnnotationResolver {
051
052 private ExpressionTypingServices expressionTypingServices;
053 private CallResolver callResolver;
054
055 @Inject
056 public void setExpressionTypingServices(ExpressionTypingServices expressionTypingServices) {
057 this.expressionTypingServices = expressionTypingServices;
058 }
059
060 @Inject
061 public void setCallResolver(CallResolver callResolver) {
062 this.callResolver = callResolver;
063 }
064
065 @NotNull
066 public List<AnnotationDescriptor> resolveAnnotations(
067 @NotNull JetScope scope,
068 @Nullable JetModifierList modifierList,
069 @NotNull BindingTrace trace)
070 {
071 return resolveAnnotations(scope, modifierList, trace, false);
072 }
073
074 @NotNull
075 public List<AnnotationDescriptor> resolveAnnotationsWithArguments(
076 @NotNull JetScope scope,
077 @Nullable JetModifierList modifierList,
078 @NotNull BindingTrace trace
079 ) {
080 return resolveAnnotations(scope, modifierList, trace, true);
081 }
082
083 private List<AnnotationDescriptor> resolveAnnotations(
084 @NotNull JetScope scope,
085 @Nullable JetModifierList modifierList,
086 @NotNull BindingTrace trace,
087 boolean shouldResolveArguments
088 ) {
089 if (modifierList == null) {
090 return Collections.emptyList();
091 }
092 List<JetAnnotationEntry> annotationEntryElements = modifierList.getAnnotationEntries();
093
094 if (annotationEntryElements.isEmpty()) return Collections.emptyList();
095 List<AnnotationDescriptor> result = Lists.newArrayList();
096 for (JetAnnotationEntry entryElement : annotationEntryElements) {
097 AnnotationDescriptor descriptor = new AnnotationDescriptor();
098 resolveAnnotationStub(scope, entryElement, descriptor, trace);
099 trace.record(BindingContext.ANNOTATION, entryElement, descriptor);
100 if (shouldResolveArguments) {
101 resolveAnnotationArguments(entryElement, scope, trace);
102 }
103 result.add(descriptor);
104 }
105 return result;
106 }
107
108 public void resolveAnnotationStub(
109 @NotNull JetScope scope,
110 @NotNull JetAnnotationEntry entryElement,
111 @NotNull AnnotationDescriptor annotationDescriptor,
112 @NotNull BindingTrace trace
113 ) {
114 TemporaryBindingTrace temporaryBindingTrace = new TemporaryBindingTrace(trace, "Trace for resolve annotation type");
115 OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(entryElement, scope, temporaryBindingTrace);
116 if (results.isSuccess()) {
117 FunctionDescriptor descriptor = results.getResultingDescriptor();
118 if (!ErrorUtils.isError(descriptor)) {
119 if (descriptor instanceof ConstructorDescriptor) {
120 ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor;
121 ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
122 if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) {
123 trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor.getName().asString()));
124 }
125 }
126 else {
127 trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor.getName().asString()));
128 }
129 }
130 JetType annotationType = results.getResultingDescriptor().getReturnType();
131 annotationDescriptor.setAnnotationType(annotationType);
132 }
133 else {
134 annotationDescriptor.setAnnotationType(ErrorUtils.createErrorType("Unresolved annotation type"));
135 }
136 }
137
138 private OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall(
139 JetAnnotationEntry annotationEntry,
140 JetScope scope,
141 BindingTrace trace
142 ) {
143 return callResolver.resolveFunctionCall(
144 trace, scope,
145 CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry),
146 NO_EXPECTED_TYPE,
147 DataFlowInfo.EMPTY);
148 }
149
150 public void resolveAnnotationsArguments(@NotNull JetScope scope, @Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
151 if (modifierList == null) {
152 return;
153 }
154
155 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
156 resolveAnnotationArguments(annotationEntry, scope, trace);
157 }
158 }
159
160 public void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace, @NotNull JetScope scope) {
161 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
162 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
163 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
164 resolveAnnotationArguments(annotationEntry, scope, trace);
165 }
166 }
167
168 private void resolveAnnotationArguments(
169 @NotNull JetAnnotationEntry annotationEntry,
170 @NotNull JetScope scope,
171 @NotNull BindingTrace trace
172 ) {
173 OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(annotationEntry, scope, trace);
174 if (results.isSuccess()) {
175 AnnotationDescriptor annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
176 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
177 resolveAnnotationArgument(annotationDescriptor, results.getResultingCall(), trace);
178 }
179 }
180
181 private void resolveAnnotationArgument(
182 @NotNull AnnotationDescriptor annotationDescriptor,
183 @NotNull ResolvedCall<? extends CallableDescriptor> call,
184 @NotNull BindingTrace trace
185 ) {
186 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
187 call.getValueArguments().entrySet()) {
188 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
189
190 JetType varargElementType = parameterDescriptor.getVarargElementType();
191 List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
192 if (varargElementType == null) {
193 for (CompileTimeConstant<?> constant : constants) {
194 annotationDescriptor.setValueArgument(parameterDescriptor, constant);
195 }
196 }
197 else {
198 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
199 if (arrayType == null) {
200 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
201 }
202 annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType));
203 }
204 }
205 }
206
207 @NotNull
208 private List<CompileTimeConstant<?>> resolveValueArguments(
209 @NotNull ResolvedValueArgument resolvedValueArgument,
210 @NotNull JetType expectedType,
211 @NotNull BindingTrace trace
212 ) {
213 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
214 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
215 JetExpression argumentExpression = argument.getArgumentExpression();
216 if (argumentExpression != null) {
217 CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
218 if (constant != null) {
219 constants.add(constant);
220 }
221 }
222 }
223 return constants;
224 }
225
226 @Nullable
227 public CompileTimeConstant<?> resolveExpressionToCompileTimeValue(
228 @NotNull JetExpression expression,
229 @NotNull final JetType expectedType,
230 @NotNull final BindingTrace trace
231 ) {
232 JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
233 @Override
234 public CompileTimeConstant<?> visitConstantExpression(JetConstantExpression expression, Void nothing) {
235 JetType type = expressionTypingServices.getType(JetScope.EMPTY, expression, expectedType, DataFlowInfo.EMPTY, trace);
236 if (type == null) {
237 // TODO:
238 // trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(expression));
239 }
240 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
241 }
242
243
244 // @Override
245 // public CompileTimeConstant visitAnnotation(JetAnnotation annotation, Void nothing) {
246 // super.visitAnnotation(annotation, null); // TODO
247 // }
248 //
249 // @Override
250 // public CompileTimeConstant visitAnnotationEntry(JetAnnotationEntry annotationEntry, Void nothing) {
251 // return super.visitAnnotationEntry(annotationEntry, null); // TODO
252 // }
253
254 @Override
255 public CompileTimeConstant<?> visitParenthesizedExpression(JetParenthesizedExpression expression, Void nothing) {
256 JetExpression innerExpression = expression.getExpression();
257 if (innerExpression == null) return null;
258 return innerExpression.accept(this, null);
259 }
260
261 @Override
262 public CompileTimeConstant<?> visitStringTemplateExpression(JetStringTemplateExpression expression,
263 Void nothing) {
264 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
265 }
266
267 @Override
268 public CompileTimeConstant<?> visitSimpleNameExpression(JetSimpleNameExpression expression, Void data) {
269 ResolvedCall<? extends CallableDescriptor> resolvedCall =
270 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
271 if (resolvedCall != null) {
272 CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
273 if (callableDescriptor instanceof PropertyDescriptor) {
274 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
275 if (isEnumProperty(propertyDescriptor)) {
276 return new EnumValue(propertyDescriptor);
277 }
278 if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
279 return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
280 }
281 }
282 }
283 return null;
284 }
285
286 @Override
287 public CompileTimeConstant<?> visitQualifiedExpression(JetQualifiedExpression expression, Void data) {
288 JetExpression selectorExpression = expression.getSelectorExpression();
289 if (selectorExpression != null) {
290 return selectorExpression.accept(this, null);
291 }
292 return super.visitQualifiedExpression(expression, data);
293 }
294
295 @Override
296 public CompileTimeConstant<?> visitCallExpression(JetCallExpression expression, Void data) {
297 ResolvedCall<? extends CallableDescriptor> call =
298 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
299 if (call != null) {
300 CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
301 if (AnnotationUtils.isArrayMethodCall(call)) {
302 JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
303 List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
304 for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
305 arguments.addAll(resolveValueArguments(descriptorToArgument, type, trace));
306 }
307 return new ArrayValue(arguments, resultingDescriptor.getReturnType());
308 }
309
310 if (resultingDescriptor instanceof ConstructorDescriptor) {
311 JetType constructorReturnType = resultingDescriptor.getReturnType();
312 assert constructorReturnType != null : "Constructor should have return type";
313 if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
314 AnnotationDescriptor descriptor = new AnnotationDescriptor();
315 descriptor.setAnnotationType(constructorReturnType);
316 resolveAnnotationArgument(descriptor, call, trace);
317 return new AnnotationValue(descriptor);
318 }
319 }
320
321 if (AnnotationUtils.isJavaClassMethodCall(call)) {
322 return new JavaClassValue(resultingDescriptor.getReturnType());
323 }
324 }
325 return null;
326 }
327
328 @Override
329 public CompileTimeConstant<?> visitJetElement(JetElement element, Void nothing) {
330 // TODO:
331 //trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(element));
332 return null;
333 }
334 };
335 return expression.accept(visitor, null);
336 }
337
338 private static boolean isEnumProperty(@NotNull PropertyDescriptor descriptor) {
339 if (DescriptorUtils.isKindOf(descriptor.getType(), ClassKind.ENUM_CLASS)) {
340 DeclarationDescriptor enumClassObject = descriptor.getContainingDeclaration();
341 if (DescriptorUtils.isKindOf(enumClassObject, ClassKind.CLASS_OBJECT)) {
342 return DescriptorUtils.isKindOf(enumClassObject.getContainingDeclaration(), ClassKind.ENUM_CLASS);
343 }
344 }
345 return false;
346 }
347
348 @NotNull
349 public List<AnnotationDescriptor> getResolvedAnnotations(@Nullable JetModifierList modifierList, BindingTrace trace) {
350 if (modifierList == null) {
351 return Collections.emptyList();
352 }
353 return getResolvedAnnotations(modifierList.getAnnotationEntries(), trace);
354 }
355
356 @SuppressWarnings("MethodMayBeStatic")
357 @NotNull
358 public List<AnnotationDescriptor> getResolvedAnnotations(List<JetAnnotationEntry> annotations, BindingTrace trace) {
359 List<AnnotationDescriptor> result = Lists.newArrayList();
360 for (JetAnnotationEntry annotation : annotations) {
361 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
362 if (annotationDescriptor == null) {
363 // TODO: Unresolved annotation
364 annotationDescriptor = new AnnotationDescriptor();
365 annotationDescriptor.setAnnotationType(ErrorUtils.createErrorType("Unresolved annotation type"));
366
367 trace.record(BindingContext.ANNOTATION, annotation, annotationDescriptor);
368 }
369
370 result.add(annotationDescriptor);
371 }
372 return result;
373 }
374 }