check-flagged-apis: add support for methods (no parameters)
Teach check-flagged-apis to parse methods. The implementation is only half done: method signatures that accept parameters are ignored. A follow-up CL will add support for these. check-flagged-apis treats constructors and regular methods the same. Bug: 334870672 Test: atest --host check-flagged-apis-test Change-Id: Ie98db767289ac2a35aa85371f60ecb3970170d86
This commit is contained in:
@@ -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,7 +137,11 @@ 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")),
|
||||
)
|
||||
|
@@ -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
|
||||
@@ -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")
|
||||
@@ -240,6 +260,29 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> {
|
||||
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.$methodName($methodArgs)"))
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user