From 08f930a190737eca212da08ece6afa8e4287c336 Mon Sep 17 00:00:00 2001 From: nnegrey Date: Fri, 12 Jun 2020 09:23:27 -0700 Subject: Make the nested @AutoValue class static otherwise you get the following error: `Nested @AutoValue class must be static` ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=316117150 --- value/userguide/howto.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/value/userguide/howto.md b/value/userguide/howto.md index 1dbc5617..6f9142c1 100644 --- a/value/userguide/howto.md +++ b/value/userguide/howto.md @@ -470,7 +470,7 @@ public abstract class StringOrInteger { } @AutoValue - abstract class StringValue extends StringOrInteger { + abstract static class StringValue extends StringOrInteger { abstract String string(); @Override @@ -480,7 +480,7 @@ public abstract class StringOrInteger { } @AutoValue - abstract class IntegerValue extends StringOrInteger { + abstract static class IntegerValue extends StringOrInteger { abstract int integer(); @Override -- cgit v1.2.3 From e62e0abd2fbdfd2512c292ef95d4d152a5ca0691 Mon Sep 17 00:00:00 2001 From: emcmanus Date: Fri, 12 Jun 2020 11:56:31 -0700 Subject: Fix a problem with references to Factory classes in other packages. Detect references to not-yet-generated Factory classes, and associate them with the correct package name if the Factory is one of the ones currently being generated. Fixes https://github.com/google/auto/issues/297. RELNOTES=Fix a problem with references to Factory classes in other packages. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=316148042 --- .../factory/processor/AutoFactoryDeclaration.java | 22 ++-- .../factory/processor/AutoFactoryProcessor.java | 135 +++++++++++---------- .../auto/factory/processor/FactoryDescriptor.java | 4 +- .../factory/processor/FactoryMethodDescriptor.java | 4 +- .../auto/factory/processor/FactoryWriter.java | 76 +++++++----- .../auto/factory/processor/PackageAndClass.java | 38 ++++++ 6 files changed, 169 insertions(+), 110 deletions(-) create mode 100644 factory/src/main/java/com/google/auto/factory/processor/PackageAndClass.java 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 ad4ccb8b..e2da6eae 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 @@ -62,21 +62,17 @@ abstract class AutoFactoryDeclaration { abstract AnnotationMirror mirror(); abstract ImmutableMap valuesMap(); - String getFactoryName() { - CharSequence packageName = getPackage(targetType()).getQualifiedName(); - StringBuilder builder = new StringBuilder(packageName); - if (packageName.length() > 0) { - builder.append('.'); - } + PackageAndClass getFactoryName() { + String packageName = getPackage(targetType()).getQualifiedName().toString(); if (className().isPresent()) { - builder.append(className().get()); - } else { - for (String enclosingSimpleName : targetEnclosingSimpleNames()) { - builder.append(enclosingSimpleName).append('_'); - } - builder.append(targetType().getSimpleName()).append("Factory"); + return PackageAndClass.of(packageName, className().get()); + } + StringBuilder builder = new StringBuilder(); + for (String enclosingSimpleName : targetEnclosingSimpleNames()) { + builder.append(enclosingSimpleName).append('_'); } - return builder.toString(); + builder.append(targetType().getSimpleName()).append("Factory"); + return PackageAndClass.of(packageName, builder.toString()); } private ImmutableList targetEnclosingSimpleNames() { 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 cf3d5ebd..5cc1d94d 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 @@ -27,13 +27,10 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Iterables; -import com.google.googlejavaformat.java.filer.FormattingFiler; import java.io.IOException; import java.util.Arrays; -import java.util.Collection; import java.util.Comparator; import java.util.List; -import java.util.Map.Entry; import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.Messager; @@ -68,7 +65,6 @@ public final class AutoFactoryProcessor extends AbstractProcessor { private Messager messager; private Elements elements; private Types types; - private FactoryWriter factoryWriter; @Override public synchronized void init(ProcessingEnvironment processingEnv) { @@ -76,11 +72,6 @@ public final class AutoFactoryProcessor extends AbstractProcessor { elements = processingEnv.getElementUtils(); types = processingEnv.getTypeUtils(); messager = processingEnv.getMessager(); - factoryWriter = - new FactoryWriter( - new FormattingFiler(processingEnv.getFiler()), - elements, - processingEnv.getSourceVersion()); providedChecker = new ProvidedChecker(messager); declarationFactory = new AutoFactoryDeclaration.Factory(elements, messager); factoryDescriptorGenerator = @@ -103,14 +94,15 @@ public final class AutoFactoryProcessor extends AbstractProcessor { providedChecker.checkProvidedParameter(element); } - ImmutableListMultimap.Builder indexedMethods = + ImmutableListMultimap.Builder indexedMethodsBuilder = ImmutableListMultimap.builder(); - ImmutableSetMultimap.Builder + ImmutableSetMultimap.Builder implementationMethodDescriptorsBuilder = ImmutableSetMultimap.builder(); + // Iterate over the classes and methods that are annotated with @AutoFactory. for (Element element : roundEnv.getElementsAnnotatedWith(AutoFactory.class)) { Optional declaration = declarationFactory.createIfValid(element); if (declaration.isPresent()) { - String factoryName = declaration.get().getFactoryName(); + PackageAndClass factoryName = declaration.get().getFactoryName(); TypeElement extendingType = declaration.get().extendingType(); implementationMethodDescriptorsBuilder.putAll( factoryName, implementationMethods(extendingType, element)); @@ -123,62 +115,61 @@ public final class AutoFactoryProcessor extends AbstractProcessor { ImmutableSet descriptors = factoryDescriptorGenerator.generateDescriptor(element); for (FactoryMethodDescriptor descriptor : descriptors) { - indexedMethods.put(descriptor.factoryName(), descriptor); + indexedMethodsBuilder.put(descriptor.factoryName(), descriptor); } } - ImmutableSetMultimap + ImmutableSetMultimap implementationMethodDescriptors = implementationMethodDescriptorsBuilder.build(); + ImmutableListMultimap indexedMethods = + indexedMethodsBuilder.build(); + ImmutableSetMultimap factoriesBeingCreated = + simpleNamesToNames(indexedMethods.keySet()); + FactoryWriter factoryWriter = new FactoryWriter(processingEnv, factoriesBeingCreated); - for (Entry> entry - : indexedMethods.build().asMap().entrySet()) { - ImmutableSet.Builder extending = ImmutableSet.builder(); - ImmutableSortedSet.Builder implementing = - ImmutableSortedSet.orderedBy( - new Comparator() { - @Override - public int compare(TypeMirror first, TypeMirror second) { - String firstName = MoreTypes.asTypeElement(first).getQualifiedName().toString(); - String secondName = MoreTypes.asTypeElement(second).getQualifiedName().toString(); - return firstName.compareTo(secondName); - } - }); - boolean publicType = false; - Boolean allowSubclasses = null; - boolean skipCreation = false; - for (FactoryMethodDescriptor methodDescriptor : entry.getValue()) { - 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( - entry.getKey(), - Iterables.getOnlyElement(extending.build()), - implementing.build(), - publicType, - ImmutableSet.copyOf(entry.getValue()), - implementationMethodDescriptors.get(entry.getKey()), - allowSubclasses)); - } catch (IOException e) { - messager.printMessage(Kind.ERROR, "failed: " + e); - } - } - } + 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 extending = newTypeSetBuilder(); + ImmutableSortedSet.Builder 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); + } + } + }); } private ImmutableSet implementationMethods( @@ -216,8 +207,24 @@ public final class AutoFactoryProcessor extends AbstractProcessor { return Iterables.getOnlyElement(types).asType(); } + private static ImmutableSetMultimap simpleNamesToNames( + ImmutableSet names) { + // .collect(toImmutableSetMultimap(...)) would make this much simpler but ran into problems in + // Google's internal build system because of multiple Guava versions. + ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); + for (PackageAndClass name : names) { + builder.put(name.className(), name); + } + return builder.build(); + } + + private static ImmutableSortedSet.Builder newTypeSetBuilder() { + return ImmutableSortedSet.orderedBy( + Comparator.comparing(t -> MoreTypes.asTypeElement(t).getQualifiedName().toString())); + } + @Override - public Set getSupportedAnnotationTypes() { + public ImmutableSet getSupportedAnnotationTypes() { return ImmutableSet.of(AutoFactory.class.getName(), Provided.class.getName()); } 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 68ae678d..5ed2307a 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 @@ -46,7 +46,7 @@ abstract class FactoryDescriptor { } }; - abstract String name(); + abstract PackageAndClass name(); abstract TypeMirror extendingType(); abstract ImmutableSet implementingTypes(); abstract boolean publicType(); @@ -76,7 +76,7 @@ abstract class FactoryDescriptor { } static FactoryDescriptor create( - String name, + PackageAndClass name, TypeMirror extendingType, ImmutableSet implementingTypes, boolean publicType, 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 c3a0159d..43e5097d 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 @@ -41,7 +41,7 @@ abstract class FactoryMethodDescriptor { abstract Builder toBuilder(); abstract boolean isVarArgs(); - final String factoryName() { + final PackageAndClass factoryName() { return declaration().getFactoryName(); } @@ -54,7 +54,7 @@ abstract class FactoryMethodDescriptor { } @AutoValue.Builder - static abstract class Builder { + abstract static class Builder { abstract Builder declaration(AutoFactoryDeclaration declaration); abstract Builder name(String name); abstract Builder returnType(TypeMirror returnType); 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 3bb68e1c..53b99cb5 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 @@ -29,6 +29,7 @@ import com.google.common.base.Joiner; import com.google.common.collect.FluentIterable; 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.squareup.javapoet.AnnotationSpec; @@ -44,10 +45,12 @@ import com.squareup.javapoet.TypeVariableName; import java.io.IOException; import java.util.Iterator; 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.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeVariable; import javax.lang.model.util.Elements; @@ -57,18 +60,22 @@ final class FactoryWriter { private final Filer filer; private final Elements elements; private final SourceVersion sourceVersion; + private final ImmutableSetMultimap factoriesBeingCreated; - FactoryWriter(Filer filer, Elements elements, SourceVersion sourceVersion) { - this.filer = filer; - this.elements = elements; - this.sourceVersion = sourceVersion; + FactoryWriter( + ProcessingEnvironment processingEnv, + ImmutableSetMultimap factoriesBeingCreated) { + this.filer = processingEnv.getFiler(); + this.elements = processingEnv.getElementUtils(); + this.sourceVersion = processingEnv.getSourceVersion(); + this.factoriesBeingCreated = factoriesBeingCreated; } private static final Joiner ARGUMENT_JOINER = Joiner.on(", "); - void writeFactory(final FactoryDescriptor descriptor) + void writeFactory(FactoryDescriptor descriptor) throws IOException { - String factoryName = getSimpleName(descriptor.name()).toString(); + String factoryName = descriptor.name().className(); TypeSpec.Builder factory = classBuilder(factoryName) .addOriginatingElement(descriptor.declaration().targetType()); @@ -98,7 +105,7 @@ final class FactoryWriter { addImplementationMethods(factory, descriptor); addCheckNotNullMethod(factory, descriptor); - JavaFile.builder(getPackage(descriptor.name()), factory.build()) + JavaFile.builder(descriptor.name().packageName(), factory.build()) .skipJavaLangImports(true) .build() .writeTo(filer); @@ -109,7 +116,7 @@ final class FactoryWriter { factory.addTypeVariables(typeVariableNames); } - private static void addConstructorAndProviderFields( + private void addConstructorAndProviderFields( TypeSpec.Builder factory, FactoryDescriptor descriptor) { MethodSpec.Builder constructor = constructorBuilder().addAnnotation(Inject.class); if (descriptor.publicType()) { @@ -118,7 +125,7 @@ final class FactoryWriter { Iterator providerFields = descriptor.providers().values().iterator(); for (int argumentIndex = 1; providerFields.hasNext(); argumentIndex++) { ProviderField provider = providerFields.next(); - TypeName typeName = TypeName.get(provider.key().type().get()).box(); + TypeName typeName = resolveTypeName(provider.key().type().get()).box(); TypeName providerType = ParameterizedTypeName.get(ClassName.get(Provider.class), typeName); factory.addField(providerType, provider.name(), PRIVATE, FINAL); if (provider.key().qualifier().isPresent()) { @@ -132,7 +139,7 @@ final class FactoryWriter { factory.addMethod(constructor.build()); } - private static void addFactoryMethods( + private void addFactoryMethods( TypeSpec.Builder factory, FactoryDescriptor descriptor, ImmutableSet factoryTypeVariables) { @@ -183,7 +190,7 @@ final class FactoryWriter { } } - private static void addImplementationMethods( + private void addImplementationMethods( TypeSpec.Builder factory, FactoryDescriptor descriptor) { for (ImplementationMethodDescriptor methodDescriptor : descriptor.implementationMethodDescriptors()) { @@ -215,11 +222,11 @@ final class FactoryWriter { * {@link ParameterSpec}s to match {@code parameters}. Note that the type of the {@link * ParameterSpec}s match {@link Parameter#type()} and not {@link Key#type()}. */ - private static Iterable parameters(Iterable parameters) { + private ImmutableList parameters(Iterable parameters) { ImmutableList.Builder builder = ImmutableList.builder(); for (Parameter parameter : parameters) { ParameterSpec.Builder parameterBuilder = - ParameterSpec.builder(TypeName.get(parameter.type().get()), parameter.name()); + 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)); @@ -266,23 +273,34 @@ final class FactoryWriter { return false; } - private static CharSequence getSimpleName(CharSequence fullyQualifiedName) { - int lastDot = lastIndexOf(fullyQualifiedName, '.'); - return fullyQualifiedName.subSequence(lastDot + 1, fullyQualifiedName.length()); - } - - private static String getPackage(CharSequence fullyQualifiedName) { - int lastDot = lastIndexOf(fullyQualifiedName, '.'); - return lastDot == -1 ? "" : fullyQualifiedName.subSequence(0, lastDot).toString(); - } - - private static int lastIndexOf(CharSequence charSequence, char c) { - for (int i = charSequence.length() - 1; i >= 0; i--) { - if (charSequence.charAt(i) == c) { - return i; - } + /** + * Returns an appropriate {@code TypeName} for the given type. If the type is an + * {@code ErrorType}, and if it is a simple-name reference to one of the {@code *Factory} + * classes that we are going to generate, then we return its fully-qualified name. In every other + * case we just return {@code TypeName.get(type)}. Specifically, if it is an {@code ErrorType} + * referencing some other type, or referencing one of the classes we are going to generate but + * using its fully-qualified name, then we leave it as-is. JavaPoet treats {@code TypeName.get(t)} + * the same for {@code ErrorType} as for {@code DeclaredType}, which means that if this is a name + * that will eventually be generated then the code we write that references the type will in fact + * compile. + * + *

A simpler alternative would be to defer processing to a later round if we find an + * {@code @AutoFactory} class that references undefined types, under the assumption that something + * else will generate those types in the meanwhile. However, this would fail if for example + * {@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. + */ + private TypeName resolveTypeName(TypeMirror type) { + if (type.getKind() != TypeKind.ERROR) { + return TypeName.get(type); + } + ImmutableSet factoryNames = factoriesBeingCreated.get(type.toString()); + if (factoryNames.size() == 1) { + PackageAndClass packageAndClass = Iterables.getOnlyElement(factoryNames); + return ClassName.get(packageAndClass.packageName(), packageAndClass.className()); } - return -1; + return TypeName.get(type); } private static ImmutableSet getFactoryTypeVariables( diff --git a/factory/src/main/java/com/google/auto/factory/processor/PackageAndClass.java b/factory/src/main/java/com/google/auto/factory/processor/PackageAndClass.java new file mode 100644 index 00000000..857fba11 --- /dev/null +++ b/factory/src/main/java/com/google/auto/factory/processor/PackageAndClass.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020 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.processor; + +import com.google.auto.value.AutoValue; + +/** A Java class name, separated into its package part and its class part. */ +@AutoValue +abstract class PackageAndClass { + /** + * The package part of this class name. For {@code java.util.Map.Entry}, it would be {@code + * java.util}. + */ + abstract String packageName(); + + /** + * The class part of this class name. For {@code java.util.Map.Entry}, it would be {@code + * Map.Entry}. + */ + abstract String className(); + + static PackageAndClass of(String packageName, String className) { + return new AutoValue_PackageAndClass(packageName, className); + } +} -- cgit v1.2.3 From df5641b2340c8a437ab2c1c9579b97db27bc9fac Mon Sep 17 00:00:00 2001 From: armandgray Date: Wed, 17 Jun 2020 14:41:47 -0700 Subject: [ #HiltMigration ] Updating BasicAnnotationProcessor to support a String-based API. Context: Per discussion in [] this change adds a String-based `Step` class as a replacement for `ProcessingStep`. The new `Step` contains the same two methods (annotations() & process()) which return and accept fully-qualified annotation names. To support the potential absence of the annotation classes from the processor classpath the corresponding methods were changed to no longer depend on explicit Class types. RELNOTES=Adding String-based `Step` as a replacement for `ProcessingStep` to BasicAnnotationProcessor. Allows for fully-qualified Annotation names to be specified in a processing Step in order to remove the requirement that implementation processors depend directly on their Annotation classes. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=316968142 --- .../auto/common/BasicAnnotationProcessor.java | 240 +++++++++---- .../auto/common/BasicAnnotationProcessorTest.java | 387 ++++++++++++++------- 2 files changed, 447 insertions(+), 180 deletions(-) diff --git a/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java b/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java index d3f67aa5..375a4cb8 100644 --- a/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java +++ b/common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java @@ -17,12 +17,14 @@ package com.google.auto.common; import static com.google.auto.common.MoreElements.asExecutable; import static com.google.auto.common.MoreElements.asPackage; -import static com.google.auto.common.MoreElements.isAnnotationPresent; import static com.google.auto.common.SuperficialValidation.validateElement; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Multimaps.filterKeys; +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; import static javax.lang.model.element.ElementKind.PACKAGE; import static javax.tools.Diagnostic.Kind.ERROR; @@ -30,8 +32,10 @@ import com.google.common.base.Ascii; import com.google.common.base.Optional; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; +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.LinkedHashMultimap; import com.google.common.collect.SetMultimap; import com.google.common.collect.Sets; @@ -57,9 +61,9 @@ import javax.lang.model.util.SimpleElementVisitor8; * An abstract {@link Processor} implementation that defers processing of {@link Element}s to later * rounds if they cannot be processed. * - *

Subclasses put their processing logic in {@link ProcessingStep} implementations. The steps are - * passed to the processor by returning them in the {@link #initSteps()} method, and can access the - * {@link ProcessingEnvironment} using {@link #processingEnv}. + *

Subclasses put their processing logic in {@link Step} implementations. The steps are passed to + * the processor by returning them in the {@link #steps()} method, and can access the {@link + * ProcessingEnvironment} using {@link #processingEnv}. * *

Any logic that needs to happen once per round can be specified by overriding {@link * #postRound(RoundEnvironment)}. @@ -67,8 +71,8 @@ import javax.lang.model.util.SimpleElementVisitor8; *

Ill-formed elements are deferred

* * Any annotated element whose nearest enclosing type is not well-formed is deferred, and not passed - * to any {@code ProcessingStep}. This helps processors to avoid many common pitfalls, such as - * {@link ErrorType} instances, {@link ClassCastException}s and badly coerced types. + * to any {@code Step}. This helps processors to avoid many common pitfalls, such as {@link + * ErrorType} instances, {@link ClassCastException}s and badly coerced types. * *

A non-package element is considered well-formed if its type, type parameters, parameters, * default values, supertypes, annotations, and enclosed elements are. Package elements are treated @@ -80,11 +84,11 @@ import javax.lang.model.util.SimpleElementVisitor8; * because the element will never be fully complete. All such compilations will fail with an error * message on the offending type that describes the issue. * - *

Each {@code ProcessingStep} can defer elements

+ *

Each {@code Step} can defer elements

* - *

Each {@code ProcessingStep} can defer elements by including them in the set returned by {@link - * ProcessingStep#process(SetMultimap)}; elements deferred by a step will be passed back to that - * step in a later round of processing. + *

Each {@code Step} can defer elements by including them in the set returned by {@link + * Step#process(ImmutableSetMultimap)}; elements deferred by a step will be passed back to that step + * in a later round of processing. * *

This feature is useful when one processor may depend on code generated by another, independent * processor, in a way that isn't caught by the well-formedness check described above. For example, @@ -102,26 +106,42 @@ import javax.lang.model.util.SimpleElementVisitor8; public abstract class BasicAnnotationProcessor extends AbstractProcessor { private final Set deferredElementNames = new LinkedHashSet<>(); - private final SetMultimap elementsDeferredBySteps = + private final SetMultimap elementsDeferredBySteps = LinkedHashMultimap.create(); private Elements elements; private Messager messager; - private ImmutableList steps; + private ImmutableList steps; @Override public final synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); this.elements = processingEnv.getElementUtils(); this.messager = processingEnv.getMessager(); - this.steps = ImmutableList.copyOf(initSteps()); + this.steps = ImmutableList.copyOf(steps()); } /** * Creates {@linkplain ProcessingStep processing steps} for this processor. {@link #processingEnv} * is guaranteed to be set when this method is invoked. + * + * @deprecated Implement {@link #steps()} instead. + */ + @Deprecated + protected Iterable initSteps() { + throw new AssertionError("If steps() is not implemented, initSteps() must be."); + } + + /** + * Creates {@linkplain Step processing steps} for this processor. {@link #processingEnv} is + * guaranteed to be set when this method is invoked. + * + *

Note: If you are migrating some steps from {@link ProcessingStep} to {@link Step}, then you + * can call {@link #asStep(ProcessingStep)} on any unmigrated steps. */ - protected abstract Iterable initSteps(); + protected Iterable steps() { + return Iterables.transform(initSteps(), BasicAnnotationProcessor::asStep); + } /** * An optional hook for logic to be executed at the end of each round. @@ -138,26 +158,30 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { } } - private ImmutableSet> getSupportedAnnotationClasses() { + private ImmutableSet getSupportedAnnotationTypeElements() { checkState(steps != null); - ImmutableSet.Builder> builder = ImmutableSet.builder(); - for (ProcessingStep step : steps) { - builder.addAll(step.annotations()); - } - return builder.build(); + return steps.stream() + .flatMap(step -> getSupportedAnnotationTypeElements(step).stream()) + .collect(collectingAndThen(toList(), ImmutableSet::copyOf)); + } + + private ImmutableSet getSupportedAnnotationTypeElements(Step step) { + return step.annotations().stream() + .map(elements::getTypeElement) + .filter(Objects::nonNull) + .collect(collectingAndThen(toList(), ImmutableSet::copyOf)); } /** - * Returns the set of supported annotation types as a collected from registered {@linkplain - * ProcessingStep processing steps}. + * Returns the set of supported annotation types as collected from registered {@linkplain Step + * processing steps}. */ @Override public final ImmutableSet getSupportedAnnotationTypes() { - ImmutableSet.Builder builder = ImmutableSet.builder(); - for (Class annotationClass : getSupportedAnnotationClasses()) { - builder.add(annotationClass.getCanonicalName()); - } - return builder.build(); + checkState(steps != null); + return steps.stream() + .flatMap(step -> step.annotations().stream()) + .collect(collectingAndThen(toList(), ImmutableSet::copyOf)); } @Override @@ -189,17 +213,19 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { } /** Processes the valid elements, including those previously deferred by each step. */ - private void process(ImmutableSetMultimap, Element> validElements) { - for (ProcessingStep step : steps) { - ImmutableSetMultimap, Element> stepElements = - new ImmutableSetMultimap.Builder, Element>() - .putAll(indexByAnnotation(elementsDeferredBySteps.get(step), step.annotations())) - .putAll(filterKeys(validElements, Predicates.in(step.annotations()))) + private void process(ImmutableSetMultimap validElements) { + for (Step step : steps) { + ImmutableSet annotationTypes = getSupportedAnnotationTypeElements(step); + ImmutableSetMultimap stepElements = + new ImmutableSetMultimap.Builder() + .putAll(indexByAnnotation(elementsDeferredBySteps.get(step), annotationTypes)) + .putAll(filterKeys(validElements, Predicates.in(annotationTypes))) .build(); if (stepElements.isEmpty()) { elementsDeferredBySteps.removeAll(step); } else { - Set rejectedElements = step.process(stepElements); + Set rejectedElements = + step.process(toClassNameKeyedMultimap(stepElements)); elementsDeferredBySteps.replaceValues( step, transform(rejectedElements, ElementName::forAnnotatedElement)); } @@ -233,43 +259,39 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { * Returns the valid annotated elements contained in all of the deferred elements. If none are * found for a deferred element, defers it again. */ - private ImmutableSetMultimap, Element> validElements( - RoundEnvironment roundEnv) { + private ImmutableSetMultimap validElements(RoundEnvironment roundEnv) { ImmutableSet prevDeferredElementNames = ImmutableSet.copyOf(deferredElementNames); deferredElementNames.clear(); - ImmutableSetMultimap.Builder, Element> - deferredElementsByAnnotationBuilder = ImmutableSetMultimap.builder(); + ImmutableSetMultimap.Builder deferredElementsByAnnotationBuilder = + ImmutableSetMultimap.builder(); for (ElementName deferredElementName : prevDeferredElementNames) { Optional deferredElement = deferredElementName.getElement(elements); if (deferredElement.isPresent()) { findAnnotatedElements( deferredElement.get(), - getSupportedAnnotationClasses(), + getSupportedAnnotationTypeElements(), deferredElementsByAnnotationBuilder); } else { deferredElementNames.add(deferredElementName); } } - ImmutableSetMultimap, Element> deferredElementsByAnnotation = + ImmutableSetMultimap deferredElementsByAnnotation = deferredElementsByAnnotationBuilder.build(); - ImmutableSetMultimap.Builder, Element> validElements = + ImmutableSetMultimap.Builder validElements = ImmutableSetMultimap.builder(); Set validElementNames = new LinkedHashSet<>(); // Look at the elements we've found and the new elements from this round and validate them. - for (Class annotationClass : getSupportedAnnotationClasses()) { - // This should just call roundEnv.getElementsAnnotatedWith(Class) directly, but there is a bug - // in some versions of eclipse that cause that method to crash. - TypeElement annotationType = elements.getTypeElement(annotationClass.getCanonicalName()); + for (TypeElement annotationType : getSupportedAnnotationTypeElements()) { Set roundElements = (annotationType == null) - ? ImmutableSet.of() + ? ImmutableSet.of() : roundEnv.getElementsAnnotatedWith(annotationType); - ImmutableSet prevRoundElements = deferredElementsByAnnotation.get(annotationClass); + ImmutableSet prevRoundElements = deferredElementsByAnnotation.get(annotationType); for (Element element : Sets.union(roundElements, prevRoundElements)) { ElementName elementName = ElementName.forAnnotatedElement(element); boolean isValidElement = @@ -278,7 +300,7 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { && validateElement( element.getKind().equals(PACKAGE) ? element : getEnclosingType(element))); if (isValidElement) { - validElements.put(annotationClass, element); + validElements.put(annotationType, element); validElementNames.add(elementName); } else { deferredElementNames.add(elementName); @@ -289,15 +311,14 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { return validElements.build(); } - private ImmutableSetMultimap, Element> indexByAnnotation( - Set annotatedElements, - Set> annotationClasses) { - ImmutableSetMultimap.Builder, Element> deferredElements = + private ImmutableSetMultimap indexByAnnotation( + Set annotatedElements, ImmutableSet annotationTypes) { + ImmutableSetMultimap.Builder deferredElements = ImmutableSetMultimap.builder(); for (ElementName elementName : annotatedElements) { Optional element = elementName.getElement(elements); if (element.isPresent()) { - findAnnotatedElements(element.get(), annotationClasses, deferredElements); + findAnnotatedElements(element.get(), annotationTypes, deferredElements); } } return deferredElements.build(); @@ -305,8 +326,8 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { /** * Adds {@code element} and its enclosed elements to {@code annotatedElements} if they are - * annotated with any annotations in {@code annotationClasses}. Does not traverse to member types - * of {@code element}, so that if {@code Outer} is passed in the example below, looking for + * annotated with any annotations in {@code annotationTypes}. Does not traverse to member types of + * {@code element}, so that if {@code Outer} is passed in the example below, looking for * {@code @X}, then {@code Outer}, {@code Outer.foo}, and {@code Outer.foo()} will be added to the * multimap, but neither {@code Inner} nor its members will. * @@ -323,27 +344,33 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { */ private static void findAnnotatedElements( Element element, - Set> annotationClasses, - ImmutableSetMultimap.Builder, Element> annotatedElements) { + ImmutableSet annotationTypes, + ImmutableSetMultimap.Builder annotatedElements) { for (Element enclosedElement : element.getEnclosedElements()) { if (!enclosedElement.getKind().isClass() && !enclosedElement.getKind().isInterface()) { - findAnnotatedElements(enclosedElement, annotationClasses, annotatedElements); + findAnnotatedElements(enclosedElement, annotationTypes, annotatedElements); } } // element.getEnclosedElements() does NOT return parameter elements if (element instanceof ExecutableElement) { for (Element parameterElement : asExecutable(element).getParameters()) { - findAnnotatedElements(parameterElement, annotationClasses, annotatedElements); + findAnnotatedElements(parameterElement, annotationTypes, annotatedElements); } } - for (Class annotationClass : annotationClasses) { - if (isAnnotationPresent(element, annotationClass)) { - annotatedElements.put(annotationClass, element); + for (TypeElement annotationType : annotationTypes) { + if (isAnnotationPresent(element, annotationType)) { + annotatedElements.put(annotationType, element); } } } + private static boolean isAnnotationPresent(Element element, TypeElement annotationType) { + return element.getAnnotationMirrors().stream() + .anyMatch( + mirror -> MoreTypes.asTypeElement(mirror.getAnnotationType()).equals(annotationType)); + } + /** * Returns the nearest enclosing {@link TypeElement} to the current element, throwing an {@link * IllegalArgumentException} if the provided {@link Element} is a {@link PackageElement} or is @@ -371,12 +398,61 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { null); } + private static ImmutableSetMultimap toClassNameKeyedMultimap( + SetMultimap elements) { + ImmutableSetMultimap.Builder builder = ImmutableSetMultimap.builder(); + elements + .asMap() + .forEach( + (annotation, element) -> + builder.putAll(annotation.getQualifiedName().toString(), element)); + return builder.build(); + } + + /** + * Wraps the passed {@link ProcessingStep} in a {@link Step}. This is a convenience method to + * allow incremental migration to a String-based API. This method can be used to return a not yet + * converted {@link ProcessingStep} from {@link BasicAnnotationProcessor#steps()}. + */ + protected static Step asStep(ProcessingStep processingStep) { + return new ProcessingStepAsStep(processingStep); + } + /** * The unit of processing logic that runs under the guarantee that all elements are complete and * well-formed. A step may reject elements that are not ready for processing but may be at a later * round. */ + public interface Step { + + /** + * The set of fully-qualified annotation type names processed by this step. + * + *

Warning: If the returned names are not names of annotations, they'll be ignored. + */ + Set annotations(); + + /** + * The implementation of processing logic for the step. It is guaranteed that the keys in {@code + * elementsByAnnotation} will be a subset of the set returned by {@link #annotations()}. + * + * @return the elements (a subset of the values of {@code elementsByAnnotation}) that this step + * is unable to process, possibly until a later processing round. These elements will be + * passed back to this step at the next round of processing. + */ + Set process(ImmutableSetMultimap elementsByAnnotation); + } + + /** + * The unit of processing logic that runs under the guarantee that all elements are complete and + * well-formed. A step may reject elements that are not ready for processing but may be at a later + * round. + * + * @deprecated Implement {@link Step} instead. See {@link BasicAnnotationProcessor#steps()}. + */ + @Deprecated public interface ProcessingStep { + /** The set of annotation types processed by this step. */ Set> annotations(); @@ -392,6 +468,46 @@ public abstract class BasicAnnotationProcessor extends AbstractProcessor { SetMultimap, Element> elementsByAnnotation); } + private static class ProcessingStepAsStep implements Step { + + private final ProcessingStep processingStep; + private final ImmutableMap> annotationsByName; + + ProcessingStepAsStep(ProcessingStep processingStep) { + this.processingStep = processingStep; + this.annotationsByName = + processingStep.annotations().stream() + .collect( + collectingAndThen( + toMap( + Class::getCanonicalName, (Class aClass) -> aClass), + ImmutableMap::copyOf)); + } + + @Override + public Set annotations() { + return annotationsByName.keySet(); + } + + @Override + public Set process( + ImmutableSetMultimap elementsByAnnotation) { + return processingStep.process(toClassKeyedMultimap(elementsByAnnotation)); + } + + private ImmutableSetMultimap, Element> toClassKeyedMultimap( + SetMultimap elements) { + ImmutableSetMultimap.Builder, Element> builder = + ImmutableSetMultimap.builder(); + elements + .asMap() + .forEach( + (annotation, annotatedElements) -> + builder.putAll(annotationsByName.get(annotation), annotatedElements)); + return builder.build(); + } + } + /** * A package or type name. * diff --git a/common/src/test/java/com/google/auto/common/BasicAnnotationProcessorTest.java b/common/src/test/java/com/google/auto/common/BasicAnnotationProcessorTest.java index 59a135c4..f7534503 100644 --- a/common/src/test/java/com/google/auto/common/BasicAnnotationProcessorTest.java +++ b/common/src/test/java/com/google/auto/common/BasicAnnotationProcessorTest.java @@ -18,28 +18,35 @@ package com.google.auto.common; import static com.google.common.collect.Multimaps.transformValues; import static com.google.common.truth.Truth.assertAbout; import static com.google.common.truth.Truth.assertThat; +import static com.google.testing.compile.CompilationSubject.assertThat; +import static com.google.testing.compile.Compiler.javac; import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; import static javax.tools.Diagnostic.Kind.ERROR; import static javax.tools.StandardLocation.SOURCE_OUTPUT; +import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; +import com.google.auto.common.BasicAnnotationProcessor.Step; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.SetMultimap; import com.google.common.truth.Correspondence; +import com.google.testing.compile.Compilation; +import com.google.testing.compile.CompilationRule; import com.google.testing.compile.JavaFileObjects; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.util.Set; import javax.annotation.processing.Filer; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; import javax.tools.JavaFileObject; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -47,30 +54,36 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class BasicAnnotationProcessorTest { + private abstract static class BaseAnnotationProcessor extends BasicAnnotationProcessor { + + static final String ENCLOSING_CLASS_NAME = + BasicAnnotationProcessorTest.class.getCanonicalName(); + + @Override + public final SourceVersion getSupportedSourceVersion() { + return SourceVersion.latestSupported(); + } + } + @Retention(RetentionPolicy.SOURCE) public @interface RequiresGeneratedCode {} /** * Rejects elements unless the class generated by {@link GeneratesCode}'s processor is present. */ - private static final class RequiresGeneratedCodeProcessor extends BasicAnnotationProcessor { + private static class RequiresGeneratedCodeProcessor extends BaseAnnotationProcessor { int rejectedRounds; - final ImmutableList.Builder, Element>> - processArguments = ImmutableList.builder(); + final ImmutableList.Builder> processArguments = + ImmutableList.builder(); @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - protected Iterable initSteps() { + protected Iterable steps() { return ImmutableSet.of( - new ProcessingStep() { + new Step() { @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { processArguments.add(ImmutableSetMultimap.copyOf(elementsByAnnotation)); TypeElement requiredClass = processingEnv.getElementUtils().getTypeElement("test.SomeGeneratedClass"); @@ -83,25 +96,25 @@ public class BasicAnnotationProcessorTest { } @Override - public Set> annotations() { - return ImmutableSet.of(RequiresGeneratedCode.class); + public ImmutableSet annotations() { + return ImmutableSet.of(ENCLOSING_CLASS_NAME + ".RequiresGeneratedCode"); } }, - new ProcessingStep() { + new Step() { @Override - public Set> annotations() { - return ImmutableSet.of(AnAnnotation.class); + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { + return ImmutableSet.of(); } @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { - return ImmutableSet.of(); + public ImmutableSet annotations() { + return ImmutableSet.of(ENCLOSING_CLASS_NAME + ".AnAnnotation"); } }); } - ImmutableList, Element>> processArguments() { + ImmutableList> processArguments() { return processArguments.build(); } } @@ -110,27 +123,21 @@ public class BasicAnnotationProcessorTest { public @interface GeneratesCode {} /** Generates a class called {@code test.SomeGeneratedClass}. */ - public class GeneratesCodeProcessor extends BasicAnnotationProcessor { - + public static class GeneratesCodeProcessor extends BaseAnnotationProcessor { @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - protected Iterable initSteps() { + protected Iterable steps() { return ImmutableSet.of( - new ProcessingStep() { + new Step() { @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { generateClass(processingEnv.getFiler(), "SomeGeneratedClass"); return ImmutableSet.of(); } @Override - public Set> annotations() { - return ImmutableSet.of(GeneratesCode.class); + public ImmutableSet annotations() { + return ImmutableSet.of(ENCLOSING_CLASS_NAME + ".GeneratesCode"); } }); } @@ -139,20 +146,15 @@ public class BasicAnnotationProcessorTest { public @interface AnAnnotation {} /** When annotating a type {@code Foo}, generates a class called {@code FooXYZ}. */ - public class AnAnnotationProcessor extends BasicAnnotationProcessor { + public static class AnAnnotationProcessor extends BaseAnnotationProcessor { @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - protected Iterable initSteps() { + protected Iterable steps() { return ImmutableSet.of( - new ProcessingStep() { + new Step() { @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { for (Element element : elementsByAnnotation.values()) { generateClass(processingEnv.getFiler(), element.getSimpleName() + "XYZ"); } @@ -160,8 +162,8 @@ public class BasicAnnotationProcessorTest { } @Override - public Set> annotations() { - return ImmutableSet.of(AnAnnotation.class); + public ImmutableSet annotations() { + return ImmutableSet.of(ENCLOSING_CLASS_NAME + ".AnAnnotation"); } }); } @@ -171,19 +173,15 @@ public class BasicAnnotationProcessorTest { public @interface CauseError {} /** Report an error for any class annotated. */ - public static class CauseErrorProcessor extends BasicAnnotationProcessor { - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } + public static class CauseErrorProcessor extends BaseAnnotationProcessor { @Override - protected Iterable initSteps() { + protected Iterable steps() { return ImmutableSet.of( - new ProcessingStep() { + new Step() { @Override - public Set process( - SetMultimap, Element> elementsByAnnotation) { + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { for (Element e : elementsByAnnotation.values()) { processingEnv.getMessager().printMessage(ERROR, "purposeful error", e); } @@ -191,26 +189,91 @@ public class BasicAnnotationProcessorTest { } @Override - public Set> annotations() { - return ImmutableSet.of(CauseError.class); + public ImmutableSet annotations() { + return ImmutableSet.of(ENCLOSING_CLASS_NAME + ".CauseError"); + } + }); + } + } + + public static class MissingAnnotationProcessor extends BaseAnnotationProcessor { + + private ImmutableSetMultimap elementsByAnnotation; + + @Override + protected Iterable steps() { + return ImmutableSet.of( + new Step() { + @Override + public ImmutableSet process( + ImmutableSetMultimap elementsByAnnotation) { + MissingAnnotationProcessor.this.elementsByAnnotation = elementsByAnnotation; + for (Element element : elementsByAnnotation.values()) { + generateClass(processingEnv.getFiler(), element.getSimpleName() + "XYZ"); + } + return ImmutableSet.of(); + } + + @Override + public ImmutableSet annotations() { + return ImmutableSet.of( + "test.SomeNonExistentClass", ENCLOSING_CLASS_NAME + ".AnAnnotation"); } }); } + + ImmutableSetMultimap getElementsByAnnotation() { + return elementsByAnnotation; + } } - @Test public void properlyDefersProcessing_typeElement() { - JavaFileObject classAFileObject = JavaFileObjects.forSourceLines("test.ClassA", - "package test;", - "", - "@" + RequiresGeneratedCode.class.getCanonicalName(), - "public class ClassA {", - " SomeGeneratedClass sgc;", - "}"); - JavaFileObject classBFileObject = JavaFileObjects.forSourceLines("test.ClassB", - "package test;", - "", - "@" + GeneratesCode.class.getCanonicalName(), - "public class ClassB {}"); + @SuppressWarnings("deprecation") // Deprecated ProcessingStep is being explicitly tested. + static final class MultiAnnotationProcessingStep implements ProcessingStep { + + private SetMultimap, Element> elementsByAnnotation; + + @Override + public ImmutableSet> annotations() { + return ImmutableSet.of(AnAnnotation.class, ReferencesAClass.class); + } + + @Override + public ImmutableSet process( + SetMultimap, Element> elementsByAnnotation) { + this.elementsByAnnotation = elementsByAnnotation; + return ImmutableSet.of(); + } + + SetMultimap, Element> getElementsByAnnotation() { + return elementsByAnnotation; + } + } + + @Retention(RetentionPolicy.SOURCE) + public @interface ReferencesAClass { + Class value(); + } + + @Rule public CompilationRule compilation = new CompilationRule(); + + @Test + public void properlyDefersProcessing_typeElement() { + JavaFileObject classAFileObject = + JavaFileObjects.forSourceLines( + "test.ClassA", + "package test;", + "", + "@" + RequiresGeneratedCode.class.getCanonicalName(), + "public class ClassA {", + " SomeGeneratedClass sgc;", + "}"); + JavaFileObject classBFileObject = + JavaFileObjects.forSourceLines( + "test.ClassB", + "package test;", + "", + "@" + GeneratesCode.class.getCanonicalName(), + "public class ClassB {}"); RequiresGeneratedCodeProcessor requiresGeneratedCodeProcessor = new RequiresGeneratedCodeProcessor(); assertAbout(javaSources()) @@ -244,22 +307,22 @@ public class BasicAnnotationProcessorTest { .generatesFileNamed(SOURCE_OUTPUT, "test", "ValidInRound2XYZ.java"); } - @Retention(RetentionPolicy.SOURCE) - public @interface ReferencesAClass { - Class value(); - } - - @Test public void properlyDefersProcessing_packageElement() { - JavaFileObject classAFileObject = JavaFileObjects.forSourceLines("test.ClassA", - "package test;", - "", - "@" + GeneratesCode.class.getCanonicalName(), - "public class ClassA {", - "}"); - JavaFileObject packageFileObject = JavaFileObjects.forSourceLines("test.package-info", - "@" + RequiresGeneratedCode.class.getCanonicalName(), - "@" + ReferencesAClass.class.getCanonicalName() + "(SomeGeneratedClass.class)", - "package test;"); + @Test + public void properlyDefersProcessing_packageElement() { + JavaFileObject classAFileObject = + JavaFileObjects.forSourceLines( + "test.ClassA", + "package test;", + "", + "@" + GeneratesCode.class.getCanonicalName(), + "public class ClassA {", + "}"); + JavaFileObject packageFileObject = + JavaFileObjects.forSourceLines( + "test.package-info", + "@" + RequiresGeneratedCode.class.getCanonicalName(), + "@" + ReferencesAClass.class.getCanonicalName() + "(SomeGeneratedClass.class)", + "package test;"); RequiresGeneratedCodeProcessor requiresGeneratedCodeProcessor = new RequiresGeneratedCodeProcessor(); assertAbout(javaSources()) @@ -272,21 +335,28 @@ public class BasicAnnotationProcessorTest { assertThat(requiresGeneratedCodeProcessor.rejectedRounds).isEqualTo(0); } - @Test public void properlyDefersProcessing_argumentElement() { - JavaFileObject classAFileObject = JavaFileObjects.forSourceLines("test.ClassA", - "package test;", - "", - "public class ClassA {", - " SomeGeneratedClass sgc;", - " public void myMethod(@" + RequiresGeneratedCode.class.getCanonicalName() + " int myInt)", - " {}", - "}"); - JavaFileObject classBFileObject = JavaFileObjects.forSourceLines("test.ClassB", - "package test;", - "", - "public class ClassB {", - " public void myMethod(@" + GeneratesCode.class.getCanonicalName() + " int myInt) {}", - "}"); + @Test + public void properlyDefersProcessing_argumentElement() { + JavaFileObject classAFileObject = + JavaFileObjects.forSourceLines( + "test.ClassA", + "package test;", + "", + "public class ClassA {", + " SomeGeneratedClass sgc;", + " public void myMethod(@" + + RequiresGeneratedCode.class.getCanonicalName() + + " int myInt)", + " {}", + "}"); + JavaFileObject classBFileObject = + JavaFileObjects.forSourceLines( + "test.ClassB", + "package test;", + "", + "public class ClassB {", + " public void myMethod(@" + GeneratesCode.class.getCanonicalName() + " int myInt) {}", + "}"); RequiresGeneratedCodeProcessor requiresGeneratedCodeProcessor = new RequiresGeneratedCodeProcessor(); assertAbout(javaSources()) @@ -311,11 +381,13 @@ public class BasicAnnotationProcessorTest { " @" + AnAnnotation.class.getCanonicalName(), " public void method() {}", "}"); - JavaFileObject classBFileObject = JavaFileObjects.forSourceLines("test.ClassB", - "package test;", - "", - "@" + GeneratesCode.class.getCanonicalName(), - "public class ClassB {}"); + JavaFileObject classBFileObject = + JavaFileObjects.forSourceLines( + "test.ClassB", + "package test;", + "", + "@" + GeneratesCode.class.getCanonicalName(), + "public class ClassB {}"); RequiresGeneratedCodeProcessor requiresGeneratedCodeProcessor = new RequiresGeneratedCodeProcessor(); assertAbout(javaSources()) @@ -332,8 +404,8 @@ public class BasicAnnotationProcessorTest { assertThat(requiresGeneratedCodeProcessor.processArguments()) .comparingElementsUsing(setMultimapValuesByString()) .containsExactly( - ImmutableSetMultimap.of(RequiresGeneratedCode.class, "test.ClassA"), - ImmutableSetMultimap.of(RequiresGeneratedCode.class, "test.ClassA")) + ImmutableSetMultimap.of(RequiresGeneratedCode.class.getCanonicalName(), "test.ClassA"), + ImmutableSetMultimap.of(RequiresGeneratedCode.class.getCanonicalName(), "test.ClassA")) .inOrder(); } @@ -345,20 +417,60 @@ public class BasicAnnotationProcessorTest { "is equivalent comparing multimap values by `toString()` to"); } - @Test public void reportsMissingType() { - JavaFileObject classAFileObject = JavaFileObjects.forSourceLines("test.ClassA", - "package test;", - "", - "@" + RequiresGeneratedCode.class.getCanonicalName(), - "public class ClassA {", - " SomeGeneratedClass bar;", - "}"); + @Test + public void properlySkipsMissingAnnotations_generatesClass() { + JavaFileObject source = + JavaFileObjects.forSourceLines( + "test.ValidInRound2", + "package test;", + "", + "@" + AnAnnotation.class.getCanonicalName(), + "public class ValidInRound2 {", + " ValidInRound1XYZ vir1xyz;", + " @" + AnAnnotation.class.getCanonicalName(), + " static class ValidInRound1 {}", + "}"); + Compilation compilation = + javac().withProcessors(new MissingAnnotationProcessor()).compile(source); + assertThat(compilation).succeeded(); + assertThat(compilation).generatedSourceFile("test.ValidInRound2XYZ"); + } + + @Test + public void properlySkipsMissingAnnotations_passesValidAnnotationsToProcess() { + JavaFileObject source = + JavaFileObjects.forSourceLines( + "test.ClassA", + "package test;", + "", + "@" + AnAnnotation.class.getCanonicalName(), + "public class ClassA {", + "}"); + MissingAnnotationProcessor missingAnnotationProcessor = new MissingAnnotationProcessor(); + assertThat(javac().withProcessors(missingAnnotationProcessor).compile(source)).succeeded(); + assertThat(missingAnnotationProcessor.getElementsByAnnotation().keySet()) + .containsExactly(AnAnnotation.class.getCanonicalName()); + assertThat(missingAnnotationProcessor.getElementsByAnnotation().values()).hasSize(1); + } + + @Test + public void reportsMissingType() { + JavaFileObject classAFileObject = + JavaFileObjects.forSourceLines( + "test.ClassA", + "package test;", + "", + "@" + RequiresGeneratedCode.class.getCanonicalName(), + "public class ClassA {", + " SomeGeneratedClass bar;", + "}"); assertAbout(javaSources()) .that(ImmutableList.of(classAFileObject)) .processedWith(new RequiresGeneratedCodeProcessor()) .failsToCompile() .withErrorContaining(RequiresGeneratedCodeProcessor.class.getCanonicalName()) - .in(classAFileObject).onLine(4); + .in(classAFileObject) + .onLine(4); } @Test @@ -378,6 +490,45 @@ public class BasicAnnotationProcessorTest { .withErrorContaining("purposeful"); } + @Test + public void processingStepAsStepAnnotationsNamesMatchClasses() { + Step step = BasicAnnotationProcessor.asStep(new MultiAnnotationProcessingStep()); + + assertThat(step.annotations()) + .containsExactly( + AnAnnotation.class.getCanonicalName(), ReferencesAClass.class.getCanonicalName()); + } + + /** + * Tests that a {@link ProcessingStep} passed to {@link + * BasicAnnotationProcessor#asStep(ProcessingStep)} still gets passed the correct arguments to + * {@link Step#process(ImmutableSetMultimap)}. + */ + @Test + public void processingStepAsStepProcessElementsMatchClasses() { + Elements elements = compilation.getElements(); + String anAnnotationName = AnAnnotation.class.getCanonicalName(); + String referencesAClassName = ReferencesAClass.class.getCanonicalName(); + TypeElement anAnnotationElement = elements.getTypeElement(anAnnotationName); + TypeElement referencesAClassElement = elements.getTypeElement(referencesAClassName); + MultiAnnotationProcessingStep processingStep = new MultiAnnotationProcessingStep(); + + BasicAnnotationProcessor.asStep(processingStep) + .process( + ImmutableSetMultimap.of( + anAnnotationName, + anAnnotationElement, + referencesAClassName, + referencesAClassElement)); + + assertThat(processingStep.getElementsByAnnotation()) + .containsExactly( + AnAnnotation.class, + anAnnotationElement, + ReferencesAClass.class, + referencesAClassElement); + } + private static void generateClass(Filer filer, String generatedClassName) { PrintWriter writer = null; try { -- cgit v1.2.3 From da84ef1fae38f2d72901c2b95674271e89600f28 Mon Sep 17 00:00:00 2001 From: emcmanus Date: Thu, 18 Jun 2020 11:47:50 -0700 Subject: Tests related to e62e0abd2fbdfd2512c292ef95d4d152a5ca0691 RELNOTES=n/a ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=317148258 --- .../java/com/google/auto/factory/DaggerModule.java | 11 ++++++ .../com/google/auto/factory/FactoryComponent.java | 5 +++ .../com/google/auto/factory/ReferencePackage.java | 38 +++++++++++++++++++++ .../auto/factory/otherpackage/OtherPackage.java | 39 ++++++++++++++++++++++ .../DependencyInjectionIntegrationTest.java | 22 ++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 factory/src/it/functional/src/main/java/com/google/auto/factory/ReferencePackage.java create mode 100644 factory/src/it/functional/src/main/java/com/google/auto/factory/otherpackage/OtherPackage.java diff --git a/factory/src/it/functional/src/main/java/com/google/auto/factory/DaggerModule.java b/factory/src/it/functional/src/main/java/com/google/auto/factory/DaggerModule.java index be9478fc..4c4a38af 100644 --- a/factory/src/it/functional/src/main/java/com/google/auto/factory/DaggerModule.java +++ b/factory/src/it/functional/src/main/java/com/google/auto/factory/DaggerModule.java @@ -15,6 +15,7 @@ */ package com.google.auto.factory; +import com.google.auto.factory.otherpackage.OtherPackage; import dagger.Module; import dagger.Provides; @@ -45,4 +46,14 @@ final class DaggerModule { Number provideNumber() { return 3; } + + @Provides + ReferencePackage provideReferencePackage(ReferencePackageFactory factory) { + return factory.create(17); + } + + @Provides + OtherPackage provideOtherPackage() { + return new OtherPackage(null, 23); + } } diff --git a/factory/src/it/functional/src/main/java/com/google/auto/factory/FactoryComponent.java b/factory/src/it/functional/src/main/java/com/google/auto/factory/FactoryComponent.java index 7d0a1627..b5bbe3d9 100644 --- a/factory/src/it/functional/src/main/java/com/google/auto/factory/FactoryComponent.java +++ b/factory/src/it/functional/src/main/java/com/google/auto/factory/FactoryComponent.java @@ -15,6 +15,7 @@ */ package com.google.auto.factory; +import com.google.auto.factory.otherpackage.OtherPackageFactory; import dagger.Component; /** A component to materialize the factory using Dagger 2 */ @@ -23,4 +24,8 @@ interface FactoryComponent { FooFactory factory(); GenericFooFactory generatedFactory(); + + ReferencePackageFactory referencePackageFactory(); + + OtherPackageFactory otherPackageFactory(); } diff --git a/factory/src/it/functional/src/main/java/com/google/auto/factory/ReferencePackage.java b/factory/src/it/functional/src/main/java/com/google/auto/factory/ReferencePackage.java new file mode 100644 index 00000000..22aff651 --- /dev/null +++ b/factory/src/it/functional/src/main/java/com/google/auto/factory/ReferencePackage.java @@ -0,0 +1,38 @@ +/* + * Copyright 2020 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; + +import com.google.auto.factory.otherpackage.OtherPackage; +import com.google.auto.factory.otherpackage.OtherPackageFactory; +import javax.inject.Inject; + +@AutoFactory +public class ReferencePackage { + private final OtherPackageFactory otherPackageFactory; + private final int random; + + @Inject + public ReferencePackage( + @Provided OtherPackageFactory otherPackageFactory, + int random) { + this.otherPackageFactory = otherPackageFactory; + this.random = random; + } + + public OtherPackage otherPackage() { + return otherPackageFactory.create(random); + } +} diff --git a/factory/src/it/functional/src/main/java/com/google/auto/factory/otherpackage/OtherPackage.java b/factory/src/it/functional/src/main/java/com/google/auto/factory/otherpackage/OtherPackage.java new file mode 100644 index 00000000..b9925a18 --- /dev/null +++ b/factory/src/it/functional/src/main/java/com/google/auto/factory/otherpackage/OtherPackage.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020 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.otherpackage; + +import com.google.auto.factory.AutoFactory; +import com.google.auto.factory.Provided; +import com.google.auto.factory.ReferencePackageFactory; + +@AutoFactory +public class OtherPackage { + private final ReferencePackageFactory referencePackageFactory; + private final int random; + + public OtherPackage(@Provided ReferencePackageFactory referencePackageFactory, int random) { + this.referencePackageFactory = referencePackageFactory; + this.random = random; + } + + public ReferencePackageFactory referencePackageFactory() { + return referencePackageFactory; + } + + public int random() { + return random; + } +} diff --git a/factory/src/it/functional/src/test/java/com/google/auto/factory/DependencyInjectionIntegrationTest.java b/factory/src/it/functional/src/test/java/com/google/auto/factory/DependencyInjectionIntegrationTest.java index ebd83367..e1412117 100644 --- a/factory/src/it/functional/src/test/java/com/google/auto/factory/DependencyInjectionIntegrationTest.java +++ b/factory/src/it/functional/src/test/java/com/google/auto/factory/DependencyInjectionIntegrationTest.java @@ -4,6 +4,7 @@ import static com.google.common.truth.Truth.assertThat; import com.google.auto.factory.GenericFoo.DepE; import com.google.auto.factory.GenericFoo.IntAndStringAccessor; +import com.google.auto.factory.otherpackage.OtherPackage; import com.google.common.collect.ImmutableList; import com.google.inject.Guice; import com.google.inject.Key; @@ -64,6 +65,16 @@ public class DependencyInjectionIntegrationTest { assertThat(four.getDepE()).isEqualTo(DepE.VALUE_2); } + @Test + public void daggerInjectedPackageSpanningFactory() { + FactoryComponent component = DaggerFactoryComponent.create(); + ReferencePackageFactory referencePackageFactory = component.referencePackageFactory(); + ReferencePackage referencePackage = referencePackageFactory.create(5); + OtherPackage otherPackage = referencePackage.otherPackage(); + assertThat(otherPackage.referencePackageFactory()).isNotSameInstanceAs(referencePackageFactory); + assertThat(otherPackage.random()).isEqualTo(5); + } + @Test public void guiceInjectedFactory() { FooFactory fooFactory = Guice.createInjector(new GuiceModule()).getInstance(FooFactory.class); Foo one = fooFactory.create("A"); @@ -109,4 +120,15 @@ public class DependencyInjectionIntegrationTest { assertThat(four.passThrough(5L)).isEqualTo(5L); assertThat(four.getDepE()).isEqualTo(DepE.VALUE_2); } + + @Test + public void guiceInjectedPackageSpanningFactory() { + ReferencePackageFactory referencePackageFactory = + Guice.createInjector(new GuiceModule()) + .getInstance(ReferencePackageFactory.class); + ReferencePackage referencePackage = referencePackageFactory.create(5); + OtherPackage otherPackage = referencePackage.otherPackage(); + assertThat(otherPackage.referencePackageFactory()).isNotSameInstanceAs(referencePackageFactory); + assertThat(otherPackage.random()).isEqualTo(5); + } } -- cgit v1.2.3 From d9d66ad60b4a09f74b7a9822fb347a1dbedf28f4 Mon Sep 17 00:00:00 2001 From: emcmanus Date: Wed, 8 Jul 2020 07:14:15 -0700 Subject: Fix handling of `@Nullable Optional foo()` properties being set by `setFoo(@Nullable T)` setters. Previously calling `setFoo(null)` resulted in the property being set to `null`, even though for `Optional foo()` (without `@Nullable`) it would set the property to `Optional.empty()`. With this change, it is set to `Optional.empty()` whether or not it is `@Nullable`. RELNOTES=Fixed handling of `@Nullable Optional foo()` properties being set by `setFoo(@Nullable T)` setters. Now `setFoo(null)` results in `Optional.empty()`, not `null`. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=320181666 --- .../com/google/auto/value/AutoValueJava8Test.java | 81 ++++++++++++---------- .../value/processor/BuilderMethodClassifier.java | 23 ++++-- .../google/auto/value/processor/BuilderSpec.java | 38 +++++++--- 3 files changed, 91 insertions(+), 51 deletions(-) diff --git a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java index 27356c52..10812f8d 100644 --- a/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java +++ b/value/src/it/functional/src/test/java/com/google/auto/value/AutoValueJava8Test.java @@ -19,7 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static com.google.common.truth.Truth8.assertThat; import static com.google.testing.compile.CompilationSubject.assertThat; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeTrue; import com.google.common.collect.ImmutableList; @@ -375,12 +375,9 @@ public class AutoValueJava8Test { @Test public void testNotNullablePrimitiveArrays() { - try { - PrimitiveArrays.create(null, new int[0]); - fail("Construction with null value for non-@Nullable array should have failed"); - } catch (NullPointerException e) { - assertThat(e.getMessage()).contains("booleans"); - } + NullPointerException e = + assertThrows(NullPointerException.class, () -> PrimitiveArrays.create(null, new int[0])); + assertThat(e).hasMessageThat().contains("booleans"); } @AutoValue @@ -421,12 +418,10 @@ public class AutoValueJava8Test { assertThat(instance3.notNullable()).isEqualTo("hello"); assertThat(instance3.nullable()).isEqualTo("world"); - try { - NullablePropertyWithBuilder.builder().build(); - fail("Expected IllegalStateException for unset non-@Nullable property"); - } catch (IllegalStateException e) { - assertThat(e.getMessage()).contains("notNullable"); - } + IllegalStateException e = + assertThrows( + IllegalStateException.class, () -> NullablePropertyWithBuilder.builder().build()); + assertThat(e).hasMessageThat().contains("notNullable"); } @AutoValue @@ -470,13 +465,41 @@ public class AutoValueJava8Test { assertThat(instance3.notOptional()).isEqualTo("hello"); assertThat(instance3.optional()).hasValue("world"); - try { - OptionalPropertyWithNullableBuilder.builder().build(); - fail("Expected IllegalStateException for unset non-Optional property"); - } catch (IllegalStateException expected) { + assertThrows( + IllegalStateException.class, () -> OptionalPropertyWithNullableBuilder.builder().build()); + } + + @AutoValue + public abstract static class NullableOptionalPropertyWithNullableBuilder { + public abstract @Nullable Optional optional(); + + public static Builder builder() { + return new AutoValue_AutoValueJava8Test_NullableOptionalPropertyWithNullableBuilder.Builder(); + } + + @AutoValue.Builder + public interface Builder { + Builder optional(@Nullable String s); + + NullableOptionalPropertyWithNullableBuilder build(); } } + @Test + public void testNullableOptional() { + NullableOptionalPropertyWithNullableBuilder instance1 = + NullableOptionalPropertyWithNullableBuilder.builder().build(); + assertThat(instance1.optional()).isNull(); + + NullableOptionalPropertyWithNullableBuilder instance2 = + NullableOptionalPropertyWithNullableBuilder.builder().optional(null).build(); + assertThat(instance2.optional()).isEmpty(); + + NullableOptionalPropertyWithNullableBuilder instance3 = + NullableOptionalPropertyWithNullableBuilder.builder().optional("haruspex").build(); + assertThat(instance3.optional()).hasValue("haruspex"); + } + @AutoValue @SuppressWarnings("AutoValueImmutableFields") public abstract static class BuilderWithUnprefixedGetters> { @@ -522,18 +545,10 @@ public class AutoValueJava8Test { BuilderWithUnprefixedGetters.Builder builder = BuilderWithUnprefixedGetters.builder(); assertThat(builder.t()).isNull(); - try { - builder.list(); - fail("Attempt to retrieve unset list property should have failed"); - } catch (IllegalStateException e) { - assertThat(e).hasMessageThat().isEqualTo("Property \"list\" has not been set"); - } - try { - builder.ints(); - fail("Attempt to retrieve unset ints property should have failed"); - } catch (IllegalStateException e) { - assertThat(e).hasMessageThat().isEqualTo("Property \"ints\" has not been set"); - } + IllegalStateException e1 = assertThrows(IllegalStateException.class, () -> builder.list()); + assertThat(e1).hasMessageThat().isEqualTo("Property \"list\" has not been set"); + IllegalStateException e2 = assertThrows(IllegalStateException.class, () -> builder.ints()); + assertThat(e2).hasMessageThat().isEqualTo("Property \"ints\" has not been set"); builder.setList(names); assertThat(builder.list()).isSameInstanceAs(names); @@ -596,12 +611,8 @@ public class AutoValueJava8Test { BuilderWithPrefixedGetters.Builder builder = BuilderWithPrefixedGetters.builder(); assertThat(builder.getInts()).isNull(); - try { - builder.getList(); - fail("Attempt to retrieve unset list property should have failed"); - } catch (IllegalStateException e) { - assertThat(e).hasMessageThat().isEqualTo("Property \"list\" has not been set"); - } + IllegalStateException e = assertThrows(IllegalStateException.class, () -> builder.getList()); + assertThat(e).hasMessageThat().isEqualTo("Property \"list\" has not been set"); builder.setList(names); assertThat(builder.getList()).isSameInstanceAs(names); diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java index 724a3225..3e510a4a 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java @@ -20,6 +20,7 @@ import static com.google.common.collect.Sets.difference; import com.google.auto.common.MoreElements; import com.google.auto.common.MoreTypes; +import com.google.auto.value.processor.BuilderSpec.Copier; import com.google.auto.value.processor.BuilderSpec.PropertySetter; import com.google.auto.value.processor.PropertyBuilderClassifier.PropertyBuilder; import com.google.common.base.Equivalence; @@ -376,7 +377,7 @@ class BuilderMethodClassifier { checkForFailedJavaBean(method); return; } - Optional> function = getSetterFunction(valueGetter, method); + Optional function = getSetterFunction(valueGetter, method); if (function.isPresent()) { DeclaredType builderTypeMirror = MoreTypes.asDeclared(builderType.asType()); ExecutableType methodMirror = @@ -419,7 +420,7 @@ class BuilderMethodClassifier { * using a method like {@code ImmutableList.copyOf} or {@code Optional.of}, when the returned * function will be something like {@code s -> "Optional.of(" + s + ")"}. */ - private Optional> getSetterFunction( + private Optional getSetterFunction( ExecutableElement valueGetter, ExecutableElement setter) { VariableElement parameterElement = Iterables.getOnlyElement(setter.getParameters()); boolean nullableParameter = @@ -445,7 +446,7 @@ class BuilderMethodClassifier { return Optional.empty(); } } - return Optional.of(s -> s); + return Optional.of(Copier.IDENTITY); } // Parameter type is not equal to property type, but might be convertible with copyOf. @@ -465,14 +466,14 @@ class BuilderMethodClassifier { * to the getter's return type using one of the given methods, or {@code Optional.empty()} if the * conversion isn't possible. An error will have been reported in the latter case. */ - private Optional> getConvertingSetterFunction( + private Optional getConvertingSetterFunction( ImmutableList copyOfMethods, ExecutableElement valueGetter, ExecutableElement setter, TypeMirror parameterType) { DeclaredType targetType = MoreTypes.asDeclared(getterToPropertyType.get(valueGetter)); for (ExecutableElement copyOfMethod : copyOfMethods) { - Optional> function = + Optional function = getConvertingSetterFunction(copyOfMethod, targetType, parameterType); if (function.isPresent()) { return function; @@ -516,7 +517,7 @@ class BuilderMethodClassifier { * @return a function that maps a string parameter to a method call using that parameter. For * example it might map {@code foo} to {@code ImmutableList.copyOf(foo)}. */ - private Optional> getConvertingSetterFunction( + private Optional getConvertingSetterFunction( ExecutableElement copyOfMethod, DeclaredType targetType, TypeMirror parameterType) { // We have a parameter type, for example Set, and we want to know if it can be // passed to the given copyOf method, which might for example be one of these methods from @@ -532,7 +533,15 @@ class BuilderMethodClassifier { if (TypeVariables.canAssignStaticMethodResult( copyOfMethod, parameterType, targetType, typeUtils)) { String method = TypeEncoder.encodeRaw(targetType) + "." + copyOfMethod.getSimpleName(); - return Optional.of(s -> method + "(" + s + ")"); + Function callMethod = s -> method + "(" + s + ")"; + // This is a big old hack. We guess that the method can accept a null parameter if it has + // "Nullable" in the name, which java.util.Optional.ofNullable and + // com.google.common.base.Optional.fromNullable do. + Copier copier = + method.contains("Nullable") + ? Copier.acceptingNull(callMethod) + : Copier.notAcceptingNull(callMethod); + return Optional.of(copier); } return Optional.empty(); } diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java index 613d5457..2c8c17b1 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java @@ -353,6 +353,30 @@ class BuilderSpec { } } + /** + * Specifies how to copy a parameter value into the target type. This might be the identity, or + * it might be something like {@code ImmutableList.of(...)} or {@code Optional.ofNullable(...)}. + */ + static class Copier { + static final Copier IDENTITY = acceptingNull(x -> x); + + private final Function copy; + private final boolean acceptsNull; + + private Copier(Function copy, boolean acceptsNull) { + this.copy = copy; + this.acceptsNull = acceptsNull; + } + + static Copier acceptingNull(Function copy) { + return new Copier(copy, true); + } + + static Copier notAcceptingNull(Function copy) { + return new Copier(copy, false); + } + } + /** * Information about a property setter, referenced from the autovalue.vm template. A property * called foo (defined by a method {@code T foo()} or {@code T getFoo()}) can have a setter method @@ -369,12 +393,11 @@ class BuilderSpec { private final String parameterTypeString; private final boolean primitiveParameter; private final String nullableAnnotation; - private final Function copyFunction; + private final Copier copier; - PropertySetter( - ExecutableElement setter, TypeMirror parameterType, Function copyFunction) { + PropertySetter(ExecutableElement setter, TypeMirror parameterType, Copier copier) { this.setter = setter; - this.copyFunction = copyFunction; + this.copier = copier; this.access = SimpleMethod.access(setter); this.name = setter.getSimpleName().toString(); primitiveParameter = parameterType.getKind().isPrimitive(); @@ -423,13 +446,10 @@ class BuilderSpec { } public String copy(AutoValueProcessor.Property property) { - String copy = copyFunction.apply(property.toString()); - - // Add a null guard only in cases where we are using copyOf and the property is @Nullable. - if (property.isNullable() && !copy.equals(property.toString())) { + String copy = copier.copy.apply(property.toString()); + if (property.isNullable() && !copier.acceptsNull) { copy = String.format("(%s == null ? null : %s)", property, copy); } - return copy; } } -- cgit v1.2.3 From b48441776bb1eefe120dd4de5711e50209f46917 Mon Sep 17 00:00:00 2001 From: spishak Date: Wed, 8 Jul 2020 08:50:55 -0700 Subject: Stop the LazyInit annotation from getting shaded by Maven, so that AutoValue can find it on the classpath. The @LazyInit annotation is added if it's found on the classpath (https://github.com/google/auto/blob/da84ef1fae38f2d72901c2b95674271e89600f28/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java#L577) but shading rewrites the package at https://github.com/google/auto/blob/da84ef1fae38f2d72901c2b95674271e89600f28/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java#L104 from "com.google.errorprone.annotations.concurrent" to "autovalue.shaded.com.google$.errorprone.annotations.$concurrent" (you can verify this by disassembling the bytecode for MemoizeExtension.class in the release JAR). This means that even with the Error Prone annotations on the classpath, it won't be able to find the LazyInit annotation. Splitting up the package with a call to String#concat means Maven will no longer rewrite it, so AutoValue will be able to find the LazyInit annotation on the classpath if it's there. Fixes https://github.com/google/auto/issues/427 RELNOTES=Stop the LazyInit annotation from getting shaded by Maven, so that AutoValue can find it on the classpath. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=320196133 --- .../auto/value/extension/memoized/processor/MemoizeExtension.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java b/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java index db2f2212..0ca46bde 100644 --- a/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java +++ b/value/src/main/java/com/google/auto/value/extension/memoized/processor/MemoizeExtension.java @@ -100,8 +100,11 @@ public final class MemoizeExtension extends AutoValueExtension { private static final String AUTO_VALUE_NAME = AUTO_VALUE_PACKAGE_NAME + "AutoValue"; private static final String COPY_ANNOTATIONS_NAME = AUTO_VALUE_NAME + ".CopyAnnotations"; + // Maven is configured to shade (rewrite) com.google packages to prevent dependency conflicts. + // Split up the package here with a call to concat to prevent Maven from finding and rewriting it, + // so that this will be able to find the LazyInit annotation if it's on the classpath. private static final ClassName LAZY_INIT = - ClassName.get("com.google.errorprone.annotations.concurrent", "LazyInit"); + ClassName.get("com".concat(".google.errorprone.annotations.concurrent"), "LazyInit"); private static final AnnotationSpec SUPPRESS_WARNINGS = AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "Immutable").build(); -- cgit v1.2.3 From c59110e29699bd2fcb3223cf306f62669ddfdc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89amonn=20McManus?= Date: Wed, 8 Jul 2020 16:32:02 -0700 Subject: Set version number for auto-value-parent to 1.7.4. --- value/annotations/pom.xml | 4 ++-- value/pom.xml | 2 +- value/processor/pom.xml | 4 ++-- value/src/it/functional/pom.xml | 4 ++-- value/src/it/gwtserializer/pom.xml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/value/annotations/pom.xml b/value/annotations/pom.xml index d0d4a6bb..d6c03de5 100644 --- a/value/annotations/pom.xml +++ b/value/annotations/pom.xml @@ -21,12 +21,12 @@ com.google.auto.value auto-value-parent - HEAD-SNAPSHOT + 1.7.4 com.google.auto.value auto-value-annotations - HEAD-SNAPSHOT + 1.7.4 AutoValue Annotations Immutable value-type code generation for Java 1.6+. diff --git a/value/pom.xml b/value/pom.xml index 9f8be5ac..dcf2cb1d 100644 --- a/value/pom.xml +++ b/value/pom.xml @@ -26,7 +26,7 @@ com.google.auto.value auto-value-parent - HEAD-SNAPSHOT + 1.7.4 AutoValue Parent Immutable value-type code generation for Java 7+. diff --git a/value/processor/pom.xml b/value/processor/pom.xml index 0aa9ec8e..5968352c 100644 --- a/value/processor/pom.xml +++ b/value/processor/pom.xml @@ -21,12 +21,12 @@ com.google.auto.value auto-value-parent - HEAD-SNAPSHOT + 1.7.4 com.google.auto.value auto-value - HEAD-SNAPSHOT + 1.7.4 AutoValue Processor Immutable value-type code generation for Java 1.6+. diff --git a/value/src/it/functional/pom.xml b/value/src/it/functional/pom.xml index 4157da96..750b9c43 100644 --- a/value/src/it/functional/pom.xml +++ b/value/src/it/functional/pom.xml @@ -22,14 +22,14 @@ com.google.auto.value auto-value-parent - HEAD-SNAPSHOT + 1.7.4 ../../../pom.xml https://github.com/google/auto/tree/master/value com.google.auto.value.it.functional functional - HEAD-SNAPSHOT + 1.7.4 Auto-Value Functional Integration Test this-matches-nothing diff --git a/value/src/it/gwtserializer/pom.xml b/value/src/it/gwtserializer/pom.xml index cd56484e..eea89528 100644 --- a/value/src/it/gwtserializer/pom.xml +++ b/value/src/it/gwtserializer/pom.xml @@ -22,14 +22,14 @@ com.google.auto.value auto-value-parent - HEAD-SNAPSHOT + 1.7.4 ../../../pom.xml https://github.com/google/auto/tree/master/value com.google.auto.value.it.gwtserializer gwtserializer - HEAD-SNAPSHOT + 1.7.4 Auto-Value GWT-RPC Serialization Integration Test -- cgit v1.2.3 From 43ff5f2d34e7ac88bd0722281d07303618c85a07 Mon Sep 17 00:00:00 2001 From: rayt Date: Tue, 14 Jul 2020 16:27:21 -0700 Subject: AutoValue annotation can be provided scope. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=321258257 --- value/userguide/index.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/value/userguide/index.md b/value/userguide/index.md index 8cbe75fc..2e05d54b 100644 --- a/value/userguide/index.md +++ b/value/userguide/index.md @@ -92,6 +92,23 @@ For `auto-value-annotations`, you can write this in `pom.xml`: ``` +Some AutoValue annotations have CLASS retention. This is mostly of use for +compile-time tools, such as AutoValue itself. If you are creating +a library, the end user rarely needs to know the original AutoValue annotations. +In that case, you can set the scope to `provided`, so that the user of your +library does not have `auto-value-annotations` as a transitive dependency. + +```xml + + + com.google.auto.value + auto-value-annotations + ${auto-value.version} + provided + + +``` + For `auto-value` (the annotation processor), you can write this: ```xml -- cgit v1.2.3 From c6e35e68633050bab97230d496ae1765605c186e Mon Sep 17 00:00:00 2001 From: emcmanus Date: Sun, 26 Jul 2020 10:27:53 -0700 Subject: Add `[tags]` to AutoValue error messages. This will enable them to be correlated so that we can potentially see which ones are commonest. RELNOTES=AutoValue error messages now have short `[tags]` so they can be correlated by tools. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=323252839 --- .../auto/value/processor/AutoOneOfProcessor.java | 26 ++++++---- .../value/processor/AutoValueOrOneOfProcessor.java | 56 ++++++++++++++-------- .../auto/value/processor/AutoValueProcessor.java | 39 ++++++++------- .../value/processor/BuilderMethodClassifier.java | 55 +++++++++++++-------- .../google/auto/value/processor/BuilderSpec.java | 24 ++++++---- .../value/processor/PropertyBuilderClassifier.java | 22 +++++---- 6 files changed, 139 insertions(+), 83 deletions(-) diff --git a/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java index d05ed43c..d73c1c29 100644 --- a/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java +++ b/value/src/main/java/com/google/auto/value/processor/AutoOneOfProcessor.java @@ -72,7 +72,9 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { void processType(TypeElement autoOneOfType) { if (autoOneOfType.getKind() != ElementKind.CLASS) { errorReporter() - .abortWithError(autoOneOfType, "@" + AUTO_ONE_OF_NAME + " only applies to classes"); + .abortWithError( + autoOneOfType, + "[AutoOneOfNotClass] @" + AUTO_ONE_OF_NAME + " only applies to classes"); } checkModifiersIfNested(autoOneOfType); DeclaredType kindMirror = mirrorForKindType(autoOneOfType); @@ -129,7 +131,7 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { errorReporter() .abortWithError( autoOneOfType, - "annotation processor for @AutoOneOf was invoked with a type" + "[AutoOneOfCompilerBug] annotation processor for @AutoOneOf was invoked with a type" + " that does not have that annotation; this is probably a compiler bug"); } AnnotationValue kindValue = @@ -184,7 +186,8 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( kindElement, - "Enum has no constant with name corresponding to property '%s'", + "[AutoOneOfNoEnumConstant] Enum has no constant with name corresponding to" + + " property '%s'", property); } }); @@ -195,7 +198,8 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( constant, - "Name of enum constant '%s' does not correspond to any property name", + "[AutoOneOfBadEnumConstant] Name of enum constant '%s' does not correspond to" + + " any property name", constant.getSimpleName()); } }); @@ -221,7 +225,7 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( autoOneOfType, - "%s must have a no-arg abstract method returning %s", + "[AutoOneOfNoKindGetter] %s must have a no-arg abstract method returning %s", autoOneOfType, kindMirror); break; @@ -230,7 +234,10 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { default: for (ExecutableElement getter : kindGetters) { errorReporter() - .reportError(getter, "More than one abstract method returns %s", kindMirror); + .reportError( + getter, + "[AutoOneOfTwoKindGetters] More than one abstract method returns %s", + kindMirror); } } throw new AbortProcessingException(); @@ -254,7 +261,8 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { // implement this alien method. errorReporter() .reportWarning( - method, "Abstract methods in @AutoOneOf classes must have no parameters"); + method, + "[AutoOneOfParams] Abstract methods in @AutoOneOf classes must have no parameters"); } } errorReporter().abortIfAnyError(); @@ -278,7 +286,9 @@ public class AutoOneOfProcessor extends AutoValueOrOneOfProcessor { @Override Optional nullableAnnotationForMethod(ExecutableElement propertyMethod) { if (nullableAnnotationFor(propertyMethod, propertyMethod.getReturnType()).isPresent()) { - errorReporter().reportError(propertyMethod, "@AutoOneOf properties cannot be @Nullable"); + errorReporter() + .reportError( + propertyMethod, "[AutoOneOfNullable] @AutoOneOf properties cannot be @Nullable"); } return Optional.empty(); } diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueOrOneOfProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoValueOrOneOfProcessor.java index 4214c128..36a82bd4 100644 --- a/value/src/main/java/com/google/auto/value/processor/AutoValueOrOneOfProcessor.java +++ b/value/src/main/java/com/google/auto/value/processor/AutoValueOrOneOfProcessor.java @@ -71,7 +71,6 @@ import javax.lang.model.element.QualifiedNameable; import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; -import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; @@ -301,7 +300,8 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { for (TypeElement type : deferredTypes) { errorReporter.reportError( type, - "Did not generate @%s class for %s because it references undefined types", + "[AutoValueUndefined] Did not generate @%s class for %s because it references" + + " undefined types", simpleAnnotationName, type.getQualifiedName()); } @@ -331,7 +331,10 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { } catch (RuntimeException e) { String trace = Throwables.getStackTraceAsString(e); errorReporter.reportError( - type, "@%s processor threw an exception: %s", simpleAnnotationName, trace); + type, + "[AutoValueException] @%s processor threw an exception: %s", + simpleAnnotationName, + trace); throw e; } } @@ -378,8 +381,9 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { ImmutableSet.Builder props = ImmutableSet.builder(); propertyMethodsAndTypes.forEach( (propertyMethod, returnType) -> { - String propertyType = TypeEncoder.encodeWithAnnotations( - returnType, getExcludedAnnotationTypes(propertyMethod)); + String propertyType = + TypeEncoder.encodeWithAnnotations( + returnType, getExcludedAnnotationTypes(propertyMethod)); String propertyName = methodToPropertyName.get(propertyMethod); String identifier = methodToIdentifier.get(propertyMethod); ImmutableList fieldAnnotations = @@ -399,7 +403,9 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { nullableAnnotation); props.add(p); if (p.isNullable() && returnType.getKind().isPrimitive()) { - errorReporter().reportError(propertyMethod, "Primitive types cannot be @Nullable"); + errorReporter() + .reportError( + propertyMethod, "[AutoValueNullPrimitive] Primitive types cannot be @Nullable"); } }); return props.build(); @@ -517,7 +523,10 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { // reportedDups prevents us from reporting more than one error for the same method. for (ExecutableElement context : contexts) { errorReporter.reportError( - context, "More than one @%s property called %s", simpleAnnotationName, name); + context, + "[AutoValueDupProperty] More than one @%s property called %s", + simpleAnnotationName, + name); } } } @@ -622,16 +631,18 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { if (enclosingKind.isClass() || enclosingKind.isInterface()) { if (type.getModifiers().contains(Modifier.PRIVATE)) { errorReporter.abortWithError( - type, "@%s class must not be private", simpleAnnotationName); + type, "[AutoValuePrivate] @%s class must not be private", simpleAnnotationName); } else if (Visibility.effectiveVisibilityOfElement(type).equals(Visibility.PRIVATE)) { // The previous case, where the class itself is private, is much commoner so it deserves // its own error message, even though it would be caught by the test here too. errorReporter.abortWithError( - type, "@%s class must not be nested in a private class", simpleAnnotationName); + type, + "[AutoValueInPrivate] @%s class must not be nested in a private class", + simpleAnnotationName); } if (!type.getModifiers().contains(Modifier.STATIC)) { errorReporter.abortWithError( - type, "Nested @%s class must be static", simpleAnnotationName); + type, "[AutoValueInner] Nested @%s class must be static", simpleAnnotationName); } } // In principle type.getEnclosingElement() could be an ExecutableElement (for a class @@ -766,13 +777,14 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { final void checkReturnType(TypeElement autoValueClass, ExecutableElement getter) { TypeMirror type = getter.getReturnType(); if (type.getKind() == TypeKind.ARRAY) { - TypeMirror componentType = ((ArrayType) type).getComponentType(); - if (componentType.getKind().isPrimitive()) { + TypeMirror componentType = MoreTypes.asArray(type).getComponentType(); + if (componentType.getKind().isPrimitive()) { warnAboutPrimitiveArrays(autoValueClass, getter); } else { errorReporter.reportError( getter, - "An @%s class cannot define an array-valued property unless it is a primitive array", + "[AutoValueArray] An @%s class cannot define an array-valued property unless it is a" + + " primitive array", simpleAnnotationName); } } @@ -799,10 +811,11 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { String context = sameClass ? "" : (" Method: " + getter.getEnclosingElement() + "." + getter); errorReporter.reportWarning( element, - "An @%s property that is a primitive array returns the original array, which can" - + " therefore be modified by the caller. If this is OK, you can suppress this warning" - + " with @SuppressWarnings(\"mutable\"). Otherwise, you should replace the property" - + " with an immutable type, perhaps a simple wrapper around the original array.%s", + "[AutoValueMutable] An @%s property that is a primitive array returns the original" + + " array, which can therefore be modified by the caller. If this is OK, you can" + + " suppress this warning with @SuppressWarnings(\"mutable\"). Otherwise, you should" + + " replace the property with an immutable type, perhaps a simple wrapper around the" + + " original array.%s", simpleAnnotationName, context); } @@ -815,8 +828,8 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { private static class ContainsMutableVisitor extends SimpleAnnotationValueVisitor8 { @Override public Boolean visitArray(List list, Void p) { - return list.stream().map(av -> av.getValue()).anyMatch("mutable"::equals); - } + return list.stream().map(AnnotationValue::getValue).anyMatch("mutable"::equals); + } } /** @@ -1102,7 +1115,10 @@ abstract class AutoValueOrOneOfProcessor extends AbstractProcessor { // error later because user code will have a reference to the code we were supposed to // generate (new AutoValue_Foo() or whatever) and that reference will be undefined. errorReporter.reportWarning( - originatingType, "Could not write generated class %s: %s", className, e); + originatingType, + "[AutoValueCouldNotWrite] Could not write generated class %s: %s", + className, + e); } } } diff --git a/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java b/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java index f3b396ca..aafffd7c 100644 --- a/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java +++ b/value/src/main/java/com/google/auto/value/processor/AutoValueProcessor.java @@ -121,8 +121,8 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportWarning( null, - "An exception occurred while looking for AutoValue extensions." - + " No extensions will function.%s\n%s", + "[AutoValueExtensionsException] An exception occurred while looking for AutoValue" + + " extensions. No extensions will function.%s\n%s", explain, Throwables.getStackTraceAsString(e)); extensions = ImmutableList.of(); @@ -170,19 +170,22 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .abortWithError( type, - "annotation processor for @AutoValue was invoked with a type" + "[AutoValueCompilerBug] annotation processor for @AutoValue was invoked with a type" + " that does not have that annotation; this is probably a compiler bug"); } if (type.getKind() != ElementKind.CLASS) { - errorReporter().abortWithError(type, "@AutoValue only applies to classes"); + errorReporter() + .abortWithError(type, "[AutoValueNotClass] @AutoValue only applies to classes"); } if (ancestorIsAutoValue(type)) { - errorReporter().abortWithError(type, "One @AutoValue class may not extend another"); + errorReporter() + .abortWithError(type, "[AutoValueExtend] One @AutoValue class may not extend another"); } if (implementsAnnotation(type)) { errorReporter() .abortWithError( - type, "@AutoValue may not be used to implement an annotation" + type, + "[AutoValueImplAnnotation] @AutoValue may not be used to implement an annotation" + " interface; try using @AutoAnnotation instead"); } checkModifiersIfNested(type); @@ -333,7 +336,8 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( type, - "More than one extension wants to generate the final class: %s", + "[AutoValueMultiFinal] More than one extension wants to generate the final class:" + + " %s", finalExtensions.stream().map(this::extensionName).collect(joining(", "))); break; } @@ -355,7 +359,8 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( type, - "Extension %s wants to consume a property that does not exist: %s", + "[AutoValueConsumeNonexist] Extension %s wants to consume a property that does" + + " not exist: %s", extensionName(extension), consumedProperty); } else { @@ -367,8 +372,8 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( type, - "Extension %s wants to consume a method that is not one of the abstract methods" - + " in this class: %s", + "[AutoValueConsumeNotAbstract] Extension %s wants to consume a method that is" + + " not one of the abstract methods in this class: %s", extensionName(extension), consumedMethod); } else { @@ -379,8 +384,8 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { errorReporter() .reportError( repeat, - "Extension %s wants to consume a method that was already consumed by another" - + " extension", + "[AutoValueMultiConsume] Extension %s wants to consume a method that was already" + + " consumed by another extension", extensionName(extension)); } consumed.addAll(consumedHere); @@ -404,10 +409,12 @@ public class AutoValueProcessor extends AutoValueOrOneOfProcessor { // another, and therefore leaves us with both an abstract method and the subclass method // that overrides it. This shows up in AutoValueTest.LukesBase for example. String extensionMessage = extensionsPresent ? ", and no extension consumed it" : ""; - errorReporter().reportWarning( - method, - "Abstract method is neither a property getter nor a Builder converter%s", - extensionMessage); + errorReporter() + .reportWarning( + method, + "[AutoValueBuilderWhat] Abstract method is neither a property getter nor a Builder" + + " converter%s", + extensionMessage); } } errorReporter().abortIfAnyError(); diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java index 3e510a4a..81751e30 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java @@ -198,7 +198,7 @@ class BuilderMethodClassifier { } else { errorReporter.reportError( propertyNameToUnprefixedSetters.values().iterator().next().getSetter(), - "If any setter methods use the setFoo convention then all must"); + "[AutoValueSetNotSet] If any setter methods use the setFoo convention then all must"); return false; } getterToPropertyName.forEach( @@ -220,10 +220,10 @@ class BuilderMethodClassifier { if (needToMakeBarBuilder && !canMakeBarBuilder) { errorReporter.reportError( propertyBuilder.getPropertyBuilderMethod(), - "Property builder method returns %1$s but there is no way to make that type" - + " from %2$s: %2$s does not have a non-static toBuilder() method that" - + " returns %1$s, and %1$s does not have a method addAll or" - + " putAll that accepts an argument of type %2$s", + "[AutoValueCantMakeBuilder] Property builder method returns %1$s but there is no" + + " way to make that type from %2$s: %2$s does not have a non-static" + + " toBuilder() method that returns %1$s, and %1$s does not have a method" + + " addAll or putAll that accepts an argument of type %2$s", propertyBuilder.getBuilderTypeMirror(), propertyType); } @@ -232,8 +232,13 @@ class BuilderMethodClassifier { String setterName = settersPrefixed ? prefixWithSet(property) : property; errorReporter.reportError( builderType, - "Expected a method with this signature: %s%s %s(%s), or a %sBuilder() method", - builderType, typeParamsString(), setterName, propertyType, property); + "[AutoValueBuilderMissingMethod] Expected a method with this signature: %s%s" + + " %s(%s), or a %sBuilder() method", + builderType, + typeParamsString(), + setterName, + propertyType, + property); } }); return errorReporter.errorCount() == startErrorCount; @@ -249,7 +254,8 @@ class BuilderMethodClassifier { classifyMethodOneArg(method); break; default: - errorReporter.reportError(method, "Builder methods must have 0 or 1 parameters"); + errorReporter.reportError( + method, "[AutoValueBuilderArgs] Builder methods must have 0 or 1 parameters"); } } @@ -297,10 +303,11 @@ class BuilderMethodClassifier { } else { errorReporter.reportError( method, - "Method without arguments should be a build method returning %1$s%2$s," - + " or a getter method with the same name and type as a getter method of %1$s," - + " or fooBuilder() where foo() or getFoo() is a getter method of %1$s", - autoValueClass, typeParamsString()); + "[AutoValueBuilderNoArg] Method without arguments should be a build method returning" + + " %1$s%2$s, or a getter method with the same name and type as a getter method of" + + " %1$s, or fooBuilder() where foo() or getFoo() is a getter method of %1$s", + autoValueClass, + typeParamsString()); } } @@ -335,9 +342,11 @@ class BuilderMethodClassifier { } errorReporter.reportError( builderGetter, - "Method matches a property of %1$s but has return type %2$s instead of %3$s " - + "or an Optional wrapping of %3$s", - autoValueClass, builderGetterType, originalGetterType); + "[AutoValueBuilderReturnType] Method matches a property of %1$s but has return type %2$s" + + " instead of %3$s or an Optional wrapping of %3$s", + autoValueClass, + builderGetterType, + originalGetterType); } /** @@ -373,7 +382,9 @@ class BuilderMethodClassifier { // The second disjunct isn't needed but convinces control-flow checkers that // propertyNameToSetters can't be null when we call put on it below. errorReporter.reportError( - method, "Method does not correspond to a property of %s", autoValueClass); + method, + "[AutoValueBuilderWhatProp] Method does not correspond to a property of %s", + autoValueClass); checkForFailedJavaBean(method); return; } @@ -441,8 +452,10 @@ class BuilderMethodClassifier { if (!nullableProperty) { errorReporter.reportError( setter, - "Parameter of setter method is @Nullable but property method %s.%s() is not", - autoValueClass, valueGetter.getSimpleName()); + "[AutoValueNullNotNull] Parameter of setter method is @Nullable but property method" + + " %s.%s() is not", + autoValueClass, + valueGetter.getSimpleName()); return Optional.empty(); } } @@ -456,7 +469,7 @@ class BuilderMethodClassifier { } errorReporter.reportError( setter, - "Parameter type %s of setter method should be %s to match getter %s.%s", + "[AutoValueGetVsSet] Parameter type %s of setter method should be %s to match getter %s.%s", parameterType, targetType, autoValueClass, valueGetter.getSimpleName()); return Optional.empty(); } @@ -482,8 +495,8 @@ class BuilderMethodClassifier { String targetTypeSimpleName = targetType.asElement().getSimpleName().toString(); errorReporter.reportError( setter, - "Parameter type %s of setter method should be %s to match getter %s.%s," - + " or it should be a type that can be passed to %s.%s to produce %s", + "[AutoValueGetVsSetOrConvert] Parameter type %s of setter method should be %s to match" + + " getter %s.%s, or it should be a type that can be passed to %s.%s to produce %s", parameterType, targetType, autoValueClass, diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java index 2c8c17b1..7e5b17c9 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderSpec.java @@ -86,14 +86,17 @@ class BuilderSpec { if (hasAnnotationMirror(containedClass, AUTO_VALUE_BUILDER_NAME)) { if (!CLASS_OR_INTERFACE.contains(containedClass.getKind())) { errorReporter.reportError( - containedClass, "@AutoValue.Builder can only apply to a class or an interface"); + containedClass, + "[AutoValueBuilderClass] @AutoValue.Builder can only apply to a class or an" + + " interface"); } else if (!containedClass.getModifiers().contains(Modifier.STATIC)) { errorReporter.reportError( - containedClass, "@AutoValue.Builder cannot be applied to a non-static class"); + containedClass, + "[AutoValueInnerBuilder] @AutoValue.Builder cannot be applied to a non-static class"); } else if (builderTypeElement.isPresent()) { errorReporter.reportError( containedClass, - "%s already has a Builder: %s", + "[AutoValueTwoBuilders] %s already has a Builder: %s", autoValueClass, builderTypeElement.get()); } else { @@ -218,7 +221,7 @@ class BuilderSpec { if (!builderTypeParamNames.equals(typeArguments)) { errorReporter.reportError( method, - "Builder converter method should return %s%s", + "[AutoValueBuilderConverterReturn] Builder converter method should return %s%s", builderTypeElement, TypeSimplifier.actualTypeParametersString(builderTypeElement)); } @@ -227,7 +230,8 @@ class BuilderSpec { ImmutableSet builderMethods = methods.build(); if (builderMethods.size() > 1) { errorReporter.reportError( - builderMethods.iterator().next(), "There can be at most one builder converter method"); + builderMethods.iterator().next(), + "[AutoValueTwoBuilderConverters] There can be at most one builder converter method"); } this.toBuilderMethods = builderMethods; return builderMethods; @@ -265,7 +269,9 @@ class BuilderSpec { // For now we ignore methods with annotations, because for example we do want to allow // Jackson's @JsonCreator. errorReporter.reportWarning( - method, "Static builder() method should be in the containing class"); + method, + "[AutoValueBuilderInBuilder] Static builder() method should be in the containing" + + " class"); } } this.classifier = optionalClassifier.get(); @@ -276,7 +282,8 @@ class BuilderSpec { for (Element buildMethod : errorElements) { errorReporter.reportError( buildMethod, - "Builder must have a single no-argument method returning %s%s", + "[AutoValueBuilderBuild] Builder must have a single no-argument method returning" + + " %s%s", autoValueClass, typeParamsString()); } @@ -470,7 +477,8 @@ class BuilderSpec { if (!sameTypeParameters(autoValueClass, builderTypeElement)) { errorReporter.reportError( builderTypeElement, - "Type parameters of %s must have same names and bounds as type parameters of %s", + "[AutoValueTypeParamMismatch] Type parameters of %s must have same names and bounds as" + + " type parameters of %s", builderTypeElement, autoValueClass); return Optional.empty(); diff --git a/value/src/main/java/com/google/auto/value/processor/PropertyBuilderClassifier.java b/value/src/main/java/com/google/auto/value/processor/PropertyBuilderClassifier.java index dafb5820..2565cddc 100644 --- a/value/src/main/java/com/google/auto/value/processor/PropertyBuilderClassifier.java +++ b/value/src/main/java/com/google/auto/value/processor/PropertyBuilderClassifier.java @@ -198,7 +198,8 @@ class PropertyBuilderClassifier { if (barBuilderTypeMirror.getKind() != TypeKind.DECLARED) { errorReporter.reportError( method, - "Method looks like a property builder, but its return type is not a class or interface"); + "[AutoValueOddBuilderMethod] Method looks like a property builder, but its return type" + + " is not a class or interface"); return Optional.empty(); } DeclaredType barBuilderDeclaredType = MoreTypes.asDeclared(barBuilderTypeMirror); @@ -210,15 +211,15 @@ class PropertyBuilderClassifier { if (barTypeMirror.getKind() != TypeKind.DECLARED) { errorReporter.reportError( method, - "Method looks like a property builder, but the type of property %s is not a class or" - + " interface", + "[AutoValueBadBuilderMethod] Method looks like a property builder, but the type of" + + " property %s is not a class or interface", property); return Optional.empty(); } if (isNullable(barGetter)) { errorReporter.reportError( barGetter, - "Property %s has a property builder so it cannot be @Nullable", + "[AutoValueNullBuilder] Property %s has a property builder so it cannot be @Nullable", property); } TypeElement barTypeElement = MoreTypes.asTypeElement(barTypeMirror); @@ -229,8 +230,8 @@ class PropertyBuilderClassifier { if (build == null || build.getModifiers().contains(Modifier.STATIC)) { errorReporter.reportError( method, - "Method looks like a property builder, but it returns %s which does not have a" - + " non-static build() method", + "[AutoValueBuilderNotBuildable] Method looks like a property builder, but it returns %s" + + " which does not have a non-static build() method", barBuilderTypeElement); return Optional.empty(); } @@ -241,7 +242,8 @@ class PropertyBuilderClassifier { if (!MoreTypes.equivalence().equivalent(barTypeMirror, buildType)) { errorReporter.reportError( method, - "Property builder for %s has type %s whose build() method returns %s instead of %s", + "[AutoValueBuilderWrongType] Property builder for %s has type %s whose build() method" + + " returns %s instead of %s", property, barBuilderTypeElement, buildType, @@ -254,9 +256,9 @@ class PropertyBuilderClassifier { if (!maybeBuilderMaker.isPresent()) { errorReporter.reportError( method, - "Method looks like a property builder, but its type %s does not have a public" - + " constructor and %s does not have a static builder() or newBuilder() method that" - + " returns %s", + "[AutoValueCantMakePropertyBuilder] Method looks like a property builder, but its type" + + " %s does not have a public constructor and %s does not have a static builder() or" + + " newBuilder() method that returns %s", barBuilderTypeElement, barTypeElement, barBuilderTypeElement); -- cgit v1.2.3 From 6c39b13727ce18e218c2b0ca47d6eb47b62164ab Mon Sep 17 00:00:00 2001 From: bcorso Date: Mon, 27 Jul 2020 13:13:45 -0700 Subject: Open SuperficialValidation#validateType(TypeMirror) to public visibility so it can be used from other internal code. RELNOTES=Open SuperficialValidation#validateType(TypeMirror) to public visibility ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=323425711 --- common/src/main/java/com/google/auto/common/SuperficialValidation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/com/google/auto/common/SuperficialValidation.java b/common/src/main/java/com/google/auto/common/SuperficialValidation.java index dddb1be9..83870754 100644 --- a/common/src/main/java/com/google/auto/common/SuperficialValidation.java +++ b/common/src/main/java/com/google/auto/common/SuperficialValidation.java @@ -163,7 +163,7 @@ public final class SuperficialValidation { } }; - private static boolean validateType(TypeMirror type) { + public static boolean validateType(TypeMirror type) { return type.accept(TYPE_VALIDATING_VISITOR, null); } -- cgit v1.2.3 From 85af4437bec3555aa14ee7c9be7234f6f5d2ec43 Mon Sep 17 00:00:00 2001 From: kpayson Date: Mon, 27 Jul 2020 16:09:49 -0700 Subject: Fully Qualify @Override to avoid name conflicts RELNOTES=Fully Qualify @Override to avoid name conflicts ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=323461838 --- .../google/auto/value/processor/autoannotation.vm | 10 +++++----- .../com/google/auto/value/processor/autooneof.vm | 20 ++++++++++---------- .../com/google/auto/value/processor/autovalue.vm | 18 +++++++++--------- .../com/google/auto/value/processor/gwtserializer.vm | 8 ++++---- .../value/processor/AutoValueCompilationTest.java | 8 +++++++- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/value/src/main/java/com/google/auto/value/processor/autoannotation.vm b/value/src/main/java/com/google/auto/value/processor/autoannotation.vm index 1d14d3fb..a953edab 100644 --- a/value/src/main/java/com/google/auto/value/processor/autoannotation.vm +++ b/value/src/main/java/com/google/auto/value/processor/autoannotation.vm @@ -108,7 +108,7 @@ final class $className implements $annotationName { ## annotationType method (defined by the Annotation interface) - @Override + @`java.lang.Override` public Class annotationType() { return ${annotationName}.class; } @@ -117,7 +117,7 @@ final class $className implements $annotationName { #foreach ($m in $members) - @Override + @`java.lang.Override` public ${m.type} ${m}() { #if ($m.kind == "ARRAY") @@ -162,7 +162,7 @@ final class $className implements $annotationName { #end #end - @Override + @`java.lang.Override` public String toString() { StringBuilder sb = new StringBuilder("@$annotationFullName("); @@ -211,7 +211,7 @@ final class $className implements $annotationName { #end #end - @Override + @`java.lang.Override` public boolean equals(Object o) { if (o == this) { return true; @@ -269,7 +269,7 @@ final class $className implements $annotationName { ## example.) We precompute the invariable part, as an optimization but also in order to avoid ## falling afoul of constant-overflow checks in the compiler. - @Override + @`java.lang.Override` public int hashCode() { return ## If the invariable part is 0, we avoid outputting `return 0 + ...` just because it generates diff --git a/value/src/main/java/com/google/auto/value/processor/autooneof.vm b/value/src/main/java/com/google/auto/value/processor/autooneof.vm index 04cc1949..0249d9eb 100644 --- a/value/src/main/java/com/google/auto/value/processor/autooneof.vm +++ b/value/src/main/java/com/google/auto/value/processor/autooneof.vm @@ -99,7 +99,7 @@ final class $generatedClass { #foreach ($p in $props) - @Override + @`java.lang.Override` $p.access $p.type ${p.getter}() { throw new UnsupportedOperationException(${kindGetter}().toString()); } @@ -128,7 +128,7 @@ final class $generatedClass { private Impl_$p() {} - @Override + @`java.lang.Override` public void ${p.getter}() {} #if ($serializable) @@ -141,7 +141,7 @@ final class $generatedClass { #if ($toString) - @Override + @`java.lang.Override` public String toString() { return "${simpleClassName}{$p.name}"; } @@ -154,7 +154,7 @@ final class $generatedClass { #if ($equals) - @Override + @`java.lang.Override` public boolean equals($equalsParameterType x) { return x == this; } @@ -163,7 +163,7 @@ final class $generatedClass { #if ($hashCode) - @Override + @`java.lang.Override` public int hashCode() { return System.identityHashCode(this); } @@ -178,14 +178,14 @@ final class $generatedClass { this.$p = $p; } - @Override + @`java.lang.Override` public $p.type ${p.getter}() { return $p; } #if ($toString) - @Override + @`java.lang.Override` public String toString() { return "${simpleClassName}{$p.name=" ## + #if ($p.kind == "ARRAY") `java.util.Arrays`.toString(this.$p) #else this.$p #end @@ -196,7 +196,7 @@ final class $generatedClass { #if ($equals) - @Override + @`java.lang.Override` public boolean equals($equalsParameterType x) { if (x instanceof $origClass) { $origClass$wildcardTypes that = ($origClass$wildcardTypes) x; @@ -211,7 +211,7 @@ final class $generatedClass { #if ($hashCode) - @Override + @`java.lang.Override` public int hashCode() { return #hashCodeExpression($p); } @@ -220,7 +220,7 @@ final class $generatedClass { #end - @Override + @`java.lang.Override` public $kindType ${kindGetter}() { return ${kindType}.$propertyToKind[$p.name]; } diff --git a/value/src/main/java/com/google/auto/value/processor/autovalue.vm b/value/src/main/java/com/google/auto/value/processor/autovalue.vm index 80ef79ae..6f50e934 100644 --- a/value/src/main/java/com/google/auto/value/processor/autovalue.vm +++ b/value/src/main/java/com/google/auto/value/processor/autovalue.vm @@ -101,7 +101,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { ${a}## #end - @Override + @`java.lang.Override` ${p.access}${p.type} ${p.getter}() { return $p; } @@ -110,7 +110,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #if ($toString) - @Override + @`java.lang.Override` public `java.lang.String` toString() { return "#if ($identifiers)$simpleClassName#end{" @@ -129,7 +129,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #if ($equals) - @Override + @`java.lang.Override` public boolean equals($equalsParameterType o) { if (o == this) { return true; @@ -162,7 +162,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #if ($hashCode) - @Override + @`java.lang.Override` public int hashCode() { int h$ = 1; @@ -185,7 +185,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #foreach ($m in $toBuilderMethods) - @Override + @`java.lang.Override` ${m.access}${builderTypeName}${builderActualTypes} ${m.name}() { return new Builder${builderActualTypes}(this); } @@ -252,7 +252,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #foreach ($setter in $builderSetters[$p.name]) - @Override + @`java.lang.Override` ${setter.access}${builderTypeName}${builderActualTypes} ## ${setter.name}(${setter.nullableAnnotation}$setter.parameterType $p) { @@ -290,7 +290,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #if ($propertyBuilder) - @Override + @`java.lang.Override` ${propertyBuilder.access}$propertyBuilder.builderType ${p.name}Builder() { if (${propertyBuilder.name} == null) { @@ -337,7 +337,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #if ($builderGetters[$p.name]) - @Override + @`java.lang.Override` ${p.nullableAnnotation}${builderGetters[$p.name].access}$builderGetters[$p.name].type ${p.getter}() { #if ($builderGetters[$p.name].optional) @@ -377,7 +377,7 @@ ${modifiers}class $subclass$formalTypes extends $origClass$actualTypes { #end #end - @Override + @`java.lang.Override` ${buildMethod.get().access}${origClass}${actualTypes} ${buildMethod.get().name}() { #foreach ($p in $props) diff --git a/value/src/main/java/com/google/auto/value/processor/gwtserializer.vm b/value/src/main/java/com/google/auto/value/processor/gwtserializer.vm index 04500360..1265aae4 100644 --- a/value/src/main/java/com/google/auto/value/processor/gwtserializer.vm +++ b/value/src/main/java/com/google/auto/value/processor/gwtserializer.vm @@ -93,26 +93,26 @@ public final class $serializerClass$formalTypes @SuppressWarnings("unused") private int dummy_$classHashString; - @Override + @`java.lang.Override` public void deserializeInstance( `com.google.gwt.user.client.rpc.SerializationStreamReader` streamReader, $subclass$actualTypes instance) { deserialize(streamReader, instance); } - @Override + @`java.lang.Override` public boolean hasCustomInstantiateInstance() { return true; } - @Override + @`java.lang.Override` public $subclass$actualTypes instantiateInstance( `com.google.gwt.user.client.rpc.SerializationStreamReader` streamReader) throws `com.google.gwt.user.client.rpc.SerializationException` { return instantiate(streamReader); } - @Override + @`java.lang.Override` public void serializeInstance( `com.google.gwt.user.client.rpc.SerializationStreamWriter` streamWriter, $subclass$actualTypes instance) diff --git a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java index 2d4aa7ca..e46c9f51 100644 --- a/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java +++ b/value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java @@ -3189,6 +3189,12 @@ public class AutoValueCompilationTest { "package foo.bar;", "", "public class Thread {}"); + JavaFileObject override = + JavaFileObjects.forSourceLines( + "foo.bar.Override", // + "package foo.bar;", + "", + "public class Override {}"); JavaFileObject test = JavaFileObjects.forSourceLines( "foo.bar.Test", @@ -3215,7 +3221,7 @@ public class AutoValueCompilationTest { javac() .withProcessors(new AutoValueProcessor()) .withOptions("-Xlint:-processing", "-implicit:none") - .compile(object, string, integer, thread, test); + .compile(object, string, integer, thread, override, test); assertThat(compilation).succeededWithoutWarnings(); } -- cgit v1.2.3 From 5384b30905c47991eed5e7d6345cfd29343209b3 Mon Sep 17 00:00:00 2001 From: emcmanus Date: Tue, 28 Jul 2020 16:55:12 -0700 Subject: Add javadoc to the methods in SuperficialValidation. Also add a private constructor, and rewrite some code to use streams. RELNOTES=Add javadoc for SuperficialValidation methods. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=323682147 --- .../google/auto/common/SuperficialValidation.java | 54 +++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/common/src/main/java/com/google/auto/common/SuperficialValidation.java b/common/src/main/java/com/google/auto/common/SuperficialValidation.java index 83870754..5ef4dbf2 100644 --- a/common/src/main/java/com/google/auto/common/SuperficialValidation.java +++ b/common/src/main/java/com/google/auto/common/SuperficialValidation.java @@ -17,6 +17,7 @@ package com.google.auto.common; import java.util.List; import java.util.Map; +import java.util.stream.StreamSupport; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.AnnotationValueVisitor; @@ -46,13 +47,12 @@ import javax.lang.model.util.SimpleTypeVisitor8; * @author Gregory Kick */ public final class SuperficialValidation { + /** + * Returns true if all of the given elements return true from {@link #validateElement(Element)}. + */ public static boolean validateElements(Iterable elements) { - for (Element element : elements) { - if (!validateElement(element)) { - return false; - } - } - return true; + return StreamSupport.stream(elements.spliterator(), false) + .allMatch(SuperficialValidation::validateElement); } private static final ElementVisitor ELEMENT_VALIDATING_VISITOR = @@ -94,6 +94,12 @@ public final class SuperficialValidation { } }; + /** + * Returns true if all types referenced by the given element are defined. The exact meaning of + * this depends on the kind of element. For packages, it means that all annotations on the package + * are fully defined. For other element kinds, it means that types referenced by the element, + * anything it contains, and any of its annotations element are all defined. + */ public static boolean validateElement(Element element) { return element.accept(ELEMENT_VALIDATING_VISITOR, null); } @@ -163,6 +169,12 @@ public final class SuperficialValidation { } }; + /** + * Returns true if the given type is fully defined. This means that the type itself is defined, as + * are any types it references, such as any type arguments or type bounds. For an {@link + * ExecutableType}, the parameter and return types must be fully defined, as must types declared + * in a {@code throws} clause or in the bounds of any type parameters. + */ public static boolean validateType(TypeMirror type) { return type.accept(TYPE_VALIDATING_VISITOR, null); } @@ -182,17 +194,14 @@ public final class SuperficialValidation { && validateAnnotationValues(annotationMirror.getElementValues()); } - @SuppressWarnings("unused") private static boolean validateAnnotationValues( Map valueMap) { - for (Map.Entry valueEntry : - valueMap.entrySet()) { - TypeMirror expectedType = valueEntry.getKey().getReturnType(); - if (!validateAnnotationValue(valueEntry.getValue(), expectedType)) { - return false; - } - } - return true; + return valueMap.entrySet().stream() + .allMatch( + valueEntry -> { + TypeMirror expectedType = valueEntry.getKey().getReturnType(); + return validateAnnotationValue(valueEntry.getValue(), expectedType); + }); } private static final AnnotationValueVisitor VALUE_VALIDATING_VISITOR = @@ -216,17 +225,8 @@ public final class SuperficialValidation { if (!expectedType.getKind().equals(TypeKind.ARRAY)) { return false; } - try { - expectedType = MoreTypes.asArray(expectedType).getComponentType(); - } catch (IllegalArgumentException e) { - return false; // Not an array expected, ergo invalid. - } - for (AnnotationValue value : values) { - if (!value.accept(this, expectedType)) { - return false; - } - } - return true; + TypeMirror componentType = MoreTypes.asArray(expectedType).getComponentType(); + return values.stream().allMatch(value -> value.accept(this, componentType)); } @Override @@ -280,4 +280,6 @@ public final class SuperficialValidation { AnnotationValue annotationValue, TypeMirror expectedType) { return annotationValue.accept(VALUE_VALIDATING_VISITOR, expectedType); } + + private SuperficialValidation() {} } -- cgit v1.2.3 From 9f870ccfcbc22bf8c64084011f7d2d7992bdf06f Mon Sep 17 00:00:00 2001 From: dpb Date: Thu, 6 Aug 2020 13:01:25 -0700 Subject: Update dependency versions. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=325291991 --- common/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/common/pom.xml b/common/pom.xml index 7d1c8773..49295b57 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -36,7 +36,7 @@ UTF-8 1.8 - 27.0.1-jre + 29.0-jre 1.0.1 @@ -75,7 +75,7 @@ If you use JavaPoet, you can use GeneratedAnnotationSpecs. --> com.squareup javapoet - 1.9.0 + 1.13.0 true @@ -107,7 +107,7 @@ org.eclipse.jdt ecj - 3.20.0 + 3.22.0 test -- cgit v1.2.3 From 123db863068570167ecf3ca7b64cf21c46e9664d Mon Sep 17 00:00:00 2001 From: Ron Shapiro Date: Tue, 11 Aug 2020 18:55:59 +0300 Subject: Set version number for auto-common to 0.11. --- common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/pom.xml b/common/pom.xml index 49295b57..e4a23e02 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -26,7 +26,7 @@ com.google.auto auto-common - HEAD-SNAPSHOT + 0.11 Auto Common Libraries Common utilities for creating annotation processors. -- cgit v1.2.3 From cd109d220edcbc6498aad59c4430daca5c54bde5 Mon Sep 17 00:00:00 2001 From: Bob Badour Date: Fri, 12 Feb 2021 20:29:48 -0800 Subject: [LSC] Add LOCAL_LICENSE_KINDS to external/auto Added SPDX-license-identifier-Apache-2.0 to: Android.bp android-annotation-stubs/Android.bp common/Android.bp factory/Android.bp service/Android.bp value/Android.bp Bug: 68860345 Bug: 151177513 Bug: 151953481 Test: m all Exempt-From-Owner-Approval: janitorial work Change-Id: I213d1de311f7729ccee0ad86219ef1bfb4d944a9 --- Android.bp | 16 +++++++++++++++- android-annotation-stubs/Android.bp | 9 +++++++++ common/Android.bp | 9 +++++++++ factory/Android.bp | 9 +++++++++ service/Android.bp | 9 +++++++++ value/Android.bp | 9 +++++++++ 6 files changed, 60 insertions(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index 7c7db3ef..a7efec44 100644 --- a/Android.bp +++ b/Android.bp @@ -1,3 +1,17 @@ package { - default_visibility: [":__subpackages__"] + default_visibility: [":__subpackages__"], + default_applicable_licenses: ["external_auto_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "external_auto_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "LICENSE", + ], } diff --git a/android-annotation-stubs/Android.bp b/android-annotation-stubs/Android.bp index a2bd9e98..3e0be03d 100644 --- a/android-annotation-stubs/Android.bp +++ b/android-annotation-stubs/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_auto_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_auto_license"], +} + java_library_host { name: "auto_android_annotation_stubs", srcs: ["src/**/*.java"], diff --git a/common/Android.bp b/common/Android.bp index 279b90d9..25f70998 100644 --- a/common/Android.bp +++ b/common/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_auto_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_auto_license"], +} + java_library_host { name: "auto_common", srcs: ["src/main/java/**/*.java"], diff --git a/factory/Android.bp b/factory/Android.bp index bf4899bf..7e75542d 100644 --- a/factory/Android.bp +++ b/factory/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_auto_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_auto_license"], +} + java_library { name: "auto_factory_annotations", host_supported: true, diff --git a/service/Android.bp b/service/Android.bp index 033fd84a..318c47b9 100644 --- a/service/Android.bp +++ b/service/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_auto_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_auto_license"], +} + java_library { name: "auto_service_annotations", host_supported: true, diff --git a/value/Android.bp b/value/Android.bp index 2e1d819d..d187821d 100644 --- a/value/Android.bp +++ b/value/Android.bp @@ -1,3 +1,12 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "external_auto_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["external_auto_license"], +} + filegroup { name: "auto_value_plugin_resources", path: "src/main/java", -- cgit v1.2.3 From d542bcf5c7c83f8c458763a5f6bb3356e07e80dc Mon Sep 17 00:00:00 2001 From: Chang Li Date: Wed, 2 Jun 2021 19:48:59 +0000 Subject: Restrict autovalue apex availability to extservices only. am: 2a66d35dd3 am: 6eabe1e8be am: bb49451a26 am: 5fe506f8a9 Original change: https://android-review.googlesource.com/c/platform/external/auto/+/1723293 Merged-In: I07ffa1a7b0720075c720e28cbbdd49d857112dfa Change-Id: I07ffa1a7b0720075c720e28cbbdd49d857112dfa --- value/Android.bp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/value/Android.bp b/value/Android.bp index d187821d..73a72154 100644 --- a/value/Android.bp +++ b/value/Android.bp @@ -44,7 +44,14 @@ java_library { host_supported: true, srcs: ["src/main/java/com/google/auto/value/*.java"], sdk_version: "core_current", + // AutoValue is a pure java library without any dependency on android framework, however due to + // a dependency from an apex it is required to have a min_sdk_version + min_sdk_version: "19", visibility: ["//visibility:public"], + apex_available: [ + "//apex_available:platform", + "com.android.extservices", + ], } java_plugin { -- cgit v1.2.3