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
|
// 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="<init>()V"/>
|
<method name="<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")),
|
||||||
)
|
)
|
||||||
|
@@ -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
|
||||||
@@ -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")
|
||||||
@@ -240,6 +260,29 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> {
|
|||||||
output.add(Symbol.create("$className.$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.$methodName($methodArgs)"))
|
||||||
|
}
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user