Automated rollback of commit 4515bb6c932ce62c7889cf322319a3b49158acad.

*** Reason for rollback ***

Trimming CoverageOptions causes and transitions on coverage flags to fail unexpectedly. Starlark transitions have no API to determine if a flag is valid in the current configuration, and because of trimming this may not be a static list.

*** Original change description ***

Preserve analysis cache through `--run_under` command changes

Along the way, also trim `CoverageOptions` as part of the test trimming configuration, matching the logic in `TestConfiguration#SHOULD_INVALIDATE_FOR_OPTION_DIFF`. Also refactor `RunUnder` into a sealed interface implemented by two records.

Work towards #3325

PiperOrigin-RevId: 698169645
Change-Id: I9b69ad7c275d6b2d65f1cd5d5ea9941bdc9cf42c
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
index c71bd73..a7d5d30 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BUILD
@@ -1720,12 +1720,10 @@
         ":config/run_under",
         ":config/starlark_defined_config_transition",
         ":platform_options",
-        ":test/test_configuration",
         "//src/main/java/com/google/devtools/build/lib/actions:action_environment",
         "//src/main/java/com/google/devtools/build/lib/actions:artifacts",
         "//src/main/java/com/google/devtools/build/lib/actions:build_configuration_event",
         "//src/main/java/com/google/devtools/build/lib/actions:commandline_limits",
-        "//src/main/java/com/google/devtools/build/lib/analysis:test/test_trimming_logic",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
@@ -2065,7 +2063,6 @@
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
         "//third_party:guava",
-        "//third_party:jsr305",
     ],
 )
 
