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