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 org.jetbrains.annotations.NotNull;
022 import org.jetbrains.annotations.Nullable;
023 import org.jetbrains.jet.lang.descriptors.*;
024 import org.jetbrains.jet.lang.descriptors.annotations.*;
025 import org.jetbrains.jet.lang.diagnostics.Errors;
026 import org.jetbrains.jet.lang.evaluate.ConstantExpressionEvaluator;
027 import org.jetbrains.jet.lang.psi.*;
028 import org.jetbrains.jet.lang.resolve.calls.ArgumentTypeResolver;
029 import org.jetbrains.jet.lang.resolve.calls.CallResolver;
030 import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
031 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
032 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
033 import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
034 import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
035 import org.jetbrains.jet.lang.resolve.constants.ArrayValue;
036 import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
037 import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
038 import org.jetbrains.jet.lang.resolve.scopes.JetScope;
039 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
040 import org.jetbrains.jet.lang.types.ErrorUtils;
041 import org.jetbrains.jet.lang.types.JetType;
042 import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
043 import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
044
045 import javax.inject.Inject;
046 import java.util.ArrayList;
047 import java.util.List;
048 import java.util.Map;
049
050 import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
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 Annotations 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 Annotations 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 Annotations 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 Annotations resolveAnnotations(
096 @NotNull JetScope scope,
097 @Nullable JetModifierList modifierList,
098 @NotNull BindingTrace trace,
099 boolean shouldResolveArguments
100 ) {
101 if (modifierList == null) {
102 return Annotations.EMPTY;
103 }
104 List<JetAnnotationEntry> annotationEntryElements = modifierList.getAnnotationEntries();
105
106 return resolveAnnotationEntries(scope, annotationEntryElements, trace, shouldResolveArguments);
107 }
108
109 private Annotations resolveAnnotationEntries(
110 @NotNull JetScope scope,
111 @NotNull List<JetAnnotationEntry> annotationEntryElements, @NotNull BindingTrace trace,
112 boolean shouldResolveArguments
113 ) {
114 if (annotationEntryElements.isEmpty()) return Annotations.EMPTY;
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 new AnnotationsImpl(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 public static void resolveAnnotationArgument(
210 @NotNull AnnotationDescriptorImpl annotationDescriptor,
211 @NotNull ResolvedCall<?> resolvedCall,
212 @NotNull BindingTrace trace
213 ) {
214 for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument : resolvedCall.getValueArguments().entrySet()) {
215 ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
216
217 JetType varargElementType = parameterDescriptor.getVarargElementType();
218 boolean argumentsAsVararg = varargElementType != null && !hasSpread(descriptorToArgument.getValue());
219 List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(),
220 argumentsAsVararg ? varargElementType : parameterDescriptor.getType(),
221 trace);
222
223 if (argumentsAsVararg) {
224 JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
225 if (arrayType == null) {
226 arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
227 }
228 annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType, true));
229 }
230 else {
231 for (CompileTimeConstant<?> constant : constants) {
232 annotationDescriptor.setValueArgument(parameterDescriptor, constant);
233 }
234 }
235 }
236 }
237
238 private static void checkCompileTimeConstant(
239 @NotNull JetExpression argumentExpression,
240 @NotNull JetType expectedType,
241 @NotNull BindingTrace trace
242 ) {
243 JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
244
245 if (expressionType == null || !expressionType.equals(expectedType)) {
246 // TYPE_MISMATCH should be reported otherwise
247 return;
248 }
249
250 // array(1, <!>null<!>, 3) - error should be reported on inner expression
251 if (argumentExpression instanceof JetCallExpression) {
252 Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
253 if (arrayArgument != null) {
254 for (JetExpression expression : arrayArgument.getFirst()) {
255 checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
256 }
257 }
258 }
259
260 CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression);
261 if (constant != null && constant.canBeUsedInAnnotations()) {
262 return;
263 }
264
265 ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
266 if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
267 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
268 }
269 else if (descriptor instanceof ClassDescriptor && CompileTimeConstantUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
270 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
271 }
272 else {
273 trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
274 }
275 }
276
277 @Nullable
278 private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
279 @NotNull JetCallExpression expression,
280 @NotNull BindingTrace trace
281 ) {
282 ResolvedCall<?> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
283 if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
284 return null;
285 }
286
287 assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
288 Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
289
290 List<JetExpression> result = Lists.newArrayList();
291 JetType elementType = argumentEntry.getKey().getVarargElementType();
292 for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
293 JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
294 if (valueArgumentExpression != null) {
295 if (elementType != null) {
296 result.add(valueArgumentExpression);
297 }
298 }
299 }
300 return new Pair<List<JetExpression>, JetType>(result, elementType);
301 }
302
303 private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
304 List<ValueArgument> arguments = argument.getArguments();
305 return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
306 }
307
308 @NotNull
309 private static List<CompileTimeConstant<?>> resolveValueArguments(
310 @NotNull ResolvedValueArgument resolvedValueArgument,
311 @NotNull JetType expectedType,
312 @NotNull BindingTrace trace
313 ) {
314 List<CompileTimeConstant<?>> constants = Lists.newArrayList();
315 for (ValueArgument argument : resolvedValueArgument.getArguments()) {
316 JetExpression argumentExpression = argument.getArgumentExpression();
317 if (argumentExpression != null) {
318 CompileTimeConstant<?> constant = ConstantExpressionEvaluator.object$.evaluate(argumentExpression, trace, expectedType);
319 if (constant instanceof IntegerValueTypeConstant) {
320 JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
321 ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
322 }
323 if (constant != null) {
324 constants.add(constant);
325 }
326 checkCompileTimeConstant(argumentExpression, expectedType, trace);
327 }
328 }
329 return constants;
330 }
331
332 @SuppressWarnings("MethodMayBeStatic")
333 @NotNull
334 public Annotations getResolvedAnnotations(@NotNull List<JetAnnotationEntry> annotations, @NotNull BindingTrace trace) {
335 List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>(annotations.size());
336 for (JetAnnotationEntry annotation : annotations) {
337 AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
338 if (annotationDescriptor == null) {
339 throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
340 }
341
342 result.add(annotationDescriptor);
343 }
344
345 return new AnnotationsImpl(result);
346 }
347
348 public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetTypeParameter jetTypeParameter, @NotNull BindingTrace trace) {
349 JetModifierList modifierList = jetTypeParameter.getModifierList();
350 if (modifierList == null) return;
351
352 for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
353 trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
354 }
355 }
356 }