check-flagged-apis: record super class when parsing classes

Extend ClassSymbol with a nullable reference to the class' superclass.

Bug: 334870672
Test: atest --host check-flagged-apis-test
Change-Id: Ia2741a4d7fb5de908a03ef640f5fcd38d0ce0e28
diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
index 3cd6a24..773f433 100644
--- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
+++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt
@@ -49,6 +49,7 @@
       <?xml version="1.0" encoding="utf-8"?>
       <api version="3">
         <class name="android/Clazz" since="1">
+          <extends name="java/lang/Object"/>
           <method name="&lt;init>()V"/>
           <field name="FOO"/>
           <method name="getErrorCode()I"/>
@@ -57,6 +58,7 @@
           <method name="innerClassArg(Landroid/Clazz${"$"}Builder;)"/>
         </class>
         <class name="android/Clazz${"$"}Builder" since="2">
+          <extends name="java/lang/Object"/>
         </class>
       </api>
 """
@@ -95,7 +97,9 @@
   fun testParseApiSignature() {
     val expected =
         setOf(
-            Pair(Symbol.createClass("android/Clazz", setOf()), Flag("android.flag.foo")),
+            Pair(
+                Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
+                Flag("android.flag.foo")),
             Pair(Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")),
             Pair(Symbol.createField("android/Clazz", "FOO"), Flag("android.flag.foo")),
             Pair(Symbol.createMethod("android/Clazz", "getErrorCode()"), Flag("android.flag.foo")),
@@ -108,7 +112,9 @@
             Pair(
                 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
                 Flag("android.flag.foo")),
-            Pair(Symbol.createClass("android/Clazz/Builder", setOf()), Flag("android.flag.bar")),
+            Pair(
+                Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
+                Flag("android.flag.bar")),
         )
     val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream())
     assertEquals(expected, actual)
@@ -126,14 +132,14 @@
   fun testParseApiVersions() {
     val expected: Set<Symbol> =
         setOf(
-            Symbol.createClass("android/Clazz", setOf()),
+            Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
             Symbol.createMethod("android/Clazz", "Clazz()"),
             Symbol.createField("android/Clazz", "FOO"),
             Symbol.createMethod("android/Clazz", "getErrorCode()"),
             Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"),
             Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"),
             Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
-            Symbol.createClass("android/Clazz/Builder", setOf()),
+            Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
         )
     val actual = parseApiVersions(API_VERSIONS.byteInputStream())
     assertEquals(expected, actual)
@@ -146,6 +152,7 @@
           <?xml version="1.0" encoding="utf-8"?>
           <api version="3">
             <class name="android/Clazz${'$'}Foo${'$'}Bar" since="1">
+              <extends name="java/lang/Object"/>
               <method name="&lt;init>()V"/>
             </class>
           </api>
@@ -153,7 +160,7 @@
             .trim()
     val expected: Set<Symbol> =
         setOf(
-            Symbol.createClass("android/Clazz/Foo/Bar", setOf()),
+            Symbol.createClass("android/Clazz/Foo/Bar", "java/lang/Object", setOf()),
             Symbol.createMethod("android/Clazz/Foo/Bar", "Bar()"),
         )
     val actual = parseApiVersions(apiVersions.byteInputStream())
@@ -193,6 +200,7 @@
           <?xml version="1.0" encoding="utf-8"?>
           <api version="3">
             <class name="android/Clazz" since="1">
+              <extends name="java/lang/Object"/>
               <implements name="android/Interface"/>
               <method name="foo()Z"/>
             </class>
@@ -217,7 +225,8 @@
     val expected =
         setOf<ApiError>(
             DisabledFlaggedApiIsPresentError(
-                Symbol.createClass("android/Clazz", setOf()), Flag("android.flag.foo")),
+                Symbol.createClass("android/Clazz", "java/lang/Object", setOf()),
+                Flag("android.flag.foo")),
             DisabledFlaggedApiIsPresentError(
                 Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")),
             DisabledFlaggedApiIsPresentError(
@@ -234,7 +243,8 @@
                 Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"),
                 Flag("android.flag.foo")),
             DisabledFlaggedApiIsPresentError(
-                Symbol.createClass("android/Clazz/Builder", setOf()), Flag("android.flag.bar")),
+                Symbol.createClass("android/Clazz/Builder", "java/lang/Object", setOf()),
+                Flag("android.flag.bar")),
         )
     val actual =
         findErrors(
diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
index 867ee94..dc0d31c 100644
--- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
+++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt
@@ -58,8 +58,11 @@
   companion object {
     private val FORBIDDEN_CHARS = listOf('#', '$', '.')
 
-    fun createClass(clazz: String, interfaces: Set<String>): Symbol {
-      return ClassSymbol(toInternalFormat(clazz), interfaces.map { toInternalFormat(it) }.toSet())
+    fun createClass(clazz: String, superclass: String?, interfaces: Set<String>): Symbol {
+      return ClassSymbol(
+          toInternalFormat(clazz),
+          superclass?.let { toInternalFormat(it) },
+          interfaces.map { toInternalFormat(it) }.toSet())
     }
 
     fun createField(clazz: String, field: String): Symbol {
@@ -83,7 +86,11 @@
   abstract fun toPrettyString(): String
 }
 
-internal data class ClassSymbol(val clazz: String, val interfaces: Set<String>) : Symbol() {
+internal data class ClassSymbol(
+    val clazz: String,
+    val superclass: String?,
+    val interfaces: Set<String>
+) : Symbol() {
   override fun toPrettyString(): String = "$clazz"
 }
 
@@ -198,6 +205,7 @@
             val symbol =
                 Symbol.createClass(
                     cls.baselineElementId(),
+                    cls.superClass()?.baselineElementId(),
                     cls.allInterfaces()
                         .map { it.baselineElementId() }
                         .filter { it != cls.baselineElementId() }
@@ -263,19 +271,28 @@
         requireNotNull(cls.getAttribute("name")) {
           "Bad XML: <class> element without name attribute"
         }
+    var superclass: String? = null
     val interfaces = mutableSetOf<String>()
     val children = cls.getChildNodes()
     for (j in 0.rangeUntil(children.getLength())) {
       val child = children.item(j)
-      if (child.getNodeName() == "implements") {
-        val interfaceName =
-            requireNotNull(child.getAttribute("name")) {
-              "Bad XML: <implements> element without name attribute"
-            }
-        interfaces.add(interfaceName)
+      when (child.getNodeName()) {
+        "extends" -> {
+          superclass =
+              requireNotNull(child.getAttribute("name")) {
+                "Bad XML: <extends> element without name attribute"
+              }
+        }
+        "implements" -> {
+          val interfaceName =
+              requireNotNull(child.getAttribute("name")) {
+                "Bad XML: <implements> element without name attribute"
+              }
+          interfaces.add(interfaceName)
+        }
       }
     }
-    output.add(Symbol.createClass(className, interfaces))
+    output.add(Symbol.createClass(className, superclass, interfaces))
   }
 
   val fields = document.getElementsByTagName("field")