Include type annotations in bounds of type parameter declarations. For example, if we have `@AutoValue abstract class Foo<T extends @NullableType Object>`, then we should generate `class AutoValue_Foo<T extends @NullableType Object> extends Foo<T>`, rather than just `class AutoValue_Foo<T> extends Foo<T>` as at present.

RELNOTES=In AutoValue code, include type annotations in bounds of type-parameter declarations.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=254752026
diff --git a/value/src/main/java/com/google/auto/value/processor/TypeEncoder.java b/value/src/main/java/com/google/auto/value/processor/TypeEncoder.java
index 8d20a66..912091f 100644
--- a/value/src/main/java/com/google/auto/value/processor/TypeEncoder.java
+++ b/value/src/main/java/com/google/auto/value/processor/TypeEncoder.java
@@ -182,14 +182,21 @@
     sb.append(typeParameter.getSimpleName());
     String sep = " extends ";
     for (TypeMirror bound : typeParameter.getBounds()) {
-      if (!bound.toString().equals("java.lang.Object")) {
+      if (!isUnannotatedJavaLangObject(bound)) {
         sb.append(sep);
         sep = " & ";
-        sb.append(encode(bound));
+        sb.append(encodeWithAnnotations(bound));
       }
     }
   }
 
+  // We can omit "extends Object" from a type bound, but not "extends @NullableType Object".
+  private static boolean isUnannotatedJavaLangObject(TypeMirror type) {
+    return type.getKind().equals(TypeKind.DECLARED)
+        && type.getAnnotationMirrors().isEmpty()
+        && MoreTypes.asTypeElement(type).getQualifiedName().contentEquals("java.lang.Object");
+  }
+
   private static void appendAnnotations(
       List<? extends AnnotationMirror> annotationMirrors, StringBuilder sb) {
     for (AnnotationMirror annotationMirror : annotationMirrors) {
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 134af63..724ea6b 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
@@ -15,11 +15,10 @@
  */
 package com.google.auto.value.processor;
 
-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.CompilationSubject.compilations;
 import static com.google.testing.compile.Compiler.javac;
-import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
 import static java.util.stream.Collectors.joining;
 
 import com.google.common.collect.ImmutableSet;
@@ -34,9 +33,11 @@
 import java.util.stream.Stream;
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.util.ElementFilter;
 import javax.tools.JavaFileObject;
 import org.junit.Rule;
@@ -352,6 +353,75 @@
         .hasSourceEquivalentTo(expectedOutput);
   }
 
+  // Tests that type annotations are correctly copied from the bounds of type parameters in the
+  // @AutoValue class to the bounds of the corresponding parameters in the generated class. For
+  // example, if we have `@AutoValue abstract class Foo<T extends @NullableType Object>`, then the
+  // generated class should be `class AutoValue_Foo<T extends @NullableType Object> extends Foo<T>`.
+  // Some buggy versions of javac do not report type annotations correctly in this context.
+  // AutoValue can't copy them if it can't see them, so we make a special annotation processor to
+  // detect if we are in the presence of this bug and if so we don't fail.
+  @Test
+  public void testTypeParametersWithAnnotationsOnBounds() {
+    @SupportedAnnotationTypes("*")
+    class CompilerBugProcessor extends AbstractProcessor {
+      boolean checkedAnnotationsOnTypeBounds;
+      boolean reportsAnnotationsOnTypeBounds;
+
+      @Override
+      public SourceVersion getSupportedSourceVersion() {
+        return SourceVersion.latestSupported();
+      }
+
+      @Override
+      public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+        if (roundEnv.processingOver()) {
+          TypeElement test = processingEnv.getElementUtils().getTypeElement("com.example.Test");
+          TypeParameterElement t = test.getTypeParameters().get(0);
+          this.checkedAnnotationsOnTypeBounds = true;
+          this.reportsAnnotationsOnTypeBounds =
+              !t.getBounds().get(0).getAnnotationMirrors().isEmpty();
+        }
+        return false;
+      }
+    }
+    CompilerBugProcessor compilerBugProcessor = new CompilerBugProcessor();
+    JavaFileObject nullableTypeFileObject =
+        JavaFileObjects.forSourceLines(
+            "foo.bar.NullableType",
+            "package foo.bar;",
+            "",
+            "import java.lang.annotation.ElementType;",
+            "import java.lang.annotation.Target;",
+            "",
+            "@Target(ElementType.TYPE_USE)",
+            "public @interface NullableType {}");
+    JavaFileObject autoValueFileObject =
+        JavaFileObjects.forSourceLines(
+            "com.example.Test",
+            "package com.example;",
+            "",
+            "import com.google.auto.value.AutoValue;",
+            "import foo.bar.NullableType;",
+            "",
+            "@AutoValue",
+            "abstract class Test<T extends @NullableType Object & @NullableType Cloneable> {}");
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoValueProcessor(), compilerBugProcessor)
+            .withOptions("-Xlint:-processing", "-implicit:none")
+            .compile(nullableTypeFileObject, autoValueFileObject);
+    assertThat(compilation).succeededWithoutWarnings();
+    assertThat(compilerBugProcessor.checkedAnnotationsOnTypeBounds).isTrue();
+    if (compilerBugProcessor.reportsAnnotationsOnTypeBounds) {
+      assertThat(compilation)
+          .generatedSourceFile("com.example.AutoValue_Test")
+          .contentsAsUtf8String()
+          .contains(
+              "class AutoValue_Test<T extends @NullableType Object & @NullableType Cloneable>"
+                  + " extends Test<T> {");
+    }
+  }
+
   // In the following few tests, see AutoValueProcessor.validateMethods for why unrecognized
   // abstract methods provoke only a warning rather than an error. Compilation will fail anyway
   // because the generated class is not abstract and does not implement the unrecognized methods.
@@ -2538,12 +2608,13 @@
             "    Baz<K, V> build();",
             "  }",
             "}");
-    assertAbout(javaSource())
-        .that(javaFileObject)
-        .processedWith(new AutoValueProcessor(), new AutoValueBuilderProcessor())
-        .failsToCompile()
-        .withErrorContaining("Builder converter method should return foo.bar.Baz.Builder<K, V>")
-        .in(javaFileObject)
+    Compilation compilation =
+        javac()
+            .withProcessors(new AutoValueProcessor(), new AutoValueBuilderProcessor())
+            .compile(javaFileObject);
+    assertThat(compilation)
+        .hadErrorContaining("Builder converter method should return foo.bar.Baz.Builder<K, V>")
+        .inFile(javaFileObject)
         .onLine(9);
   }