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