From 5c2ae41c23f9657a712e131f8699c16717cbf063 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Mon, 10 Aug 2026 00:09:29 -0700 Subject: [PATCH] Add tests for TYPE_USE annotations on outer classes and arrays For e.g. `@Nullable String []` and `@Nullable Enclosing.Inner`, the annotation applies to the array component type and the enclosing class type respectively. Auto includes the type annotation in the generated output and emits an additional annotation for nullable proprties, resulting in an invalid repeated annotation. RELNOTES=n/a PiperOrigin-RevId: 961975126 --- .../processor/AutoValueCompilationTest.java | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) 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 46988ac204..59095336b8 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 @@ -4293,6 +4293,175 @@ public void notNullOnOuterClassWithNullableInnerType() { .hasSourceEquivalentTo(expectedOutput); } + @Test + public void notNullTypeUseAnnotationOnOuterClass() { + assume().that(typeAnnotationsWork).isTrue(); + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "import java.lang.annotation.ElementType;", + "import java.lang.annotation.Target;", + "", + "@AutoValue", + "public abstract class Baz {", + " @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER})", + " public @interface NotNull {}", + "", + " @NotNull", + " abstract Outer.Inner inner();", + "", + " @AutoValue.Builder", + " public abstract static class Builder {", + " public abstract Builder setInner(Outer.Inner inner);", + " public abstract Baz build();", + " }", + "}", + "class Outer {", + " class Inner {}", + "}"); + // TODO(b/540040170): Fix the duplicate annotation bug that causes compilation failure. + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) + .compile(javaFileObject); + assertThat(compilation) + .hadErrorContaining("foo.bar.Baz.NotNull is not a repeatable annotation"); + } + + @Test + public void notNullTypeUseAnnotationOnStaticOuterClass() { + assume().that(typeAnnotationsWork).isTrue(); + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "import java.lang.annotation.ElementType;", + "import java.lang.annotation.Target;", + "", + "@AutoValue", + "public abstract class Baz {", + " @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER})", + " public @interface NotNull {}", + "", + " @NotNull", + " abstract Outer.Inner inner();", + "", + " @AutoValue.Builder", + " public abstract static class Builder {", + " public abstract Builder setInner(Outer.Inner inner);", + " public abstract Baz build();", + " }", + "}", + "class Outer {", + " static class Inner {}", + "}"); + // Type-use annotations on static nested classes are associated directly with the member type + // rather than an enclosing instance type (JLS 9.7.4), so annotation propagation works + // correctly. + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) + .compile(javaFileObject); + assertThat(compilation).succeeded(); + assertThat(compilation) + .generatedSourceFile("foo.bar.AutoValue_Baz") + .contentsAsUtf8String() + .contains( + " @Baz.NotNull\n" + + " @Override\n" + + " Outer.Inner inner() {\n" + + " return inner;\n" + + " }\n"); + assertThat(compilation) + .generatedSourceFile("foo.bar.AutoValue_Baz") + .contentsAsUtf8String() + .contains("private Outer.@Nullable Inner inner;"); + } + + @Test + public void nullableTypeUseAnnotationOnOuterClass() { + assume().that(typeAnnotationsWork).isTrue(); + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "import java.lang.annotation.ElementType;", + "import java.lang.annotation.Target;", + "", + "@AutoValue", + "public abstract class Baz {", + " @Target({ElementType.TYPE_USE, ElementType.METHOD, ElementType.PARAMETER})", + " public @interface Nullable {}", + "", + " @Nullable", + " abstract Outer.Inner inner();", + "", + " @AutoValue.Builder", + " public abstract static class Builder {", + " public abstract Builder setInner(Outer.Inner inner);", + " public abstract Baz build();", + " }", + "}", + "class Outer {", + " class Inner {}", + "}"); + // TODO(b/540040170): Fix the duplicate annotation bug that causes compilation failure. + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) + .compile(javaFileObject); + assertThat(compilation) + .hadErrorContaining("foo.bar.Baz.Nullable is not a repeatable annotation"); + } + + @Test + public void notNullTypeUseAnnotationOnArray() { + assume().that(typeAnnotationsWork).isTrue(); + JavaFileObject javaFileObject = + JavaFileObjects.forSourceLines( + "foo.bar.Baz", + "package foo.bar;", + "", + "import com.google.auto.value.AutoValue;", + "import java.lang.annotation.ElementType;", + "import java.lang.annotation.Target;", + "", + "@AutoValue", + "public abstract class Baz {", + " @Target({", + " ElementType.TYPE_USE,", + " ElementType.FIELD,", + " ElementType.PARAMETER,", + " ElementType.METHOD", + " })", + " public @interface NotNull {}", + "", + " @SuppressWarnings(\"mutable\")", + " @NotNull", + " abstract byte[] bytes();", + "", + " @AutoValue.Builder", + " public abstract static class Builder {", + " public abstract Builder setBytes(byte[] bytes);", + " public abstract Baz build();", + " }", + "}"); + // TODO(b/540040170): Fix the duplicate annotation bug that causes compilation failure. + Compilation compilation = + javac() + .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor()) + .compile(javaFileObject); + assertThat(compilation) + .hadErrorContaining("foo.bar.Baz.NotNull is not a repeatable annotation"); + } + private static String sorted(String... imports) { return stream(imports).sorted().collect(joining("\n")); }