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