diff options
author | Michael Wright <michaelwr@google.com> | 2024-04-29 20:29:35 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-04-29 20:29:35 +0000 |
commit | cfbcdc1ec59b4304b8f493baccd2080b98e52874 (patch) | |
tree | 2645a085ecb6d72452cbc81077526bf1b45926cd | |
parent | 013330b02889e12d8cc8f23c91f5f7cff7e985d6 (diff) | |
parent | 8d74fd0a3115cf45f16acd412a073a01ffb11b53 (diff) | |
download | build-cfbcdc1ec59b4304b8f493baccd2080b98e52874.tar.gz |
Merge changes Ia860d7b0,Ie98db767 into main
* changes:
check-flagged-apis: allow / chars in Symbol names
check-flagged-apis: add support for methods (no parameters)
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt | 12 | ||||
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt | 52 |
2 files changed, 58 insertions, 6 deletions
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 62c9cbb832..0569bfd71b 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt @@ -31,8 +31,9 @@ private val API_SIGNATURE = // Signature format: 2.0 package android { @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 + method @FlaggedApi("android.flag.foo") public int getErrorCode(); } @FlaggedApi("android.flag.bar") public static class Clazz.Builder { } @@ -47,6 +48,7 @@ private val API_VERSIONS = <class name="android/Clazz" since="1"> <method name="<init>()V"/> <field name="FOO"/> + <method name="getErrorCode()I"/> </class> <class name="android/Clazz${"$"}Builder" since="2"> </class> @@ -88,7 +90,9 @@ class CheckFlaggedApisTest { val expected = setOf( 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.getErrorCode()"), Flag("android.flag.foo")), Pair(Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), ) val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()) @@ -108,7 +112,9 @@ class CheckFlaggedApisTest { val expected: Set<Symbol> = setOf( Symbol("android.Clazz"), + Symbol("android.Clazz.Clazz()"), Symbol("android.Clazz.FOO"), + Symbol("android.Clazz.getErrorCode()"), Symbol("android.Clazz.Builder"), ) val actual = parseApiVersions(API_VERSIONS.byteInputStream()) @@ -131,8 +137,12 @@ class CheckFlaggedApisTest { val expected = setOf<ApiError>( 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.getErrorCode()"), Flag("android.flag.foo")), + DisabledFlaggedApiIsPresentError( Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), ) val actual = 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 918a5d9bf3..c3a323bb59 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt @@ -22,6 +22,7 @@ import com.android.tools.metalava.model.BaseItemVisitor import com.android.tools.metalava.model.ClassItem import com.android.tools.metalava.model.FieldItem import com.android.tools.metalava.model.Item +import com.android.tools.metalava.model.MethodItem import com.android.tools.metalava.model.text.ApiFile import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.ProgramResult @@ -48,7 +49,7 @@ import org.w3c.dom.Node @JvmInline internal value class Symbol(val name: String) { 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. */ 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? { return item.modifiers .findAnnotation("android.annotation.FlaggedApi") @@ -223,7 +243,7 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> { requireNotNull(cls.getAttribute("name")) { "Bad XML: <class> element without name attribute" } - output.add(Symbol.create(className)) + output.add(Symbol.create(className.replace("/", "."))) } val fields = document.getElementsByTagName("field") @@ -235,9 +255,31 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> { "Bad XML: <field> element without name attribute" } val className = - requireNotNull(field.getParentNode()) { "Bad XML: top level <field> element" } - .getAttribute("name") - output.add(Symbol.create("$className.$fieldName")) + requireNotNull(field.getParentNode()?.getAttribute("name")) { "Bad XML: top level <field> element" } + output.add(Symbol.create("${className.replace("/", ".")}.$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 |