aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉamonn McManus <emcmanus@google.com>2021-04-09 14:39:34 -0700
committerGoogle Java Core Libraries <java-libraries-firehose+copybara@google.com>2021-04-09 14:40:16 -0700
commit09d3d20bb5a8e2bbe7c00a43bd3a95b27e576b46 (patch)
tree5b3242c615f425b3a525690f282957b7df565d6d
parente234a84b334957a6bc5e42b3c3e77c4fdbe12c42 (diff)
downloadauto-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
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifier.java46
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoBuilder.java15
-rw-r--r--value/src/main/java/com/google/auto/value/processor/BuilderMethodClassifierForAutoValue.java20
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoBuilderCompilationTest.java177
-rw-r--r--value/src/test/java/com/google/auto/value/processor/AutoValueCompilationTest.java76
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"));
+ }
}