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