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