diff options
author | Mårten Kongstad <amhk@google.com> | 2024-05-08 10:00:32 +0200 |
---|---|---|
committer | Mårten Kongstad <amhk@google.com> | 2024-05-08 13:30:58 +0200 |
commit | 0d44e721ed0539d9c3ad75aec138204ae2054faa (patch) | |
tree | ebf6b756c411be99fa4de30fdf7767f57980aa4e | |
parent | 32b652fd68e9d17be61b3a6a0c5ceff213b29b36 (diff) | |
download | build-0d44e721ed0539d9c3ad75aec138204ae2054faa.tar.gz |
check-flagged-apis: handle nested flags
Consider
@FlaggedApi(FLAG_OUTER) Clazz {
@FlaggedApi(FLAG_INNER) method();
}
If FLAG_OUTER is disabled, any class members are ignored. Teach
check-flagged-apis to recognize this and stop reporting false positives.
Bug: 339183637
Test: atest --host check-flagged-apis-test
Change-Id: Ie6799e952dc33874c1239231f841d7dfd947c7ce
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt | 36 | ||||
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt | 40 |
2 files changed, 75 insertions, 1 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 cd859448b0..111ea91f85 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt @@ -270,6 +270,42 @@ class CheckFlaggedApisTest { } @Test + fun testNestedFlagsOuterFlagWins() { + val apiSignature = + """ + // Signature format: 2.0 + package android { + @FlaggedApi("android.flag.foo") public final class A { + method @FlaggedApi("android.flag.bar") public boolean method(); + } + @FlaggedApi("android.flag.bar") public final class B { + method @FlaggedApi("android.flag.foo") public boolean method(); + } + } + """ + .trim() + + val apiVersions = + """ + <?xml version="1.0" encoding="utf-8"?> + <api version="3"> + <class name="android/B" since="1"> + <extends name="java/lang/Object"/> + </class> + </api> + """ + .trim() + + val expected = setOf<ApiError>() + val actual = + findErrors( + parseApiSignature("in-memory", apiSignature.byteInputStream()), + parseFlagValues(generateFlagsProto(DISABLED, ENABLED)), + parseApiVersions(apiVersions.byteInputStream())) + assertEquals(expected, actual) + } + + @Test fun testFindErrorsDisabledFlaggedApiIsPresent() { val expected = setOf<ApiError>( 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 b514048bd6..a277ce815f 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt @@ -385,10 +385,48 @@ internal fun findErrors( return false } + + /** + * Returns whether the given flag is enabled for the given symbol. + * + * A flagged member inside a flagged class is ignored (and the flag value considered disabled) if + * the class' flag is disabled. + * + * @param symbol the symbol to check + * @param flag the flag to check + * @return whether the flag is enabled for the given symbol + */ + fun isFlagEnabledForSymbol(symbol: Symbol, flag: Flag): Boolean { + when (symbol) { + is ClassSymbol -> return flags.getValue(flag) + is MemberSymbol -> { + val memberFlagValue = flags.getValue(flag) + if (!memberFlagValue) { + return false + } + // Special case: if the MemberSymbol's flag is enabled, but the outer + // ClassSymbol's flag (if the class is flagged) is disabled, consider + // the MemberSymbol's flag as disabled: + // + // @FlaggedApi(this-flag-is-disabled) Clazz { + // @FlaggedApi(this-flag-is-enabled) method(); // The Clazz' flag "wins" + // } + // + // Note: the current implementation does not handle nested classes. + val classFlagValue = + flaggedSymbolsInSource + .find { it.first.toPrettyString() == symbol.clazz } + ?.let { flags.getValue(it.second) } + ?: true + return classFlagValue + } + } + } + val errors = mutableSetOf<ApiError>() for ((symbol, flag) in flaggedSymbolsInSource) { try { - if (flags.getValue(flag)) { + if (isFlagEnabledForSymbol(symbol, flag)) { if (!symbolsInOutput.containsSymbol(symbol)) { errors.add(EnabledFlaggedApiNotPresentError(symbol, flag)) } |