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<? extends CallableDescriptor> call,
212                @NotNull BindingTrace trace
213        ) {
214            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
215                    call.getValueArguments().entrySet()) {
216                ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
217    
218                JetType varargElementType = parameterDescriptor.getVarargElementType();
219                boolean argumentsAsVararg = varargElementType != null && !hasSpread(descriptorToArgument.getValue());
220                List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(),
221                                                                               argumentsAsVararg ? varargElementType : parameterDescriptor.getType(),
222                                                                               trace);
223    
224                if (argumentsAsVararg) {
225                    JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
226                    if (arrayType == null) {
227                        arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
228                    }
229                    annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType, true));
230                }
231                else {
232                    for (CompileTimeConstant<?> constant : constants) {
233                        annotationDescriptor.setValueArgument(parameterDescriptor, constant);
234                    }
235                }
236            }
237        }
238    
239        private static void checkCompileTimeConstant(
240                @NotNull JetExpression argumentExpression,
241                @NotNull JetType expectedType,
242                @NotNull BindingTrace trace
243        ) {
244            JetType expressionType = trace.get(BindingContext.EXPRESSION_TYPE, argumentExpression);
245    
246            if (expressionType == null || !expressionType.equals(expectedType)) {
247                // TYPE_MISMATCH should be reported otherwise
248                return;
249            }
250    
251            // array(1, <!>null<!>, 3) - error should be reported on inner expression
252            if (argumentExpression instanceof JetCallExpression) {
253                Pair<List<JetExpression>, JetType> arrayArgument = getArgumentExpressionsForArrayCall((JetCallExpression) argumentExpression, trace);
254                if (arrayArgument != null) {
255                    for (JetExpression expression : arrayArgument.getFirst()) {
256                        checkCompileTimeConstant(expression, arrayArgument.getSecond(), trace);
257                    }
258                }
259            }
260    
261            CompileTimeConstant<?> constant = trace.get(BindingContext.COMPILE_TIME_VALUE, argumentExpression);
262            if (constant != null && constant.canBeUsedInAnnotations()) {
263                return;
264            }
265    
266            ClassifierDescriptor descriptor = expressionType.getConstructor().getDeclarationDescriptor();
267            if (descriptor != null && DescriptorUtils.isEnumClass(descriptor)) {
268                trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_ENUM_CONST.on(argumentExpression));
269            }
270            else if (descriptor instanceof ClassDescriptor && CompileTimeConstantUtils.isJavaLangClass((ClassDescriptor) descriptor)) {
271                trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CLASS_LITERAL.on(argumentExpression));
272            }
273            else {
274                trace.report(Errors.ANNOTATION_PARAMETER_MUST_BE_CONST.on(argumentExpression));
275            }
276        }
277    
278        @Nullable
279        private static Pair<List<JetExpression>, JetType> getArgumentExpressionsForArrayCall(
280                @NotNull JetCallExpression expression,
281                @NotNull BindingTrace trace
282        ) {
283            ResolvedCall<?> resolvedCall = trace.get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
284            if (resolvedCall == null || !CompileTimeConstantUtils.isArrayMethodCall(resolvedCall)) {
285                return null;
286            }
287    
288            assert resolvedCall.getValueArguments().size() == 1 : "Array function should have only one vararg parameter";
289            Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> argumentEntry = resolvedCall.getValueArguments().entrySet().iterator().next();
290    
291            List<JetExpression> result = Lists.newArrayList();
292            JetType elementType = argumentEntry.getKey().getVarargElementType();
293            for (ValueArgument valueArgument : argumentEntry.getValue().getArguments()) {
294                JetExpression valueArgumentExpression = valueArgument.getArgumentExpression();
295                if (valueArgumentExpression != null) {
296                    if (elementType != null) {
297                        result.add(valueArgumentExpression);
298                    }
299                }
300            }
301            return new Pair<List<JetExpression>, JetType>(result, elementType);
302        }
303    
304        private static boolean hasSpread(@NotNull ResolvedValueArgument argument) {
305            List<ValueArgument> arguments = argument.getArguments();
306            return arguments.size() == 1 && arguments.get(0).getSpreadElement() != null;
307        }
308    
309        @NotNull
310        private static List<CompileTimeConstant<?>> resolveValueArguments(
311                @NotNull ResolvedValueArgument resolvedValueArgument,
312                @NotNull JetType expectedType,
313                @NotNull BindingTrace trace
314        ) {
315            List<CompileTimeConstant<?>> constants = Lists.newArrayList();
316            for (ValueArgument argument : resolvedValueArgument.getArguments()) {
317                JetExpression argumentExpression = argument.getArgumentExpression();
318                if (argumentExpression != null) {
319                    CompileTimeConstant<?> constant = ConstantExpressionEvaluator.object$.evaluate(argumentExpression, trace, expectedType);
320                    if (constant instanceof IntegerValueTypeConstant) {
321                        JetType defaultType = ((IntegerValueTypeConstant) constant).getType(expectedType);
322                        ArgumentTypeResolver.updateNumberType(defaultType, argumentExpression, trace);
323                    }
324                    if (constant != null) {
325                        constants.add(constant);
326                    }
327                    checkCompileTimeConstant(argumentExpression, expectedType, trace);
328                }
329            }
330            return constants;
331        }
332    
333        @SuppressWarnings("MethodMayBeStatic")
334        @NotNull
335        public Annotations getResolvedAnnotations(@NotNull List<JetAnnotationEntry> annotations, @NotNull BindingTrace trace) {
336            List<AnnotationDescriptor> result = new ArrayList<AnnotationDescriptor>(annotations.size());
337            for (JetAnnotationEntry annotation : annotations) {
338                AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
339                if (annotationDescriptor == null) {
340                    throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
341                }
342    
343                result.add(annotationDescriptor);
344            }
345    
346            return new AnnotationsImpl(result);
347        }
348    
349        public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetModifierListOwner modifierListOwner, BindingTrace trace) {
350            JetModifierList modifierList = modifierListOwner.getModifierList();
351            if (modifierList == null) return;
352    
353            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
354                trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
355            }
356        }
357    }