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 org.jetbrains.annotations.NotNull;
021    import org.jetbrains.annotations.Nullable;
022    import org.jetbrains.jet.lang.descriptors.*;
023    import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
024    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
025    import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptorImpl;
026    import org.jetbrains.jet.lang.diagnostics.Errors;
027    import org.jetbrains.jet.lang.psi.*;
028    import org.jetbrains.jet.lang.resolve.calls.CallResolver;
029    import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
030    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
031    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
032    import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
033    import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
034    import org.jetbrains.jet.lang.resolve.constants.*;
035    import org.jetbrains.jet.lang.resolve.scopes.JetScope;
036    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
037    import org.jetbrains.jet.lang.types.ErrorUtils;
038    import org.jetbrains.jet.lang.types.JetType;
039    import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
040    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
041    
042    import javax.inject.Inject;
043    import java.util.Collections;
044    import java.util.List;
045    import java.util.Map;
046    
047    import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT;
048    import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER;
049    import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
050    
051    public class AnnotationResolver {
052    
053        private ExpressionTypingServices expressionTypingServices;
054        private CallResolver callResolver;
055    
056        @Inject
057        public void setExpressionTypingServices(ExpressionTypingServices expressionTypingServices) {
058            this.expressionTypingServices = expressionTypingServices;
059        }
060    
061        @Inject
062        public void setCallResolver(CallResolver callResolver) {
063            this.callResolver = callResolver;
064        }
065    
066        @NotNull
067        public List<AnnotationDescriptor> resolveAnnotationsWithoutArguments(
068                @NotNull JetScope scope,
069                @Nullable JetModifierList modifierList,
070                @NotNull BindingTrace trace
071        ) {
072            return resolveAnnotations(scope, modifierList, trace, false);
073        }
074    
075        @NotNull
076        public List<AnnotationDescriptor> resolveAnnotationsWithArguments(
077                @NotNull JetScope scope,
078                @Nullable JetModifierList modifierList,
079                @NotNull BindingTrace trace
080        ) {
081            return resolveAnnotations(scope, modifierList, trace, true);
082        }
083    
084        @NotNull
085        public List<AnnotationDescriptor> resolveAnnotationsWithArguments(
086                @NotNull JetScope scope,
087                @NotNull List<JetAnnotationEntry> annotationEntries,
088                @NotNull BindingTrace trace
089        ) {
090            return resolveAnnotationEntries(scope, annotationEntries, trace, true);
091        }
092    
093        private List<AnnotationDescriptor> resolveAnnotations(
094                @NotNull JetScope scope,
095                @Nullable JetModifierList modifierList,
096                @NotNull BindingTrace trace,
097                boolean shouldResolveArguments
098        ) {
099            if (modifierList == null) {
100                return Collections.emptyList();
101            }
102            List<JetAnnotationEntry> annotationEntryElements = modifierList.getAnnotationEntries();
103    
104            return resolveAnnotationEntries(scope, annotationEntryElements, trace, shouldResolveArguments);
105        }
106    
107        private List<AnnotationDescriptor> resolveAnnotationEntries(
108                @NotNull JetScope scope,
109                @NotNull List<JetAnnotationEntry> annotationEntryElements, @NotNull BindingTrace trace,
110                boolean shouldResolveArguments
111        ) {
112            if (annotationEntryElements.isEmpty()) return Collections.emptyList();
113            List<AnnotationDescriptor> result = Lists.newArrayList();
114            for (JetAnnotationEntry entryElement : annotationEntryElements) {
115                AnnotationDescriptorImpl descriptor = trace.get(BindingContext.ANNOTATION, entryElement);
116                if (descriptor == null) {
117                    descriptor = new AnnotationDescriptorImpl();
118                    resolveAnnotationStub(scope, entryElement, descriptor, trace);
119                    trace.record(BindingContext.ANNOTATION, entryElement, descriptor);
120                }
121    
122                if (shouldResolveArguments) {
123                    resolveAnnotationArguments(entryElement, scope, trace);
124                }
125    
126                result.add(descriptor);
127            }
128            return result;
129        }
130    
131        public void resolveAnnotationStub(
132                @NotNull JetScope scope,
133                @NotNull JetAnnotationEntry entryElement,
134                @NotNull AnnotationDescriptorImpl annotationDescriptor,
135                @NotNull BindingTrace trace
136        ) {
137            TemporaryBindingTrace temporaryBindingTrace = new TemporaryBindingTrace(trace, "Trace for resolve annotation type");
138            OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(entryElement, scope, temporaryBindingTrace);
139            if (results.isSingleResult()) {
140                FunctionDescriptor descriptor = results.getResultingDescriptor();
141                if (!ErrorUtils.isError(descriptor)) {
142                    if (descriptor instanceof ConstructorDescriptor) {
143                        ConstructorDescriptor constructor = (ConstructorDescriptor)descriptor;
144                        ClassDescriptor classDescriptor = constructor.getContainingDeclaration();
145                        if (classDescriptor.getKind() != ClassKind.ANNOTATION_CLASS) {
146                            trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, classDescriptor.getName().asString()));
147                        }
148                    }
149                    else {
150                        trace.report(Errors.NOT_AN_ANNOTATION_CLASS.on(entryElement, descriptor.getName().asString()));
151                    }
152                }
153                JetType annotationType = results.getResultingDescriptor().getReturnType();
154                annotationDescriptor.setAnnotationType(annotationType);
155            }
156            else {
157                JetConstructorCalleeExpression calleeExpression = entryElement.getCalleeExpression();
158                annotationDescriptor.setAnnotationType(ErrorUtils.createErrorType("Unresolved annotation type: " +
159                                                                                  (calleeExpression == null ? "null" : calleeExpression.getText())));
160            }
161        }
162    
163        private OverloadResolutionResults<FunctionDescriptor> resolveAnnotationCall(
164                JetAnnotationEntry annotationEntry,
165                JetScope scope,
166                BindingTrace trace
167        ) {
168            return callResolver.resolveFunctionCall(
169                    trace, scope,
170                    CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, annotationEntry),
171                    NO_EXPECTED_TYPE,
172                    DataFlowInfo.EMPTY,
173                    true);
174        }
175    
176        public void resolveAnnotationsArguments(@NotNull JetScope scope, @Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
177            if (modifierList == null) {
178                return;
179            }
180    
181            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
182                resolveAnnotationArguments(annotationEntry, scope, trace);
183            }
184        }
185    
186        public void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace, @NotNull JetScope scope) {
187            for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
188                JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
189                assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
190                resolveAnnotationArguments(annotationEntry, scope, trace);
191            }
192        }
193    
194        private void resolveAnnotationArguments(
195                @NotNull JetAnnotationEntry annotationEntry,
196                @NotNull JetScope scope,
197                @NotNull BindingTrace trace
198        ) {
199            OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(annotationEntry, scope, trace);
200            if (results.isSingleResult()) {
201                AnnotationDescriptorImpl annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
202                assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
203                resolveAnnotationArgument(annotationDescriptor, results.getResultingCall(), trace);
204            }
205        }
206    
207        private void resolveAnnotationArgument(
208                @NotNull AnnotationDescriptorImpl annotationDescriptor,
209                @NotNull ResolvedCall<? extends CallableDescriptor> call,
210                @NotNull BindingTrace trace
211        ) {
212            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
213                    call.getValueArguments().entrySet()) {
214                ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
215    
216                JetType varargElementType = parameterDescriptor.getVarargElementType();
217                List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
218                if (varargElementType == null) {
219                    for (CompileTimeConstant<?> constant : constants) {
220                        annotationDescriptor.setValueArgument(parameterDescriptor, constant);
221                    }
222                }
223                else {
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));
229                }
230            }
231        }
232    
233        @NotNull
234        private List<CompileTimeConstant<?>> resolveValueArguments(
235                @NotNull ResolvedValueArgument resolvedValueArgument,
236                @NotNull JetType expectedType,
237                @NotNull BindingTrace trace
238        ) {
239            List<CompileTimeConstant<?>> constants = Lists.newArrayList();
240            for (ValueArgument argument : resolvedValueArgument.getArguments()) {
241                JetExpression argumentExpression = argument.getArgumentExpression();
242                if (argumentExpression != null) {
243                    CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
244                    if (constant != null) {
245                        constants.add(constant);
246                    }
247                }
248            }
249            return constants;
250        }
251    
252        @Nullable
253        public CompileTimeConstant<?> resolveExpressionToCompileTimeValue(
254                @NotNull JetExpression expression,
255                @NotNull final JetType expectedType,
256                @NotNull final BindingTrace trace
257        ) {
258            JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
259                @Override
260                public CompileTimeConstant<?> visitConstantExpression(@NotNull JetConstantExpression expression, Void nothing) {
261                    JetType type = expressionTypingServices.getType(JetScope.EMPTY, expression, expectedType, DataFlowInfo.EMPTY, trace);
262                    if (type == null) {
263                        // TODO:
264                        //  trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(expression));
265                    }
266                    return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
267                }
268    
269    
270                // @Override
271    //            public CompileTimeConstant visitAnnotation(JetAnnotation annotation, Void nothing) {
272    //                super.visitAnnotation(annotation, null); // TODO
273    //            }
274    //
275    //            @Override
276    //            public CompileTimeConstant visitAnnotationEntry(JetAnnotationEntry annotationEntry, Void nothing) {
277    //                return super.visitAnnotationEntry(annotationEntry, null); // TODO
278    //            }
279    
280                @Override
281                public CompileTimeConstant<?> visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void nothing) {
282                    JetExpression innerExpression = expression.getExpression();
283                    if (innerExpression == null) return null;
284                    return innerExpression.accept(this, null);
285                }
286    
287                @Override
288                public CompileTimeConstant<?> visitStringTemplateExpression(
289                        @NotNull JetStringTemplateExpression expression,
290                                                                            Void nothing) {
291                    return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
292                }
293    
294                @Override
295                public CompileTimeConstant<?> visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, Void data) {
296                    ResolvedCall<? extends CallableDescriptor> resolvedCall =
297                            trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
298                    if (resolvedCall != null) {
299                        CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
300                        if (callableDescriptor instanceof PropertyDescriptor) {
301                            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
302                            if (isEnumProperty(propertyDescriptor)) {
303                                return new EnumValue(propertyDescriptor);
304                            }
305                            if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
306                                return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
307                            }
308                        }
309                    }
310                    return null;
311                }
312    
313                @Override
314                public CompileTimeConstant<?> visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
315                    JetExpression selectorExpression = expression.getSelectorExpression();
316                    if (selectorExpression != null) {
317                        return selectorExpression.accept(this, null);
318                    }
319                    return super.visitQualifiedExpression(expression, data);
320                }
321    
322                @Override
323                public CompileTimeConstant<?> visitCallExpression(@NotNull JetCallExpression expression, Void data) {
324                    ResolvedCall<? extends CallableDescriptor> call =
325                            trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
326                    if (call != null) {
327                        CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
328                        if (AnnotationUtils.isArrayMethodCall(call)) {
329                            JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
330                            List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
331                            for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
332                                arguments.addAll(resolveValueArguments(descriptorToArgument, type, trace));
333                            }
334                            return new ArrayValue(arguments, resultingDescriptor.getReturnType());
335                        }
336    
337                        if (resultingDescriptor instanceof ConstructorDescriptor) {
338                            JetType constructorReturnType = resultingDescriptor.getReturnType();
339                            assert constructorReturnType != null : "Constructor should have return type";
340                            if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
341                                AnnotationDescriptorImpl descriptor = new AnnotationDescriptorImpl();
342                                descriptor.setAnnotationType(constructorReturnType);
343                                resolveAnnotationArgument(descriptor, call, trace);
344                                return new AnnotationValue(descriptor);
345                            }
346                        }
347    
348                        if (AnnotationUtils.isJavaClassMethodCall(call)) {
349                            return new JavaClassValue(resultingDescriptor.getReturnType());
350                        }
351                    }
352                    return null;
353                }
354    
355                @Override
356                public CompileTimeConstant<?> visitJetElement(@NotNull JetElement element, Void nothing) {
357                    // TODO:
358                    //trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(element));
359                    return null;
360                }
361            };
362            return expression.accept(visitor, null);
363        }
364    
365        private static boolean isEnumProperty(@NotNull PropertyDescriptor descriptor) {
366            ClassifierDescriptor classifier = descriptor.getType().getConstructor().getDeclarationDescriptor();
367            return classifier != null &&
368                   DescriptorUtils.isEnumClass(classifier) &&
369                   DescriptorUtils.isEnumClassObject(descriptor.getContainingDeclaration());
370        }
371    
372        @NotNull
373        public List<AnnotationDescriptor> getResolvedAnnotations(@Nullable JetModifierList modifierList, BindingTrace trace) {
374            if (modifierList == null) {
375                return Collections.emptyList();
376            }
377            return getResolvedAnnotations(modifierList.getAnnotationEntries(), trace);
378        }
379    
380        @SuppressWarnings("MethodMayBeStatic")
381        @NotNull
382        public List<AnnotationDescriptor> getResolvedAnnotations(List<JetAnnotationEntry> annotations, BindingTrace trace) {
383            List<AnnotationDescriptor> result = Lists.newArrayList();
384            for (JetAnnotationEntry annotation : annotations) {
385                AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
386                if (annotationDescriptor == null) {
387                    throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
388                }
389    
390                result.add(annotationDescriptor);
391            }
392    
393            return result;
394        }
395    
396        public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetModifierListOwner modifierListOwner, BindingTrace trace) {
397            JetModifierList modifierList = modifierListOwner.getModifierList();
398            if (modifierList == null) return;
399    
400            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
401                trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
402            }
403        }
404    }