Merge changes Ia860d7b0,Ie98db767 into main am: cfbcdc1ec5

Original change: https://android-review.googlesource.com/c/platform/build/+/3061972

Change-Id: I7cc0303acf9c3bfe1e21d0f945b654119e2c4111
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Michael Wright
2024-04-29 20:49:56 +00:00
committed by Automerger Merge Worker
2 changed files with 58 additions and 6 deletions

View File

@@ -31,8 +31,9 @@ private val API_SIGNATURE =
// Signature format: 2.0 // Signature format: 2.0
package android { package android {
@FlaggedApi("android.flag.foo") public final class Clazz { @FlaggedApi("android.flag.foo") public final class Clazz {
ctor public Clazz(); ctor @FlaggedApi("android.flag.foo") public Clazz();
field @FlaggedApi("android.flag.foo") public static final int FOO = 1; // 0x1 field @FlaggedApi("android.flag.foo") public static final int FOO = 1; // 0x1
method @FlaggedApi("android.flag.foo") public int getErrorCode();
} }
@FlaggedApi("android.flag.bar") public static class Clazz.Builder { @FlaggedApi("android.flag.bar") public static class Clazz.Builder {
} }
@@ -47,6 +48,7 @@ private val API_VERSIONS =
<class name="android/Clazz" since="1"> <class name="android/Clazz" since="1">
<method name="&lt;init>()V"/> <method name="&lt;init>()V"/>
<field name="FOO"/> <field name="FOO"/>
<method name="getErrorCode()I"/>
</class> </class>
<class name="android/Clazz${"$"}Builder" since="2"> <class name="android/Clazz${"$"}Builder" since="2">
</class> </class>
@@ -88,7 +90,9 @@ class CheckFlaggedApisTest {
val expected = val expected =
setOf( setOf(
Pair(Symbol("android.Clazz"), Flag("android.flag.foo")), Pair(Symbol("android.Clazz"), Flag("android.flag.foo")),
Pair(Symbol("android.Clazz.Clazz()"), Flag("android.flag.foo")),
Pair(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")), Pair(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")),
Pair(Symbol("android.Clazz.getErrorCode()"), Flag("android.flag.foo")),
Pair(Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), Pair(Symbol("android.Clazz.Builder"), Flag("android.flag.bar")),
) )
val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()) val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream())
@@ -108,7 +112,9 @@ class CheckFlaggedApisTest {
val expected: Set<Symbol> = val expected: Set<Symbol> =
setOf( setOf(
Symbol("android.Clazz"), Symbol("android.Clazz"),
Symbol("android.Clazz.Clazz()"),
Symbol("android.Clazz.FOO"), Symbol("android.Clazz.FOO"),
Symbol("android.Clazz.getErrorCode()"),
Symbol("android.Clazz.Builder"), Symbol("android.Clazz.Builder"),
) )
val actual = parseApiVersions(API_VERSIONS.byteInputStream()) val actual = parseApiVersions(API_VERSIONS.byteInputStream())
@@ -131,7 +137,11 @@ class CheckFlaggedApisTest {
val expected = val expected =
setOf<ApiError>( setOf<ApiError>(
DisabledFlaggedApiIsPresentError(Symbol("android.Clazz"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError(Symbol("android.Clazz"), Flag("android.flag.foo")),
DisabledFlaggedApiIsPresentError(
Symbol("android.Clazz.Clazz()"), Flag("android.flag.foo")),
DisabledFlaggedApiIsPresentError(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")),
DisabledFlaggedApiIsPresentError(
Symbol("android.Clazz.getErrorCode()"), Flag("android.flag.foo")),
DisabledFlaggedApiIsPresentError( DisabledFlaggedApiIsPresentError(
Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), Symbol("android.Clazz.Builder"), Flag("android.flag.bar")),
) )

View File

@@ -22,6 +22,7 @@ import com.android.tools.metalava.model.BaseItemVisitor
import com.android.tools.metalava.model.ClassItem import com.android.tools.metalava.model.ClassItem
import com.android.tools.metalava.model.FieldItem import com.android.tools.metalava.model.FieldItem
import com.android.tools.metalava.model.Item import com.android.tools.metalava.model.Item
import com.android.tools.metalava.model.MethodItem
import com.android.tools.metalava.model.text.ApiFile import com.android.tools.metalava.model.text.ApiFile
import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.ProgramResult import com.github.ajalt.clikt.core.ProgramResult
@@ -48,7 +49,7 @@ import org.w3c.dom.Node
@JvmInline @JvmInline
internal value class Symbol(val name: String) { internal value class Symbol(val name: String) {
companion object { companion object {
private val FORBIDDEN_CHARS = listOf('/', '#', '$') private val FORBIDDEN_CHARS = listOf('#', '$')
/** Create a new Symbol from a String that may include delimiters other than dot. */ /** Create a new Symbol from a String that may include delimiters other than dot. */
fun create(name: String): Symbol { fun create(name: String): Symbol {
@@ -187,6 +188,25 @@ internal fun parseApiSignature(path: String, input: InputStream): Set<Pair<Symbo
} }
} }
override fun visitMethod(method: MethodItem) {
getFlagOrNull(method)?.let { flag ->
val name = buildString {
append(method.containingClass().qualifiedName())
append(".")
append(method.name())
append("(")
// TODO(334870672): replace this early return with proper parsing of the command line
// arguments, followed by translation to Lname/of/class; + III format
if (!method.parameters().isEmpty()) {
return
}
append(")")
}
val symbol = Symbol.create(name)
output.add(Pair(symbol, flag))
}
}
private fun getFlagOrNull(item: Item): Flag? { private fun getFlagOrNull(item: Item): Flag? {
return item.modifiers return item.modifiers
.findAnnotation("android.annotation.FlaggedApi") .findAnnotation("android.annotation.FlaggedApi")
@@ -223,7 +243,7 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> {
requireNotNull(cls.getAttribute("name")) { requireNotNull(cls.getAttribute("name")) {
"Bad XML: <class> element without name attribute" "Bad XML: <class> element without name attribute"
} }
output.add(Symbol.create(className)) output.add(Symbol.create(className.replace("/", ".")))
} }
val fields = document.getElementsByTagName("field") val fields = document.getElementsByTagName("field")
@@ -235,9 +255,31 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> {
"Bad XML: <field> element without name attribute" "Bad XML: <field> element without name attribute"
} }
val className = val className =
requireNotNull(field.getParentNode()) { "Bad XML: top level <field> element" } requireNotNull(field.getParentNode()?.getAttribute("name")) { "Bad XML: top level <field> element" }
.getAttribute("name") output.add(Symbol.create("${className.replace("/", ".")}.$fieldName"))
output.add(Symbol.create("$className.$fieldName")) }
val methods = document.getElementsByTagName("method")
// ktfmt doesn't understand the `..<` range syntax; explicitly call .rangeUntil instead
for (i in 0.rangeUntil(methods.getLength())) {
val method = methods.item(i)
val methodSignature =
requireNotNull(method.getAttribute("name")) {
"Bad XML: <method> element without name attribute"
}
val methodSignatureParts = methodSignature.split(Regex("\\(|\\)"))
if (methodSignatureParts.size != 3) {
throw Exception("Bad XML: method signature '$methodSignature': debug $methodSignatureParts")
}
var (methodName, methodArgs, methodReturnValue) = methodSignatureParts
val packageAndClassName =
requireNotNull(method.getParentNode()?.getAttribute("name")) {
"Bad XML: top level <method> element, or <class> element missing name attribute"
}
if (methodName == "<init>") {
methodName = packageAndClassName.split("/").last()
}
output.add(Symbol.create("${packageAndClassName.replace("/", ".")}.$methodName($methodArgs)"))
} }
return output return output