diff options
author | Éamonn McManus <emcmanus@google.com> | 2020-11-16 10:46:55 -0800 |
---|---|---|
committer | Google Java Core Libraries <java-core-libraries-team+copybara@google.com> | 2020-11-16 10:47:30 -0800 |
commit | f2cb2247898dcdcb05d52f1faf9689ecef4c0c41 (patch) | |
tree | a614486b8af8a1bb88281887c2f84b98fa6e2f08 /value/src/test | |
parent | 97863af8fda6e87250dae9e477f98de62d1ff28b (diff) | |
download | auto-f2cb2247898dcdcb05d52f1faf9689ecef4c0c41.tar.gz |
The methods returned by `BuilderContext.buildMethod()` and `.toBuilderMethods()` can be inherited.
This change addresses cases like this:
```java
interface Parent<BuilderT> {
BuilderT toBuilder();
interface Builder<BuilderT, BuiltT> {",
BuilderT setThing(String x);",
BuiltT build();",
}
}
@AutoValue abstract class Foo implements Parent<Foo.Builder> {
@AutoValue.Builder
abstract static class Builder implements Parent.Builder<Builder, Foo> {}
}
```
Previously, there would be two problems with this. First, inheriting `toBuilder()` like this didn't work at all, because its return type is `BuilderT` and not `Foo.Builder`. Now we correctly interpret the inherited return type in the context of `Foo`. Second, in `BuilderContext.buildMethod()` we were looking for methods returning `Foo`, and again this failed because the inherited `build()` method returns `BuiltT`. The fix in both cases is to use `Types.asMemberOf` to determine the correct return type in context.
Fixes https://github.com/google/auto/issues/933.
RELNOTES=The methods returned by `BuilderContext.buildMethod()` and `.toBuilderMethods()` can be inherited.
PiperOrigin-RevId: 342670816
Diffstat (limited to 'value/src/test')
-rw-r--r-- | value/src/test/java/com/google/auto/value/processor/ExtensionTest.java | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java b/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java index ce9eeed0..8f74d5df 100644 --- a/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java +++ b/value/src/test/java/com/google/auto/value/processor/ExtensionTest.java @@ -1075,6 +1075,78 @@ public class ExtensionTest { } @Test + public void builderContextWithInheritance() { + JavaFileObject parent = JavaFileObjects.forSourceLines( + "foo.bar.Parent", + "package foo.bar;", + "", + "interface Parent<BuilderT> {", + " BuilderT toBuilder();", + " interface Builder<T, BuilderT, BuiltT> {", + " BuilderT setThing(T x);", + " BuiltT build();", + " }", + "}"); + JavaFileObject autoValueClass = JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "", + "@AutoValue", + "abstract class Baz<T> implements Parent<Baz.Builder<T>> {", + " abstract T thing();", + " static <T> Builder<T> builder() {", + " return new AutoValue_Baz.Builder<>();", + " }", + "", + " @AutoValue.Builder", + " abstract static class Builder<T> implements Parent.Builder<T, Builder<T>, Baz<T>> {", + " }", + "}"); + ContextChecker checker = + context -> { + assertThat(context.builder()).isPresent(); + BuilderContext builderContext = context.builder().get(); + + assertThat(builderContext.builderType().getQualifiedName().toString()) + .isEqualTo("foo.bar.Baz.Builder"); + + Set<ExecutableElement> builderMethods = builderContext.builderMethods(); + assertThat(builderMethods).hasSize(1); + ExecutableElement builderMethod = Iterables.getOnlyElement(builderMethods); + assertThat(builderMethod.getSimpleName().toString()).isEqualTo("builder"); + + Set<ExecutableElement> toBuilderMethods = builderContext.toBuilderMethods(); + assertThat(toBuilderMethods).hasSize(1); + ExecutableElement toBuilderMethod = Iterables.getOnlyElement(toBuilderMethods); + assertThat(toBuilderMethod.getSimpleName().toString()).isEqualTo("toBuilder"); + + Optional<ExecutableElement> buildMethod = builderContext.buildMethod(); + assertThat(buildMethod).isPresent(); + assertThat(buildMethod.get().getSimpleName().toString()).isEqualTo("build"); + assertThat(buildMethod.get().getParameters()).isEmpty(); + assertThat(buildMethod.get().getReturnType().toString()).isEqualTo("BuiltT"); + + ExecutableElement autoBuildMethod = builderContext.autoBuildMethod(); + assertThat(autoBuildMethod).isEqualTo(buildMethod.get()); + + Map<String, Set<ExecutableElement>> setters = builderContext.setters(); + assertThat(setters.keySet()).containsExactly("thing"); + Set<ExecutableElement> thingSetters = setters.get("thing"); + assertThat(thingSetters).hasSize(1); + ExecutableElement thingSetter = Iterables.getOnlyElement(thingSetters); + assertThat(thingSetter.getSimpleName().toString()).isEqualTo("setThing"); + }; + ContextCheckingExtension extension = new ContextCheckingExtension(checker); + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(ImmutableList.of(extension))) + .compile(autoValueClass, parent); + assertThat(compilation).succeededWithoutWarnings(); + } + + @Test public void oddBuilderContext() { JavaFileObject autoValueClass = JavaFileObjects.forSourceLines( "foo.bar.Baz", |