Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c71d88e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "check-flagged-apis: handle nested flags" into main

parents 8211cb24 0d44e721
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -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 =
+39 −1
Original line number Diff line number Diff line
@@ -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))
        }