Merge remote-tracking branch 'aosp/metalava-main' into 'aosp/main'

Merge performed by:
  scripts/merge-from-metalava-main.sh

This merge includes a number of changes so this contains a list of all
the affected bugs.

Bug: 298052340
Bug: 299048934
Bug: 302579866
Bug: 302654813
Bug: 303787736
Bug: 303842244
Bug: 304226685
Bug: 304503426
Test: m checkapi
(cherry picked from https://android-review.googlesource.com/q/commit:51c3353bb95eedced2ec230c44f8ab5dcd690a72)
Merged-In: I3da9b00ba29ff97155038adf21c3b59e6c2271d3
Change-Id: I3da9b00ba29ff97155038adf21c3b59e6c2271d3
diff --git a/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiPackageItem.kt b/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiPackageItem.kt
index 9b08fd5..e5fb166 100644
--- a/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiPackageItem.kt
+++ b/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiPackageItem.kt
@@ -47,12 +47,9 @@
 
     lateinit var containingPackageField: PsiPackageItem
 
-    override fun containingClass(strict: Boolean): ClassItem? = null
+    override fun containingClass(): ClassItem? = null
 
-    override fun containingPackage(strict: Boolean): PackageItem? {
-        if (!strict) {
-            return this
-        }
+    override fun containingPackage(): PackageItem? {
         return if (qualifiedName.isEmpty()) null
         else {
             if (!::containingPackageField.isInitialized) {
diff --git a/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiSourceFileItem.kt b/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiSourceFileItem.kt
index 62f19f9..d20d68e 100644
--- a/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiSourceFileItem.kt
+++ b/metalava-model-psi/src/main/java/com/android/tools/metalava/model/psi/PsiSourceFileItem.kt
@@ -229,7 +229,7 @@
             .orEmpty()
     }
 
-    override fun containingPackage(strict: Boolean): PackageItem? {
+    override fun containingPackage(): PackageItem? {
         return when {
             uFile != null -> codebase.findPackage(uFile.packageName)
             file is PsiJavaFile -> codebase.findPackage(file.packageName)
diff --git a/metalava-model-testsuite/src/main/java/com/android/tools/metalava/model/testsuite/BootstrapSourceModelProviderTest.kt b/metalava-model-testsuite/src/main/java/com/android/tools/metalava/model/testsuite/BootstrapSourceModelProviderTest.kt
index 54b891b..3bac336 100644
--- a/metalava-model-testsuite/src/main/java/com/android/tools/metalava/model/testsuite/BootstrapSourceModelProviderTest.kt
+++ b/metalava-model-testsuite/src/main/java/com/android/tools/metalava/model/testsuite/BootstrapSourceModelProviderTest.kt
@@ -94,6 +94,7 @@
             val testClass = codebase.assertClass("test.pkg.Test")
             val fieldItem = testClass.assertField("field")
             assertEquals("field", fieldItem.name())
+            assertEquals(testClass, fieldItem.containingClass())
         }
     }
 
@@ -234,11 +235,14 @@
         ) { codebase ->
             val packageItem = codebase.assertPackage("test.pkg")
             val parentPackageItem = codebase.assertPackage("test")
+            val rootPackageItem = codebase.assertPackage("")
             val classItem = codebase.assertClass("test.pkg.Test")
             val innerClassItem = codebase.assertClass("test.pkg.Test.Inner")
             assertEquals(1, packageItem.topLevelClasses().count())
             assertEquals(0, parentPackageItem.topLevelClasses().count())
             assertEquals(parentPackageItem, packageItem.containingPackage())
+            assertEquals(rootPackageItem, parentPackageItem.containingPackage())
+            assertEquals(null, rootPackageItem.containingPackage())
             assertEquals(packageItem, classItem.containingPackage())
             assertEquals(packageItem, innerClassItem.containingPackage())
         }
diff --git a/metalava-model-text/src/main/java/com/android/tools/metalava/model/text/TextPackageItem.kt b/metalava-model-text/src/main/java/com/android/tools/metalava/model/text/TextPackageItem.kt
index e8f01a9..4a3c694 100644
--- a/metalava-model-text/src/main/java/com/android/tools/metalava/model/text/TextPackageItem.kt
+++ b/metalava-model-text/src/main/java/com/android/tools/metalava/model/text/TextPackageItem.kt
@@ -61,7 +61,7 @@
 
     override fun qualifiedName(): String = name
 
-    override fun containingClass(strict: Boolean): ClassItem? = null
+    override fun containingClass(): ClassItem? = null
 
     override fun equals(other: Any?): Boolean {
         if (this === other) return true
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineBasedCodebase.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineBasedCodebase.kt
index 5541790..cce0e82 100644
--- a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineBasedCodebase.kt
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineBasedCodebase.kt
@@ -90,6 +90,10 @@
         classMap.put(classItem.qualifiedName(), classItem)
     }
 
+    fun addPackage(packageItem: TurbinePackageItem) {
+        packageMap.put(packageItem.qualifiedName(), packageItem)
+    }
+
     fun initialize() {
         topLevelClassesFromSource = ArrayList(CLASS_ESTIMATE)
         classMap = HashMap(CLASS_ESTIMATE)
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineClassItem.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineClassItem.kt
index 10c676e..104d9c1 100644
--- a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineClassItem.kt
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineClassItem.kt
@@ -21,14 +21,12 @@
 import com.android.tools.metalava.model.Codebase
 import com.android.tools.metalava.model.ConstructorItem
 import com.android.tools.metalava.model.FieldItem
-import com.android.tools.metalava.model.ItemVisitor
 import com.android.tools.metalava.model.MethodItem
 import com.android.tools.metalava.model.ModifierList
 import com.android.tools.metalava.model.PackageItem
 import com.android.tools.metalava.model.PropertyItem
 import com.android.tools.metalava.model.TypeItem
 import com.android.tools.metalava.model.TypeParameterList
-import com.android.tools.metalava.model.TypeVisitor
 
 open class TurbineClassItem(
     override val codebase: Codebase,
@@ -58,6 +56,10 @@
 
     private var allInterfaces: List<TurbineClassItem>? = null
 
+    internal lateinit var containingPackage: TurbinePackageItem
+
+    internal lateinit var fields: List<TurbineFieldItem>
+
     override fun allInterfaces(): Sequence<TurbineClassItem> {
         if (allInterfaces == null) {
             val interfaces = mutableSetOf<TurbineClassItem>()
@@ -87,13 +89,10 @@
 
     override fun containingClass(): ClassItem? = containingClass
 
-    override fun containingPackage(): PackageItem {
-        TODO("b/295800205")
-    }
+    override fun containingPackage(): PackageItem =
+        containingClass?.containingPackage() ?: containingPackage
 
-    override fun fields(): List<FieldItem> {
-        TODO("b/295800205")
-    }
+    override fun fields(): List<FieldItem> = fields
 
     override fun getRetention(): AnnotationRetention {
         TODO("b/295800205")
@@ -158,17 +157,12 @@
         TODO("b/295800205")
     }
 
-    override fun accept(visitor: ItemVisitor) {
-        TODO("b/295800205")
-    }
-
-    override fun acceptTypes(visitor: TypeVisitor) {
-        TODO("b/295800205")
-    }
-
     override fun hashCode(): Int = qualifiedName.hashCode()
 
     override fun equals(other: Any?): Boolean {
+        if (this === other) {
+            return true
+        }
         return other is ClassItem && qualifiedName() == other.qualifiedName()
     }
 }
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
index a0decf2..438a386 100644
--- a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineCodebaseInitialiser.kt
@@ -27,7 +27,9 @@
 import com.google.turbine.tree.Tree
 import com.google.turbine.tree.Tree.CompUnit
 import com.google.turbine.tree.Tree.Kind.TY_DECL
+import com.google.turbine.tree.Tree.Kind.VAR_DECL
 import com.google.turbine.tree.Tree.TyDecl
+import com.google.turbine.tree.Tree.VarDecl
 import java.io.File
 import java.util.Optional
 
@@ -62,6 +64,8 @@
         for (unit in units) {
             createItems(unit)
         }
+        // Create root package
+        findOrCreatePackage("")
 
         // This method sets up hierarchy using only parsed source files
         setInnerClassHierarchy(units)
@@ -81,7 +85,7 @@
     }
 
     /** Extracts data from the compilation units. A unit corresponds to one parsed source file. */
-    fun createItems(unit: CompUnit) {
+    private fun createItems(unit: CompUnit) {
         val optPkg = unit.pkg()
         val pkg = if (optPkg.isPresent()) optPkg.get() else null
         var pkgName = ""
@@ -89,22 +93,40 @@
             val pkgNameList = pkg.name().map { it.value() }
             pkgName = pkgNameList.joinToString(separator = ".")
         }
+        val pkgItem = findOrCreatePackage(pkgName)
+
         val typeDecls = unit.decls()
         for (typeDecl in typeDecls) {
-            populateClass(typeDecl, pkgName, null, true)
+            populateClass(typeDecl, pkgItem, null, true)
+        }
+    }
+
+    /**
+     * Searches for the package with supplied name in the codebase's package map and if not found
+     * creates the corresponding TurbinePackageItem and adds it to the package map.
+     */
+    private fun findOrCreatePackage(name: String): TurbinePackageItem {
+        val pkgItem = codebase.findPackage(name)
+        if (pkgItem != null) {
+            return pkgItem as TurbinePackageItem
+        } else {
+            val modifers = DefaultModifierList(codebase)
+            val turbinePkgItem = TurbinePackageItem(codebase, name, modifers)
+            codebase.addPackage(turbinePkgItem)
+            return turbinePkgItem
         }
     }
 
     /** Creates a TurbineClassItem and adds the classitem to the various maps in codebase. */
-    fun populateClass(
+    private fun populateClass(
         typeDecl: TyDecl,
-        pkgName: String,
+        pkgItem: TurbinePackageItem,
         containingClass: TurbineClassItem?,
         isTopClass: Boolean,
     ) {
         val className = typeDecl.name().value()
         val fullName = if (isTopClass) className else containingClass?.fullName() + "." + className
-        val qualifiedName = pkgName + "." + fullName
+        val qualifiedName = pkgItem.qualifiedName() + "." + fullName
         val modifers = DefaultModifierList(codebase)
         val classItem =
             TurbineClassItem(
@@ -118,23 +140,37 @@
             )
 
         val members = typeDecl.members()
+        val fields = mutableListOf<TurbineFieldItem>()
         for (member in members) {
             when (member.kind()) {
                 // A class or an interface declaration
                 TY_DECL -> {
-                    populateClass(member as TyDecl, pkgName, classItem, false)
+                    populateClass(member as TyDecl, pkgItem, classItem, false)
+                }
+                // A field declaration
+                VAR_DECL -> {
+                    val field = member as VarDecl
+                    val fieldItem =
+                        TurbineFieldItem(codebase, field.name().value(), classItem, modifers)
+                    fields.add(fieldItem)
                 }
                 else -> {
                     // Do nothing for now
                 }
             }
         }
+        classItem.fields = fields
         codebase.addClass(classItem, isTopClass)
         itemMap.put(typeDecl, qualifiedName)
+
+        if (isTopClass) {
+            classItem.containingPackage = pkgItem
+            pkgItem.addTopClass(classItem)
+        }
     }
 
     /** This method sets up inner class hierarchy without using binder. */
-    fun setInnerClassHierarchy(units: List<CompUnit>) {
+    private fun setInnerClassHierarchy(units: List<CompUnit>) {
         for (unit in units) {
             val typeDecls = unit.decls()
             for (typeDecl in typeDecls) {
@@ -144,7 +180,7 @@
     }
 
     /** Method to setup innerclasses for a single class */
-    fun setInnerClasses(typeDecl: TyDecl) {
+    private fun setInnerClasses(typeDecl: TyDecl) {
         val className = itemMap[typeDecl]!!
         val classItem = codebase.findClass(className)!!
         val innerClasses =
@@ -159,7 +195,7 @@
     }
 
     /** This method uses output from binder to setup superclass and implemented interfaces */
-    fun setSuperClassHierarchy(units: ImmutableMap<ClassSymbol, SourceTypeBoundClass>) {
+    private fun setSuperClassHierarchy(units: ImmutableMap<ClassSymbol, SourceTypeBoundClass>) {
         for ((sym, cls) in units) {
             val classItem = codebase.findClass(sym.toString())
             if (classItem != null) {
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineFieldItem.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineFieldItem.kt
new file mode 100644
index 0000000..1b8e79e
--- /dev/null
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbineFieldItem.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava.model.turbine
+
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.FieldItem
+import com.android.tools.metalava.model.ModifierList
+import com.android.tools.metalava.model.TypeItem
+
+class TurbineFieldItem(
+    override val codebase: Codebase,
+    private val name: String,
+    private val containingClass: TurbineClassItem,
+    override val modifiers: ModifierList,
+) : TurbineItem(codebase, modifiers), FieldItem {
+
+    override var inheritedFrom: ClassItem? = null
+
+    override var inheritedField: Boolean = false
+
+    override fun name(): String = name
+
+    override fun containingClass(): ClassItem = containingClass
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) {
+            return true
+        }
+        return other is FieldItem &&
+            name == other.name() &&
+            containingClass == other.containingClass()
+    }
+
+    override fun hashCode(): Int = name.hashCode()
+
+    override fun type(): TypeItem {
+        TODO("b/295800205")
+    }
+
+    override fun duplicate(targetContainingClass: ClassItem): FieldItem {
+        TODO("b/295800205")
+    }
+
+    override fun initialValue(requireConstant: Boolean): Any? {
+        TODO("b/295800205")
+    }
+
+    override fun isEnumConstant(): Boolean {
+        TODO("b/295800205")
+    }
+}
diff --git a/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbinePackageItem.kt b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbinePackageItem.kt
new file mode 100644
index 0000000..89409b2
--- /dev/null
+++ b/metalava-model-turbine/src/main/java/com/android/tools/metalava/model/turbine/TurbinePackageItem.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.metalava.model.turbine
+
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.Codebase
+import com.android.tools.metalava.model.ModifierList
+import com.android.tools.metalava.model.PackageItem
+
+class TurbinePackageItem(
+    override val codebase: Codebase,
+    private val qualifiedName: String,
+    override val modifiers: ModifierList,
+) : PackageItem, TurbineItem(codebase, modifiers) {
+
+    private var topClasses = mutableListOf<TurbineClassItem>()
+
+    private var containingPackage: PackageItem? = null
+
+    // N.A. a package cannot be contained in a class
+    override fun containingClass(): ClassItem? = null
+
+    override fun equals(other: Any?): Boolean {
+        if (this === other) {
+            return true
+        }
+        return other is PackageItem && qualifiedName == other.qualifiedName()
+    }
+
+    override fun hashCode(): Int = qualifiedName.hashCode()
+
+    override fun qualifiedName(): String = qualifiedName
+
+    override fun topLevelClasses(): Sequence<ClassItem> = topClasses.asSequence()
+
+    internal fun addTopClass(classItem: TurbineClassItem) {
+        topClasses.add(classItem)
+    }
+
+    override fun containingPackage(): PackageItem? {
+        // if this package is root package, then return null
+        return if (qualifiedName.isEmpty()) null
+        else {
+            if (containingPackage == null) {
+                // If package is of the form A.B then the containing package is A
+                // If package is top level, then containing package is the root package
+                val name = qualifiedName()
+                val lastDot = name.lastIndexOf('.')
+                containingPackage =
+                    if (lastDot != -1) codebase.findPackage(name.substring(0, lastDot))
+                    else codebase.findPackage("")
+            }
+            return containingPackage
+        }
+    }
+}
diff --git a/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt b/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
index e17e011..b2f1a41 100644
--- a/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
+++ b/metalava-model-turbine/src/test/resources/model-test-suite-baseline.txt
@@ -1,9 +1,6 @@
 com.android.tools.metalava.model.testsuite.BootstrapSourceModelProviderTest
-  040 - check package exists[turbine,java]
-  050 - check field exists[turbine,java]
   060 - check method exists[turbine,java]
   070 - check constructor exists[turbine,java]
-  110 - advanced package test[turbine,java]
 
 com.android.tools.metalava.model.testsuite.CommonClassItemTest
   empty class[turbine,java]
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/ClassItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/ClassItem.kt
index 7151bc7..6913e01 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/ClassItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/ClassItem.kt
@@ -194,16 +194,10 @@
     fun isClass(): Boolean = !isInterface() && !isAnnotationType() && !isEnum()
 
     /** The containing class, for inner classes */
-    @MetalavaApi fun containingClass(): ClassItem?
+    @MetalavaApi override fun containingClass(): ClassItem?
 
     /** The containing package */
-    fun containingPackage(): PackageItem
-
-    override fun containingPackage(strict: Boolean): PackageItem = containingPackage()
-
-    override fun containingClass(strict: Boolean): ClassItem? {
-        return if (strict) containingClass() else this
-    }
+    override fun containingPackage(): PackageItem
 
     /** Gets the type for this class */
     fun toType(): TypeItem
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/ConstructorItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/ConstructorItem.kt
index f6807ea..5d71275 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/ConstructorItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/ConstructorItem.kt
@@ -23,9 +23,8 @@
     override fun internalName(): String = "<init>"
 
     /**
-     * The constructor that this method delegates to initially (e.g. super- or this- or
-     * default/implicit null constructor). Note that it may not be in a super class, as in the case
-     * of a this-call.
+     * The constructor that the stub version of this constructor must delegate to in its `super`
+     * call. Is `null` if the super class has a default constructor.
      */
     var superConstructor: ConstructorItem?
 
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/Item.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/Item.kt
index 98414a7..83d12f9 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/Item.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/Item.kt
@@ -270,19 +270,11 @@
      */
     fun describe(capitalize: Boolean = false) = describe(this, capitalize)
 
-    /**
-     * Returns the package that contains this item. If [strict] is false, this will return self if
-     * called on a package, otherwise it will return the containing package (e.g. "foo" for
-     * "foo.bar"). The parameter is ignored on other item types.
-     */
-    fun containingPackage(strict: Boolean = true): PackageItem?
+    /** Returns the package that contains this item. */
+    fun containingPackage(): PackageItem?
 
-    /**
-     * Returns the class that contains this item. If [strict] is false, this will return self if
-     * called on a class, otherwise it will return the outer class, if any. The parameter is ignored
-     * on other item types.
-     */
-    fun containingClass(strict: Boolean = true): ClassItem?
+    /** Returns the class that contains this item. */
+    fun containingClass(): ClassItem?
 
     /**
      * Returns the associated type if any. For example, for a field, property or parameter, this is
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/MemberItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/MemberItem.kt
index 04baf26..a57ec0f 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/MemberItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/MemberItem.kt
@@ -27,12 +27,9 @@
     fun internalName(): String = name()
 
     /** The containing class */
-    @MetalavaApi fun containingClass(): ClassItem
+    @MetalavaApi override fun containingClass(): ClassItem
 
-    override fun containingClass(strict: Boolean): ClassItem = containingClass()
-
-    override fun containingPackage(strict: Boolean): PackageItem =
-        containingClass().containingPackage(false)
+    override fun containingPackage(): PackageItem = containingClass().containingPackage()
 
     override fun parent(): ClassItem? = containingClass()
 
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/MethodItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/MethodItem.kt
index fa98dbe..899eae0 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/MethodItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/MethodItem.kt
@@ -575,6 +575,30 @@
         }
     }
 
+    private fun getUniqueSuperInterfaceMethods(
+        superInterfaceMethods: List<MethodItem>
+    ): List<MethodItem> {
+        val visitCountMap = mutableMapOf<ClassItem, Int>()
+
+        // perform BFS on all super interfaces of each super interface methods'
+        // containing interface to determine the leaf interface of each unique hierarchy.
+        superInterfaceMethods.forEach {
+            val superInterface = it.containingClass()
+            val queue = mutableListOf(superInterface)
+            while (queue.isNotEmpty()) {
+                val s = queue.removeFirst()
+                visitCountMap[s] = visitCountMap.getOrDefault(s, 0) + 1
+                queue.addAll(
+                    s.interfaceTypes().mapNotNull { interfaceType -> interfaceType.asClass() }
+                )
+            }
+        }
+
+        // If visit count is greater than 1, it means the interface is within the hierarchy of
+        // another method, thus filter out.
+        return superInterfaceMethods.filter { visitCountMap[it.containingClass()]!! == 1 }
+    }
+
     /**
      * Determines if the method needs to be added to the signature file in order to prevent errors
      * when compiling the stubs or the reverse dependencies of the stubs.
@@ -593,10 +617,34 @@
                     // changes)
                     !sameSignature(this, it.first())
                 } else {
-                    it.all { superMethod ->
-                        superMethod.containingClass().isJavaLangObject() ||
-                            superMethod.requiresOverride()
-                    }
+                    // Since a class can extend a single class except Object,
+                    // there is only one non-Object super class method at max.
+                    val superClassMethods =
+                        it.firstOrNull { superMethod ->
+                            superMethod.containingClass().isClass() &&
+                                !superMethod.containingClass().isJavaLangObject()
+                        }
+
+                    // Assume a class implements two interfaces A and B;
+                    // A provides a default super method, and B provides an abstract super method.
+                    // In such case, the child method is a required overriding method when:
+                    // - A and B do not extend each other or
+                    // - A is a super interface of B
+                    // On the other hand, the child method is not a required overriding method when:
+                    // - B is a super interface of A
+                    // Given this, we should make decisions only based on the leaf interface of each
+                    // unique hierarchy.
+                    val uniqueSuperInterfaceMethods =
+                        getUniqueSuperInterfaceMethods(
+                            it.filter { superMethod -> superMethod.containingClass().isInterface() }
+                        )
+
+                    // If super method is non-null, whether this method is required
+                    // is determined by whether the super method requires override.
+                    // If super method is null, this method is required if there is a
+                    // unique super interface that requires override.
+                    superClassMethods?.requiresOverride()
+                        ?: uniqueSuperInterfaceMethods.any { s -> s.requiresOverride() }
                 }
             }) ||
             // To inherit methods with override-equivalent signatures
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/PackageItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/PackageItem.kt
index 3ee5e12..fd303d8 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/PackageItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/PackageItem.kt
@@ -36,10 +36,7 @@
     override fun parent(): PackageItem? =
         if (qualifiedName().isEmpty()) null else containingPackage()
 
-    override fun containingPackage(strict: Boolean): PackageItem? {
-        if (!strict) {
-            return this
-        }
+    override fun containingPackage(): PackageItem? {
         val name = qualifiedName()
         val lastDot = name.lastIndexOf('.')
         return if (lastDot != -1) {
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/ParameterItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/ParameterItem.kt
index 9ea761b..6630cbf 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/ParameterItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/ParameterItem.kt
@@ -126,11 +126,9 @@
         return null
     }
 
-    override fun containingClass(strict: Boolean): ClassItem? =
-        containingMethod().containingClass(false)
+    override fun containingClass(): ClassItem? = containingMethod().containingClass()
 
-    override fun containingPackage(strict: Boolean): PackageItem? =
-        containingMethod().containingPackage(false)
+    override fun containingPackage(): PackageItem? = containingMethod().containingPackage()
 
     // TODO: modifier list
 }
diff --git a/metalava-model/src/main/java/com/android/tools/metalava/model/SourceFileItem.kt b/metalava-model/src/main/java/com/android/tools/metalava/model/SourceFileItem.kt
index 16faaa1..c4e09ed 100644
--- a/metalava-model/src/main/java/com/android/tools/metalava/model/SourceFileItem.kt
+++ b/metalava-model/src/main/java/com/android/tools/metalava/model/SourceFileItem.kt
@@ -29,7 +29,7 @@
 
     override fun parent(): PackageItem? = containingPackage()
 
-    override fun containingClass(strict: Boolean): ClassItem? = null
+    override fun containingClass(): ClassItem? = null
 
     override fun type(): TypeItem? = null
 
diff --git a/metalava/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt b/metalava/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
index 1904ec9..68f3b9c 100644
--- a/metalava/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
+++ b/metalava/src/main/java/com/android/tools/metalava/ApiAnalyzer.kt
@@ -162,16 +162,14 @@
     }
 
     /**
-     * Handle computing constructor hierarchy. We'll be setting several attributes:
-     * [ClassItem.stubConstructor] : The default constructor to invoke in this class from
-     * subclasses. **NOTE**: This constructor may not be part of the [ClassItem.constructors] list,
-     * e.g. for package private default constructors we've inserted (because there were no public
-     * constructors or constructors not using hidden parameter types.)
+     * Handle computing constructor hierarchy.
      *
-     * If we can find a public constructor we'll put that here instead.
+     * We'll be setting several attributes: [ClassItem.stubConstructor] : The default constructor to
+     * invoke in this class from subclasses. **NOTE**: This constructor may not be part of the
+     * [ClassItem.constructors] list, e.g. for package private default constructors we've inserted
+     * (because there were no public constructors or constructors not using hidden parameter types.)
      *
-     * [ConstructorItem.superConstructor] The default constructor to invoke. If set, use this rather
-     * than the [ClassItem.stubConstructor].
+     * [ConstructorItem.superConstructor] : The default constructor to invoke.
      *
      * @param visited contains the [ClassItem]s that have already been visited; this method adds
      *   [cls] to it so [cls] will not be visited again.
@@ -186,33 +184,25 @@
         //     public class A { public A(int) }
         //  package bar
         //     public class B extends A { public B(int) }
-        // If I just try inserting package private constructors here things will NOT work:
+        // If we just try inserting package private constructors here things will NOT work:
         //  package foo:
         //     public class A { public A(int); A() {} }
         //  package bar
         //     public class B extends A { public B(int); B() }
-        //  because A <() is not accessible from B() -- it's outside the same package.
+        // because A <() is not accessible from B() -- it's outside the same package.
         //
-        // So, I'll need to model the real constructors for all the scenarios where that
-        // works.
+        // So, we'll need to model the real constructors for all the scenarios where that works.
         //
-        // The remaining challenge is that there will be some gaps: when I don't have
-        // a default constructor, subclass constructors will have to have an explicit
-        // super(args) call to pick the parent constructor to use. And which one?
-        // It generally doesn't matter; just pick one, but unfortunately, the super
-        // constructor can throw exceptions, and in that case the subclass constructor
-        // must also throw all those constructors (you can't surround a super call
-        // with try/catch.)  Luckily, the source code already needs to do this to
-        // compile, so we can just use the same constructor as the super call.
-        // But there are two cases we have to deal with:
-        //   (1) the constructor doesn't call a super constructor; it calls another
-        //       constructor on this class.
-        //   (2) the super constructor it *does* call isn't available.
+        // The remaining challenge is that there will be some gaps: when we don't have a default
+        // constructor, subclass constructors will have to have an explicit super(args) call to pick
+        // the parent constructor to use. And which one? It generally doesn't matter; just pick one,
+        // but unfortunately, the super constructor can throw exceptions, and in that case the
+        // subclass constructor must also throw all those exceptions (you can't surround a super
+        // call with try/catch.)
         //
-        // For (1), this means that our stub code generator should be prepared to
-        // handle both super- and this- dispatches; we'll handle this by pointing
-        // it to the constructor to use, and it checks to see if the containing class
-        // for the constructor is the same to decide whether to emit "this" or "super".
+        // Luckily, this does not seem to be an actual problem with any of the source code that
+        // metalava currently processes. If it did become a problem then the solution would be to
+        // pick super constructors with a compatible set of throws.
 
         if (cls in visited) {
             return
@@ -234,45 +224,40 @@
         val superClass = cls.filteredSuperclass(filter)
         superClass?.let { addConstructors(it, filter, visited) }
 
-        if (superClass != null) {
-            val superDefaultConstructor = superClass.stubConstructor
-            if (superDefaultConstructor != null) {
-                val constructors = cls.constructors()
-                for (constructor in constructors) {
-                    val superConstructor = constructor.superConstructor
-                    if (
-                        superConstructor == null ||
-                            (superConstructor.containingClass() != superClass &&
-                                superConstructor.containingClass() != cls)
-                    ) {
-                        constructor.superConstructor = superDefaultConstructor
-                    }
-                }
+        val superDefaultConstructor = superClass?.stubConstructor
+        if (superDefaultConstructor != null) {
+            cls.constructors().forEach { constructor ->
+                constructor.superConstructor = superDefaultConstructor
             }
         }
 
         // Find default constructor, if one doesn't exist
-        val constructors = cls.filteredConstructors(filter).toList()
-        if (constructors.isNotEmpty()) {
-            // Try to pick the constructor, select first by fewest throwables,
-            // then fewest parameters, then based on order in listFilter.test(cls)
-            cls.stubConstructor = constructors.reduce { first, second -> pickBest(first, second) }
-            return
-        }
+        val filteredConstructors = cls.filteredConstructors(filter).toList()
+        cls.stubConstructor =
+            if (filteredConstructors.isNotEmpty()) {
+                // Try to pick the constructor, select first by fewest throwables,
+                // then fewest parameters, then based on order in listFilter.test(cls)
+                filteredConstructors.reduce { first, second -> pickBest(first, second) }
+            } else if (
+                cls.constructors().isNotEmpty() ||
+                    // For text based codebase, stub constructor needs to be generated even if
+                    // cls.constructors() is empty, so that public default constructor is not
+                    // created.
+                    cls.codebase.preFiltered
+            ) {
 
-        // For text based codebase, stub constructor needs to be generated even if
-        // cls.constructors() is empty, so that public default constructor is not created.
-        if (cls.constructors().isNotEmpty() || cls.codebase.preFiltered) {
-            // No accessible constructors are available so a package private constructor is created.
-            // Technically, the stub now has a constructor that isn't available at runtime,
-            // but apps creating subclasses inside the android.* package is not supported.
-            cls.stubConstructor =
+                // No accessible constructors are available so a package private constructor is
+                // created. Technically, the stub now has a constructor that isn't available at
+                // runtime, but apps creating subclasses inside the android.* package is not
+                // supported.
                 cls.createDefaultConstructor().also {
                     it.mutableModifiers().setVisibilityLevel(VisibilityLevel.PACKAGE_PRIVATE)
                     it.hidden = false
-                    it.superConstructor = superClass?.stubConstructor
+                    it.superConstructor = superDefaultConstructor
                 }
-        }
+            } else {
+                null
+            }
     }
 
     // TODO: Annotation test: @ParameterName, if present, must be supplied on *all* the arguments!
diff --git a/metalava/src/main/java/com/android/tools/metalava/DefaultReporter.kt b/metalava/src/main/java/com/android/tools/metalava/DefaultReporter.kt
index bc69406..6ca5ea0 100644
--- a/metalava/src/main/java/com/android/tools/metalava/DefaultReporter.kt
+++ b/metalava/src/main/java/com/android/tools/metalava/DefaultReporter.kt
@@ -22,6 +22,7 @@
 import com.android.tools.metalava.model.AnnotationArrayAttributeValue
 import com.android.tools.metalava.model.Item
 import com.android.tools.metalava.model.Location
+import com.android.tools.metalava.model.PackageItem
 import com.android.tools.metalava.reporter.Baseline
 import com.android.tools.metalava.reporter.IssueConfiguration
 import com.android.tools.metalava.reporter.Issues
@@ -99,7 +100,7 @@
         // issues from other packages
         if (item != null) {
             if (packageFilter != null) {
-                val pkg = item.containingPackage(false)
+                val pkg = (item as? PackageItem) ?: item.containingPackage()
                 if (pkg != null && !packageFilter.matches(pkg)) {
                     return false
                 }
diff --git a/metalava/src/main/java/com/android/tools/metalava/lint/ApiLint.kt b/metalava/src/main/java/com/android/tools/metalava/lint/ApiLint.kt
index df54cbd..64cee17 100644
--- a/metalava/src/main/java/com/android/tools/metalava/lint/ApiLint.kt
+++ b/metalava/src/main/java/com/android/tools/metalava/lint/ApiLint.kt
@@ -1594,15 +1594,6 @@
         }
     }
 
-    fun Item.containingClass(): ClassItem? {
-        return when (this) {
-            is MemberItem -> this.containingClass()
-            is ParameterItem -> this.containingMethod().containingClass()
-            is ClassItem -> this
-            else -> null
-        }
-    }
-
     private fun checkNullableCollections(type: TypeItem, item: Item) {
         if (type is PrimitiveTypeItem) return
         if (!item.modifiers.isNullable()) return
@@ -1785,7 +1776,21 @@
     }
 
     private fun checkHasFlaggedApi(item: Item) {
-        if (!item.modifiers.hasAnnotation { it.qualifiedName == flaggedApi }) {
+        fun itemOrAnyContainingClasses(predicate: Predicate<Item>): Boolean {
+            var it: Item? = item
+            while (it != null) {
+                if (predicate.test(it)) {
+                    return true
+                }
+                it = it.containingClass()
+            }
+            return false
+        }
+        if (
+            !itemOrAnyContainingClasses {
+                it.modifiers.hasAnnotation { it.qualifiedName == flaggedApi }
+            }
+        ) {
             val elidedField =
                 if (item is FieldItem) {
                     val inheritedFrom = item.inheritedFrom
diff --git a/metalava/src/main/java/com/android/tools/metalava/stub/JavaStubWriter.kt b/metalava/src/main/java/com/android/tools/metalava/stub/JavaStubWriter.kt
index 6a76573..ac621c6 100644
--- a/metalava/src/main/java/com/android/tools/metalava/stub/JavaStubWriter.kt
+++ b/metalava/src/main/java/com/android/tools/metalava/stub/JavaStubWriter.kt
@@ -250,24 +250,14 @@
         writer.println(" }")
     }
 
-    private fun writeConstructorBody(constructor: MethodItem?, superConstructor: MethodItem?) {
+    private fun writeConstructorBody(constructor: MethodItem, superConstructor: MethodItem?) {
         // Find any constructor in parent that we can compile against
         superConstructor?.let { it ->
             val parameters = it.parameters()
-            val invokeOnThis =
-                constructor != null && constructor.containingClass() == it.containingClass()
-            if (invokeOnThis || parameters.isNotEmpty()) {
+            if (parameters.isNotEmpty()) {
                 val includeCasts =
-                    parameters.isNotEmpty() &&
-                        it.containingClass()
-                            .constructors()
-                            .filter { filterReference.test(it) }
-                            .size > 1
-                if (invokeOnThis) {
-                    writer.print("this(")
-                } else {
-                    writer.print("super(")
-                }
+                    it.containingClass().constructors().filter { filterReference.test(it) }.size > 1
+                writer.print("super(")
                 parameters.forEachIndexed { index, parameter ->
                     if (index > 0) {
                         writer.write(", ")
@@ -284,9 +274,9 @@
                                 // type in this class
                                 val map =
                                     constructor
-                                        ?.containingClass()
-                                        ?.mapTypeVariables(it.containingClass())
-                                val cast = map?.get(type.toTypeString(context = it)) ?: typeString
+                                        .containingClass()
+                                        .mapTypeVariables(it.containingClass())
+                                val cast = map.get(type.toTypeString(context = it)) ?: typeString
                                 writer.write(cast)
                             } else {
                                 writer.write(typeString)
diff --git a/metalava/src/test/java/com/android/tools/metalava/AddAdditionalOverridesTest.kt b/metalava/src/test/java/com/android/tools/metalava/AddAdditionalOverridesTest.kt
index f802880..c1575d3 100644
--- a/metalava/src/test/java/com/android/tools/metalava/AddAdditionalOverridesTest.kt
+++ b/metalava/src/test/java/com/android/tools/metalava/AddAdditionalOverridesTest.kt
@@ -388,4 +388,73 @@
                 )
         )
     }
+
+    @Test
+    fun `Add additional overrides -- Method with multiple interface parent methods in same hierarchy not elided`() {
+        checkAddAdditionalOverrides(
+            sourceFiles =
+                arrayOf(
+                    // Although ParentInterface provides the default super method, it is abstracted
+                    // in AnotherParentInterface and thus ChildClass.Foo() is an essential method.
+                    java(
+                        """
+                    package test.pkg;
+
+                    public class ChildClass implements ParentInterface, AnotherParentInterface {
+                        public void Foo() {}
+                    }
+                    """
+                    ),
+                    java(
+                        """
+                    package test.pkg;
+
+                    public interface ParentInterface {
+                        public default void Foo() {}
+                    }
+                    """
+                    ),
+                    java(
+                        """
+                    package test.pkg;
+
+                    public interface AnotherParentInterface extends ParentInterface {
+                        public void Foo();
+                    }
+                    """
+                    ),
+                ),
+            apiOriginal =
+                """
+            // Signature format: 2.0
+            package test.pkg {
+              public interface AnotherParentInterface extends test.pkg.ParentInterface {
+                method public void Foo();
+              }
+              public class ChildClass implements test.pkg.AnotherParentInterface test.pkg.ParentInterface {
+                ctor public ChildClass();
+              }
+              public interface ParentInterface {
+                method public default void Foo();
+              }
+            }
+        """,
+            apiWithAdditionalOverrides =
+                """
+            // Signature format: 2.0
+            package test.pkg {
+              public interface AnotherParentInterface extends test.pkg.ParentInterface {
+                method public void Foo();
+              }
+              public class ChildClass implements test.pkg.AnotherParentInterface test.pkg.ParentInterface {
+                ctor public ChildClass();
+                method public void Foo();
+              }
+              public interface ParentInterface {
+                method public default void Foo();
+              }
+            }
+        """,
+        )
+    }
 }
diff --git a/metalava/src/test/java/com/android/tools/metalava/lint/FlaggedApiLintTest.kt b/metalava/src/test/java/com/android/tools/metalava/lint/FlaggedApiLintTest.kt
index 729d916..db2e69a 100644
--- a/metalava/src/test/java/com/android/tools/metalava/lint/FlaggedApiLintTest.kt
+++ b/metalava/src/test/java/com/android/tools/metalava/lint/FlaggedApiLintTest.kt
@@ -212,15 +212,9 @@
 
                         @FlaggedApi("foo/bar")
                         public class Ok extends ExistingSuperClass implements ExistingInterface {
-                            @FlaggedApi("foo/bar")
-                            Ok() {}
-                            @FlaggedApi("foo/bar")
                             public static final String OK = "bar";
-                            @FlaggedApi("foo/bar")
                             public void ok() {}
-                            @FlaggedApi("foo/bar")
                             public interface OkInterface {}
-                            @FlaggedApi("foo/bar")
                             public @interface OkAnnotation {}
                         }
                     """
@@ -274,8 +268,8 @@
             showAnnotations = arrayOf("android.annotation.SystemApi"),
             expectedIssues =
                 """
-                src/android/foobar/BadHiddenSuperClass.java:7: warning: New API must be flagged with @FlaggedApi: method android.foobar.Bad.badInherited() [UnflaggedApi]
-                src/android/foobar/BadHiddenSuperClass.java:6: warning: New API must be flagged with @FlaggedApi: field android.foobar.Bad.BAD_INHERITED [UnflaggedApi]
+                src/android/foobar/BadHiddenSuperClass.java:5: warning: New API must be flagged with @FlaggedApi: method android.foobar.Bad.badInherited() [UnflaggedApi]
+                src/android/foobar/BadHiddenSuperClass.java:4: warning: New API must be flagged with @FlaggedApi: field android.foobar.Bad.BAD_INHERITED [UnflaggedApi]
             """,
             apiLint =
                 """
@@ -329,8 +323,6 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
-
                         public interface ExistingPublicInterface {
                             public static final String EXISTING_PUBLIC_INTERFACE_FIELD = "foo";
                             public default void existingPublicInterfaceMethod() {}
@@ -341,8 +333,6 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
-
                         class BadHiddenSuperClass {
                             public static final String BAD_INHERITED = "foo";
                             public default void badInherited() {}
@@ -353,8 +343,6 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
-
                         public class ExistingPublicSuperClass {
                             public static final String EXISTING_PUBLIC_SUPER_FIELD = "foo";
                             public void existingPublicSuperMethod() {}
@@ -365,13 +353,11 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
-
                         import android.annotation.SystemApi;
 
                         /** @hide */
                         @SystemApi
-                        @FlaggedApi("namespace/flag")
+                        @SuppressWarnings("UnflaggedApi")  // Ignore the class itself for this test.
                         public class Ok extends ExistingSystemSuperClass implements ExistingSystemInterface {
                             private Ok() {}
                         }
@@ -381,13 +367,11 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
-
                         import android.annotation.SystemApi;
 
                         /** @hide */
                         @SystemApi
-                        @FlaggedApi("namespace/flag")
+                        @SuppressWarnings("UnflaggedApi")  // Ignore the class itself for this test.
                         public class Bad extends BadHiddenSuperClass {
                             private Bad() {}
                         }
@@ -397,12 +381,11 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
                         import android.annotation.SystemApi;
 
                         /** @hide */
                         @SystemApi
-                        @FlaggedApi("namespace/flag")
+                        @SuppressWarnings("UnflaggedApi")  // Ignore the class itself for this test.
                         public class Ok2 extends ExistingPublicSuperClass implements ExistingPublicInterface {
                             private Ok2() {}
                         }
@@ -412,7 +395,6 @@
                         """
                         package android.foobar;
 
-                        import android.annotation.FlaggedApi;
                         import android.annotation.SystemApi;
 
                         /** @hide */