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.AnnotationDescriptor;
027 import org.jetbrains.jet.lang.descriptors.annotations.Annotations;
028 import org.jetbrains.jet.lang.descriptors.annotations.AnnotationsImpl;
029 import org.jetbrains.jet.lang.diagnostics.Errors;
030 import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
031 import org.jetbrains.jet.lang.psi.*;
032 import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
033 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
034 import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage;
035 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
036 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
037 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
038 import org.jetbrains.jet.lang.resolve.calls.smartcasts.DataFlowInfo;
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.LazyAnnotationsContextImpl;
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 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(new LazyAnnotationsContextImpl(this, storageManager, trace, scope), entryElement);
136 }
137 if (shouldResolveArguments) {
138 resolveAnnotationArguments(entryElement, trace);
139 }
140
141 result.add(descriptor);
142 }
143 return new AnnotationsImpl(result);
144 }
145
146 @NotNull
147 public JetType resolveAnnotationType(@NotNull JetScope scope, @NotNull JetAnnotationEntry entryElement) {
148 JetTypeReference typeReference = entryElement.getTypeReference();
149 if (typeReference == null) {
150 return ErrorUtils.createErrorType("No type reference: " + entryElement.getText());
151 }
152
153 return typeResolver.resolveType(scope, typeReference, new BindingTraceContext(), true);
154 }
155
156 public static void checkAnnotationType(
157 @NotNull JetAnnotationEntry entryElement,
158 @NotNull BindingTrace trace,
159 @NotNull OverloadResolutionResults<FunctionDescriptor> results
160 ) {
161 if (!results.isSingleResult()) return;
162 FunctionDescriptor descriptor = results.getResultingDescriptor();
163 if (!ErrorUtils.isError(descriptor)) {
164 if (descriptor instanceof ConstructorDescriptor) {
165 ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor;
166 ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
167 if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) {
168 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor));
169 }
170 }
171 else {
172 trace.report(NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor));
173 }
174 }
175 }
176
177 @NotNull
178 public OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall(
179 JetAnnotationEntry annotationEntry,
180 JetScope scope,
181 BindingTrace trace
182 ) {
183 return callResolver.resolveFunctionCall(
184 trace, scope,
185 CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry),
186 NO_EXPECTED_TYPE,
187 DataFlowInfo.EMPTY,
188 true
189 );
190 }
191
192 public static void resolveAnnotationsArguments(@Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
193 if (modifierList == null) {
194 return;
195 }
196
197 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
198 resolveAnnotationArguments(annotationEntry, trace);
199 }
200 }
201
202 public static void resolveAnnotationsArguments(@NotNull Annotations annotations, @NotNull BindingTrace trace) {
203 for (AnnotationDescriptor annotationDescriptor : annotations) {
204 JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
205 assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
206 resolveAnnotationArguments(annotationEntry, trace);
207 }
208 }
209
210 private static void resolveAnnotationArguments(
211 @NotNull JetAnnotationEntry annotationEntry,
212 @NotNull BindingTrace trace
213 ) {
214 AnnotationDescriptor annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
215 assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
216 if (annotationDescriptor instanceof LazyAnnotationDescriptor) {
217 ((LazyAnnotationDescriptor) annotationDescriptor).forceResolveAllContents();
218 }
219 }
220
221 @NotNull
222 public static Map<ValueParameterDescriptor, CompileTimeConstant<?>> resolveAnnotationArguments(
223 @NotNull ResolvedCall<?> resolvedCall,
224 @NotNull BindingTrace trace
225 ) {
226 Map<ValueParameterDescriptor, CompileTimeConstant<?>> arguments = new HashMap<ValueParameterDescriptor, CompileTimeConstant<?>>();
227 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : resolvedCall.getValueArguments().entrySet()) {
228 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
229 ResolvedValueArgument resolvedArgument = descriptorToArgument.getValue();
230
231 CompileTimeConstant<?> value = getAnnotationArgumentValue(trace, parameterDescriptor, resolvedArgument);
232 if (value != null) {
233 arguments.put(parameterDescriptor, value);
234 }
235 }
236 return arguments;
237 }
238
239 @Nullable
240 public static CompileTimeConstant<?> getAnnotationArgumentValue(
241 BindingTrace trace,
242 ValueParameterDescriptor parameterDescriptor,
243 ResolvedValueArgument resolvedArgument
244 ) {
245 JetType varargElementType = parameterDescriptor.getVarargElementType();
246 boolean argumentsAsVararg = varargElementType != null && !hasSpread(resolvedArgument);
247 List<CompileTimeConstant<?>> constants = resolveValueArguments(resolvedArgument,
248 argumentsAsVararg ? varargElementType : parameterDescriptor.getType(),
249 trace);
250
251 if (argumentsAsVararg) {
252
253 boolean usesVariableAsConstant = KotlinPackage.any(constants, new Function1<CompileTimeConstant<?>, Boolean>() {
254 @Override
255 public Boolean invoke(CompileTimeConstant<?> constant) {
256 return constant.usesVariableAsConstant();
257 }
258 });
259
260 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
261 if (arrayType == null) {
262 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
263 }
264
265 return new ArrayValue(constants, arrayType, true, usesVariableAsConstant);
266 }
267 else {
268 // we should actually get only one element, but just in case of getting many, we take the last one
269 return !constants.isEmpty() ? KotlinPackage.last(constants) : null;
270 }
271 }
272
273 private static void checkCompileTimeConstant(
274 @NotNull JetExpression argumentExpression,
275 @NotNull JetType expectedType,
276 @NotNull BindingTrace trace
277 ) {
278 JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
279
280 if (expressionType == null || !expressionType.equals(expectedType)) {
281 // TYPE_MISMATCH should be reported otherwise
282 return;
283 }
284
285 // array(1, <!>null<!>, 3) - error should be reported on inner expression
286 if (argumentExpression instanceof JetCallExpression) {
287 Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
288 if (arrayArgument != null) {
289 for (JetExpression expression : arrayArgument.getFirst()) {
290 checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
291 }
292 }
293 }
294
295 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression);
296 if (constant != null && constant.canBeUsedInAnnotations()) {
297 return;
298 }
299
300 ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
301 if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
302 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
303 }
304 else if (descriptor instanceof ClassDescriptor && CompileTimeConstantUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
305 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
306 }
307 else {
308 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
309 }
310 }
311
312 @Nullable
313 private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
314 @NotNull JetCallExpression expression,
315 @NotNull BindingTrace trace
316 ) {
317 ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, trace.getBindingContext());
318 if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
319 return null;
320 }
321
322 assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
323 Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
324
325 List<JetExpression> result = Lists.newArrayList();
326 JetType elementType = argumentEntry.getKey().getVarargElementType();
327 for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
328 JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
329 if (valueArgumentExpression != null) {
330 if (elementType != null) {
331 result.add(valueArgumentExpression);
332 }
333 }
334 }
335 return new Pair<List<JetExpression>, JetType>(result, elementType);
336 }
337
338 private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
339 List<ValueArgument> arguments = argument.getArguments();
340 return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
341 }
342
343 @NotNull
344 private static List<CompileTimeConstant<?>> resolveValueArguments(
345 @NotNull ResolvedValueArgument resolvedValueArgument,
346 @NotNull JetType expectedType,
347 @NotNull BindingTrace trace
348 ) {
349 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
350 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
351 JetExpression argumentExpression = argument.getArgumentExpression();
352 if (argumentExpression != null) {
353 CompileTimeConstant<?> constant = ConstantExpressionEvaluator.OBJECT$.evaluate(argumentExpression, trace, expectedType);
354 if (constant instanceof IntegerValueTypeConstant) {
355 JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
356 ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
357 }
358 if (constant != null) {
359 constants.add(constant);
360 }
361 checkCompileTimeConstant(argumentExpression, expectedType, trace);
362 }
363 }
364 return constants;
365 }
366
367 @SuppressWarnings("MethodMayBeStatic")
368 @NotNull
369 public Annotations getResolvedAnnotations(@NotNull List<JetAnnotationEntry> annotations, @NotNull BindingTrace trace) {
370 List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>(annotations.size());
371 for (JetAnnotationEntry annotation : annotations) {
372 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
373 if (annotationDescriptor == null) {
374 throw new IllegalStateException("Annotation for annotation should have been resolved: \n" +
375 JetPsiUtil.getElementTextWithContext(annotation));
376 }
377
378 result.add(annotationDescriptor);
379 }
380
381 return new AnnotationsImpl(result);
382 }
383
384 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) {
385 JetModifierList modifierList = jetTypeParameter.getModifierList();
386 if (modifierList == null) return;
387
388 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
389 trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
390 }
391 }
392 }