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 com.intellij.openapi.util.Pair;
021 import kotlin.Function1;
022 import kotlin.KotlinPackage;
023 import org.jetbrains.annotations.NotNull;
024 import org.jetbrains.annotations.Nullable;
025 import org.jetbrains.jet.lang.descriptors.*;
026 import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
027 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
028 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
029 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationsImpl;
030 import org.jetbrains.jet.lang.diagnostics.Errors;
031 import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
032 import org.jetbrains.jet.lang.psi.*;
033 import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
034 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
035 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
036 import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
037 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
038 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
039 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
040 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
041 import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
042 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
043 import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
044 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyAnnotationDescriptor;
045 import org.jetbrains.jet.lang.resolve.lazy.descriptors.LazyAnnotationsContext;
046 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
047 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
048 import org.jetbrains.jet.lang.types.ErrorUtils;
049 import org.jetbrains.jet.lang.types.JetType;
050 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
051 import org.jetbrains.jet.storage.StorageManager;
052
053 import javax.inject.Inject;
054 import java.util.ArrayList;
055 import java.util.HashMap;
056 import java.util.List;
057 import java.util.Map;
058
059 import static org.jetbrains.jet.lang.diagnostics.Errors.NOT_AN_ANNOTATION_CLASS;
060 import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
061 import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
062
063 public class AnnotationResolver {
064
065 private CallResolver callResolver;
066 private StorageManager storageManager;
067 private TypeResolver typeResolver;
068
069 @Inject
070 public void setCallResolver(CallResolver callResolver) {
071 this.callResolver = callResolver;
072 }
073
074 @Inject
075 public void setStorageManager(StorageManager storageManager) {
076 this.storageManager = storageManager;
077 }
078
079 @Inject
080 public void setTypeResolver(TypeResolver typeResolver) {
081 this.typeResolver = typeResolver;
082 }
083
084 @NotNull
085 public Annotations resolveAnnotationsWithoutArguments(
086 @NotNull JetScope scope,
087 @Nullable JetModifierList modifierList,
088 @NotNull BindingTrace trace
089 ) {
090 return resolveAnnotations(scope, modifierList, trace, false);
091 }
092
093 @NotNull
094 public Annotations resolveAnnotationsWithArguments(
095 @NotNull JetScope scope,
096 @Nullable JetModifierList modifierList,
097 @NotNull BindingTrace trace
098 ) {
099 return resolveAnnotations(scope, modifierList, trace, true);
100 }
101
102 @NotNull
103 public Annotations resolveAnnotationsWithArguments(
104 @NotNull JetScope scope,
105 @NotNull List<JetAnnotationEntry> annotationEntries,
106 @NotNull BindingTrace trace
107 ) {
108 return resolveAnnotationEntries(scope, annotationEntries, trace, true);
109 }
110
111 private Annotations resolveAnnotations(
112 @NotNull JetScope scope,
113 @Nullable JetModifierList modifierList,
114 @NotNull BindingTrace trace,
115 boolean shouldResolveArguments
116 ) {
117 if (modifierList == null) {
118 return Annotations.EMPTY;
119 }
120 List<JetAnnotationEntry> annotationEntryElements = modifierList.getAnnotationEntries();
121
122 return resolveAnnotationEntries(scope, annotationEntryElements, trace, shouldResolveArguments);
123 }
124
125 private Annotations resolveAnnotationEntries(
126 @NotNull final JetScope scope,
127 @NotNull List<JetAnnotationEntry> annotationEntryElements,
128 @NotNull BindingTrace trace,
129 boolean shouldResolveArguments
130 ) {
131 if (annotationEntryElements.isEmpty()) return Annotations.EMPTY;
132 List<AnnotationDescriptor> result = Lists.newArrayList();
133 for (JetAnnotationEntry entryElement : annotationEntryElements) {
134 AnnotationDescriptor descriptor = trace.get(BindingContext.ANNOTATION, entryElement);
135 if (descriptor == null) {
136 descriptor = new LazyAnnotationDescriptor(
137 new LazyAnnotationsContext(this, storageManager, trace) {
138
139 @NotNull
140 @Override
141 public JetScope getScope() {
142 return scope;
143 }
144 },
145 entryElement
146 );
147 }
148 if (shouldResolveArguments) {
149 resolveAnnotationArguments(entryElement, trace);
150 }
151
152 result.add(descriptor);
153 }
154 return new AnnotationsImpl(result);
155 }
156
157 @NotNull
158 public JetType resolveAnnotationType(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement) {
159 JetTypeReference typeReference = entryElement.getTypeReference();
160 if (typeReference == null) {
161 return ErrorUtils.createErrorType("No type reference: " + entryElement.getText());
162 }
163
164 return typeResolver.resolveType(scope, typeReference, new BindingTraceContext(), true);
165 }
166
167 public static void checkAnnotationType(
168 @NotNull JetAnnotationEntry entryElement,
169 @NotNull BindingTrace trace,
170 @NotNull OverloadResolutionResults<FunctionDescriptor> results
171 ) {
172 if (!results.isSingleResult()) return;
173 FunctionDescriptor descriptor = results.getResultingDescriptor();
174 if (!ErrorUtils.isError(descriptor)) {
175 if (descriptor instanceof ConstructorDescriptor) {
176 ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor;
177 ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
178 if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) {
179 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor));
180 }
181 }
182 else {
183 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor));
184 }
185 }
186 }
187
188 @NotNull
189 public OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall(
190 JetAnnotationEntry annotationEntry,
191 JetScope scope,
192 BindingTrace trace
193 ) {
194 return callResolver.resolveFunctionCall(
195 trace, scope,
196 CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry),
197 NO_EXPECTED_TYPE,
198 DataFlowInfo.EMPTY,
199 true
200 );
201 }
202
203 public static void resolveAnnotationsArguments(@Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
204 if (modifierList == null) {
205 return;
206 }
207
208 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
209 resolveAnnotationArguments(annotationEntry, trace);
210 }
211 }
212
213 public static void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace) {
214 for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
215 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
216 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
217 resolveAnnotationArguments(annotationEntry, trace);
218 }
219 }
220
221 private static void resolveAnnotationArguments(
222 @NotNull JetAnnotationEntry annotationEntry,
223 @NotNull BindingTrace trace
224 ) {
225 AnnotationDescriptor annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
226 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
227 if (annotationDescriptor instanceof LazyAnnotationDescriptor) {
228 ((LazyAnnotationDescriptor) annotationDescriptor).forceResolveAllContents();
229 }
230 }
231
232 @NotNull
233 public static Map<ValueParameterDescriptor, CompileTimeConstant<?>> resolveAnnotationArguments(
234 @NotNull ResolvedCall<?> resolvedCall,
235 @NotNull BindingTrace trace
236 ) {
237 Map<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = new HashMap<ValueParameterDescriptor, CompileTimeConstant<?>>();
238 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : resolvedCall.getValueArguments().entrySet()) {
239 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
240 ResolvedValueArgument resolvedArgument = descriptorToArgument.getValue();
241
242 CompileTimeConstant<?> value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument);
243 if (value != null) {
244 arguments.put(parameterDescriptor, value);
245 }
246 }
247 return arguments;
248 }
249
250 @Nullable
251 public static CompileTimeConstant<?> getAnnotationArgumentValue(
252 BindingTrace trace,
253 ValueParameterDescriptor parameterDescriptor,
254 ResolvedValueArgument resolvedArgument
255 ) {
256 JetType varargElementType = parameterDescriptor.getVarargElementType();
257 boolean argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument);
258 List<CompileTimeConstant<?>> constants = resolveValueArguments(resolvedArgument,
259 argumentsAsVararg ? varargElementType : parameterDescriptor.getType(),
260 trace);
261
262 if (argumentsAsVararg) {
263
264 boolean usesVariableAsConstant = KotlinPackage.any(constants, new Function1<CompileTimeConstant<?>, Boolean>() {
265 @Override
266 public Boolean invoke(CompileTimeConstant<?> constant) {
267 return constant.usesVariableAsConstant();
268 }
269 });
270
271 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
272 if (arrayType == null) {
273 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
274 }
275
276 return new ArrayValue(constants, arrayType, true, usesVariableAsConstant);
277 }
278 else {
279 // we should actually get only one element, but just in case of getting many, we take the last one
280 return !constants.isEmpty() ? KotlinPackage.last(constants) : null;
281 }
282 }
283
284 private static void checkCompileTimeConstant(
285 @NotNull JetExpression argumentExpression,
286 @NotNull JetType expectedType,
287 @NotNull BindingTrace trace
288 ) {
289 JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
290
291 if (expressionType == null || !expressionType.equals(expectedType)) {
292 // TYPE_MISMATCH should be reported otherwise
293 return;
294 }
295
296 // array(1, <!>null<!>, 3) - error should be reported on inner expression
297 if (argumentExpression instanceof JetCallExpression) {
298 Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
299 if (arrayArgument != null) {
300 for (JetExpression expression : arrayArgument.getFirst()) {
301 checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
302 }
303 }
304 }
305
306 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression);
307 if (constant != null && constant.canBeUsedInAnnotations()) {
308 return;
309 }
310
311 ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
312 if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
313 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
314 }
315 else if (descriptor instanceof ClassDescriptor && CompileTimeConstantUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
316 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
317 }
318 else {
319 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
320 }
321 }
322
323 @Nullable
324 private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
325 @NotNull JetCallExpression expression,
326 @NotNull BindingTrace trace
327 ) {
328 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, trace.getBindingContext());
329 if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
330 return null;
331 }
332
333 assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
334 Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
335
336 List<JetExpression> result = Lists.newArrayList();
337 JetType elementType = argumentEntry.getKey().getVarargElementType();
338 for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
339 JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
340 if (valueArgumentExpression != null) {
341 if (elementType != null) {
342 result.add(valueArgumentExpression);
343 }
344 }
345 }
346 return new Pair<List<JetExpression>, JetType>(result, elementType);
347 }
348
349 private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
350 List<ValueArgument> arguments = argument.getArguments();
351 return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
352 }
353
354 @NotNull
355 private static List<CompileTimeConstant<?>> resolveValueArguments(
356 @NotNull ResolvedValueArgument resolvedValueArgument,
357 @NotNull JetType expectedType,
358 @NotNull BindingTrace trace
359 ) {
360 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
361 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
362 JetExpression argumentExpression = argument.getArgumentExpression();
363 if (argumentExpression != null) {
364 CompileTimeConstant<?> constant = ConstantExpressionEvaluator.OBJECT$.evaluate(argumentExpression, trace, expectedType);
365 if (constant instanceof IntegerValueTypeConstant) {
366 JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
367 ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
368 }
369 if (constant != null) {
370 constants.add(constant);
371 }
372 checkCompileTimeConstant(argumentExpression, expectedType, trace);
373 }
374 }
375 return constants;
376 }
377
378 @SuppressWarnings("MethodMayBeStatic")
379 @NotNull
380 public Annotations getResolvedAnnotations(@NotNull List<JetAnnotationEntry> annotations, @NotNull BindingTrace trace) {
381 List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>(annotations.size());
382 for (JetAnnotationEntry annotation : annotations) {
383 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
384 if (annotationDescriptor == null) {
385 throw new IllegalStateException("Annotation for annotation should have been resolved: \n" +
386 JetPsiUtil.getElementTextWithContext(annotation));
387 }
388
389 result.add(annotationDescriptor);
390 }
391
392 return new AnnotationsImpl(result);
393 }
394
395 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) {
396 JetModifierList modifierList = jetTypeParameter.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 }