1 /* 2 * Copyright (C) 2016 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.internal.codegen.binding; 18 19 import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults; 20 import static dagger.internal.codegen.binding.SourceFiles.classFileName; 21 import static dagger.internal.codegen.javapoet.CodeBlocks.makeParametersCodeBlock; 22 import static java.util.stream.Collectors.toList; 23 24 import com.google.auto.common.MoreElements; 25 import com.google.auto.common.MoreTypes; 26 import com.google.common.collect.ImmutableList; 27 import com.squareup.javapoet.ClassName; 28 import com.squareup.javapoet.CodeBlock; 29 import com.squareup.javapoet.TypeName; 30 import java.util.List; 31 import javax.lang.model.element.AnnotationMirror; 32 import javax.lang.model.element.AnnotationValue; 33 import javax.lang.model.element.TypeElement; 34 import javax.lang.model.element.VariableElement; 35 import javax.lang.model.type.ArrayType; 36 import javax.lang.model.type.DeclaredType; 37 import javax.lang.model.type.TypeMirror; 38 import javax.lang.model.util.SimpleAnnotationValueVisitor6; 39 import javax.lang.model.util.SimpleTypeVisitor6; 40 41 /** 42 * Returns an expression creating an instance of the visited annotation type. Its parameter must be 43 * a class as generated by {@link dagger.internal.codegen.writing.AnnotationCreatorGenerator}. 44 * 45 * <p>Note that {@link AnnotationValue#toString()} is the source-code representation of the value 46 * <em>when used in an annotation</em>, which is not always the same as the representation needed 47 * when creating the value in a method body. 48 * 49 * <p>For example, inside an annotation, a nested array of {@code int}s is simply {@code {1, 2, 3}}, 50 * but in code it would have to be {@code new int[] {1, 2, 3}}. 51 */ 52 public class AnnotationExpression 53 extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> { 54 55 private final AnnotationMirror annotation; 56 private final ClassName creatorClass; 57 AnnotationExpression(AnnotationMirror annotation)58 AnnotationExpression(AnnotationMirror annotation) { 59 this.annotation = annotation; 60 this.creatorClass = 61 getAnnotationCreatorClassName( 62 MoreTypes.asTypeElement(annotation.getAnnotationType())); 63 } 64 65 /** 66 * Returns an expression that calls static methods on the annotation's creator class to create an 67 * annotation instance equivalent the annotation passed to the constructor. 68 */ getAnnotationInstanceExpression()69 CodeBlock getAnnotationInstanceExpression() { 70 return getAnnotationInstanceExpression(annotation); 71 } 72 getAnnotationInstanceExpression(AnnotationMirror annotation)73 private CodeBlock getAnnotationInstanceExpression(AnnotationMirror annotation) { 74 return CodeBlock.of( 75 "$T.$L($L)", 76 creatorClass, 77 createMethodName( 78 MoreElements.asType(annotation.getAnnotationType().asElement())), 79 makeParametersCodeBlock( 80 getAnnotationValuesWithDefaults(annotation) 81 .entrySet() 82 .stream() 83 .map(entry -> getValueExpression(entry.getKey().getReturnType(), entry.getValue())) 84 .collect(toList()))); 85 } 86 87 /** 88 * Returns the name of the generated class that contains the static {@code create} methods for an 89 * annotation type. 90 */ getAnnotationCreatorClassName(TypeElement annotationType)91 public static ClassName getAnnotationCreatorClassName(TypeElement annotationType) { 92 ClassName annotationTypeName = ClassName.get(annotationType); 93 return annotationTypeName 94 .topLevelClassName() 95 .peerClass(classFileName(annotationTypeName) + "Creator"); 96 } 97 createMethodName(TypeElement annotationType)98 public static String createMethodName(TypeElement annotationType) { 99 return "create" + annotationType.getSimpleName(); 100 } 101 102 /** 103 * Returns an expression that evaluates to a {@code value} of a given type on an {@code 104 * annotation}. 105 */ getValueExpression(TypeMirror valueType, AnnotationValue value)106 CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) { 107 return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value)); 108 } 109 110 @Override visitEnumConstant(VariableElement c, AnnotationValue p)111 public CodeBlock visitEnumConstant(VariableElement c, AnnotationValue p) { 112 return CodeBlock.of("$T.$L", c.getEnclosingElement(), c.getSimpleName()); 113 } 114 115 @Override visitAnnotation(AnnotationMirror a, AnnotationValue p)116 public CodeBlock visitAnnotation(AnnotationMirror a, AnnotationValue p) { 117 return getAnnotationInstanceExpression(a); 118 } 119 120 @Override visitType(TypeMirror t, AnnotationValue p)121 public CodeBlock visitType(TypeMirror t, AnnotationValue p) { 122 return CodeBlock.of("$T.class", t); 123 } 124 125 @Override visitString(String s, AnnotationValue p)126 public CodeBlock visitString(String s, AnnotationValue p) { 127 return CodeBlock.of("$S", s); 128 } 129 130 @Override visitByte(byte b, AnnotationValue p)131 public CodeBlock visitByte(byte b, AnnotationValue p) { 132 return CodeBlock.of("(byte) $L", b); 133 } 134 135 @Override visitChar(char c, AnnotationValue p)136 public CodeBlock visitChar(char c, AnnotationValue p) { 137 return CodeBlock.of("$L", p); 138 } 139 140 @Override visitDouble(double d, AnnotationValue p)141 public CodeBlock visitDouble(double d, AnnotationValue p) { 142 return CodeBlock.of("$LD", d); 143 } 144 145 @Override visitFloat(float f, AnnotationValue p)146 public CodeBlock visitFloat(float f, AnnotationValue p) { 147 return CodeBlock.of("$LF", f); 148 } 149 150 @Override visitLong(long i, AnnotationValue p)151 public CodeBlock visitLong(long i, AnnotationValue p) { 152 return CodeBlock.of("$LL", i); 153 } 154 155 @Override visitShort(short s, AnnotationValue p)156 public CodeBlock visitShort(short s, AnnotationValue p) { 157 return CodeBlock.of("(short) $L", s); 158 } 159 160 @Override defaultAction(Object o, AnnotationValue p)161 protected CodeBlock defaultAction(Object o, AnnotationValue p) { 162 return CodeBlock.of("$L", o); 163 } 164 165 @Override visitArray(List<? extends AnnotationValue> values, AnnotationValue p)166 public CodeBlock visitArray(List<? extends AnnotationValue> values, AnnotationValue p) { 167 ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder(); 168 for (AnnotationValue value : values) { 169 codeBlocks.add(this.visit(value, p)); 170 } 171 return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build())); 172 } 173 174 /** 175 * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where 176 * {@code T} is the raw array component type. 177 */ 178 private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX = 179 new SimpleTypeVisitor6<CodeBlock, CodeBlock>() { 180 181 @Override 182 public CodeBlock visitArray(ArrayType t, CodeBlock p) { 183 return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p); 184 } 185 186 @Override 187 protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) { 188 return p; 189 } 190 }; 191 192 /** 193 * If the visited type is an array, returns the name of its raw component type; otherwise returns 194 * the name of the type itself. 195 */ 196 private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME = 197 new SimpleTypeVisitor6<TypeName, Void>() { 198 @Override 199 public TypeName visitDeclared(DeclaredType t, Void p) { 200 return ClassName.get(MoreTypes.asTypeElement(t)); 201 } 202 203 @Override 204 protected TypeName defaultAction(TypeMirror e, Void p) { 205 return TypeName.get(e); 206 } 207 }; 208 } 209