@@ -2830,11 +2827,9 @@
     deps = [
         ":config/build_options",
         ":config/core_option_converters",
-        ":config/core_options",
         ":config/fragment",
         ":config/fragment_options",
         ":config/per_label_options",
-        ":config/run_under",
         ":options_diff_predicate",
         ":test/coverage_configuration",
         ":test/test_sharding_strategy",
@@ -2866,12 +2861,13 @@
     deps = [
         ":analysis_cluster",
         ":config/build_options",
+        ":config/build_options_cache",
+        ":config/core_options",
         ":config/fragment_options",
         ":config/transitions/no_transition",
         ":config/transitions/patch_transition",
         ":config/transitions/transition_factory",
         ":test/test_configuration",
-        ":test/test_trimming_logic",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
@@ -2881,21 +2877,6 @@
 )
 
 java_library(
-    name = "test/test_trimming_logic",
-    srcs = ["test/TestTrimmingLogic.java"],
-    deps = [
-        ":config/build_options",
-        ":config/build_options_cache",
-        ":config/core_options",
-        ":config/fragment_options",
-        ":config/run_under",
-        ":test/coverage_configuration",
-        ":test/test_configuration",
-        "//third_party:guava",
-    ],
-)
-
-java_library(
     name = "test/test_progress",
     srcs = ["test/TestProgress.java"],
     deps = [
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/OutputPathMnemonicComputer.java b/src/main/java/com/google/devtools/build/lib/analysis/config/OutputPathMnemonicComputer.java
index ef4d3bd..c0b3b71 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/OutputPathMnemonicComputer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/OutputPathMnemonicComputer.java
@@ -25,8 +25,6 @@
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.analysis.PlatformOptions;
-import com.google.devtools.build.lib.analysis.test.TestConfiguration;
-import com.google.devtools.build.lib.analysis.test.TestTrimmingLogic;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.server.FailureDetails.BuildConfiguration.Code;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -300,10 +298,6 @@
       return "";
     }
 
-    if (!toOptions.contains(TestConfiguration.TestOptions.class)) {
-      baselineOptions = TestTrimmingLogic.trim(baselineOptions);
-    }
-
     // TODO(blaze-configurability-team): As a mild performance update, getFirst already includes
     //   details of the corresponding option. Could incorporate this instead of hashChosenOptions
     //   regenerating the OptionDefinitions and values.
@@ -313,8 +307,8 @@
     //   trimmings. See longform note in {@link ConfiguredTargetKey} for details.
     ImmutableSet<String> chosenNativeOptions =
         diff.getFirst().keySet().stream()
+            .filter(optionDef -> !explicitInOutputPathOptions.contains(optionDef.getOptionName()))
             .map(OptionDefinition::getOptionName)
-            .filter(optionName -> !explicitInOutputPathOptions.contains(optionName))
             .collect(toImmutableSet());
     // Note: getChangedStarlarkOptions includes all changed options, added options and removed
     //   options between baselineOptions and toOptions. This is necessary since there is no current
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/RunUnder.java b/src/main/java/com/google/devtools/build/lib/analysis/config/RunUnder.java
index 2add13d..8dcf462 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/RunUnder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/RunUnder.java
@@ -16,7 +16,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import javax.annotation.Nullable;
 
 /** Components of the {@code --run_under} option. */
 public sealed interface RunUnder {
@@ -32,19 +31,6 @@
   ImmutableList<String> options();
 
   /**
-   * Returns a new instance that only retains the information that is relevant for the analysis of
-   * non-test targets.
-   */
-  @Nullable
-  static RunUnder trimForNonTestConfiguration(@Nullable RunUnder runUnder) {
-    return switch (runUnder) {
-      case LabelRunUnder labelRunUnder ->
-          new LabelRunUnder("", ImmutableList.of(), labelRunUnder.label());
-      case null, default -> null;
-    };
-  }
-
-  /**
    * Represents a value of {@code --run_under} whose first word (according to shell tokenization)
    * starts with {@code "//"} or {@code "@"}. It is treated as a label referencing a target that
    * should be used as the {@code --run_under} executable.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestConfiguration.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestConfiguration.java
index 7874dc6..0c6080b 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestConfiguration.java
@@ -21,12 +21,10 @@
 import com.google.devtools.build.lib.analysis.OptionsDiffPredicate;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.CoreOptionConverters.LabelConverter;
-import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.Fragment;
 import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.PerLabelOptions;
 import com.google.devtools.build.lib.analysis.config.RequiresOptions;
-import com.google.devtools.build.lib.analysis.config.RunUnder;
 import com.google.devtools.build.lib.analysis.test.CoverageConfiguration.CoverageOptions;
 import com.google.devtools.build.lib.analysis.test.TestShardingStrategy.ShardingStrategyConverter;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -46,7 +44,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Objects;
 
 /** Test-related options. */
 @RequiresOptions(options = {TestConfiguration.TestOptions.class})
@@ -57,21 +54,13 @@
           // changes in --trim_test_configuration itself or related flags always prompt invalidation
           return true;
         }
-        // LINT.IfChange
         Class<? extends FragmentOptions> affectedOptionsClass =
             changedOption.getDeclaringClass(FragmentOptions.class);
         if (!affectedOptionsClass.equals(TestOptions.class)
             && !affectedOptionsClass.equals(CoverageOptions.class)) {
-          // options outside of TestOptions always prompt invalidation, except for --run_under.
-          if (affectedOptionsClass.equals(CoreOptions.class)
-              && changedOption.getOptionName().equals("run_under")) {
-            return !Objects.equals(
-                RunUnder.trimForNonTestConfiguration((RunUnder) oldValue),
-                RunUnder.trimForNonTestConfiguration((RunUnder) newValue));
-          }
+          // options outside of TestOptions always prompt invalidation
           return true;
         }
-        // LINT.ThenChange(TestTrimmingLogic.java)
         // other options in TestOptions require invalidation when --trim_test_configuration is off
         return !options.get(TestOptions.class).trimTestConfiguration;
       };
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingLogic.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingLogic.java
deleted file mode 100644
index a725742..0000000
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingLogic.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2024 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.analysis.test;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.analysis.config.BuildOptions;
-import com.google.devtools.build.lib.analysis.config.BuildOptionsCache;
-import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
-import com.google.devtools.build.lib.analysis.config.CoreOptions;
-import com.google.devtools.build.lib.analysis.config.FragmentOptions;
-import com.google.devtools.build.lib.analysis.config.RunUnder;
-import com.google.devtools.build.lib.analysis.test.CoverageConfiguration.CoverageOptions;
-import com.google.devtools.build.lib.analysis.test.TestConfiguration.TestOptions;
-
-/**
- * Contains the pure logic for trimming test configuration from non-test targets that backs {@link
- * com.google.devtools.build.lib.analysis.test.TestTrimmingTransitionFactory}.
- */
-public final class TestTrimmingLogic {
-
-  static final ImmutableSet<Class<? extends FragmentOptions>> REQUIRED_FRAGMENTS =
-      ImmutableSet.of(CoreOptions.class, TestOptions.class);
-
-  // This cache is to prevent major slowdowns when using --trim_test_configuration. This
-  // transition is always invoked on every target in the top-level invocation. Thus, a wide
-  // invocation, like //..., will cause the transition to be invoked on a large number of targets
-  // leading to significant performance degradation. (Notably, the transition itself is somewhat
-  // fast; however, the post-processing of the BuildOptions into the actual BuildConfigurationValue
-  // takes a significant amount of time).
-  //
-  // Test any caching changes for performance impact in a longwide scenario with
-  // --trim_test_configuration on versus off.
-  // LINT.IfChange
-  private static final BuildOptionsCache<Boolean> CACHE =
-      new BuildOptionsCache<>(
-          (options, unused, unusedNonEventHandler) -> {
-            BuildOptions.Builder builder = options.underlying().toBuilder();
-            builder.removeFragmentOptions(TestOptions.class);
-            builder.removeFragmentOptions(CoverageOptions.class);
-            // Only the label of the --run_under target (if any) needs to be part of the
-            // configuration for non-test targets, all other information is directly obtained
-            // from the options in RunCommand.
-            CoreOptions coreOptions = builder.getFragmentOptions(CoreOptions.class);
-            coreOptions.runUnder = RunUnder.trimForNonTestConfiguration(coreOptions.runUnder);
-            return builder.build();
-          });
-
-  // LINT.ThenChange(TestConfiguration.java)
-
-  /** Returns a new {@link BuildOptions} instance with test configuration removed. */
-  public static BuildOptions trim(BuildOptions buildOptions) {
-    return trim(new BuildOptionsView(buildOptions, REQUIRED_FRAGMENTS));
-  }
-
-  /** Returns a new {@link BuildOptions} instance with test configuration removed. */
-  static BuildOptions trim(BuildOptionsView buildOptions) {
-    try {
-      return CACHE.applyTransition(buildOptions, Boolean.TRUE, /* eventHandler= */ null);
-    } catch (InterruptedException e) {
-      // The transition logic doesn't throw InterruptedException.
-      throw new IllegalStateException(e);
-    }
-  }
-
-  private TestTrimmingLogic() {}
-}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingTransitionFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingTransitionFactory.java
index adc5764..879c50c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingTransitionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/test/TestTrimmingTransitionFactory.java
@@ -21,7 +21,9 @@
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsCache;
 import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.transitions.NoTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
@@ -35,8 +37,7 @@
 import com.google.devtools.common.options.Options;
 
 /**
- * Trimming transition factory which removes the test config fragment and certain options that are
- * only relevant for tests when entering a non-test rule.
+ * Trimming transition factory which removes the test config fragment when entering a non-test rule.
  */
 public final class TestTrimmingTransitionFactory implements TransitionFactory<RuleTransitionData> {
 
@@ -66,9 +67,24 @@
       this.testonly = testonly;
     }
 
+    // This cache is to prevent major slowdowns when using --trim_test_configuration. This
+    // transition is always invoked on every target in the top-level invocation. Thus, a wide
+    // invocation, like //..., will cause the transition to be invoked on a large number of targets
+    // leading to significant performance degradation. (Notably, the transition itself is somewhat
+    // fast; however, the post-processing of the BuildOptions into the actual
+    // BuildConfigurationValue
+    // takes a significant amount of time).
+    //
+    // Test any caching changes for performance impact in a longwide scenario with
+    // --trim_test_configuration on versus off.
+    private static final BuildOptionsCache<Boolean> cache =
+        new BuildOptionsCache<>(
+            (options, unused, unusedNonEventHandler) ->
+                options.underlying().toBuilder().removeFragmentOptions(TestOptions.class).build());
+
     @Override
     public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
-      return TestTrimmingLogic.REQUIRED_FRAGMENTS;
+      return ImmutableSet.of(TestOptions.class, CoreOptions.class);
     }
 
     @Override
