diff options
author | Éamonn McManus <emcmanus@google.com> | 2021-04-09 14:39:34 -0700 |
---|---|---|
committer | Google Java Core Libraries <java-libraries-firehose+copybara@google.com> | 2021-04-09 14:40:16 -0700 |
commit | 09d3d20bb5a8e2bbe7c00a43bd3a95b27e576b46 (patch) | |
tree | 5b3242c615f425b3a525690f282957b7df565d6d | |
parent | e234a84b334957a6bc5e42b3c3e77c4fdbe12c42 (diff) | |
download | auto-09d3d20bb5a8e2bbe7c00a43bd3a95b27e576b46.tar.gz |
Compilation error tests for further errors in `BuilderMethodClassifier`.
Almost all errors in that class should now be covered by tests in both `AutoValueCompilationTest` and `AutoBuilderCompilationTest`. The exception is coverage of builder getters, which AutoBuilder does not yet support fully.
RELNOTES=n/a
PiperOrigin-RevId: 367706511
5 files changed, 278 insertions, 56 deletions
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 cc5bbb88..a40467dc 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 @@ -374,8 +374,9 @@ abstract class BuilderMethodClassifier<E extends Element> { // propertyNameToSetters can't be null when we call put on it below. errorReporter.reportError( method, - "[AutoValueBuilderWhatProp] Method does not correspond to a property of %s", - builtType); + "[%sBuilderWhatProp] Method does not correspond to %s", + autoWhat(), + getterMustMatch()); checkForFailedJavaBean(method); return; } @@ -389,7 +390,11 @@ abstract class BuilderMethodClassifier<E extends Element> { propertyNameToSetters.put( propertyName, new PropertySetter(method, parameterType, function.get())); } else { - errorReporter.reportError(method, "Setter methods must return %s", builderType.asType()); + errorReporter.reportError( + method, + "[%sBuilderRet] Setter methods must return %s", + autoWhat(), + builderType.asType()); } } } @@ -456,10 +461,9 @@ abstract class BuilderMethodClassifier<E extends Element> { if (!nullableProperty) { errorReporter.reportError( setter, - "[AutoValueNullNotNull] Parameter of setter method is @Nullable but property method" - + " %s.%s() is not", - typeUtils.erasure(builtType), - propertyElement.getSimpleName()); + "[%sNullNotNull] Parameter of setter method is @Nullable but %s is not", + autoWhat(), + propertyString(propertyElement)); return Optional.empty(); } } @@ -473,11 +477,11 @@ abstract class BuilderMethodClassifier<E extends Element> { } errorReporter.reportError( setter, - "[AutoValueGetVsSet] Parameter type %s of setter method should be %s to match getter %s.%s", + "[%sGetVsSet] Parameter type %s of setter method should be %s to match %s", + autoWhat(), parameterType, targetType, - typeUtils.erasure(builtType), - propertyElement.getSimpleName()); + propertyString(propertyElement)); return Optional.empty(); } @@ -503,12 +507,12 @@ abstract class BuilderMethodClassifier<E extends Element> { String targetTypeSimpleName = targetType.asElement().getSimpleName().toString(); errorReporter.reportError( setter, - "[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", + "[%sGetVsSetOrConvert] Parameter type %s of setter method should be %s to match %s, or it" + + " should be a type that can be passed to %s.%s to produce %s", + autoWhat(), parameterType, targetType, - typeUtils.erasure(builtType), - propertyElement.getSimpleName(), + propertyString(propertyElement), targetTypeSimpleName, copyOfMethods.get(0).getSimpleName(), targetType); @@ -673,6 +677,12 @@ abstract class BuilderMethodClassifier<E extends Element> { abstract TypeMirror originalPropertyType(E propertyElement); /** + * A string identifying the given property element, which is a method for AutoValue or a parameter + * for AutoBuilder. + */ + abstract String propertyString(E propertyElement); + + /** * Returns the name of the property that a no-arg builder method of the given name queries, if * any. For example, if your {@code @AutoValue} class has a method {@code abstract String * getBar()} then an abstract method in its builder with the same signature will query the {@code @@ -693,7 +703,9 @@ abstract class BuilderMethodClassifier<E extends Element> { */ abstract void checkForFailedJavaBean(ExecutableElement rejectedSetter); - /** A string describing what sort of Auto this is, {@code "AutoValue"} or {@code "AutoBuilder"}. */ + /** + * A string describing what sort of Auto this is, {@code "AutoValue"} or {@code "AutoBuilder"}. + */ abstract String autoWhat(); /** @@ -703,8 +715,8 @@ abstract class BuilderMethodClassifier<E extends Element> { abstract String getterMustMatch(); /** - * A string describing what a property builder for property {@code foo} must match, {@code "foo() - * or getFoo()"} for AutoValue, {@code "foo"} for AutoBuilder. + * A string describing what a property builder for property {@code foo} must match, {@code foo() + * or getFoo()} for AutoValue, {@code foo} for AutoBuilder. */ abstract String fooBuilderMustMatch(); } diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoBuilder.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoBuilder.java index 9d8ad555..6bb3f3ae 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoBuilder.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoBuilder.java @@ -40,12 +40,7 @@ class BuilderMethodClassifierForAutoBuilder extends BuilderMethodClassifier<Vari TypeElement builderType, ImmutableBiMap<VariableElement, String> paramToPropertyName, ImmutableMap<String, TypeMirror> propertyTypes) { - super( - errorReporter, - processingEnv, - builtType, - builderType, - propertyTypes); + super(errorReporter, processingEnv, builtType, builderType, propertyTypes); this.executable = executable; this.paramToPropertyName = paramToPropertyName; } @@ -113,6 +108,14 @@ class BuilderMethodClassifierForAutoBuilder extends BuilderMethodClassifier<Vari } @Override + String propertyString(VariableElement propertyElement) { + return "parameter \"" + + propertyElement.getSimpleName() + + "\" of " + + AutoBuilderProcessor.executableString(executable); + } + + @Override String autoWhat() { return "AutoBuilder"; } diff --git a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoValue.java b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoValue.java index 9427fc7d..39fa157d 100644 --- a/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoValue.java +++ b/value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoValue.java @@ -17,6 +17,7 @@ package com.google.auto.value.processor; import static com.google.common.collect.Sets.difference; +import com.google.auto.common.MoreElements; import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -40,12 +41,7 @@ class BuilderMethodClassifierForAutoValue extends BuilderMethodClassifier<Execut TypeElement builderType, ImmutableBiMap<ExecutableElement, String> getterToPropertyName, ImmutableMap<String, TypeMirror> rewrittenPropertyTypes) { - super( - errorReporter, - processingEnv, - builtType, - builderType, - rewrittenPropertyTypes); + super(errorReporter, processingEnv, builtType, builderType, rewrittenPropertyTypes); this.errorReporter = errorReporter; this.getterToPropertyName = getterToPropertyName; this.getterNameToGetter = @@ -100,6 +96,16 @@ class BuilderMethodClassifierForAutoValue extends BuilderMethodClassifier<Execut } @Override + String propertyString(ExecutableElement propertyElement) { + TypeElement type = MoreElements.asType(propertyElement.getEnclosingElement()); + return "property method " + + type.getQualifiedName() + + "." + + propertyElement.getSimpleName() + + "()"; + } + + @Override ImmutableBiMap<String, ExecutableElement> propertyElements() { return getterToPropertyName.inverse(); } @@ -131,7 +137,7 @@ class BuilderMethodClassifierForAutoValue extends BuilderMethodClassifier<Execut @Override String getterMustMatch() { - return "a getter method of " + builtType; + return "a property method of " + builtType; } @Override diff --git a/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java index 497705ec..7923c3e0 100644 --- a/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java +++ b/value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java @@ -618,4 +618,181 @@ public final class AutoBuilderCompilationTest { .inFile(javaFileObject) .onLineContaining("String alien()"); } + + @Test + public void alienOneArgMethod() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoBuilder;", + "", + "class Baz {", + " Baz(int one, int two) {}", + "", + " @AutoBuilder", + " interface Builder {", + " abstract Builder one(int x);", + " abstract Builder two(int x);", + " abstract Builder three(int x);", + " abstract Baz build();", + " }", + "}"); + Compilation compilation = + javac() + .withProcessors(new AutoBuilderProcessor()) + .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable") + .compile(javaFileObject); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining( + "[AutoBuilderBuilderWhatProp] Method does not correspond to a parameter of Baz(int one," + + " int two)") + .inFile(javaFileObject) + .onLineContaining("three(int x)"); + } + + @Test + public void setterReturnType() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoBuilder;", + "", + "class Baz {", + " Baz(int one, int two) {}", + "", + " @AutoBuilder", + " interface Builder {", + " abstract Builder one(int x);", + " abstract void two(int x);", + " abstract Baz build();", + " }", + "}"); + Compilation compilation = + javac() + .withProcessors(new AutoBuilderProcessor()) + .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable") + .compile(javaFileObject); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining( + "[AutoBuilderBuilderRet] Setter methods must return foo.bar.Baz.Builder") + .inFile(javaFileObject) + .onLineContaining("two(int x)"); + } + + @Test + public void nullableSetterForNonNullableParameter() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoBuilder;", + "import org.jspecify.nullness.Nullable;", + "", + "class Baz {", + " Baz(String thing) {}", + "", + " @AutoBuilder", + " interface Builder {", + " abstract Builder thing(@Nullable String x);", + " abstract Baz build();", + " }", + "}"); + JavaFileObject nullableFileObject = + JavaFileObjects.forSourceLines( + "org.jspecify.nullness.Nullable", + "package org.jspecify.nullness;", + "", + "import java.lang.annotation.ElementType;", + "import java.lang.annotation.Target;", + "", + "@Target(ElementType.TYPE_USE)", + "public @interface Nullable {}"); + Compilation compilation = + javac() + .withProcessors(new AutoBuilderProcessor()) + .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable") + .compile(javaFileObject, nullableFileObject); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining( + "[AutoBuilderNullNotNull] Parameter of setter method is @Nullable but parameter" + + " \"thing\" of Baz(java.lang.String thing) is not") + .inFile(javaFileObject) + .onLineContaining("thing(@Nullable String x)"); + } + + @Test + public void setterWrongType() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoBuilder;", + "", + "class Baz {", + " Baz(int up, int down) {}", + "", + " @AutoBuilder", + " interface Builder {", + " abstract Builder up(int x);", + " abstract Builder down(String x);", + " abstract Baz build();", + " }", + "}"); + Compilation compilation = + javac() + .withProcessors(new AutoBuilderProcessor()) + .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable") + .compile(javaFileObject); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining( + "[AutoBuilderGetVsSet] Parameter type java.lang.String of setter method should be int" + + " to match parameter \"down\" of Baz(int up, int down)") + .inFile(javaFileObject) + .onLineContaining("down(String x)"); + } + + @Test + public void setterWrongTypeEvenWithConversion() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoBuilder;", + "import java.util.Optional;", + "", + "class Baz {", + " Baz(Optional<String> maybe) {}", + "", + " @AutoBuilder", + " interface Builder {", + " abstract Builder maybe(int x);", + " abstract Baz build();", + " }", + "}"); + Compilation compilation = + javac() + .withProcessors(new AutoBuilderProcessor()) + .withOptions("-Acom.google.auto.value.AutoBuilderIsUnstable") + .compile(javaFileObject); + assertThat(compilation).failed(); + assertThat(compilation) + .hadErrorContaining( + "[AutoBuilderGetVsSetOrConvert] Parameter type int of setter method should be" + + " java.util.Optional<java.lang.String> to match parameter \"maybe\" of" + + " Baz(java.util.Optional<java.lang.String> maybe), or it should be a type that" + + " can be passed to Optional.of to produce java.util.Optional<java.lang.String>") + .inFile(javaFileObject) + .onLineContaining("maybe(int x)"); + } } 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 e20eb448..546bb576 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 @@ -335,7 +335,6 @@ public class AutoValueCompilationTest { " return false;", " }", "", - " @Override", " public int hashCode() {", " int h$ = 1;", @@ -1587,7 +1586,7 @@ public class AutoValueCompilationTest { assertThat(compilation) .hadErrorContaining( "Parameter type java.lang.String of setter method should be int " - + "to match getter foo.bar.Baz.blim") + + "to match property method foo.bar.Baz.blim()") .inFile(javaFileObject) .onLineContaining("Builder blim(String x)"); } @@ -1620,10 +1619,10 @@ public class AutoValueCompilationTest { .compile(javaFileObject); assertThat(compilation) .hadErrorContaining( - "Parameter type java.lang.String of setter method should be " - + "com.google.common.collect.ImmutableList<java.lang.String> to match getter " - + "foo.bar.Baz.blam, or it should be a type that can be passed to " - + "ImmutableList.copyOf") + "Parameter type java.lang.String of setter method should be" + + " com.google.common.collect.ImmutableList<java.lang.String> to match property" + + " method foo.bar.Baz.blam(), or it should be a type that can be passed to" + + " ImmutableList.copyOf") .inFile(javaFileObject) .onLineContaining("Builder blam(String x)"); } @@ -1657,11 +1656,11 @@ public class AutoValueCompilationTest { .compile(javaFileObject); assertThat(compilation) .hadErrorContaining( - "Parameter type java.util.Collection<java.lang.Integer> of setter method should be " - + "com.google.common.collect.ImmutableList<java.lang.String> to match getter " - + "foo.bar.Baz.blam, or it should be a type that can be passed to " - + "ImmutableList.copyOf to produce " - + "com.google.common.collect.ImmutableList<java.lang.String>") + "Parameter type java.util.Collection<java.lang.Integer> of setter method should be" + + " com.google.common.collect.ImmutableList<java.lang.String> to match property" + + " method foo.bar.Baz.blam(), or it should be a type that can be passed to" + + " ImmutableList.copyOf to produce" + + " com.google.common.collect.ImmutableList<java.lang.String>") .inFile(javaFileObject) .onLineContaining("Builder blam(Collection<Integer> x)"); } @@ -1694,7 +1693,7 @@ public class AutoValueCompilationTest { assertThat(compilation) .hadErrorContaining( "Parameter type java.lang.String of setter method should be int " - + "to match getter foo.bar.Baz.getBlim") + + "to match property method foo.bar.Baz.getBlim()") .inFile(javaFileObject) .onLineContaining("Builder blim(String x)"); } @@ -1768,7 +1767,7 @@ public class AutoValueCompilationTest { .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) .compile(javaFileObject); assertThat(compilation) - .hadErrorContaining("Method does not correspond to a property of foo.bar.Item") + .hadErrorContaining("Method does not correspond to a property method of foo.bar.Item") .inFile(javaFileObject) .onLineContaining("Builder setTitle(String title)"); assertThat(compilation) @@ -1802,7 +1801,7 @@ public class AutoValueCompilationTest { .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) .compile(javaFileObject); assertThat(compilation) - .hadErrorContaining("Method does not correspond to a property of foo.bar.Baz") + .hadErrorContaining("Method does not correspond to a property method of foo.bar.Baz") .inFile(javaFileObject) .onLineContaining("Builder blim(int x)"); } @@ -1839,6 +1838,35 @@ public class AutoValueCompilationTest { } @Test + public void autoValueBuilderSetterReturnType() { + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "", + "@AutoValue", + "public abstract class Baz {", + " abstract int blim();", + "", + " @AutoValue.Builder", + " public interface Builder {", + " void blim(int x);", + " Baz build();", + " }", + "}"); + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) + .compile(javaFileObject); + assertThat(compilation) + .hadErrorContaining("Setter methods must return foo.bar.Baz.Builder") + .inFile(javaFileObject) + .onLineContaining("void blim(int x)"); + } + + @Test public void autoValueBuilderWrongTypeGetter() { JavaFileObject javaFileObject = JavaFileObjects.forSourceLines( @@ -2456,8 +2484,8 @@ public class AutoValueCompilationTest { assertThat(compilation) .hadErrorContaining( "Method without arguments should be a build method returning foo.bar.Baz, or a getter" - + " method with the same name and type as a getter method of foo.bar.Baz, or" - + " fooBuilder() where foo() or getFoo() is a getter method of foo.bar.Baz") + + " method with the same name and type as a property method of foo.bar.Baz, or" + + " fooBuilder() where foo() or getFoo() is a property method of foo.bar.Baz") .inFile(javaFileObject) .onLineContaining("Builder whut()"); } @@ -2486,7 +2514,7 @@ public class AutoValueCompilationTest { .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) .compile(javaFileObject); assertThat(compilation) - .hadErrorContaining("Method does not correspond to a property of foo.bar.Baz") + .hadErrorContaining("Method does not correspond to a property method of foo.bar.Baz") .inFile(javaFileObject) .onLineContaining("void whut(String x)"); } @@ -3296,7 +3324,7 @@ public class AutoValueCompilationTest { "}"); private static final String GENERATED_PROPERTY_TYPE = String.join( - "\n", + "\n", // "package foo.baz;", "", "public class GeneratedPropertyType {}"); @@ -3325,18 +3353,14 @@ public class AutoValueCompilationTest { GENERATED_TYPES.forEach( (typeName, source) -> { try { - JavaFileObject generated = - processingEnv - .getFiler() - .createSourceFile(typeName); + JavaFileObject generated = processingEnv.getFiler().createSourceFile(typeName); try (Writer writer = generated.openWriter()) { writer.write(source); } } catch (IOException e) { throw new UncheckedIOException(e); } - } - ); + }); } return false; } @@ -3348,6 +3372,6 @@ public class AutoValueCompilationTest { } private String sorted(String... imports) { - return Arrays.stream(imports).sorted().collect(joining("\n")); - } + return Arrays.stream(imports).sorted().collect(joining("\n")); + } } |