• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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