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 1f36a640dc..483546151d 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt @@ -95,20 +95,20 @@ class CheckFlaggedApisTest { fun testParseApiSignature() { 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.createClass("android/Clazz"), 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")), Pair( - Symbol("android/Clazz/setData(I[[ILandroid/util/Utility;)"), + Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"), Flag("android.flag.foo")), Pair( - Symbol("android/Clazz/setVariableData(I[Landroid/util/Atom;)"), + Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"), Flag("android.flag.foo")), Pair( - Symbol("android/Clazz/innerClassArg(Landroid/Clazz/Builder;)"), + Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"), Flag("android.flag.foo")), - Pair(Symbol("android/Clazz/Builder"), Flag("android.flag.bar")), + Pair(Symbol.createClass("android/Clazz/Builder"), Flag("android.flag.bar")), ) val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()) assertEquals(expected, actual) @@ -126,14 +126,14 @@ class CheckFlaggedApisTest { fun testParseApiVersions() { val expected: Set = setOf( - Symbol("android/Clazz"), - Symbol("android/Clazz/Clazz()"), - Symbol("android/Clazz/FOO"), - Symbol("android/Clazz/getErrorCode()"), - Symbol("android/Clazz/setData(I[[ILandroid/util/Utility;)"), - Symbol("android/Clazz/setVariableData(I[Landroid/util/Atom;)"), - Symbol("android/Clazz/innerClassArg(Landroid/Clazz/Builder;)"), - Symbol("android/Clazz/Builder"), + Symbol.createClass("android/Clazz"), + 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"), ) val actual = parseApiVersions(API_VERSIONS.byteInputStream()) assertEquals(expected, actual) @@ -153,8 +153,8 @@ class CheckFlaggedApisTest { .trim() val expected: Set = setOf( - Symbol("android/Clazz/Foo/Bar"), - Symbol("android/Clazz/Foo/Bar/Bar()"), + Symbol.createClass("android/Clazz/Foo/Bar"), + Symbol.createMethod("android/Clazz/Foo/Bar", "Bar()"), ) val actual = parseApiVersions(apiVersions.byteInputStream()) assertEquals(expected, actual) @@ -175,23 +175,25 @@ class CheckFlaggedApisTest { fun testFindErrorsDisabledFlaggedApiIsPresent() { val expected = setOf( - 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")), + Symbol.createClass("android/Clazz"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError( - Symbol("android/Clazz/getErrorCode()"), Flag("android.flag.foo")), + Symbol.createMethod("android/Clazz", "Clazz()"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError( - Symbol("android/Clazz/setData(I[[ILandroid/util/Utility;)"), + Symbol.createField("android/Clazz", "FOO"), Flag("android.flag.foo")), + DisabledFlaggedApiIsPresentError( + Symbol.createMethod("android/Clazz", "getErrorCode()"), Flag("android.flag.foo")), + DisabledFlaggedApiIsPresentError( + Symbol.createMethod("android/Clazz", "setData(I[[ILandroid/util/Utility;)"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError( - Symbol("android/Clazz/setVariableData(I[Landroid/util/Atom;)"), + Symbol.createMethod("android/Clazz", "setVariableData(I[Landroid/util/Atom;)"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError( - Symbol("android/Clazz/innerClassArg(Landroid/Clazz/Builder;)"), + Symbol.createMethod("android/Clazz", "innerClassArg(Landroid/Clazz/Builder;)"), Flag("android.flag.foo")), DisabledFlaggedApiIsPresentError( - Symbol("android/Clazz/Builder"), Flag("android.flag.bar")), + Symbol.createClass("android/Clazz/Builder"), 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 4e7335756f..4ff9880a59 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt @@ -54,29 +54,41 @@ import org.w3c.dom.Node * * 1. https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.3.2 */ -@JvmInline -internal value class Symbol(val name: String) { +internal sealed class Symbol { companion object { private val FORBIDDEN_CHARS = listOf('#', '$', '.') - /** Create a new Symbol from a String that may include delimiters other than dot. */ - fun create(name: String): Symbol { - var sanitizedName = name + fun createClass(clazz: String): Symbol { + return ClassSymbol(toInternalFormat(clazz)) + } + + fun createField(clazz: String, field: String): Symbol { + require(!field.contains("(") && !field.contains(")")) + return MemberSymbol(toInternalFormat(clazz), toInternalFormat(field)) + } + + fun createMethod(clazz: String, method: String): Symbol { + return MemberSymbol(toInternalFormat(clazz), toInternalFormat(method)) + } + + protected fun toInternalFormat(name: String): String { + var internalName = name for (ch in FORBIDDEN_CHARS) { - sanitizedName = sanitizedName.replace(ch, '/') + internalName = internalName.replace(ch, '/') } - return Symbol(sanitizedName) + return internalName } } - init { - require(!name.isEmpty()) { "empty string" } - for (ch in FORBIDDEN_CHARS) { - require(!name.contains(ch)) { "$name: contains $ch" } - } - } + abstract fun toPrettyString(): String +} - override fun toString(): String = name.toString() +internal data class ClassSymbol(val clazz: String) : Symbol() { + override fun toPrettyString(): String = "$clazz" +} + +internal data class MemberSymbol(val clazz: String, val member: String) : Symbol() { + override fun toPrettyString(): String = "$clazz/$member" } /** @@ -102,7 +114,7 @@ internal data class EnabledFlaggedApiNotPresentError( override val flag: Flag ) : ApiError() { override fun toString(): String { - return "error: enabled @FlaggedApi not present in built artifact: symbol=$symbol flag=$flag" + return "error: enabled @FlaggedApi not present in built artifact: symbol=${symbol.toPrettyString()} flag=$flag" } } @@ -111,14 +123,14 @@ internal data class DisabledFlaggedApiIsPresentError( override val flag: Flag ) : ApiError() { override fun toString(): String { - return "error: disabled @FlaggedApi is present in built artifact: symbol=$symbol flag=$flag" + return "error: disabled @FlaggedApi is present in built artifact: symbol=${symbol.toPrettyString()} flag=$flag" } } internal data class UnknownFlagError(override val symbol: Symbol, override val flag: Flag) : ApiError() { override fun toString(): String { - return "error: unknown flag: symbol=$symbol flag=$flag" + return "error: unknown flag: symbol=${symbol.toPrettyString()} flag=$flag" } } @@ -183,29 +195,28 @@ internal fun parseApiSignature(path: String, input: InputStream): Set - val symbol = Symbol.create(cls.baselineElementId()) + val symbol = Symbol.createClass(cls.baselineElementId()) output.add(Pair(symbol, flag)) } } override fun visitField(field: FieldItem) { getFlagOrNull(field)?.let { flag -> - val symbol = Symbol.create(field.baselineElementId()) + val symbol = + Symbol.createField(field.containingClass().baselineElementId(), field.name()) output.add(Pair(symbol, flag)) } } override fun visitMethod(method: MethodItem) { getFlagOrNull(method)?.let { flag -> - val name = buildString { - append(method.containingClass().qualifiedName()) - append(".") + val methodName = buildString { append(method.name()) append("(") method.parameters().joinTo(this, separator = "") { it.type().internalName() } append(")") } - val symbol = Symbol.create(name) + val symbol = Symbol.createMethod(method.containingClass().qualifiedName(), methodName) output.add(Pair(symbol, flag)) } } @@ -246,7 +257,7 @@ internal fun parseApiVersions(input: InputStream): Set { requireNotNull(cls.getAttribute("name")) { "Bad XML: element without name attribute" } - output.add(Symbol.create(className.replace("/", "."))) + output.add(Symbol.createClass(className)) } val fields = document.getElementsByTagName("field") @@ -261,7 +272,7 @@ internal fun parseApiVersions(input: InputStream): Set { requireNotNull(field.getParentNode()?.getAttribute("name")) { "Bad XML: top level element" } - output.add(Symbol.create("${className.replace("/", ".")}.$fieldName")) + output.add(Symbol.createField(className, fieldName)) } val methods = document.getElementsByTagName("method") @@ -285,7 +296,7 @@ internal fun parseApiVersions(input: InputStream): Set { if (methodName == "") { methodName = packageAndClassName.split("/").last() } - output.add(Symbol.create("$packageAndClassName/$methodName($methodArgs)")) + output.add(Symbol.createMethod(packageAndClassName, "$methodName($methodArgs)")) } return output