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    }