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