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