|
26 | 26 | import static javax.lang.model.element.Modifier.PUBLIC;
|
27 | 27 | import static javax.lang.model.element.Modifier.STATIC;
|
28 | 28 |
|
| 29 | +import com.google.auto.common.AnnotationMirrors; |
| 30 | +import com.google.auto.common.AnnotationValues; |
29 | 31 | import com.google.common.collect.ImmutableList;
|
30 | 32 | import com.google.common.collect.ImmutableSet;
|
31 | 33 | import com.google.common.collect.ImmutableSetMultimap;
|
|
43 | 45 | import com.squareup.javapoet.TypeSpec;
|
44 | 46 | import com.squareup.javapoet.TypeVariableName;
|
45 | 47 | import java.io.IOException;
|
| 48 | +import java.lang.annotation.Target; |
46 | 49 | import java.util.Iterator;
|
| 50 | +import java.util.List; |
| 51 | +import java.util.Optional; |
47 | 52 | import java.util.stream.Stream;
|
48 | 53 | import javax.annotation.processing.Filer;
|
49 | 54 | import javax.annotation.processing.ProcessingEnvironment;
|
50 | 55 | import javax.inject.Inject;
|
51 | 56 | import javax.inject.Provider;
|
52 | 57 | import javax.lang.model.SourceVersion;
|
| 58 | +import javax.lang.model.element.AnnotationMirror; |
| 59 | +import javax.lang.model.element.Element; |
| 60 | +import javax.lang.model.element.VariableElement; |
53 | 61 | import javax.lang.model.type.TypeKind;
|
54 | 62 | import javax.lang.model.type.TypeMirror;
|
55 | 63 | import javax.lang.model.type.TypeVariable;
|
@@ -143,7 +151,7 @@ private void addFactoryMethods(
|
143 | 151 | ImmutableSet<TypeVariableName> factoryTypeVariables) {
|
144 | 152 | for (FactoryMethodDescriptor methodDescriptor : descriptor.methodDescriptors()) {
|
145 | 153 | MethodSpec.Builder method =
|
146 |
| - MethodSpec.methodBuilder(methodDescriptor.name()) |
| 154 | + methodBuilder(methodDescriptor.name()) |
147 | 155 | .addTypeVariables(getMethodTypeVariables(methodDescriptor, factoryTypeVariables))
|
148 | 156 | .returns(TypeName.get(methodDescriptor.returnType()))
|
149 | 157 | .varargs(methodDescriptor.isVarArgs());
|
@@ -219,17 +227,45 @@ private void addImplementationMethods(
|
219 | 227 | private ImmutableList<ParameterSpec> parameters(Iterable<Parameter> parameters) {
|
220 | 228 | ImmutableList.Builder<ParameterSpec> builder = ImmutableList.builder();
|
221 | 229 | for (Parameter parameter : parameters) {
|
222 |
| - ParameterSpec.Builder parameterBuilder = |
223 |
| - ParameterSpec.builder(resolveTypeName(parameter.type().get()), parameter.name()); |
224 |
| - Stream.of(parameter.nullable(), parameter.key().qualifier()) |
225 |
| - .flatMap(Streams::stream) |
226 |
| - .map(AnnotationSpec::get) |
227 |
| - .forEach(parameterBuilder::addAnnotation); |
228 |
| - builder.add(parameterBuilder.build()); |
| 230 | + TypeName type = resolveTypeName(parameter.type().get()); |
| 231 | + // Remove TYPE_USE annotations, since resolveTypeName will already have included those in |
| 232 | + // the TypeName it returns. |
| 233 | + List<AnnotationSpec> annotations = |
| 234 | + Stream.of(parameter.nullable(), parameter.key().qualifier()) |
| 235 | + .flatMap(Streams::stream) |
| 236 | + .filter(a -> !isTypeUseAnnotation(a)) |
| 237 | + .map(AnnotationSpec::get) |
| 238 | + .collect(toList()); |
| 239 | + ParameterSpec parameterSpec = |
| 240 | + ParameterSpec.builder(type, parameter.name()) |
| 241 | + .addAnnotations(annotations) |
| 242 | + .build(); |
| 243 | + builder.add(parameterSpec); |
229 | 244 | }
|
230 | 245 | return builder.build();
|
231 | 246 | }
|
232 | 247 |
|
| 248 | + private static boolean isTypeUseAnnotation(AnnotationMirror mirror) { |
| 249 | + Element annotationElement = mirror.getAnnotationType().asElement(); |
| 250 | + // This is basically equivalent to: |
| 251 | + // Target target = annotationElement.getAnnotation(Target.class); |
| 252 | + // return target != null |
| 253 | + // && Arrays.asList(annotationElement.getAnnotation(Target.class)).contains(TYPE_USE); |
| 254 | + // but that might blow up if the annotation is being compiled at the same time and has an |
| 255 | + // undefined identifier in its @Target values. The rigmarole below avoids that problem. |
| 256 | + Optional<AnnotationMirror> maybeTargetMirror = |
| 257 | + Mirrors.getAnnotationMirror(annotationElement, Target.class); |
| 258 | + return maybeTargetMirror |
| 259 | + .map( |
| 260 | + targetMirror -> |
| 261 | + AnnotationValues.getEnums( |
| 262 | + AnnotationMirrors.getAnnotationValue(targetMirror, "value")) |
| 263 | + .stream() |
| 264 | + .map(VariableElement::getSimpleName) |
| 265 | + .anyMatch(name -> name.contentEquals("TYPE_USE"))) |
| 266 | + .orElse(false); |
| 267 | + } |
| 268 | + |
233 | 269 | private static void addCheckNotNullMethod(
|
234 | 270 | TypeSpec.Builder factory, FactoryDescriptor descriptor) {
|
235 | 271 | if (shouldGenerateCheckNotNull(descriptor)) {
|
@@ -284,17 +320,20 @@ private static boolean shouldGenerateCheckNotNull(FactoryDescriptor descriptor)
|
284 | 320 | * {@code @AutoFactory class Foo} has a constructor parameter of type {@code BarFactory} and
|
285 | 321 | * {@code @AutoFactory class Bar} has a constructor parameter of type {@code FooFactory}. We did
|
286 | 322 | * in fact find instances of this in Google's source base.
|
| 323 | + * |
| 324 | + * <p>If the type has type annotations then include those in the returned {@link TypeName}. |
287 | 325 | */
|
288 | 326 | private TypeName resolveTypeName(TypeMirror type) {
|
289 |
| - if (type.getKind() != TypeKind.ERROR) { |
290 |
| - return TypeName.get(type); |
291 |
| - } |
292 |
| - ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString()); |
293 |
| - if (factoryNames.size() == 1) { |
294 |
| - PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames); |
295 |
| - return ClassName.get(packageAndClass.packageName(), packageAndClass.className()); |
| 327 | + TypeName typeName = TypeName.get(type); |
| 328 | + if (type.getKind() == TypeKind.ERROR) { |
| 329 | + ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString()); |
| 330 | + if (factoryNames.size() == 1) { |
| 331 | + PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames); |
| 332 | + typeName = ClassName.get(packageAndClass.packageName(), packageAndClass.className()); |
| 333 | + } |
296 | 334 | }
|
297 |
| - return TypeName.get(type); |
| 335 | + return typeName.annotated( |
| 336 | + type.getAnnotationMirrors().stream().map(AnnotationSpec::get).collect(toList())); |
298 | 337 | }
|
299 | 338 |
|
300 | 339 | private static ImmutableSet<TypeVariableName> getFactoryTypeVariables(
|
|
0 commit comments