Merge "Do not enforce nullability on generic types."
diff --git a/src/main/java/com/android/tools/metalava/ApiLint.kt b/src/main/java/com/android/tools/metalava/ApiLint.kt
index 106d9d6..a82e159 100644
--- a/src/main/java/com/android/tools/metalava/ApiLint.kt
+++ b/src/main/java/com/android/tools/metalava/ApiLint.kt
@@ -1780,6 +1780,13 @@
 
     private fun checkHasNullability(item: Item) {
         if (item.requiresNullnessInfo() && !item.hasNullnessInfo()) {
+            val type = item.type()
+            if (type != null && type.isTypeParameter()) {
+              // Generic types should have declarations of nullability set at the site of where
+              // the type is set, so that for Foo<T>, T does not need to specify nullability, but
+              // for Foo<Bar>, Bar does.
+              return // Do not enforce nullability for generics
+            }
             val where = when (item) {
                 is ParameterItem -> "parameter `${item.name()}` in method `${item.parent()?.name()}`"
                 is FieldItem -> "field `${item.name()}` in class `${item.parent()}`"
diff --git a/src/main/java/com/android/tools/metalava/model/TypeItem.kt b/src/main/java/com/android/tools/metalava/model/TypeItem.kt
index ca9266c..e7dbd6d 100644
--- a/src/main/java/com/android/tools/metalava/model/TypeItem.kt
+++ b/src/main/java/com/android/tools/metalava/model/TypeItem.kt
@@ -162,6 +162,11 @@
     fun asTypeParameter(context: MemberItem? = null): TypeParameterItem?
 
     /**
+     * Whether this type is a type parameter.
+     */
+    fun isTypeParameter(context: MemberItem? = null): Boolean = asTypeParameter(context) != null
+
+    /**
      * Mark nullness annotations in the type as recent.
      * TODO: This isn't very clean; we should model individual annotations.
      */
diff --git a/src/test/java/com/android/tools/metalava/ApiLintTest.kt b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
index 626c2e9..02a38c3 100644
--- a/src/test/java/com/android/tools/metalava/ApiLintTest.kt
+++ b/src/test/java/com/android/tools/metalava/ApiLintTest.kt
@@ -2258,7 +2258,7 @@
                 src/android/pkg/Foo.java:11: error: Missing nullability on parameter `name` in method `Foo` [MissingNullability]
                 src/android/pkg/Foo.java:12: error: Missing nullability on parameter `value` in method `setBadValue` [MissingNullability]
                 src/android/pkg/Foo.java:13: error: Missing nullability on method `getBadValue` return [MissingNullability]
-                src/android/pkg/Foo.java:19: error: Missing nullability on parameter `duration` in method `methodMissingParamAnnotations` [MissingNullability]
+                src/android/pkg/Foo.java:20: error: Missing nullability on parameter `duration` in method `methodMissingParamAnnotations` [MissingNullability]
                 src/android/pkg/Foo.java:7: error: Missing nullability on field `badField` in class `class android.pkg.Foo` [MissingNullability]
                 """,
             sourceFiles = *arrayOf(
@@ -2269,7 +2269,7 @@
                         import androidx.annotation.NonNull;
                         import androidx.annotation.Nullable;
 
-                        public class Foo {
+                        public class Foo<T> {
                             public Foo badField;
                             @Nullable
                             public Foo goodField;
@@ -2278,9 +2278,10 @@
                             public void setBadValue(Foo value) { }
                             public Foo getBadValue(int number) { throw UnsupportedOperationExceptions(); }
                             public void setGoodValue(@Nullable Foo value) { }
+                            public void setGoodIgnoredGenericValue(T value) { }
                             @NonNull
                             public Foo getGoodValue(int number) { throw UnsupportedOperationExceptions(); }
-                            
+
                             @NonNull
                             public Foo methodMissingParamAnnotations(java.time.Duration duration) {
                                 throw UnsupportedOperationException();