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> resolveAnnotationsWithoutArguments(
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 = trace.get(BindingContext.ANNOTATION, entryElement);
098 if (descriptor == null) {
099 descriptor = new AnnotationDescriptor();
100 resolveAnnotationStub(scope, entryElement, descriptor, trace);
101 trace.record(BindingContext.ANNOTATION, entryElement, descriptor);
102 }
103
104 if (shouldResolveArguments) {
105 resolveAnnotationArguments(entryElement, scope, trace);
106 }
107
108 result.add(descriptor);
109 }
110 return result;
111 }
112
113 public void resolveAnnotationStub(
114 @NotNull JetScope scope,
115 @NotNull JetAnnotationEntry entryElement,
116 @NotNull AnnotationDescriptor annotationDescriptor,
117 @NotNull BindingTrace trace
118 ) {
119 TemporaryBindingTrace temporaryBindingTrace = new TemporaryBindingTrace(trace, "Trace for resolve annotation type");
120 OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(entryElement, scope, temporaryBindingTrace);
121 if (results.isSuccess()) {
122 FunctionDescriptor descriptor = results.getResultingDescriptor();
123 if (!ErrorUtils.isError(descriptor)) {
124 if (descriptor instanceof ConstructorDescriptor) {
125 ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor;
126 ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
127 if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) {
128 trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor.getName().asString()));
129 }
130 }
131 else {
132 trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor.getName().asString()));
133 }
134 }
135 JetType annotationType = results.getResultingDescriptor().getReturnType();
136 annotationDescriptor.setAnnotationType(annotationType);
137 }
138 else {
139 annotationDescriptor.setAnnotationType(ErrorUtils.createErrorType("Unresolved annotation type"));
140 }
141 }
142
143 private OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall(
144 JetAnnotationEntry annotationEntry,
145 JetScope scope,
146 BindingTrace trace
147 ) {
148 return callResolver.resolveFunctionCall(
149 trace, scope,
150 CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry),
151 NO_EXPECTED_TYPE,
152 DataFlowInfo.EMPTY);
153 }
154
155 public void resolveAnnotationsArguments(@NotNull JetScope scope, @Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
156 if (modifierList == null) {
157 return;
158 }
159
160 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
161 resolveAnnotationArguments(annotationEntry, scope, trace);
162 }
163 }
164
165 public void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace, @NotNull JetScope scope) {
166 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
167 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
168 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
169 resolveAnnotationArguments(annotationEntry, scope, trace);
170 }
171 }
172
173 private void resolveAnnotationArguments(
174 @NotNull JetAnnotationEntry annotationEntry,
175 @NotNull JetScope scope,
176 @NotNull BindingTrace trace
177 ) {
178 OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(annotationEntry, scope, trace);
179 if (results.isSuccess()) {
180 AnnotationDescriptor annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
181 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
182 resolveAnnotationArgument(annotationDescriptor, results.getResultingCall(), trace);
183 }
184 }
185
186 private void resolveAnnotationArgument(
187 @NotNull AnnotationDescriptor annotationDescriptor,
188 @NotNull ResolvedCall<? extends CallableDescriptor> call,
189 @NotNull BindingTrace trace
190 ) {
191 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
192 call.getValueArguments().entrySet()) {
193 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
194
195 JetType varargElementType = parameterDescriptor.getVarargElementType();
196 List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
197 if (varargElementType == null) {
198 for (CompileTimeConstant<?> constant : constants) {
199 annotationDescriptor.setValueArgument(parameterDescriptor, constant);
200 }
201 }
202 else {
203 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
204 if (arrayType == null) {
205 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
206 }
207 annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType));
208 }
209 }
210 }
211
212 @NotNull
213 private List<CompileTimeConstant<?>> resolveValueArguments(
214 @NotNull ResolvedValueArgument resolvedValueArgument,
215 @NotNull JetType expectedType,
216 @NotNull BindingTrace trace
217 ) {
218 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
219 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
220 JetExpression argumentExpression = argument.getArgumentExpression();
221 if (argumentExpression != null) {
222 CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
223 if (constant != null) {
224 constants.add(constant);
225 }
226 }
227 }
228 return constants;
229 }
230
231 @Nullable
232 public CompileTimeConstant<?> resolveExpressionToCompileTimeValue(
233 @NotNull JetExpression expression,
234 @NotNull final JetType expectedType,
235 @NotNull final BindingTrace trace
236 ) {
237 JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
238 @Override
239 public CompileTimeConstant<?> visitConstantExpression(JetConstantExpression expression, Void nothing) {
240 JetType type = expressionTypingServices.getType(JetScope.EMPTY, expression, expectedType, DataFlowInfo.EMPTY, trace);
241 if (type == null) {
242 // TODO:
243 // trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(expression));
244 }
245 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
246 }
247
248
249 // @Override
250 // public CompileTimeConstant visitAnnotation(JetAnnotation annotation, Void nothing) {
251 // super.visitAnnotation(annotation, null); // TODO
252 // }
253 //
254 // @Override
255 // public CompileTimeConstant visitAnnotationEntry(JetAnnotationEntry annotationEntry, Void nothing) {
256 // return super.visitAnnotationEntry(annotationEntry, null); // TODO
257 // }
258
259 @Override
260 public CompileTimeConstant<?> visitParenthesizedExpression(JetParenthesizedExpression expression, Void nothing) {
261 JetExpression innerExpression = expression.getExpression();
262 if (innerExpression == null) return null;
263 return innerExpression.accept(this, null);
264 }
265
266 @Override
267 public CompileTimeConstant<?> visitStringTemplateExpression(JetStringTemplateExpression expression,
268 Void nothing) {
269 return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
270 }
271
272 @Override
273 public CompileTimeConstant<?> visitSimpleNameExpression(JetSimpleNameExpression expression, Void data) {
274 ResolvedCall<? extends CallableDescriptor> resolvedCall =
275 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
276 if (resolvedCall != null) {
277 CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
278 if (callableDescriptor instanceof PropertyDescriptor) {
279 PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
280 if (isEnumProperty(propertyDescriptor)) {
281 return new EnumValue(propertyDescriptor);
282 }
283 if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
284 return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
285 }
286 }
287 }
288 return null;
289 }
290
291 @Override
292 public CompileTimeConstant<?> visitQualifiedExpression(JetQualifiedExpression expression, Void data) {
293 JetExpression selectorExpression = expression.getSelectorExpression();
294 if (selectorExpression != null) {
295 return selectorExpression.accept(this, null);
296 }
297 return super.visitQualifiedExpression(expression, data);
298 }
299
300 @Override
301 public CompileTimeConstant<?> visitCallExpression(JetCallExpression expression, Void data) {
302 ResolvedCall<? extends CallableDescriptor> call =
303 trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
304 if (call != null) {
305 CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
306 if (AnnotationUtils.isArrayMethodCall(call)) {
307 JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
308 List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
309 for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
310 arguments.addAll(resolveValueArguments(descriptorToArgument, type, trace));
311 }
312 return new ArrayValue(arguments, resultingDescriptor.getReturnType());
313 }
314
315 if (resultingDescriptor instanceof ConstructorDescriptor) {
316 JetType constructorReturnType = resultingDescriptor.getReturnType();
317 assert constructorReturnType != null : "Constructor should have return type";
318 if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
319 AnnotationDescriptor descriptor = new AnnotationDescriptor();
320 descriptor.setAnnotationType(constructorReturnType);
321 resolveAnnotationArgument(descriptor, call, trace);
322 return new AnnotationValue(descriptor);
323 }
324 }
325
326 if (AnnotationUtils.isJavaClassMethodCall(call)) {
327 return new JavaClassValue(resultingDescriptor.getReturnType());
328 }
329 }
330 return null;
331 }
332
333 @Override
334 public CompileTimeConstant<?> visitJetElement(JetElement element, Void nothing) {
335 // TODO:
336 //trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(element));
337 return null;
338 }
339 };
340 return expression.accept(visitor, null);
341 }
342
343 private static boolean isEnumProperty(@NotNull PropertyDescriptor descriptor) {
344 if (DescriptorUtils.isKindOf(descriptor.getType(), ClassKind.ENUM_CLASS)) {
345 DeclarationDescriptor enumClassObject = descriptor.getContainingDeclaration();
346 if (DescriptorUtils.isKindOf(enumClassObject, ClassKind.CLASS_OBJECT)) {
347 return DescriptorUtils.isKindOf(enumClassObject.getContainingDeclaration(), ClassKind.ENUM_CLASS);
348 }
349 }
350 return false;
351 }
352
353 @NotNull
354 public List<AnnotationDescriptor> getResolvedAnnotations(@Nullable JetModifierList modifierList, BindingTrace trace) {
355 if (modifierList == null) {
356 return Collections.emptyList();
357 }
358 return getResolvedAnnotations(modifierList.getAnnotationEntries(), trace);
359 }
360
361 @SuppressWarnings("MethodMayBeStatic")
362 @NotNull
363 public List<AnnotationDescriptor> getResolvedAnnotations(List<JetAnnotationEntry> annotations, BindingTrace trace) {
364 List<AnnotationDescriptor> result = Lists.newArrayList();
365 for (JetAnnotationEntry annotation : annotations) {
366 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
367 if (annotationDescriptor == null) {
368 throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
369 }
370
371 result.add(annotationDescriptor);
372 }
373
374 return result;
375 }
376
377 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetModifierListOwner modifierListOwner, BindingTrace trace) {
378 JetModifierList modifierList = modifierListOwner.getModifierList();
379 if (modifierList == null) return;
380
381 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
382 trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
383 }
384 }
385 }