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; 18 19 import static com.google.auto.common.AnnotationMirrors.getAnnotationValuesWithDefaults; 20 import static dagger.internal.codegen.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 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 class AnnotationExpression extends SimpleAnnotationValueVisitor6<CodeBlock, AnnotationValue> { 53 54 private final AnnotationMirror annotation; 55 private final ClassName creatorClass; 56 AnnotationExpression(AnnotationMirror annotation)57 AnnotationExpression(AnnotationMirror annotation) { 58 this.annotation = annotation; 59 this.creatorClass = 60 getAnnotationCreatorClassName( 61 MoreTypes.asTypeElement(annotation.getAnnotationType())); 62 } 63 64 /** 65 * Returns an expression that calls static methods on the annotation's creator class to create an 66 * annotation instance equivalent the annotation passed to the constructor. 67 */ getAnnotationInstanceExpression()68 CodeBlock getAnnotationInstanceExpression() { 69 return getAnnotationInstanceExpression(annotation); 70 } 71 getAnnotationInstanceExpression(AnnotationMirror annotation)72 private CodeBlock getAnnotationInstanceExpression(AnnotationMirror annotation) { 73 return CodeBlock.of( 74 "$T.$L($L)", 75 creatorClass, 76 createMethodName( 77 MoreElements.asType(annotation.getAnnotationType().asElement())), 78 makeParametersCodeBlock( 79 getAnnotationValuesWithDefaults(annotation) 80 .entrySet() 81 .stream() 82 .map(entry -> getValueExpression(entry.getKey().getReturnType(), entry.getValue())) 83 .collect(toList()))); 84 } 85 86 /** 87 * Returns the name of the generated class that contains the static {@code create} methods for an 88 * annotation type. 89 */ getAnnotationCreatorClassName(TypeElement annotationType)90 static ClassName getAnnotationCreatorClassName(TypeElement annotationType) { 91 ClassName annotationTypeName = ClassName.get(annotationType); 92 return annotationTypeName 93 .topLevelClassName() 94 .peerClass(classFileName(annotationTypeName) + "Creator"); 95 } 96 createMethodName(TypeElement annotationType)97 static String createMethodName(TypeElement annotationType) { 98 return "create" + annotationType.getSimpleName(); 99 } 100 101 /** 102 * Returns an expression that evaluates to a {@code value} of a given type on an {@code 103 * annotation}. 104 */ getValueExpression(TypeMirror valueType, AnnotationValue value)105 CodeBlock getValueExpression(TypeMirror valueType, AnnotationValue value) { 106 return ARRAY_LITERAL_PREFIX.visit(valueType, this.visit(value, value)); 107 } 108 109 @Override visitEnumConstant(VariableElement c, AnnotationValue p)110 public CodeBlock visitEnumConstant(VariableElement c, AnnotationValue p) { 111 return CodeBlock.of("$T.$L", c.getEnclosingElement(), c.getSimpleName()); 112 } 113 114 @Override visitAnnotation(AnnotationMirror a, AnnotationValue p)115 public CodeBlock visitAnnotation(AnnotationMirror a, AnnotationValue p) { 116 return getAnnotationInstanceExpression(a); 117 } 118 119 @Override visitType(TypeMirror t, AnnotationValue p)120 public CodeBlock visitType(TypeMirror t, AnnotationValue p) { 121 return CodeBlock.of("$T.class", t); 122 } 123 124 @Override visitString(String s, AnnotationValue p)125 public CodeBlock visitString(String s, AnnotationValue p) { 126 return CodeBlock.of("$S", s); 127 } 128 129 @Override visitByte(byte b, AnnotationValue p)130 public CodeBlock visitByte(byte b, AnnotationValue p) { 131 return CodeBlock.of("(byte) $L", b); 132 } 133 134 @Override visitChar(char c, AnnotationValue p)135 public CodeBlock visitChar(char c, AnnotationValue p) { 136 return CodeBlock.of("$L", p); 137 } 138 139 @Override visitDouble(double d, AnnotationValue p)140 public CodeBlock visitDouble(double d, AnnotationValue p) { 141 return CodeBlock.of("$LD", d); 142 } 143 144 @Override visitFloat(float f, AnnotationValue p)145 public CodeBlock visitFloat(float f, AnnotationValue p) { 146 return CodeBlock.of("$LF", f); 147 } 148 149 @Override visitLong(long i, AnnotationValue p)150 public CodeBlock visitLong(long i, AnnotationValue p) { 151 return CodeBlock.of("$LL", i); 152 } 153 154 @Override visitShort(short s, AnnotationValue p)155 public CodeBlock visitShort(short s, AnnotationValue p) { 156 return CodeBlock.of("(short) $L", s); 157 } 158 159 @Override defaultAction(Object o, AnnotationValue p)160 protected CodeBlock defaultAction(Object o, AnnotationValue p) { 161 return CodeBlock.of("$L", o); 162 } 163 164 @Override visitArray(List<? extends AnnotationValue> values, AnnotationValue p)165 public CodeBlock visitArray(List<? extends AnnotationValue> values, AnnotationValue p) { 166 ImmutableList.Builder<CodeBlock> codeBlocks = ImmutableList.builder(); 167 for (AnnotationValue value : values) { 168 codeBlocks.add(this.visit(value, p)); 169 } 170 return CodeBlock.of("{$L}", makeParametersCodeBlock(codeBlocks.build())); 171 } 172 173 /** 174 * If the visited type is an array, prefixes the parameter code block with {@code new T[]}, where 175 * {@code T} is the raw array component type. 176 */ 177 private static final SimpleTypeVisitor6<CodeBlock, CodeBlock> ARRAY_LITERAL_PREFIX = 178 new SimpleTypeVisitor6<CodeBlock, CodeBlock>() { 179 180 @Override 181 public CodeBlock visitArray(ArrayType t, CodeBlock p) { 182 return CodeBlock.of("new $T[] $L", RAW_TYPE_NAME.visit(t.getComponentType()), p); 183 } 184 185 @Override 186 protected CodeBlock defaultAction(TypeMirror e, CodeBlock p) { 187 return p; 188 } 189 }; 190 191 /** 192 * If the visited type is an array, returns the name of its raw component type; otherwise returns 193 * the name of the type itself. 194 */ 195 private static final SimpleTypeVisitor6<TypeName, Void> RAW_TYPE_NAME = 196 new SimpleTypeVisitor6<TypeName, Void>() { 197 @Override 198 public TypeName visitDeclared(DeclaredType t, Void p) { 199 return ClassName.get(MoreTypes.asTypeElement(t)); 200 } 201 202 @Override 203 protected TypeName defaultAction(TypeMirror e, Void p) { 204 return TypeName.get(e); 205 } 206 }; 207 } 208