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