| /* |
| * Copyright (C) 2016 The Dagger Authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package dagger.internal.codegen.binding; |
| |
| import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults; |
| import static dagger.internal.codegen.binding.SourceFiles.classFileName; |
| import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock; |
| import static java.util.stream.Collectors.toList; |
| |
| import com.google.auto.common.MoreElements; |
| import com.google.auto.common.MoreTypes; |
| import com.google.common.collect.ImmutableList; |
| import com.squareup.javapoet.ClassName; |
| import com.squareup.javapoet.CodeBlock; |
| import com.squareup.javapoet.TypeName; |
| import java.util.List; |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.AnnotationValue; |
| import javax.lang.model.element.TypeElement; |
| import javax.lang.model.element.VariableElement; |
| import javax.lang.model.type.ArrayType; |
| import javax.lang.model.type.DeclaredType; |
| import javax.lang.model.type.TypeMirror; |
| import javax.lang.model.util.SimpleAnnotationValueVisitor6; |
| import javax.lang.model.util.SimpleTypeVisitor6; |
| |
| /** |
| * Returns an expression creating an instance of the visited annotation type. Its parameter must be |
| * a class as generated by {@link dagger.internal.codegen.writing.AnnotationCreatorGenerator}. |
| * |
| * <p>Note that {@link AnnotationValue#toString()} is the source-code representation of the value |
| * <em>when used in an annotation</em>, which is not always the same as the representation needed |
| * when creating the value in a method body. |
| * |
| * <p>For example, inside an annotation, a nested array of {@code int}s is simply {@code {1, 2, 3}}, |
| * but in code it would have to be {@code new int[] {1, 2, 3}}. |
| */ |
| public class AnnotationExpression |
| extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> { |
| |
| private final AnnotationMirror annotation; |
| private final ClassName creatorClass; |
| |
| AnnotationExpression(AnnotationMirror annotation) { |
| this.annotation = annotation; |
| this.creatorClass = |
| getAnnotationCreatorClassName( |
| MoreTypes.asTypeElement(annotation.getAnnotationType())); |
| } |
| |
| /** |
| * Returns an expression that calls static methods on the annotation's creator class to create an |
| * annotation instance equivalent the annotation passed to the constructor. |
| */ |
| CodeBlock getAnnotationInstanceExpression() { |
| return getAnnotationInstanceExpression(annotation); |
| } |
| |
| private CodeBlock getAnnotationInstanceExpression(AnnotationMirror annotation) { |
| return CodeBlock.of( |
| "$T.$L($L)", |
| creatorClass, |
| createMethodName( |
| MoreElements.asType(annotation.getAnnotationType().asElement())), |
| makeParametersCodeBlock( |
| getAnnotationValuesWithDefaults(annotation) |
| .entrySet() |
| .stream() |
| .map(entry -> getValueExpression(entry.getKey().getReturnType(), entry.getValue())) |
| .collect(toList()))); |
| } |
| |
| /** |
| * Returns the name of the generated class that contains the static {@code create} methods for an |
| * annotation type. |
| */ |
| public static ClassName getAnnotationCreatorClassName(TypeElement annotationType) { |
| ClassName annotationTypeName = ClassName.get(annotationType); |
| return annotationTypeName |
| .topLevelClassName() |
| .peerClass(classFileName(annotationTypeName) + "Creator"); |
| } |
| |
| public static String createMethodName(TypeElement annotationType) { |
| return "create" + annotationType.getSimpleName(); |
| } |
| |
| /** |
| * Returns an expression that evaluates to a {@code value} of a given type on an {@code |
| * annotation}. |
| */ |
| CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) { |
| return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value)); |
| } |
| |
| @Override |
| public CodeBlock visitEnumConstant(VariableElement c, AnnotationValue p) { |
| return CodeBlock.of("$T.$L", c.getEnclosingElement(), c.getSimpleName()); |
| } |
| |
| @Override |
| public CodeBlock visitAnnotation(AnnotationMirror a, AnnotationValue p) { |
| return getAnnotationInstanceExpression(a); |
| } |
| |
| @Override |
| public CodeBlock visitType(TypeMirror t, AnnotationValue p) { |
| return CodeBlock.of("$T.class", t); |
| } |
| |
| @Override |
| public CodeBlock visitString(String s, AnnotationValue p) { |
| return CodeBlock.of("$S", s); |
| } |
| |
| @Override |
| public CodeBlock visitByte(byte b, AnnotationValue p) { |
| return CodeBlock.of("(byte) $L", b); |
| } |
| |
| @Override |
| public CodeBlock visitChar(char c, AnnotationValue p) { |
| return CodeBlock.of("$L", p); |
| } |
| |
| @Override |
| public CodeBlock visitDouble(double d, AnnotationValue p) { |
| return CodeBlock.of("$LD", d); |
| } |
| |
| @Override |
| public CodeBlock visitFloat(float f, AnnotationValue p) { |
| return CodeBlock.of("$LF", f); |
| } |
| |
| @Override |
| public CodeBlock visitLong(long i, AnnotationValue p) { |
| return CodeBlock.of("$LL", i); |
| } |
| |
| @Override |
| public CodeBlock visitShort(short s, AnnotationValue p) { |
| return CodeBlock.of("(short) $L", s); |
| } |
| |
| @Override |
| protected CodeBlock defaultAction(Object o, AnnotationValue p) { |
| return CodeBlock.of("$L", o); |
| } |
| |
| @Override |
| public CodeBlock visitArray(List<? extends AnnotationValue> values, AnnotationValue p) { |
| ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder(); |
| for (AnnotationValue value : values) { |
| codeBlocks.add(this.visit(value, p)); |
| } |
| return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build())); |
| } |
| |
| /** |
| * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where |
| * {@code T} is the raw array component type. |
| */ |
| private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX = |
| new SimpleTypeVisitor6<CodeBlock, CodeBlock>() { |
| |
| @Override |
| public CodeBlock visitArray(ArrayType t, CodeBlock p) { |
| return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p); |
| } |
| |
| @Override |
| protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) { |
| return p; |
| } |
| }; |
| |
| /** |
| * If the visited type is an array, returns the name of its raw component type; otherwise returns |
| * the name of the type itself. |
| */ |
| private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME = |
| new SimpleTypeVisitor6<TypeName, Void>() { |
| @Override |
| public TypeName visitDeclared(DeclaredType t, Void p) { |
| return ClassName.get(MoreTypes.asTypeElement(t)); |
| } |
| |
| @Override |
| protected TypeName defaultAction(TypeMirror e, Void p) { |
| return TypeName.get(e); |
| } |
| }; |
| } |