@@ -85,7 +101,7 @@
         return originalOptions.underlying();
       }
       // No context needed, use the constant Boolean.TRUE.
-      return TestTrimmingLogic.trim(originalOptions);
+      return cache.applyTransition(originalOptions, Boolean.TRUE, null);
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/starlark/BUILD b/src/test/java/com/google/devtools/build/lib/analysis/starlark/BUILD
index 3580ed8e..22bea24 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/starlark/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/analysis/starlark/BUILD
@@ -113,7 +113,6 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
         "//src/main/java/com/google/devtools/build/lib/analysis:platform_options",
         "//src/main/java/com/google/devtools/build/lib/analysis:required_config_fragments_provider",
-        "//src/main/java/com/google/devtools/build/lib/analysis:test/coverage_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:test/test_configuration",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/packages",
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProviderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProviderTest.java
index 18c8b4d..1d91f30 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProviderTest.java
@@ -27,7 +27,6 @@
 import com.google.devtools.build.lib.analysis.RequiredConfigFragmentsProvider;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
-import com.google.devtools.build.lib.analysis.test.CoverageConfiguration.CoverageOptions;
 import com.google.devtools.build.lib.analysis.test.TestConfiguration.TestOptions;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.analysis.util.DummyTestFragment;
@@ -1354,12 +1353,11 @@
 
         my_rule(name = "test")
         """);
-    // --trim_test_configuration means only the top-level configuration has CoverageOptions and
-    // TestOptions.
+    // --trim_test_configuration means only the top-level configuration has TestOptions.
     assertConfigurationsEqual(
         getConfiguration(getConfiguredTarget("//test")),
         targetConfig,
-        ImmutableSet.of(CoverageOptions.class, TestOptions.class));
+        ImmutableSet.of(TestOptions.class));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubruleTest.java b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubruleTest.java
index 3f06edd..3bc7837 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubruleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/starlark/StarlarkSubruleTest.java
@@ -1200,10 +1200,7 @@
         my_rule(name = "foo")
         """);
     // TODO: b/293304174 - use a custom fragment instead of coverage
-    useConfiguration(
-        "--collect_code_coverage",
-        "--coverage_output_generator=//my:tool",
-        "--notrim_test_configuration");
+    useConfiguration("--collect_code_coverage", "--coverage_output_generator=//my:tool");
 
     StructImpl provider =
         getProvider("//subrule_testing:foo", "//subrule_testing:myrule.bzl", "MyInfo");