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 }
174
175 public void resolveAnnotationsArguments(@NotNull JetScope scope, @Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
176 if (modifierList == null) {
177 return;
178 }
179
180 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
181 resolveAnnotationArguments(annotationEntry, scope, trace);
182 }
183 }
184
185 public void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace, @NotNull JetScope scope) {
186 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
187 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
188 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
189 resolveAnnotationArguments(annotationEntry, scope, trace);
190 }
191 }
192
193 private void resolveAnnotationArguments(
194 @NotNull JetAnnotationEntry annotationEntry,
195 @NotNull JetScope scope,
196 @NotNull BindingTrace trace
197 ) {
198 OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(annotationEntry, scope, trace);
199 if (results.isSingleResult()) {
200 AnnotationDescriptorImpl annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
201 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
202 resolveAnnotationArgument(annotationDescriptor, results.getResultingCall(), trace);
203 }
204 }
205
206 private void resolveAnnotationArgument(
207 @NotNull AnnotationDescriptorImpl annotationDescriptor,
208 @NotNull ResolvedCall<? extends CallableDescriptor> call,
209 @NotNull BindingTrace trace
210 ) {
211 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
212 call.getValueArguments().entrySet()) {
213 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
214
215 JetType varargElementType = parameterDescriptor.getVarargElementType();
216 List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
217 if (varargElementType == null) {
218 for (CompileTimeConstant<?> constant : constants) {
219 annotationDescriptor.setValueArgument(parameterDescriptor, constant);
220 }
221 }
222 else {
223 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
224 if (arrayType == null) {
225 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
226 }
227 annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType));
228 }
229 }
230 }
231
232 @NotNull
233 private List<CompileTimeConstant<?>> resolveValueArguments(
234 @NotNull ResolvedValueArgument resolvedValueArgument,
235 @NotNull JetType expectedType,
236 @NotNull BindingTrace trace
237 ) {
238 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
239 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
240 JetExpression argumentExpression = argument.getArgumentExpression();
241 if (argumentExpression != null) {
242 CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
243 if (constant != null) {
244 constants.add(constant);
245 }
246 }
247 }
248 return constants;
249 }
250
251 @Nullable
252 public CompileTimeConstant<?> resolveExpressionToCompileTimeValue(
253 @NotNull JetExpression expression,
254 @NotNull final JetType expectedType,
255 @NotNull final BindingTrace trace
256 ) {
257 JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
258 @Override
259 public CompileTimeConstant<?> visitConstantExpression(@NotNull JetConstantExpression expression, Void nothing) {
260 JetType type = expressionTypingServices.getType(JetScope.EMPTY, expression, expectedType, DataFlowInfo.EMPTY, trace);
261 if (type == null) {
262 // TODO:
263 // trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(expression));
264 }
265 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
266 }
267
268
269 // @Override
270 // public CompileTimeConstant visitAnnotation(JetAnnotation annotation, Void nothing) {
271 // super.visitAnnotation(annotation, null); // TODO
272 // }
273 //
274 // @Override
275 // public CompileTimeConstant visitAnnotationEntry(JetAnnotationEntry annotationEntry, Void nothing) {
276 // return super.visitAnnotationEntry(annotationEntry, null); // TODO
277 // }
278
279 @Override
280 public CompileTimeConstant<?> visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void nothing) {
281 JetExpression innerExpression = expression.getExpression();
282 if (innerExpression == null) return null;
283 return innerExpression.accept(this, null);
284 }
285
286 @Override
287 public CompileTimeConstant<?> visitStringTemplateExpression(
288 @NotNull JetStringTemplateExpression expression,
289 Void nothing) {
290 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
291 }
292
293 @Override
294 public CompileTimeConstant<?> visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, Void data) {
295 ResolvedCall<? extends CallableDescriptor> resolvedCall =
296 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
297 if (resolvedCall != null) {
298 CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
299 if (callableDescriptor instanceof PropertyDescriptor) {
300 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
301 if (isEnumProperty(propertyDescriptor)) {
302 return new EnumValue(propertyDescriptor);
303 }
304 if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
305 return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
306 }
307 }
308 }
309 return null;
310 }
311
312 @Override
313 public CompileTimeConstant<?> visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
314 JetExpression selectorExpression = expression.getSelectorExpression();
315 if (selectorExpression != null) {
316 return selectorExpression.accept(this, null);
317 }
318 return super.visitQualifiedExpression(expression, data);
319 }
320
321 @Override
322 public CompileTimeConstant<?> visitCallExpression(@NotNull JetCallExpression expression, Void data) {
323 ResolvedCall<? extends CallableDescriptor> call =
324 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
325 if (call != null) {
326 CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
327 if (AnnotationUtils.isArrayMethodCall(call)) {
328 JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
329 List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
330 for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
331 arguments.addAll(resolveValueArguments(descriptorToArgument, type, trace));
332 }
333 return new ArrayValue(arguments, resultingDescriptor.getReturnType());
334 }
335
336 if (resultingDescriptor instanceof ConstructorDescriptor) {
337 JetType constructorReturnType = resultingDescriptor.getReturnType();
338 assert constructorReturnType != null : "Constructor should have return type";
339 if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
340 AnnotationDescriptorImpl descriptor = new AnnotationDescriptorImpl();
341 descriptor.setAnnotationType(constructorReturnType);
342 resolveAnnotationArgument(descriptor, call, trace);
343 return new AnnotationValue(descriptor);
344 }
345 }
346
347 if (AnnotationUtils.isJavaClassMethodCall(call)) {
348 return new JavaClassValue(resultingDescriptor.getReturnType());
349 }
350 }
351 return null;
352 }
353
354 @Override
355 public CompileTimeConstant<?> visitJetElement(@NotNull JetElement element, Void nothing) {
356 // TODO:
357 //trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(element));
358 return null;
359 }
360 };
361 return expression.accept(visitor, null);
362 }
363
364 private static boolean isEnumProperty(@NotNull PropertyDescriptor descriptor) {
365 ClassifierDescriptor classifier = descriptor.getType().getConstructor().getDeclarationDescriptor();
366 return classifier != null &&
367 DescriptorUtils.isEnumClass(classifier) &&
368 DescriptorUtils.isEnumClassObject(descriptor.getContainingDeclaration());
369 }
370
371 @NotNull
372 public List<AnnotationDescriptor> getResolvedAnnotations(@Nullable JetModifierList modifierList, BindingTrace trace) {
373 if (modifierList == null) {
374 return Collections.emptyList();
375 }
376 return getResolvedAnnotations(modifierList.getAnnotationEntries(), trace);
377 }
378
379 @SuppressWarnings("MethodMayBeStatic")
380 @NotNull
381 public List<AnnotationDescriptor> getResolvedAnnotations(List<JetAnnotationEntry> annotations, BindingTrace trace) {
382 List<AnnotationDescriptor> result = Lists.newArrayList();
383 for (JetAnnotationEntry annotation : annotations) {
384 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
385 if (annotationDescriptor == null) {
386 throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
387 }
388
389 result.add(annotationDescriptor);
390 }
391
392 return result;
393 }
394
395 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetModifierListOwner modifierListOwner, BindingTrace trace) {
396 JetModifierList modifierList = modifierListOwner.getModifierList();
397 if (modifierList == null) return;
398
399 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
400 trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
401 }
402 }
403 }