Loading tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,42 @@ class CheckFlaggedApisTest { assertEquals(expected, actual) } @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 = Loading tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +39 −1 Original line number Diff line number Diff line Loading @@ -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)) } Loading Loading
tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +36 −0 Original line number Diff line number Diff line Loading @@ -269,6 +269,42 @@ class CheckFlaggedApisTest { assertEquals(expected, actual) } @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 = Loading
tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +39 −1 Original line number Diff line number Diff line Loading @@ -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)) } Loading