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        }
174    
175        public void resolveAnnotationsArguments(@NotNull JetScope scope, @Nullable JetModifierList modifierList, @NotNull BindingTrace trace) {
176            if (modifierList == null) {
177                return;
178            }
179    
180            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
181                resolveAnnotationArguments(annotationEntry, scope, trace);
182            }
183        }
184    
185        public void resolveAnnotationsArguments(@NotNull Annotated descriptor, @NotNull BindingTrace trace, @NotNull JetScope scope) {
186            for (AnnotationDescriptor annotationDescriptor : descriptor.getAnnotations()) {
187                JetAnnotationEntry annotationEntry = trace.getBindingContext().get(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotationDescriptor);
188                assert annotationEntry != null : "Cannot find annotation entry: " + annotationDescriptor;
189                resolveAnnotationArguments(annotationEntry, scope, trace);
190            }
191        }
192    
193        private void resolveAnnotationArguments(
194                @NotNull JetAnnotationEntry annotationEntry,
195                @NotNull JetScope scope,
196                @NotNull BindingTrace trace
197        ) {
198            OverloadResolutionResults<FunctionDescriptor> results = resolveAnnotationCall(annotationEntry, scope, trace);
199            if (results.isSingleResult()) {
200                AnnotationDescriptorImpl annotationDescriptor = trace.getBindingContext().get(BindingContext.ANNOTATION, annotationEntry);
201                assert annotationDescriptor != null : "Annotation descriptor should be created before resolving arguments for " + annotationEntry.getText();
202                resolveAnnotationArgument(annotationDescriptor, results.getResultingCall(), trace);
203            }
204        }
205    
206        private void resolveAnnotationArgument(
207                @NotNull AnnotationDescriptorImpl annotationDescriptor,
208                @NotNull ResolvedCall<? extends CallableDescriptor> call,
209                @NotNull BindingTrace trace
210        ) {
211            for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> descriptorToArgument :
212                    call.getValueArguments().entrySet()) {
213                ValueParameterDescriptor parameterDescriptor = descriptorToArgument.getKey();
214    
215                JetType varargElementType = parameterDescriptor.getVarargElementType();
216                List<CompileTimeConstant<?>> constants = resolveValueArguments(descriptorToArgument.getValue(), parameterDescriptor.getType(), trace);
217                if (varargElementType == null) {
218                    for (CompileTimeConstant<?> constant : constants) {
219                        annotationDescriptor.setValueArgument(parameterDescriptor, constant);
220                    }
221                }
222                else {
223                    JetType arrayType = KotlinBuiltIns.getInstance().getPrimitiveArrayJetTypeByPrimitiveJetType(varargElementType);
224                    if (arrayType == null) {
225                        arrayType = KotlinBuiltIns.getInstance().getArrayType(varargElementType);
226                    }
227                    annotationDescriptor.setValueArgument(parameterDescriptor, new ArrayValue(constants, arrayType));
228                }
229            }
230        }
231    
232        @NotNull
233        private List<CompileTimeConstant<?>> resolveValueArguments(
234                @NotNull ResolvedValueArgument resolvedValueArgument,
235                @NotNull JetType expectedType,
236                @NotNull BindingTrace trace
237        ) {
238            List<CompileTimeConstant<?>> constants = Lists.newArrayList();
239            for (ValueArgument argument : resolvedValueArgument.getArguments()) {
240                JetExpression argumentExpression = argument.getArgumentExpression();
241                if (argumentExpression != null) {
242                    CompileTimeConstant<?> constant = resolveExpressionToCompileTimeValue(argumentExpression, expectedType, trace);
243                    if (constant != null) {
244                        constants.add(constant);
245                    }
246                }
247            }
248            return constants;
249        }
250    
251        @Nullable
252        public CompileTimeConstant<?> resolveExpressionToCompileTimeValue(
253                @NotNull JetExpression expression,
254                @NotNull final JetType expectedType,
255                @NotNull final BindingTrace trace
256        ) {
257            JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
258                @Override
259                public CompileTimeConstant<?> visitConstantExpression(@NotNull JetConstantExpression expression, Void nothing) {
260                    JetType type = expressionTypingServices.getType(JetScope.EMPTY, expression, expectedType, DataFlowInfo.EMPTY, trace);
261                    if (type == null) {
262                        // TODO:
263                        //  trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(expression));
264                    }
265                    return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
266                }
267    
268    
269                // @Override
270    //            public CompileTimeConstant visitAnnotation(JetAnnotation annotation, Void nothing) {
271    //                super.visitAnnotation(annotation, null); // TODO
272    //            }
273    //
274    //            @Override
275    //            public CompileTimeConstant visitAnnotationEntry(JetAnnotationEntry annotationEntry, Void nothing) {
276    //                return super.visitAnnotationEntry(annotationEntry, null); // TODO
277    //            }
278    
279                @Override
280                public CompileTimeConstant<?> visitParenthesizedExpression(@NotNull JetParenthesizedExpression expression, Void nothing) {
281                    JetExpression innerExpression = expression.getExpression();
282                    if (innerExpression == null) return null;
283                    return innerExpression.accept(this, null);
284                }
285    
286                @Override
287                public CompileTimeConstant<?> visitStringTemplateExpression(
288                        @NotNull JetStringTemplateExpression expression,
289                                                                            Void nothing) {
290                    return trace.get(BindingContext.COMPILE_TIME_VALUE, expression);
291                }
292    
293                @Override
294                public CompileTimeConstant<?> visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, Void data) {
295                    ResolvedCall<? extends CallableDescriptor> resolvedCall =
296                            trace.getBindingContext().get(BindingContext.RESOLVED_CALL, expression);
297                    if (resolvedCall != null) {
298                        CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
299                        if (callableDescriptor instanceof PropertyDescriptor) {
300                            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) callableDescriptor;
301                            if (isEnumProperty(propertyDescriptor)) {
302                                return new EnumValue(propertyDescriptor);
303                            }
304                            if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) {
305                                return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor);
306                            }
307                        }
308                    }
309                    return null;
310                }
311    
312                @Override
313                public CompileTimeConstant<?> visitQualifiedExpression(@NotNull JetQualifiedExpression expression, Void data) {
314                    JetExpression selectorExpression = expression.getSelectorExpression();
315                    if (selectorExpression != null) {
316                        return selectorExpression.accept(this, null);
317                    }
318                    return super.visitQualifiedExpression(expression, data);
319                }
320    
321                @Override
322                public CompileTimeConstant<?> visitCallExpression(@NotNull JetCallExpression expression, Void data) {
323                    ResolvedCall<? extends CallableDescriptor> call =
324                            trace.getBindingContext().get(BindingContext.RESOLVED_CALL, (expression).getCalleeExpression());
325                    if (call != null) {
326                        CallableDescriptor resultingDescriptor = call.getResultingDescriptor();
327                        if (AnnotationUtils.isArrayMethodCall(call)) {
328                            JetType type = resultingDescriptor.getValueParameters().iterator().next().getVarargElementType();
329                            List<CompileTimeConstant<?>> arguments = Lists.newArrayList();
330                            for (ResolvedValueArgument descriptorToArgument : call.getValueArguments().values()) {
331                                arguments.addAll(resolveValueArguments(descriptorToArgument, type, trace));
332                            }
333                            return new ArrayValue(arguments, resultingDescriptor.getReturnType());
334                        }
335    
336                        if (resultingDescriptor instanceof ConstructorDescriptor) {
337                            JetType constructorReturnType = resultingDescriptor.getReturnType();
338                            assert constructorReturnType != null : "Constructor should have return type";
339                            if (DescriptorUtils.isAnnotationClass(constructorReturnType.getConstructor().getDeclarationDescriptor())) {
340                                AnnotationDescriptorImpl descriptor = new AnnotationDescriptorImpl();
341                                descriptor.setAnnotationType(constructorReturnType);
342                                resolveAnnotationArgument(descriptor, call, trace);
343                                return new AnnotationValue(descriptor);
344                            }
345                        }
346    
347                        if (AnnotationUtils.isJavaClassMethodCall(call)) {
348                            return new JavaClassValue(resultingDescriptor.getReturnType());
349                        }
350                    }
351                    return null;
352                }
353    
354                @Override
355                public CompileTimeConstant<?> visitJetElement(@NotNull JetElement element, Void nothing) {
356                    // TODO:
357                    //trace.report(ANNOTATION_PARAMETER_SHOULD_BE_CONSTANT.on(element));
358                    return null;
359                }
360            };
361            return expression.accept(visitor, null);
362        }
363    
364        private static boolean isEnumProperty(@NotNull PropertyDescriptor descriptor) {
365            ClassifierDescriptor classifier = descriptor.getType().getConstructor().getDeclarationDescriptor();
366            return classifier != null &&
367                   DescriptorUtils.isEnumClass(classifier) &&
368                   DescriptorUtils.isEnumClassObject(descriptor.getContainingDeclaration());
369        }
370    
371        @NotNull
372        public List<AnnotationDescriptor> getResolvedAnnotations(@Nullable JetModifierList modifierList, BindingTrace trace) {
373            if (modifierList == null) {
374                return Collections.emptyList();
375            }
376            return getResolvedAnnotations(modifierList.getAnnotationEntries(), trace);
377        }
378    
379        @SuppressWarnings("MethodMayBeStatic")
380        @NotNull
381        public List<AnnotationDescriptor> getResolvedAnnotations(List<JetAnnotationEntry> annotations, BindingTrace trace) {
382            List<AnnotationDescriptor> result = Lists.newArrayList();
383            for (JetAnnotationEntry annotation : annotations) {
384                AnnotationDescriptor annotationDescriptor = trace.get(BindingContext.ANNOTATION, annotation);
385                if (annotationDescriptor == null) {
386                    throw new IllegalStateException("Annotation for annotation should have been resolved: " + annotation);
387                }
388    
389                result.add(annotationDescriptor);
390            }
391    
392            return result;
393        }
394    
395        public static void reportUnsupportedAnnotationForTypeParameter(@NotNull JetModifierListOwner modifierListOwner, BindingTrace trace) {
396            JetModifierList modifierList = modifierListOwner.getModifierList();
397            if (modifierList == null) return;
398    
399            for (JetAnnotationEntry annotationEntry : modifierList.getAnnotationEntries()) {
400                trace.report(Errors.UNSUPPORTED.on(annotationEntry, "Annotations for type parameters are not supported yet"));
401            }
402        }
403    }