diff options
Diffstat (limited to 'factory/src/main/java/com/google/auto')
19 files changed, 484 insertions, 344 deletions
diff --git a/factory/src/main/java/com/google/auto/factory/AutoFactory.java b/factory/src/main/java/com/google/auto/factory/AutoFactory.java index 2ef84cc3..3b5d90ea 100644 --- a/factory/src/main/java/com/google/auto/factory/AutoFactory.java +++ b/factory/src/main/java/com/google/auto/factory/AutoFactory.java @@ -32,7 +32,7 @@ import java.lang.annotation.Target; * * @author Gregory Kick */ -@Target({ TYPE, CONSTRUCTOR }) +@Target({TYPE, CONSTRUCTOR}) public @interface AutoFactory { /** * The <i>simple</i> name of the generated factory; the factory is always generated in the same @@ -50,7 +50,7 @@ public @interface AutoFactory { /** * A list of interfaces that the generated factory is required to implement. */ - Class<?>[] implementing() default { }; + Class<?>[] implementing() default {}; /** * The type that the generated factory is require to extend. diff --git a/factory/src/main/java/com/google/auto/factory/Provided.java b/factory/src/main/java/com/google/auto/factory/Provided.java index e81e4aa6..226a16f4 100644 --- a/factory/src/main/java/com/google/auto/factory/Provided.java +++ b/factory/src/main/java/com/google/auto/factory/Provided.java @@ -26,4 +26,4 @@ import java.lang.annotation.Target; * @author Gregory Kick */ @Target(PARAMETER) -public @interface Provided { } +public @interface Provided {} diff --git a/factory/src/main/java/com/google/auto/factory/package-info.java b/factory/src/main/java/com/google/auto/factory/package-info.java new file mode 100644 index 00000000..ea1ddd88 --- /dev/null +++ b/factory/src/main/java/com/google/auto/factory/package-info.java @@ -0,0 +1,17 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.auto.factory; + diff --git a/factory/src/main/java/com/google/auto/factory/processor/AnnotationValues.java b/factory/src/main/java/com/google/auto/factory/processor/AnnotationValues.java index b767c47f..53d38a40 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/AnnotationValues.java +++ b/factory/src/main/java/com/google/auto/factory/processor/AnnotationValues.java @@ -32,24 +32,29 @@ final class AnnotationValues { static boolean asBoolean(AnnotationValue value) { return value.accept( new SimpleAnnotationValueVisitor6<Boolean, Void>() { - @Override protected Boolean defaultAction(Object o, Void p) { + @Override + protected Boolean defaultAction(Object o, Void p) { throw new IllegalArgumentException(); } - @Override public Boolean visitBoolean(boolean b, Void p) { + @Override + public Boolean visitBoolean(boolean b, Void p) { return b; } - }, null); + }, + null); } static TypeElement asType(AnnotationValue value) { return value.accept( new SimpleAnnotationValueVisitor6<TypeElement, Void>() { - @Override protected TypeElement defaultAction(Object o, Void p) { + @Override + protected TypeElement defaultAction(Object o, Void p) { throw new IllegalArgumentException(); } - @Override public TypeElement visitType(TypeMirror t, Void p) { + @Override + public TypeElement visitType(TypeMirror t, Void p) { return t.accept( new SimpleTypeVisitor6<TypeElement, Void>() { @Override @@ -59,12 +64,14 @@ final class AnnotationValues { @Override public TypeElement visitDeclared(DeclaredType t, Void p) { - return Iterables.getOnlyElement(ElementFilter.typesIn( - ImmutableList.of(t.asElement()))); + return Iterables.getOnlyElement( + ElementFilter.typesIn(ImmutableList.of(t.asElement()))); } - }, null); + }, + null); } - }, null); + }, + null); } static ImmutableList<? extends AnnotationValue> asList(AnnotationValue value) { @@ -80,6 +87,7 @@ final class AnnotationValues { List<? extends AnnotationValue> vals, Void p) { return ImmutableList.copyOf(vals); } - }, null); + }, + null); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryDeclaration.java b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryDeclaration.java index e2da6eae..889d8e41 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryDeclaration.java +++ b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryDeclaration.java @@ -21,13 +21,13 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.getOnlyElement; +import static java.util.Objects.requireNonNull; import static javax.lang.model.element.ElementKind.PACKAGE; import static javax.lang.model.util.ElementFilter.typesIn; import static javax.tools.Diagnostic.Kind.ERROR; import com.google.auto.factory.AutoFactory; import com.google.auto.value.AutoValue; -import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableList; @@ -36,6 +36,7 @@ import com.google.common.collect.ImmutableSet; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.annotation.processing.Messager; import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; @@ -54,12 +55,19 @@ import javax.lang.model.util.Elements; @AutoValue abstract class AutoFactoryDeclaration { abstract TypeElement targetType(); + abstract Element target(); + abstract Optional<String> className(); + abstract TypeElement extendingType(); + abstract ImmutableSet<TypeElement> implementingTypes(); + abstract boolean allowSubclasses(); + abstract AnnotationMirror mirror(); + abstract ImmutableMap<String, AnnotationValue> valuesMap(); PackageAndClass getFactoryName() { @@ -97,52 +105,70 @@ abstract class AutoFactoryDeclaration { Optional<AutoFactoryDeclaration> createIfValid(Element element) { checkNotNull(element); AnnotationMirror mirror = Mirrors.getAnnotationMirror(element, AutoFactory.class).get(); - checkArgument(Mirrors.getQualifiedName(mirror.getAnnotationType()). - contentEquals(AutoFactory.class.getName())); + checkArgument( + Mirrors.getQualifiedName(mirror.getAnnotationType()) + .contentEquals(AutoFactory.class.getName())); Map<String, AnnotationValue> values = Mirrors.simplifyAnnotationValueMap(elements.getElementValuesWithDefaults(mirror)); checkState(values.size() == 4); - // className value is a string, so we can just call toString - AnnotationValue classNameValue = values.get("className"); + // className value is a string, so we can just call toString. We know values.get("className") + // is non-null because @AutoFactory has an annotation element of that name. + AnnotationValue classNameValue = requireNonNull(values.get("className")); String className = classNameValue.getValue().toString(); if (!className.isEmpty() && !isValidIdentifier(className)) { - messager.printMessage(ERROR, + messager.printMessage( + ERROR, String.format("\"%s\" is not a valid Java identifier", className), - element, mirror, classNameValue); - return Optional.absent(); + element, + mirror, + classNameValue); + return Optional.empty(); } AnnotationValue extendingValue = checkNotNull(values.get("extending")); TypeElement extendingType = AnnotationValues.asType(extendingValue); if (extendingType == null) { - messager.printMessage(ERROR, "Unable to find the type: " - + extendingValue.getValue().toString(), - element, mirror, extendingValue); - return Optional.absent(); + messager.printMessage( + ERROR, + "Unable to find the type: " + extendingValue.getValue(), + element, + mirror, + extendingValue); + return Optional.empty(); } else if (!isValidSupertypeForClass(extendingType)) { - messager.printMessage(ERROR, - String.format("%s is not a valid supertype for a factory. " - + "Supertypes must be non-final classes.", - extendingType.getQualifiedName()), - element, mirror, extendingValue); - return Optional.absent(); + messager.printMessage( + ERROR, + String.format( + "%s is not a valid supertype for a factory. " + + "Supertypes must be non-final classes.", + extendingType.getQualifiedName()), + element, + mirror, + extendingValue); + return Optional.empty(); } ImmutableList<ExecutableElement> noParameterConstructors = FluentIterable.from(ElementFilter.constructorsIn(extendingType.getEnclosedElements())) - .filter(new Predicate<ExecutableElement>() { - @Override public boolean apply(ExecutableElement constructor) { - return constructor.getParameters().isEmpty(); - } - }) + .filter( + new Predicate<ExecutableElement>() { + @Override + public boolean apply(ExecutableElement constructor) { + return constructor.getParameters().isEmpty(); + } + }) .toList(); - if (noParameterConstructors.size() == 0) { - messager.printMessage(ERROR, - String.format("%s is not a valid supertype for a factory. " - + "Factory supertypes must have a no-arg constructor.", - extendingType.getQualifiedName()), - element, mirror, extendingValue); - return Optional.absent(); + if (noParameterConstructors.isEmpty()) { + messager.printMessage( + ERROR, + String.format( + "%s is not a valid supertype for a factory. " + + "Factory supertypes must have a no-arg constructor.", + extendingType.getQualifiedName()), + element, + mirror, + extendingValue); + return Optional.empty(); } else if (noParameterConstructors.size() > 1) { throw new IllegalStateException("Multiple constructors with no parameters??"); } @@ -161,7 +187,7 @@ abstract class AutoFactoryDeclaration { new AutoValue_AutoFactoryDeclaration( getAnnotatedType(element), element, - className.isEmpty() ? Optional.<String>absent() : Optional.of(className), + className.isEmpty() ? Optional.empty() : Optional.of(className), extendingType, implementingTypes, allowSubclasses, diff --git a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java index 5cc1d94d..82349f21 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/AutoFactoryProcessor.java @@ -19,7 +19,6 @@ import com.google.auto.common.MoreTypes; import com.google.auto.factory.AutoFactory; import com.google.auto.factory.Provided; import com.google.auto.service.AutoService; -import com.google.common.base.Optional; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; @@ -30,7 +29,9 @@ import com.google.common.collect.Iterables; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; +import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; @@ -83,8 +84,9 @@ public final class AutoFactoryProcessor extends AbstractProcessor { try { doProcess(roundEnv); } catch (Throwable e) { - messager.printMessage(Kind.ERROR, "Failed to process @AutoFactory annotations:\n" - + Throwables.getStackTraceAsString(e)); + messager.printMessage( + Kind.ERROR, + "Failed to process @AutoFactory annotations:\n" + Throwables.getStackTraceAsString(e)); } return false; } @@ -127,49 +129,58 @@ public final class AutoFactoryProcessor extends AbstractProcessor { simpleNamesToNames(indexedMethods.keySet()); FactoryWriter factoryWriter = new FactoryWriter(processingEnv, factoriesBeingCreated); - indexedMethods.asMap().forEach( - (factoryName, methodDescriptors) -> { - // The sets of classes that are mentioned in the `extending` and `implementing` elements, - // respectively, of the @AutoFactory annotations for this factory. - ImmutableSet.Builder<TypeMirror> extending = newTypeSetBuilder(); - ImmutableSortedSet.Builder<TypeMirror> implementing = newTypeSetBuilder(); - boolean publicType = false; - Boolean allowSubclasses = null; - boolean skipCreation = false; - for (FactoryMethodDescriptor methodDescriptor : methodDescriptors) { - extending.add(methodDescriptor.declaration().extendingType().asType()); - for (TypeElement implementingType : - methodDescriptor.declaration().implementingTypes()) { - implementing.add(implementingType.asType()); - } - publicType |= methodDescriptor.publicMethod(); - if (allowSubclasses == null) { - allowSubclasses = methodDescriptor.declaration().allowSubclasses(); - } else if (!allowSubclasses.equals(methodDescriptor.declaration().allowSubclasses())) { - skipCreation = true; - messager.printMessage(Kind.ERROR, - "Cannot mix allowSubclasses=true and allowSubclasses=false in one factory.", - methodDescriptor.declaration().target(), - methodDescriptor.declaration().mirror(), - methodDescriptor.declaration().valuesMap().get("allowSubclasses")); - } - } - if (!skipCreation) { - try { - factoryWriter.writeFactory( - FactoryDescriptor.create( - factoryName, - Iterables.getOnlyElement(extending.build()), - implementing.build(), - publicType, - ImmutableSet.copyOf(methodDescriptors), - implementationMethodDescriptors.get(factoryName), - allowSubclasses)); - } catch (IOException e) { - messager.printMessage(Kind.ERROR, "failed: " + e); - } - } - }); + indexedMethods + .asMap() + .forEach( + (factoryName, methodDescriptors) -> { + if (methodDescriptors.isEmpty()) { + // This shouldn't happen, but check anyway to avoid an exception for + // methodDescriptors.iterator().next() below. + return; + } + // The sets of classes that are mentioned in the `extending` and `implementing` + // elements, respectively, of the @AutoFactory annotations for this factory. + ImmutableSet.Builder<TypeMirror> extending = newTypeSetBuilder(); + ImmutableSortedSet.Builder<TypeMirror> implementing = newTypeSetBuilder(); + boolean publicType = false; + Set<Boolean> allowSubclassesSet = new HashSet<>(); + boolean skipCreation = false; + for (FactoryMethodDescriptor methodDescriptor : methodDescriptors) { + extending.add(methodDescriptor.declaration().extendingType().asType()); + for (TypeElement implementingType : + methodDescriptor.declaration().implementingTypes()) { + implementing.add(implementingType.asType()); + } + publicType |= methodDescriptor.publicMethod(); + allowSubclassesSet.add(methodDescriptor.declaration().allowSubclasses()); + if (allowSubclassesSet.size() > 1) { + skipCreation = true; + messager.printMessage( + Kind.ERROR, + "Cannot mix allowSubclasses=true and allowSubclasses=false in one factory.", + methodDescriptor.declaration().target(), + methodDescriptor.declaration().mirror(), + methodDescriptor.declaration().valuesMap().get("allowSubclasses")); + } + } + // The set can't be empty because we eliminated methodDescriptors.isEmpty() above. + boolean allowSubclasses = allowSubclassesSet.iterator().next(); + if (!skipCreation) { + try { + factoryWriter.writeFactory( + FactoryDescriptor.create( + factoryName, + Iterables.getOnlyElement(extending.build()), + implementing.build(), + publicType, + ImmutableSet.copyOf(methodDescriptors), + implementationMethodDescriptors.get(factoryName), + allowSubclasses)); + } catch (IOException e) { + messager.printMessage(Kind.ERROR, "failed: " + e); + } + } + }); } private ImmutableSet<ImplementationMethodDescriptor> implementationMethods( @@ -180,8 +191,7 @@ public final class AutoFactoryProcessor extends AbstractProcessor { ElementFilter.methodsIn(elements.getAllMembers(supertype))) { if (implementationMethod.getModifiers().contains(Modifier.ABSTRACT)) { ExecutableType methodType = - Elements2.getExecutableElementAsMemberOf( - types, implementationMethod, supertype); + Elements2.getExecutableElementAsMemberOf(types, implementationMethod, supertype); ImmutableSet<Parameter> passedParameters = Parameter.forParameterList( implementationMethod.getParameters(), methodType.getParameterTypes(), types); @@ -192,6 +202,7 @@ public final class AutoFactoryProcessor extends AbstractProcessor { .publicMethod() .passedParameters(passedParameters) .isVarArgs(implementationMethod.isVarArgs()) + .exceptions(implementationMethod.getThrownTypes()) .build()); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/Elements2.java b/factory/src/main/java/com/google/auto/factory/processor/Elements2.java index 30230f7f..3663f370 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/Elements2.java +++ b/factory/src/main/java/com/google/auto/factory/processor/Elements2.java @@ -22,10 +22,10 @@ import static javax.lang.model.element.ElementKind.PACKAGE; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.STATIC; +import com.google.auto.common.MoreTypes; import com.google.common.collect.ImmutableSet; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; -import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -33,7 +33,7 @@ import javax.lang.model.util.ElementFilter; import javax.lang.model.util.Types; final class Elements2 { - private Elements2() { } + private Elements2() {} static ImmutableSet<ExecutableElement> getConstructors(TypeElement type) { checkNotNull(type); @@ -72,11 +72,11 @@ final class Elements2 { throw new IllegalStateException( "Expected subTypeElement.asType() to return a class/interface type."); } - TypeMirror subExecutableTypeMirror = types.asMemberOf( - (DeclaredType) subTypeMirror, executableElement); + TypeMirror subExecutableTypeMirror = + types.asMemberOf(MoreTypes.asDeclared(subTypeMirror), executableElement); if (!subExecutableTypeMirror.getKind().equals(TypeKind.EXECUTABLE)) { throw new IllegalStateException("Expected subExecutableTypeMirror to be an executable type."); } - return (ExecutableType) subExecutableTypeMirror; + return MoreTypes.asExecutable(subExecutableTypeMirror); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java index 5ed2307a..019295f6 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptor.java @@ -17,16 +17,15 @@ package com.google.auto.factory.processor; import com.google.auto.value.AutoValue; import com.google.common.base.CharMatcher; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import java.util.Collection; +import com.google.common.collect.Streams; import java.util.HashSet; -import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeMirror; @@ -47,20 +46,28 @@ abstract class FactoryDescriptor { }; abstract PackageAndClass name(); + abstract TypeMirror extendingType(); + abstract ImmutableSet<TypeMirror> implementingTypes(); + abstract boolean publicType(); + abstract ImmutableSet<FactoryMethodDescriptor> methodDescriptors(); + abstract ImmutableSet<ImplementationMethodDescriptor> implementationMethodDescriptors(); + abstract boolean allowSubclasses(); + abstract ImmutableMap<Key, ProviderField> providers(); final AutoFactoryDeclaration declaration() { - return Iterables.getFirst(methodDescriptors(), null).declaration(); + // There is always at least one method descriptor. + return methodDescriptors().iterator().next().declaration(); } private static class UniqueNameSet { - private final Set<String> uniqueNames = new HashSet<String>(); + private final Set<String> uniqueNames = new HashSet<>(); /** * Generates a unique name using {@code base}. If {@code base} has not yet been added, it will @@ -92,33 +99,37 @@ abstract class FactoryDescriptor { } ImmutableMap.Builder<Key, ProviderField> providersBuilder = ImmutableMap.builder(); UniqueNameSet uniqueNames = new UniqueNameSet(); - for (Entry<Key, Collection<Parameter>> entry : - parametersForProviders.build().asMap().entrySet()) { - Key key = entry.getKey(); - switch (entry.getValue().size()) { - case 0: - throw new AssertionError(); - case 1: - Parameter parameter = Iterables.getOnlyElement(entry.getValue()); - providersBuilder.put( - key, - ProviderField.create( - uniqueNames.getUniqueName(parameter.name() + "Provider"), - key, - parameter.nullable())); - break; - default: - String providerName = - uniqueNames.getUniqueName( - invalidIdentifierCharacters.replaceFrom(key.toString(), '_') + "Provider"); - Optional<AnnotationMirror> nullable = Optional.absent(); - for (Parameter param : entry.getValue()) { - nullable = nullable.or(param.nullable()); - } - providersBuilder.put(key, ProviderField.create(providerName, key, nullable)); - break; - } - } + parametersForProviders + .build() + .asMap() + .forEach( + (key, parameters) -> { + switch (parameters.size()) { + case 0: + throw new AssertionError(); + case 1: + Parameter parameter = Iterables.getOnlyElement(parameters); + providersBuilder.put( + key, + ProviderField.create( + uniqueNames.getUniqueName(parameter.name() + "Provider"), + key, + parameter.nullable())); + break; + default: + String providerName = + uniqueNames.getUniqueName( + invalidIdentifierCharacters.replaceFrom(key.toString(), '_') + + "Provider"); + Optional<AnnotationMirror> nullable = + parameters.stream() + .map(Parameter::nullable) + .flatMap(Streams::stream) + .findFirst(); + providersBuilder.put(key, ProviderField.create(providerName, key, nullable)); + break; + } + }); ImmutableBiMap<FactoryMethodDescriptor, ImplementationMethodDescriptor> duplicateMethodDescriptors = @@ -129,8 +140,8 @@ abstract class FactoryDescriptor { getDeduplicatedMethodDescriptors(methodDescriptors, duplicateMethodDescriptors); ImmutableSet<ImplementationMethodDescriptor> deduplicatedImplementationMethodDescriptors = - ImmutableSet.copyOf( - Sets.difference(implementationMethodDescriptors, duplicateMethodDescriptors.values())); + Sets.difference(implementationMethodDescriptors, duplicateMethodDescriptors.values()) + .immutableCopy(); return new AutoValue_FactoryDescriptor( name, @@ -191,12 +202,12 @@ abstract class FactoryDescriptor { duplicateMethodDescriptors.get(methodDescriptor); FactoryMethodDescriptor newMethodDescriptor = - (duplicateMethodDescriptor != null) - ? methodDescriptor - .toBuilder() + (duplicateMethodDescriptor != null) + ? methodDescriptor.toBuilder() .overridingMethod(true) .publicMethod(duplicateMethodDescriptor.publicMethod()) .returnType(duplicateMethodDescriptor.returnType()) + .exceptions(duplicateMethodDescriptor.exceptions()) .build() : methodDescriptor; deduplicatedMethodDescriptors.add(newMethodDescriptor); @@ -213,8 +224,7 @@ abstract class FactoryDescriptor { * in the same order. */ private static boolean areDuplicateMethodDescriptors( - FactoryMethodDescriptor factory, - ImplementationMethodDescriptor implementation) { + FactoryMethodDescriptor factory, ImplementationMethodDescriptor implementation) { if (!factory.name().equals(implementation.name())) { return false; diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java index d2331f42..70a21ea2 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryDescriptorGenerator.java @@ -18,6 +18,8 @@ package com.google.auto.factory.processor; import static com.google.auto.common.MoreElements.isAnnotationPresent; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.partitioningBy; import static javax.lang.model.element.Modifier.ABSTRACT; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.tools.Diagnostic.Kind.ERROR; @@ -26,13 +28,11 @@ import com.google.auto.common.MoreElements; import com.google.auto.factory.AutoFactory; import com.google.auto.factory.Provided; import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Optional; -import com.google.common.base.Predicate; import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimaps; +import java.util.List; +import java.util.Map; +import java.util.Optional; import javax.annotation.processing.Messager; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; @@ -54,9 +54,7 @@ final class FactoryDescriptorGenerator { private final AutoFactoryDeclaration.Factory declarationFactory; FactoryDescriptorGenerator( - Messager messager, - Types types, - AutoFactoryDeclaration.Factory declarationFactory) { + Messager messager, Types types, AutoFactoryDeclaration.Factory declarationFactory) { this.messager = messager; this.types = types; this.declarationFactory = declarationFactory; @@ -68,70 +66,75 @@ final class FactoryDescriptorGenerator { if (!declaration.isPresent()) { return ImmutableSet.of(); } - return element.accept(new ElementKindVisitor6<ImmutableSet<FactoryMethodDescriptor>, Void>() { - @Override - protected ImmutableSet<FactoryMethodDescriptor> defaultAction(Element e, Void p) { - throw new AssertionError("@AutoFactory applied to an impossible element"); - } + return element.accept( + new ElementKindVisitor6<ImmutableSet<FactoryMethodDescriptor>, Void>() { + @Override + protected ImmutableSet<FactoryMethodDescriptor> defaultAction(Element e, Void p) { + throw new AssertionError("@AutoFactory applied to an impossible element"); + } - @Override - public ImmutableSet<FactoryMethodDescriptor> visitTypeAsClass(TypeElement type, Void p) { - if (type.getModifiers().contains(ABSTRACT)) { - // applied to an abstract factory - messager.printMessage(ERROR, - "Auto-factory doesn't support being applied to abstract classes.", type, mirror); - return ImmutableSet.of(); - } else { - // applied to the type to be created - ImmutableSet<ExecutableElement> constructors = Elements2.getConstructors(type); - if (constructors.isEmpty()) { - return generateDescriptorForDefaultConstructor(declaration.get(), type); - } else { - return FluentIterable.from(constructors) - .transform(new Function<ExecutableElement, FactoryMethodDescriptor>() { - @Override public FactoryMethodDescriptor apply(ExecutableElement constructor) { - return generateDescriptorForConstructor(declaration.get(), constructor); - } - }) - .toSet(); + @Override + public ImmutableSet<FactoryMethodDescriptor> visitTypeAsClass(TypeElement type, Void p) { + if (type.getModifiers().contains(ABSTRACT)) { + // applied to an abstract factory + messager.printMessage( + ERROR, + "Auto-factory doesn't support being applied to abstract classes.", + type, + mirror); + return ImmutableSet.of(); + } else { + // applied to the type to be created + ImmutableSet<ExecutableElement> constructors = Elements2.getConstructors(type); + if (constructors.isEmpty()) { + return generateDescriptorForDefaultConstructor(declaration.get(), type); + } else { + return FluentIterable.from(constructors) + .transform( + new Function<ExecutableElement, FactoryMethodDescriptor>() { + @Override + public FactoryMethodDescriptor apply(ExecutableElement constructor) { + return generateDescriptorForConstructor(declaration.get(), constructor); + } + }) + .toSet(); + } + } } - } - } - @Override - public ImmutableSet<FactoryMethodDescriptor> visitTypeAsInterface(TypeElement type, Void p) { - // applied to the factory interface - messager.printMessage(ERROR, - "Auto-factory doesn't support being applied to interfaces.", type, mirror); - return ImmutableSet.of(); - } + @Override + public ImmutableSet<FactoryMethodDescriptor> visitTypeAsInterface( + TypeElement type, Void p) { + // applied to the factory interface + messager.printMessage( + ERROR, "Auto-factory doesn't support being applied to interfaces.", type, mirror); + return ImmutableSet.of(); + } - @Override - public ImmutableSet<FactoryMethodDescriptor> visitExecutableAsConstructor(ExecutableElement e, - Void p) { - // applied to a constructor of a type to be created - return ImmutableSet.of(generateDescriptorForConstructor(declaration.get(), e)); - } - }, null); + @Override + public ImmutableSet<FactoryMethodDescriptor> visitExecutableAsConstructor( + ExecutableElement e, Void p) { + // applied to a constructor of a type to be created + return ImmutableSet.of(generateDescriptorForConstructor(declaration.get(), e)); + } + }, + null); } - FactoryMethodDescriptor generateDescriptorForConstructor(final AutoFactoryDeclaration declaration, - ExecutableElement constructor) { + FactoryMethodDescriptor generateDescriptorForConstructor( + final AutoFactoryDeclaration declaration, ExecutableElement constructor) { checkNotNull(constructor); checkArgument(constructor.getKind() == ElementKind.CONSTRUCTOR); TypeElement classElement = MoreElements.asType(constructor.getEnclosingElement()); - ImmutableListMultimap<Boolean, ? extends VariableElement> parameterMap = - Multimaps.index(constructor.getParameters(), Functions.forPredicate( - new Predicate<VariableElement>() { - @Override - public boolean apply(VariableElement parameter) { - return isAnnotationPresent(parameter, Provided.class); - } - })); + Map<Boolean, List<VariableElement>> parameterMap = + constructor.getParameters().stream() + .collect(partitioningBy(parameter -> isAnnotationPresent(parameter, Provided.class))); + // The map returned by partitioningBy always has entries for both key values but our + // null-checker isn't yet smart enough to know that. ImmutableSet<Parameter> providedParameters = - Parameter.forParameterList(parameterMap.get(true), types); + Parameter.forParameterList(requireNonNull(parameterMap.get(true)), types); ImmutableSet<Parameter> passedParameters = - Parameter.forParameterList(parameterMap.get(false), types); + Parameter.forParameterList(requireNonNull(parameterMap.get(false)), types); return FactoryMethodDescriptor.builder(declaration) .name("create") .returnType(classElement.asType()) @@ -140,6 +143,8 @@ final class FactoryDescriptorGenerator { .passedParameters(passedParameters) .creationParameters(Parameter.forParameterList(constructor.getParameters(), types)) .isVarArgs(constructor.isVarArgs()) + .exceptions(constructor.getThrownTypes()) + .overridingMethod(false) .build(); } @@ -150,9 +155,12 @@ final class FactoryDescriptorGenerator { .name("create") .returnType(type.asType()) .publicMethod(type.getModifiers().contains(PUBLIC)) - .passedParameters(ImmutableSet.<Parameter>of()) - .creationParameters(ImmutableSet.<Parameter>of()) - .providedParameters(ImmutableSet.<Parameter>of()) + .providedParameters(ImmutableSet.of()) + .passedParameters(ImmutableSet.of()) + .creationParameters(ImmutableSet.of()) + .isVarArgs(false) + .exceptions(ImmutableSet.of()) + .overridingMethod(false) .build()); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java index 43e5097d..45259573 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryMethodDescriptor.java @@ -31,45 +31,65 @@ import javax.lang.model.type.TypeMirror; @AutoValue abstract class FactoryMethodDescriptor { abstract AutoFactoryDeclaration declaration(); + abstract String name(); + abstract TypeMirror returnType(); + abstract boolean publicMethod(); + abstract boolean overridingMethod(); + abstract ImmutableSet<Parameter> passedParameters(); + abstract ImmutableSet<Parameter> providedParameters(); + abstract ImmutableSet<Parameter> creationParameters(); - abstract Builder toBuilder(); + abstract boolean isVarArgs(); + abstract ImmutableSet<TypeMirror> exceptions(); + + abstract Builder toBuilder(); + final PackageAndClass factoryName() { return declaration().getFactoryName(); } static Builder builder(AutoFactoryDeclaration declaration) { - return new AutoValue_FactoryMethodDescriptor.Builder() - .declaration(checkNotNull(declaration)) - .publicMethod(false) - .overridingMethod(false) - .isVarArgs(false); + return new AutoValue_FactoryMethodDescriptor.Builder().declaration(checkNotNull(declaration)); } @AutoValue.Builder abstract static class Builder { abstract Builder declaration(AutoFactoryDeclaration declaration); + abstract Builder name(String name); + abstract Builder returnType(TypeMirror returnType); + abstract Builder publicMethod(boolean publicMethod); + abstract Builder overridingMethod(boolean overridingMethod); + abstract Builder passedParameters(Iterable<Parameter> passedParameters); + abstract Builder providedParameters(Iterable<Parameter> providedParameters); + abstract Builder creationParameters(Iterable<Parameter> creationParameters); + abstract Builder isVarArgs(boolean isVarargs); + + abstract Builder exceptions(Iterable<? extends TypeMirror> exceptions); + abstract FactoryMethodDescriptor buildImpl(); FactoryMethodDescriptor build() { FactoryMethodDescriptor descriptor = buildImpl(); - checkState(descriptor.creationParameters().equals( - Sets.union(descriptor.passedParameters(), descriptor.providedParameters()))); + checkState( + descriptor + .creationParameters() + .equals(Sets.union(descriptor.passedParameters(), descriptor.providedParameters()))); return descriptor; } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java index 53b99cb5..b7f9c3e4 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java +++ b/factory/src/main/java/com/google/auto/factory/processor/FactoryWriter.java @@ -19,19 +19,22 @@ import static com.google.auto.common.GeneratedAnnotationSpecs.generatedAnnotatio import static com.squareup.javapoet.MethodSpec.constructorBuilder; import static com.squareup.javapoet.MethodSpec.methodBuilder; import static com.squareup.javapoet.TypeSpec.classBuilder; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; import static javax.lang.model.element.Modifier.FINAL; import static javax.lang.model.element.Modifier.PRIVATE; import static javax.lang.model.element.Modifier.PUBLIC; import static javax.lang.model.element.Modifier.STATIC; -import com.google.common.base.Function; -import com.google.common.base.Joiner; -import com.google.common.collect.FluentIterable; +import com.google.auto.common.AnnotationMirrors; +import com.google.auto.common.AnnotationValues; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +import com.google.common.collect.Streams; import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; @@ -43,13 +46,19 @@ import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeVariableName; import java.io.IOException; +import java.lang.annotation.Target; import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; import javax.annotation.processing.Filer; import javax.annotation.processing.ProcessingEnvironment; import javax.inject.Inject; import javax.inject.Provider; import javax.lang.model.SourceVersion; import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; @@ -71,14 +80,10 @@ final class FactoryWriter { this.factoriesBeingCreated = factoriesBeingCreated; } - private static final Joiner ARGUMENT_JOINER = Joiner.on(", "); - - void writeFactory(FactoryDescriptor descriptor) - throws IOException { + void writeFactory(FactoryDescriptor descriptor) throws IOException { String factoryName = descriptor.name().className(); TypeSpec.Builder factory = - classBuilder(factoryName) - .addOriginatingElement(descriptor.declaration().targetType()); + classBuilder(factoryName).addOriginatingElement(descriptor.declaration().targetType()); generatedAnnotationSpec( elements, sourceVersion, @@ -145,7 +150,7 @@ final class FactoryWriter { ImmutableSet<TypeVariableName> factoryTypeVariables) { for (FactoryMethodDescriptor methodDescriptor : descriptor.methodDescriptors()) { MethodSpec.Builder method = - MethodSpec.methodBuilder(methodDescriptor.name()) + methodBuilder(methodDescriptor.name()) .addTypeVariables(getMethodTypeVariables(methodDescriptor, factoryTypeVariables)) .returns(TypeName.get(methodDescriptor.returnType())) .varargs(methodDescriptor.isVarArgs()); @@ -155,6 +160,8 @@ final class FactoryWriter { if (methodDescriptor.publicMethod()) { method.addModifiers(PUBLIC); } + method.addExceptions( + methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList())); CodeBlock.Builder args = CodeBlock.builder(); method.addParameters(parameters(methodDescriptor.passedParameters())); Iterator<Parameter> parameters = methodDescriptor.creationParameters().iterator(); @@ -168,7 +175,7 @@ final class FactoryWriter { checkNotNull = false; } } else { - ProviderField provider = descriptor.providers().get(parameter.key()); + ProviderField provider = requireNonNull(descriptor.providers().get(parameter.key())); argument = CodeBlock.of(provider.name()); if (parameter.isProvider()) { // Providers are checked for nullness in the Factory's constructor. @@ -190,8 +197,7 @@ final class FactoryWriter { } } - private void addImplementationMethods( - TypeSpec.Builder factory, FactoryDescriptor descriptor) { + private void addImplementationMethods(TypeSpec.Builder factory, FactoryDescriptor descriptor) { for (ImplementationMethodDescriptor methodDescriptor : descriptor.implementationMethodDescriptors()) { MethodSpec.Builder implementationMethod = @@ -202,18 +208,12 @@ final class FactoryWriter { if (methodDescriptor.publicMethod()) { implementationMethod.addModifiers(PUBLIC); } + implementationMethod.addExceptions( + methodDescriptor.exceptions().stream().map(TypeName::get).collect(toList())); implementationMethod.addParameters(parameters(methodDescriptor.passedParameters())); implementationMethod.addStatement( "return create($L)", - FluentIterable.from(methodDescriptor.passedParameters()) - .transform( - new Function<Parameter, String>() { - @Override - public String apply(Parameter parameter) { - return parameter.name(); - } - }) - .join(ARGUMENT_JOINER)); + methodDescriptor.passedParameters().stream().map(Parameter::name).collect(joining(", "))); factory.addMethod(implementationMethod.build()); } } @@ -225,17 +225,43 @@ final class FactoryWriter { private ImmutableList<ParameterSpec> parameters(Iterable<Parameter> parameters) { ImmutableList.Builder<ParameterSpec> builder = ImmutableList.builder(); for (Parameter parameter : parameters) { - ParameterSpec.Builder parameterBuilder = - ParameterSpec.builder(resolveTypeName(parameter.type().get()), parameter.name()); - for (AnnotationMirror annotation : - Iterables.concat(parameter.nullable().asSet(), parameter.key().qualifier().asSet())) { - parameterBuilder.addAnnotation(AnnotationSpec.get(annotation)); - } - builder.add(parameterBuilder.build()); + TypeName type = resolveTypeName(parameter.type().get()); + // Remove TYPE_USE annotations, since resolveTypeName will already have included those in + // the TypeName it returns. + List<AnnotationSpec> annotations = + Stream.of(parameter.nullable(), parameter.key().qualifier()) + .flatMap(Streams::stream) + .filter(a -> !isTypeUseAnnotation(a)) + .map(AnnotationSpec::get) + .collect(toList()); + ParameterSpec parameterSpec = + ParameterSpec.builder(type, parameter.name()).addAnnotations(annotations).build(); + builder.add(parameterSpec); } return builder.build(); } + private static boolean isTypeUseAnnotation(AnnotationMirror mirror) { + Element annotationElement = mirror.getAnnotationType().asElement(); + // This is basically equivalent to: + // Target target = annotationElement.getAnnotation(Target.class); + // return target != null + // && Arrays.asList(annotationElement.getAnnotation(Target.class)).contains(TYPE_USE); + // but that might blow up if the annotation is being compiled at the same time and has an + // undefined identifier in its @Target values. The rigmarole below avoids that problem. + Optional<AnnotationMirror> maybeTargetMirror = + Mirrors.getAnnotationMirror(annotationElement, Target.class); + return maybeTargetMirror + .map( + targetMirror -> + AnnotationValues.getEnums( + AnnotationMirrors.getAnnotationValue(targetMirror, "value")) + .stream() + .map(VariableElement::getSimpleName) + .anyMatch(name -> name.contentEquals("TYPE_USE"))) + .orElse(false); + } + private static void addCheckNotNullMethod( TypeSpec.Builder factory, FactoryDescriptor descriptor) { if (shouldGenerateCheckNotNull(descriptor)) { @@ -290,17 +316,20 @@ final class FactoryWriter { * {@code @AutoFactory class Foo} has a constructor parameter of type {@code BarFactory} and * {@code @AutoFactory class Bar} has a constructor parameter of type {@code FooFactory}. We did * in fact find instances of this in Google's source base. + * + * <p>If the type has type annotations then include those in the returned {@link TypeName}. */ private TypeName resolveTypeName(TypeMirror type) { - if (type.getKind() != TypeKind.ERROR) { - return TypeName.get(type); - } - ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString()); - if (factoryNames.size() == 1) { - PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames); - return ClassName.get(packageAndClass.packageName(), packageAndClass.className()); + TypeName typeName = TypeName.get(type); + if (type.getKind() == TypeKind.ERROR) { + ImmutableSet<PackageAndClass> factoryNames = factoriesBeingCreated.get(type.toString()); + if (factoryNames.size() == 1) { + PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames); + typeName = ClassName.get(packageAndClass.packageName(), packageAndClass.className()); + } } - return TypeName.get(type); + return typeName.annotated( + type.getAnnotationMirrors().stream().map(AnnotationSpec::get).collect(toList())); } private static ImmutableSet<TypeVariableName> getFactoryTypeVariables( diff --git a/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java b/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java index 9ddc249f..b2705b7e 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java +++ b/factory/src/main/java/com/google/auto/factory/processor/ImplementationMethodDescriptor.java @@ -22,21 +22,25 @@ import javax.lang.model.type.TypeMirror; @AutoValue abstract class ImplementationMethodDescriptor { abstract String name(); + abstract TypeMirror returnType(); + abstract boolean publicMethod(); + abstract ImmutableSet<Parameter> passedParameters(); + abstract boolean isVarArgs(); + abstract ImmutableSet<TypeMirror> exceptions(); + static Builder builder() { - return new AutoValue_ImplementationMethodDescriptor.Builder() - .publicMethod(true) - .isVarArgs(false); + return new AutoValue_ImplementationMethodDescriptor.Builder(); } @AutoValue.Builder - static abstract class Builder { + abstract static class Builder { abstract Builder name(String name); - + abstract Builder returnType(TypeMirror returnTypeElement); abstract Builder publicMethod(boolean publicMethod); @@ -49,6 +53,8 @@ abstract class ImplementationMethodDescriptor { abstract Builder isVarArgs(boolean isVarargs); + abstract Builder exceptions(Iterable<? extends TypeMirror> exceptions); + abstract ImplementationMethodDescriptor build(); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/Key.java b/factory/src/main/java/com/google/auto/factory/processor/Key.java index 04bd4f37..728149eb 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/Key.java +++ b/factory/src/main/java/com/google/auto/factory/processor/Key.java @@ -24,9 +24,8 @@ import com.google.auto.common.AnnotationMirrors; import com.google.auto.common.MoreTypes; import com.google.auto.value.AutoValue; import com.google.common.base.Equivalence; -import com.google.common.base.Optional; -import com.google.common.collect.FluentIterable; -import com.google.common.collect.ImmutableSet; +import java.util.Collection; +import java.util.Optional; import javax.inject.Qualifier; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.type.TypeMirror; @@ -65,17 +64,15 @@ abstract class Key { * <tr><td>{@code int} <td>{@code Integer} * </table> */ - static Key create( - TypeMirror type, Iterable<? extends AnnotationMirror> annotations, Types types) { - ImmutableSet.Builder<AnnotationMirror> qualifiers = ImmutableSet.builder(); - for (AnnotationMirror annotation : annotations) { - if (isAnnotationPresent(annotation.getAnnotationType().asElement(), Qualifier.class)) { - qualifiers.add(annotation); - } - } - + static Key create(TypeMirror type, Collection<AnnotationMirror> annotations, Types types) { // TODO(gak): check for only one qualifier rather than using the first - Optional<AnnotationMirror> qualifier = FluentIterable.from(qualifiers.build()).first(); + Optional<AnnotationMirror> qualifier = + annotations.stream() + .filter( + annotation -> + isAnnotationPresent( + annotation.getAnnotationType().asElement(), Qualifier.class)) + .findFirst(); TypeMirror keyType = isProvider(type) @@ -97,7 +94,7 @@ abstract class Key { } @Override - public String toString() { + public final String toString() { String typeQualifiedName = MoreTypes.asTypeElement(type().get()).toString(); return qualifier().isPresent() ? qualifier().get() + "/" + typeQualifiedName diff --git a/factory/src/main/java/com/google/auto/factory/processor/Mirrors.java b/factory/src/main/java/com/google/auto/factory/processor/Mirrors.java index c5b7d8bf..313fc9ee 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/Mirrors.java +++ b/factory/src/main/java/com/google/auto/factory/processor/Mirrors.java @@ -17,11 +17,11 @@ package com.google.auto.factory.processor; import com.google.auto.common.MoreTypes; import com.google.common.base.Equivalence; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import java.lang.annotation.Annotation; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import javax.inject.Provider; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; @@ -34,20 +34,23 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor6; final class Mirrors { - private Mirrors() { } + private Mirrors() {} static Name getQualifiedName(DeclaredType type) { - return type.asElement().accept(new SimpleElementVisitor6<Name, Void>() { - @Override - protected Name defaultAction(Element e, Void p) { - throw new AssertionError("DeclaredTypes should be TypeElements"); - } + return type.asElement() + .accept( + new SimpleElementVisitor6<Name, Void>() { + @Override + protected Name defaultAction(Element e, Void p) { + throw new AssertionError("DeclaredTypes should be TypeElements"); + } - @Override - public Name visitType(TypeElement e, Void p) { - return e.getQualifiedName(); - } - }, null); + @Override + public Name visitType(TypeElement e, Void p) { + return e.getQualifiedName(); + } + }, + null); } /** {@code true} if {@code type} is a {@link Provider}. */ @@ -62,8 +65,8 @@ final class Mirrors { static ImmutableMap<String, AnnotationValue> simplifyAnnotationValueMap( Map<? extends ExecutableElement, ? extends AnnotationValue> annotationValueMap) { ImmutableMap.Builder<String, AnnotationValue> builder = ImmutableMap.builder(); - for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry - : annotationValueMap.entrySet()) { + for (Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : + annotationValueMap.entrySet()) { builder.put(entry.getKey().getSimpleName().toString(), entry.getValue()); } return builder.build(); @@ -73,15 +76,13 @@ final class Mirrors { * Get the {@link AnnotationMirror} for the type {@code annotationType} present on the given * {@link Element} if it exists. */ - static Optional<AnnotationMirror> getAnnotationMirror(Element element, - Class<? extends Annotation> annotationType) { + static Optional<AnnotationMirror> getAnnotationMirror( + Element element, Class<? extends Annotation> annotationType) { String annotationName = annotationType.getName(); - for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) { - if (getQualifiedName(annotationMirror.getAnnotationType()).contentEquals(annotationName)) { - return Optional.of(annotationMirror); - } - } - return Optional.absent(); + return element.getAnnotationMirrors().stream() + .filter(a -> getQualifiedName(a.getAnnotationType()).contentEquals(annotationName)) + .<AnnotationMirror>map(x -> x) // get rid of wildcard <? extends AnnotationMirror> + .findFirst(); } /** @@ -91,9 +92,7 @@ final class Mirrors { // TODO(ronshapiro): this is used in AutoFactory and Dagger, consider moving it into auto-common. static <T> Optional<Equivalence.Wrapper<T>> wrapOptionalInEquivalence( Equivalence<T> equivalence, Optional<T> optional) { - return optional.isPresent() - ? Optional.of(equivalence.wrap(optional.get())) - : Optional.<Equivalence.Wrapper<T>>absent(); + return optional.map(equivalence::wrap); } /** @@ -102,8 +101,6 @@ final class Mirrors { */ static <T> Optional<T> unwrapOptionalEquivalence( Optional<Equivalence.Wrapper<T>> wrappedOptional) { - return wrappedOptional.isPresent() - ? Optional.of(wrappedOptional.get().get()) - : Optional.<T>absent(); + return wrappedOptional.map(Equivalence.Wrapper::get); } } diff --git a/factory/src/main/java/com/google/auto/factory/processor/Parameter.java b/factory/src/main/java/com/google/auto/factory/processor/Parameter.java index 781225a2..c5059ece 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/Parameter.java +++ b/factory/src/main/java/com/google/auto/factory/processor/Parameter.java @@ -18,19 +18,20 @@ package com.google.auto.factory.processor; import static com.google.auto.factory.processor.Mirrors.unwrapOptionalEquivalence; import static com.google.auto.factory.processor.Mirrors.wrapOptionalInEquivalence; import static com.google.common.base.Preconditions.checkArgument; +import static java.util.stream.Collectors.toList; import com.google.auto.common.AnnotationMirrors; import com.google.auto.common.MoreElements; import com.google.auto.common.MoreTypes; import com.google.auto.value.AutoValue; import com.google.common.base.Equivalence; -import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import java.util.List; +import java.util.Optional; import java.util.Set; +import java.util.stream.Stream; import javax.inject.Provider; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.TypeElement; @@ -63,6 +64,7 @@ abstract class Parameter { abstract String name(); abstract Key key(); + abstract Optional<Equivalence.Wrapper<AnnotationMirror>> nullableWrapper(); Optional<AnnotationMirror> nullable() { @@ -71,15 +73,12 @@ abstract class Parameter { private static Parameter forVariableElement( VariableElement variable, TypeMirror type, Types types) { - Optional<AnnotationMirror> nullable = Optional.absent(); - Iterable<? extends AnnotationMirror> annotations = - Iterables.concat(variable.getAnnotationMirrors(), type.getAnnotationMirrors()); - for (AnnotationMirror annotation : annotations) { - if (isNullable(annotation)) { - nullable = Optional.of(annotation); - break; - } - } + List<AnnotationMirror> annotations = + Stream.of(variable.getAnnotationMirrors(), type.getAnnotationMirrors()) + .flatMap(List::stream) + .collect(toList()); + Optional<AnnotationMirror> nullable = + annotations.stream().filter(Parameter::isNullable).findFirst(); Key key = Key.create(type, annotations, types); return new AutoValue_Parameter( @@ -108,7 +107,7 @@ abstract class Parameter { Set<String> names = Sets.newHashSetWithExpectedSize(variables.size()); for (int i = 0; i < variables.size(); i++) { Parameter parameter = forVariableElement(variables.get(i), variableTypes.get(i), types); - checkArgument(names.add(parameter.name())); + checkArgument(names.add(parameter.name()), "Duplicate parameter name: %s", parameter.name()); builder.add(parameter); } ImmutableSet<Parameter> parameters = builder.build(); diff --git a/factory/src/main/java/com/google/auto/factory/processor/ProvidedChecker.java b/factory/src/main/java/com/google/auto/factory/processor/ProvidedChecker.java index fe4c1fd2..bd88f837 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/ProvidedChecker.java +++ b/factory/src/main/java/com/google/auto/factory/processor/ProvidedChecker.java @@ -26,6 +26,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.VariableElement; import javax.lang.model.util.ElementKindVisitor6; +import org.checkerframework.checker.nullness.qual.Nullable; final class ProvidedChecker { private final Messager messager; @@ -35,41 +36,54 @@ final class ProvidedChecker { } void checkProvidedParameter(Element element) { - checkArgument(isAnnotationPresent(element, Provided.class), "%s not annoated with @Provided", - element); - element.accept(new ElementKindVisitor6<Void, Void>() { - @Override - protected Void defaultAction(Element e, Void p) { - throw new AssertionError("Provided can only be applied to parameters"); - } - - @Override - public Void visitVariableAsParameter(final VariableElement providedParameter, Void p) { - providedParameter.getEnclosingElement().accept(new ElementKindVisitor6<Void, Void>() { + checkArgument( + isAnnotationPresent(element, Provided.class), "%s not annoated with @Provided", element); + element.accept( + new ElementKindVisitor6<@Nullable Void, @Nullable Void>() { @Override - protected Void defaultAction(Element e, Void p) { - raiseError(providedParameter, "@%s may only be applied to constructor parameters"); - return null; + protected @Nullable Void defaultAction(Element e, @Nullable Void p) { + throw new AssertionError("Provided can only be applied to parameters"); } @Override - public Void visitExecutableAsConstructor(ExecutableElement constructor, Void p) { - if (!(annotatedWithAutoFactory(constructor) - || annotatedWithAutoFactory(constructor.getEnclosingElement()))) { - raiseError(providedParameter, - "@%s may only be applied to constructors requesting an auto-factory"); - } + public @Nullable Void visitVariableAsParameter( + VariableElement providedParameter, @Nullable Void p) { + providedParameter + .getEnclosingElement() + .accept( + new ElementKindVisitor6<@Nullable Void, @Nullable Void>() { + @Override + protected @Nullable Void defaultAction(Element e, @Nullable Void p) { + raiseError( + providedParameter, "@%s may only be applied to constructor parameters"); + return null; + } + + @Override + public @Nullable Void visitExecutableAsConstructor( + ExecutableElement constructor, @Nullable Void p) { + if (!(annotatedWithAutoFactory(constructor) + || annotatedWithAutoFactory(constructor.getEnclosingElement()))) { + raiseError( + providedParameter, + "@%s may only be applied to constructors requesting an auto-factory"); + } + return null; + } + }, + p); return null; } - }, p); - return null; - } - }, null); + }, + null); } private void raiseError(VariableElement providedParameter, String messageFormat) { - messager.printMessage(ERROR, String.format(messageFormat, Provided.class.getSimpleName()), - providedParameter, Mirrors.getAnnotationMirror(providedParameter, Provided.class).get()); + messager.printMessage( + ERROR, + String.format(messageFormat, Provided.class.getSimpleName()), + providedParameter, + Mirrors.getAnnotationMirror(providedParameter, Provided.class).get()); } private static boolean annotatedWithAutoFactory(Element e) { diff --git a/factory/src/main/java/com/google/auto/factory/processor/ProviderField.java b/factory/src/main/java/com/google/auto/factory/processor/ProviderField.java index 855c1feb..99847ec0 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/ProviderField.java +++ b/factory/src/main/java/com/google/auto/factory/processor/ProviderField.java @@ -21,13 +21,15 @@ import static com.google.auto.factory.processor.Mirrors.wrapOptionalInEquivalenc import com.google.auto.common.AnnotationMirrors; import com.google.auto.value.AutoValue; import com.google.common.base.Equivalence; -import com.google.common.base.Optional; +import java.util.Optional; import javax.lang.model.element.AnnotationMirror; @AutoValue abstract class ProviderField { abstract String name(); + abstract Key key(); + abstract Optional<Equivalence.Wrapper<AnnotationMirror>> nullableWrapper(); Optional<AnnotationMirror> nullable() { diff --git a/factory/src/main/java/com/google/auto/factory/processor/TypeVariables.java b/factory/src/main/java/com/google/auto/factory/processor/TypeVariables.java index 1f894732..4bd546e8 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/TypeVariables.java +++ b/factory/src/main/java/com/google/auto/factory/processor/TypeVariables.java @@ -38,8 +38,8 @@ final class TypeVariables { return type.accept(ReferencedTypeVariables.INSTANCE, new HashSet<>()); } - private static final class ReferencedTypeVariables extends - SimpleTypeVisitor8<ImmutableSet<TypeVariable>, Set<Element>> { + private static final class ReferencedTypeVariables + extends SimpleTypeVisitor8<ImmutableSet<TypeVariable>, Set<Element>> { private static final ReferencedTypeVariables INSTANCE = new ReferencedTypeVariables(); @@ -53,8 +53,7 @@ final class TypeVariables { } @Override - public ImmutableSet<TypeVariable> visitDeclared( - DeclaredType t, Set<Element> visited) { + public ImmutableSet<TypeVariable> visitDeclared(DeclaredType t, Set<Element> visited) { if (!visited.add(t.asElement())) { return ImmutableSet.of(); } @@ -66,8 +65,7 @@ final class TypeVariables { } @Override - public ImmutableSet<TypeVariable> visitTypeVariable( - TypeVariable t, Set<Element> visited) { + public ImmutableSet<TypeVariable> visitTypeVariable(TypeVariable t, Set<Element> visited) { if (!visited.add(t.asElement())) { return ImmutableSet.of(); } @@ -79,8 +77,7 @@ final class TypeVariables { } @Override - public ImmutableSet<TypeVariable> visitUnion( - UnionType t, Set<Element> visited) { + public ImmutableSet<TypeVariable> visitUnion(UnionType t, Set<Element> visited) { ImmutableSet.Builder<TypeVariable> typeVariables = ImmutableSet.builder(); for (TypeMirror unionType : t.getAlternatives()) { typeVariables.addAll(unionType.accept(this, visited)); @@ -89,8 +86,7 @@ final class TypeVariables { } @Override - public ImmutableSet<TypeVariable> visitIntersection( - IntersectionType t, Set<Element> visited) { + public ImmutableSet<TypeVariable> visitIntersection(IntersectionType t, Set<Element> visited) { ImmutableSet.Builder<TypeVariable> typeVariables = ImmutableSet.builder(); for (TypeMirror intersectionType : t.getBounds()) { typeVariables.addAll(intersectionType.accept(this, visited)); @@ -99,8 +95,7 @@ final class TypeVariables { } @Override - public ImmutableSet<TypeVariable> visitWildcard( - WildcardType t, Set<Element> visited) { + public ImmutableSet<TypeVariable> visitWildcard(WildcardType t, Set<Element> visited) { ImmutableSet.Builder<TypeVariable> typeVariables = ImmutableSet.builder(); TypeMirror extendsBound = t.getExtendsBound(); if (extendsBound != null) { diff --git a/factory/src/main/java/com/google/auto/factory/processor/package-info.java b/factory/src/main/java/com/google/auto/factory/processor/package-info.java index 7339020a..4a7c4b10 100644 --- a/factory/src/main/java/com/google/auto/factory/processor/package-info.java +++ b/factory/src/main/java/com/google/auto/factory/processor/package-info.java @@ -15,4 +15,5 @@ * This package contains the annotation processor that implements the * {@link com.google.auto.factory.AutoFactory} API. */ -package com.google.auto.factory.processor;
\ No newline at end of file +package com.google.auto.factory.processor; + |