• 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.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