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