Fix: some flagged APIs are not recorded.

* The @FlaggedApi annotation can be used for classes. When a class is
  annotated but its APIs are not, they should be counted as flagged.
* Class constructors are also APIs.

Bug: 331294167
Test: manual test `extract-flagged-apis <input> <output>`
Change-Id: Ic6d25eb59faa381f033751557343ad85c1602e41
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index caa1929..d5adfd0 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -16,51 +16,69 @@
 
 package android.platform.coverage
 
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.text.ApiFile
 import java.io.File
 import java.io.FileWriter
 
 /** Usage: extract-flagged-apis <api text file> <output .pb file> */
 fun main(args: Array<String>) {
-    var cb = ApiFile.parseApi(listOf(File(args[0])))
-    var builder = FlagApiMap.newBuilder()
+    val cb = ApiFile.parseApi(listOf(File(args[0])))
+    val builder = FlagApiMap.newBuilder()
     for (pkg in cb.getPackages().packages) {
-        var packageName = pkg.qualifiedName()
+        val packageName = pkg.qualifiedName()
         pkg.allClasses()
             .filter { it.methods().size > 0 }
             .forEach {
-                for (method in it.methods()) {
-                    val flagValue =
-                        method.modifiers
-                            .findAnnotation("android.annotation.FlaggedApi")
-                            ?.findAttribute("value")
-                            ?.value
-                            ?.value()
-                    if (flagValue != null && flagValue is String) {
-                        var api =
-                            JavaMethod.newBuilder()
-                                .setPackageName(packageName)
-                                .setClassName(it.fullName())
-                                .setMethodName(method.name())
-                        for (param in method.parameters()) {
-                            api.addParameters(param.type().toTypeString())
-                        }
-                        if (builder.containsFlagToApi(flagValue)) {
-                            var updatedApis =
-                                builder
-                                    .getFlagToApiOrThrow(flagValue)
-                                    .toBuilder()
-                                    .addJavaMethods(api)
-                                    .build()
-                            builder.putFlagToApi(flagValue, updatedApis)
-                        } else {
-                            var apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
-                            builder.putFlagToApi(flagValue, apis)
-                        }
-                    }
-                }
+                extractFlaggedApisFromClass(it, it.methods(), packageName, builder)
+                extractFlaggedApisFromClass(it, it.constructors(), packageName, builder)
             }
     }
     val flagApiMap = builder.build()
     FileWriter(args[1]).use { it.write(flagApiMap.toString()) }
 }
+
+fun extractFlaggedApisFromClass(
+    classItem: ClassItem,
+    methods: List<MethodItem>,
+    packageName: String,
+    builder: FlagApiMap.Builder
+) {
+    val classFlag =
+        classItem.modifiers
+            .findAnnotation("android.annotation.FlaggedApi")
+            ?.findAttribute("value")
+            ?.value
+            ?.value() as? String
+    for (method in methods) {
+        val methodFlag =
+            method.modifiers
+                .findAnnotation("android.annotation.FlaggedApi")
+                ?.findAttribute("value")
+                ?.value
+                ?.value() as? String
+                ?: classFlag
+        val api =
+            JavaMethod.newBuilder()
+                .setPackageName(packageName)
+                .setClassName(classItem.fullName())
+                .setMethodName(method.name())
+        for (param in method.parameters()) {
+            api.addParameters(param.type().toTypeString())
+        }
+        if (methodFlag != null) {
+            addFlaggedApi(builder, api, methodFlag)
+        }
+    }
+}
+
+fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
+    if (builder.containsFlagToApi(flag)) {
+        val updatedApis = builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
+        builder.putFlagToApi(flag, updatedApis)
+    } else {
+        val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
+        builder.putFlagToApi(flag, apis)
+    }
+}