Convert remaining native uses of patch() / split().

In service of https://github.com/bazelbuild/bazel/issues/11258.

PiperOrigin-RevId: 315986864
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/HostTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/HostTransition.java
index 4eca3f3..860512e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/HostTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/HostTransition.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.analysis.config;
 
 import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.events.EventHandler;
@@ -32,12 +33,18 @@
   }
 
   @Override
-  public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
+  public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+    return ImmutableSet.of(CoreOptions.class);
+  }
+
+  @Override
+  public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
     if (options.get(CoreOptions.class).isHost) {
       // If the input already comes from the host configuration, just return the existing values.
       //
       // We don't do this just for convenience: if an
-      // {@link com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy}
+      // {@link
+      // com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy}
       // overrides option defaults, {@link FragmentOptions#getHost} won't honor that policy. That's
       // because it uses its own options parser that's not aware of the policy. This can create
       // problems for, e.g., {@link JavaOptions#getHost}, which promotes --host_foo flags to
@@ -48,9 +55,9 @@
       // manually set host.hostFoo = original.hostFoo). But those raise larger questions about the
       // nature of host/target relationships, so for the time being this is a straightforward
       // and practical fix.
-      return options.clone();
+      return options.clone().underlying();
     } else {
-      return options.createHostOptions();
+      return options.underlying().createHostOptions();
     }
   }
 
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 772f2f4..a759b25 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
@@ -15,6 +15,8 @@
 
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+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;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
@@ -41,17 +43,24 @@
     INSTANCE;
 
     @Override
-    public BuildOptions patch(BuildOptions originalOptions, EventHandler eventHandler) {
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView originalOptions, EventHandler eventHandler) {
       if (!originalOptions.contains(TestOptions.class)) {
         // nothing to do, already trimmed this fragment
-        return originalOptions;
+        return originalOptions.underlying();
       }
       TestOptions originalTestOptions = originalOptions.get(TestOptions.class);
       if (!originalTestOptions.trimTestConfiguration) {
         // nothing to do, trimming is disabled
-        return originalOptions;
+        return originalOptions.underlying();
       }
-      return originalOptions.toBuilder().removeFragmentOptions(TestOptions.class).build();
+      return originalOptions.underlying().toBuilder()
+          .removeFragmentOptions(TestOptions.class)
+          .build();
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTaggedTrimmingTransitionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTaggedTrimmingTransitionFactory.java
index 18b3546..9c5d6bc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTaggedTrimmingTransitionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTaggedTrimmingTransitionFactory.java
@@ -17,10 +17,13 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL_KEYED_STRING_DICT;
 import static com.google.devtools.build.lib.packages.BuildType.NODEP_LABEL_LIST;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedSet;
 import com.google.common.collect.Ordering;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+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.PatchTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -49,14 +52,19 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(ConfigFeatureFlagOptions.class, CoreOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
       if (!(options.contains(ConfigFeatureFlagOptions.class)
           && options.get(ConfigFeatureFlagOptions.class)
               .enforceTransitiveConfigsForConfigFeatureFlag
           && options.get(CoreOptions.class).useDistinctHostConfiguration)) {
-        return options;
+        return options.underlying();
       }
-      return FeatureFlagValue.trimFlagValues(options, flags);
+      return FeatureFlagValue.trimFlagValues(options.underlying(), flags);
     }
 
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactory.java
index aa4f4fc..ee2640a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactory.java
@@ -16,8 +16,11 @@
 
 import static com.google.devtools.build.lib.packages.BuildType.LABEL_KEYED_STRING_DICT;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSortedMap;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+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;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
@@ -56,11 +59,16 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(ConfigFeatureFlagOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
       if (!options.contains(ConfigFeatureFlagOptions.class)) {
-        return options;
+        return options.underlying();
       }
-      return FeatureFlagValue.replaceFlagValues(options, flagValues);
+      return FeatureFlagValue.replaceFlagValues(options.underlying(), flagValues);
     }
 
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index c40d927..5c63a8a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -245,6 +245,7 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/configuration_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/no_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/null_transition",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/patch_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:configurations_collector",
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_object_value",
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index e5161b2..bb122c9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -46,10 +46,12 @@
 import com.google.devtools.build.lib.analysis.ToolchainContext;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 import com.google.devtools.build.lib.analysis.config.DependencyEvaluationException;
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
+import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.analysis.skylark.StarlarkTransition.TransitionException;
 import com.google.devtools.build.lib.causes.AnalysisFailedCause;
@@ -488,10 +490,14 @@
     //         ...
     //
     // None of this has any effect on rules that don't utilize manual trimming.
+    PatchTransition toolchainTaggedTrimmingTransition =
+        ((ConfiguredRuleClassProvider) ruleClassProvider).getToolchainTaggedTrimmingTransition();
     BuildOptions toolchainOptions =
-        ((ConfiguredRuleClassProvider) ruleClassProvider)
-            .getToolchainTaggedTrimmingTransition()
-            .patch(configuration.getOptions(), env.getListener());
+        toolchainTaggedTrimmingTransition.patch(
+            new BuildOptionsView(
+                configuration.getOptions(),
+                toolchainTaggedTrimmingTransition.requiresOptionFragments()),
+            env.getListener());
 
     BuildConfigurationValue.Key toolchainConfig =
         BuildConfigurationValue.keyWithoutPlatformMapping(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
index 1ae9235..ebab3da 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PrepareAnalysisPhaseFunction.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.Fragment;
@@ -79,9 +80,11 @@
     PrepareAnalysisPhaseKey options = (PrepareAnalysisPhaseKey) key.argument();
 
     BuildOptions targetOptions = defaultBuildOptions.applyDiff(options.getOptionsDiff());
+    BuildOptionsView hostTransitionOptionsView =
+        new BuildOptionsView(targetOptions, HostTransition.INSTANCE.requiresOptionFragments());
     BuildOptions hostOptions =
         targetOptions.get(CoreOptions.class).useDistinctHostConfiguration
-            ? HostTransition.INSTANCE.patch(targetOptions, env.getListener())
+            ? HostTransition.INSTANCE.patch(hostTransitionOptionsView, env.getListener())
             : targetOptions;
 
     ImmutableSortedSet<Class<? extends Fragment>> allFragments =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 0a6a05a..e01f2b4 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -82,6 +82,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptions.OptionsDiffForReconstruction;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.Fragment;
@@ -1511,9 +1512,12 @@
     BuildConfiguration firstTargetConfig = topLevelTargetConfigs.get(0);
 
     BuildOptions targetOptions = firstTargetConfig.getOptions();
+    BuildOptionsView hostTransitionOptionsView =
+        new BuildOptionsView(
+            firstTargetConfig.getOptions(), HostTransition.INSTANCE.requiresOptionFragments());
     BuildOptions hostOptions =
         targetOptions.get(CoreOptions.class).useDistinctHostConfiguration
-            ? HostTransition.INSTANCE.patch(targetOptions, eventHandler)
+            ? HostTransition.INSTANCE.patch(hostTransitionOptionsView, eventHandler)
             : targetOptions;
     BuildConfiguration hostConfig = getConfiguration(eventHandler, hostOptions, keepGoing);
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java
index 8e4f081..095935c 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AnalysisCachingTest.java
@@ -23,6 +23,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
 import com.google.devtools.build.lib.analysis.config.Fragment;
 import com.google.devtools.build.lib.analysis.config.FragmentOptions;
@@ -547,11 +548,16 @@
     public static final PatchTransition CLEAR_IRRELEVANT =
         new PatchTransition() {
           @Override
-          public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-            BuildOptions cloned = options.clone();
+          public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+            return ImmutableSet.of(DiffResetOptions.class);
+          }
+
+          @Override
+          public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+            BuildOptionsView cloned = options.clone();
             cloned.get(DiffResetOptions.class).probablyIrrelevantOption = "(cleared)";
             cloned.get(DiffResetOptions.class).alsoIrrelevantOption = "(cleared)";
-            return cloned;
+            return cloned.underlying();
           }
         };
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurationsForLateBoundTargetsTest.java b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurationsForLateBoundTargetsTest.java
index 150bdae..bf05379 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/ConfigurationsForLateBoundTargetsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/ConfigurationsForLateBoundTargetsTest.java
@@ -19,8 +19,11 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.TransitionFactories;
 import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
@@ -51,10 +54,15 @@
   private static final PatchTransition CHANGE_FOO_FLAG_TRANSITION =
       new PatchTransition() {
         @Override
-        public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-          BuildOptions toOptions = options.clone();
+        public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+          return ImmutableSet.of(LateBoundSplitUtil.TestOptions.class);
+        }
+
+        @Override
+        public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+          BuildOptionsView toOptions = options.clone();
           toOptions.get(LateBoundSplitUtil.TestOptions.class).fooFlag = "PATCHED!";
-          return toOptions;
+          return toOptions.underlying();
         }
       };
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionFactoryTest.java b/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionFactoryTest.java
index fb31d78..a2784d0 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionFactoryTest.java
@@ -18,8 +18,10 @@
 import static org.junit.Assert.assertThrows;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.HostTransition;
 import com.google.devtools.build.lib.analysis.config.TransitionFactories;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -217,8 +219,8 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-      return updateOptions(options, flagLabel, flagValue);
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+      return updateOptions(options.underlying(), flagLabel, flagValue);
     }
   }
 
@@ -232,13 +234,14 @@
     }
 
     @Override
-    public Map<String, BuildOptions> split(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableMap<String, BuildOptions> split(
+        BuildOptionsView options, EventHandler eventHandler) {
       return IntStream.range(0, flagValues.size())
           .boxed()
           .collect(
               toImmutableMap(
                   i -> "stub_split" + i,
-                  i -> updateOptions(options, flagLabel, flagValues.get(i))));
+                  i -> updateOptions(options.underlying(), flagLabel, flagValues.get(i))));
     }
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionTest.java b/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionTest.java
index b7798d7..dd6cd04 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingTransitionTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertThrows;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -183,8 +184,8 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-      return updateOptions(options, flagLabel, flagValue);
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+      return updateOptions(options.underlying(), flagLabel, flagValue);
     }
   }
 
@@ -198,13 +199,14 @@
     }
 
     @Override
-    public Map<String, BuildOptions> split(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableMap<String, BuildOptions> split(
+        BuildOptionsView options, EventHandler eventHandler) {
       return IntStream.range(0, flagValues.size())
           .boxed()
           .collect(
               toImmutableMap(
                   i -> "stub_split" + i,
-                  i -> updateOptions(options, flagLabel, flagValues.get(i))));
+                  i -> updateOptions(options.underlying(), flagLabel, flagValues.get(i))));
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java b/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
index 2fe73f4..998a9fe 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/AttributeTest.java
@@ -25,6 +25,7 @@
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.HostTransition;
 import com.google.devtools.build.lib.analysis.config.TransitionFactories;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
@@ -287,8 +288,10 @@
 
   private static class TestSplitTransition implements SplitTransition {
     @Override
-    public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
-      return ImmutableMap.of("test0", buildOptions.clone(), "test1", buildOptions.clone());
+    public Map<String, BuildOptions> split(
+        BuildOptionsView buildOptions, EventHandler eventHandler) {
+      return ImmutableMap.of(
+          "test0", buildOptions.clone().underlying(), "test1", buildOptions.clone().underlying());
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
index 4577c31..3500847 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/BUILD
@@ -89,6 +89,7 @@
         ":configured_target_query_helper",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_options",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_options",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/split_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
         "//src/main/java/com/google/devtools/build/lib/analysis:test/test_configuration",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQuerySemanticsTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQuerySemanticsTest.java
index d6b5350..c7a7f6e 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQuerySemanticsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQuerySemanticsTest.java
@@ -21,10 +21,12 @@
 import static org.junit.Assert.assertThrows;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory;
 import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.HostTransition;
@@ -486,9 +488,14 @@
   /** Return an empty BuildOptions for testing fragment dropping. * */
   public static class RemoveTestOptionsTransition implements PatchTransition {
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
       BuildOptions.Builder builder = BuildOptions.builder();
-      for (FragmentOptions option : options.getNativeOptions()) {
+      for (FragmentOptions option : options.underlying().getNativeOptions()) {
         if (!(option instanceof TestOptions)) {
           builder.addFragmentOptions(option);
         }
diff --git a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryTest.java b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryTest.java
index 5aabe65..152dc1c 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/cquery/ConfiguredTargetQueryTest.java
@@ -17,9 +17,12 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.transitions.SplitTransition;
 import com.google.devtools.build.lib.analysis.test.TestConfiguration.TestOptions;
 import com.google.devtools.build.lib.events.EventHandler;
@@ -76,12 +79,17 @@
     }
 
     @Override
-    public Map<String, BuildOptions> split(BuildOptions options, EventHandler eventHandler) {
-      BuildOptions result1 = options.clone();
-      BuildOptions result2 = options.clone();
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestOptions.class);
+    }
+
+    @Override
+    public Map<String, BuildOptions> split(BuildOptionsView options, EventHandler eventHandler) {
+      BuildOptionsView result1 = options.clone();
+      BuildOptionsView result2 = options.clone();
       result1.get(TestOptions.class).testArguments = Collections.singletonList(toOption1);
       result2.get(TestOptions.class).testArguments = Collections.singletonList(toOption2);
-      return ImmutableMap.of("result1", result1, "result2", result2);
+      return ImmutableMap.of("result1", result1.underlying(), "result2", result2.underlying());
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
index e19cb8c..4f2565c 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/BUILD
@@ -21,6 +21,7 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:blaze_directories",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/build_options",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_options",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/patch_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:server_directories",
         "//src/main/java/com/google/devtools/build/lib/analysis:test/test_configuration",
diff --git a/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java b/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
index 4c2b91c..aa229a0 100644
--- a/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/query2/testutil/PostAnalysisQueryTest.java
@@ -18,10 +18,13 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 import static com.google.devtools.build.lib.testutil.TestConstants.PLATFORM_LABEL;
 
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.FragmentOptions;
 import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.test.TestConfiguration.TestOptions;
 import com.google.devtools.build.lib.analysis.util.MockRule;
@@ -349,10 +352,15 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-      BuildOptions result = options.clone();
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+      BuildOptionsView result = options.clone();
       result.get(TestOptions.class).testArguments = Collections.singletonList(toOption);
-      return result;
+      return result.underlying();
     }
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
index d671cf7..6595da8 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
@@ -21,6 +21,7 @@
 import com.google.common.testing.EqualsTester;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 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;
@@ -61,7 +62,9 @@
     PatchTransition transition = new ConfigFeatureFlagTransitionFactory("flag_values").create(rule);
 
     BuildOptions original = getOptionsWithoutFlagFragment();
-    BuildOptions converted = transition.patch(original, eventCollector);
+    BuildOptions converted =
+        transition.patch(
+            new BuildOptionsView(original, transition.requiresOptionFragments()), eventCollector);
 
     assertThat(converted).isSameInstanceAs(original);
     assertThat(original.contains(ConfigFeatureFlagOptions.class)).isFalse();
@@ -83,7 +86,9 @@
     PatchTransition transition = new ConfigFeatureFlagTransitionFactory("flag_values").create(rule);
 
     BuildOptions original = getOptionsWithoutFlagFragment();
-    BuildOptions converted = transition.patch(original, eventCollector);
+    BuildOptions converted =
+        transition.patch(
+            new BuildOptionsView(original, transition.requiresOptionFragments()), eventCollector);
 
     assertThat(converted).isSameInstanceAs(original);
     assertThat(original.contains(ConfigFeatureFlagOptions.class)).isFalse();
@@ -97,7 +102,9 @@
         ImmutableMap.of(Label.parseAbsolute("//a:flag", ImmutableMap.of()), "value");
 
     BuildOptions original = getOptionsWithFlagFragment(originalFlagMap);
-    BuildOptions converted = transition.patch(original, eventCollector);
+    BuildOptions converted =
+        transition.patch(
+            new BuildOptionsView(original, transition.requiresOptionFragments()), eventCollector);
 
     assertThat(converted).isNotSameInstanceAs(original);
     assertThat(FeatureFlagValue.getFlagValues(original)).containsExactlyEntriesIn(originalFlagMap);
@@ -125,7 +132,9 @@
         ImmutableMap.of(Label.parseAbsolute("//a:flag", ImmutableMap.of()), "a");
 
     BuildOptions original = getOptionsWithFlagFragment(originalFlagMap);
-    BuildOptions converted = transition.patch(original, eventCollector);
+    BuildOptions converted =
+        transition.patch(
+            new BuildOptionsView(original, transition.requiresOptionFragments()), eventCollector);
 
     assertThat(converted).isNotSameInstanceAs(original);
     assertThat(FeatureFlagValue.getFlagValues(original)).containsExactlyEntriesIn(originalFlagMap);
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
index 76274cf..7b63d67 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
@@ -32,6 +32,8 @@
 import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.Rule;
@@ -885,10 +887,13 @@
 
     BuildOptions topLevelOptions =
         getConfiguration(getConfiguredTarget("//test:toplevel_target")).getOptions();
-    BuildOptions depOptions =
+    PatchTransition transition =
         new ConfigFeatureFlagTaggedTrimmingTransitionFactory(BaseRuleClasses.TAGGED_TRIMMING_ATTR)
-            .create((Rule) getTarget("//test:dep"))
-            .patch(topLevelOptions, eventCollector);
+            .create((Rule) getTarget("//test:dep"));
+    BuildOptions depOptions =
+        transition.patch(
+            new BuildOptionsView(topLevelOptions, transition.requiresOptionFragments()),
+            eventCollector);
     assertThat(depOptions).isSameInstanceAs(topLevelOptions);
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
index 2a3b95c..9833ca1 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ConfigurationsForTargetsWithTrimmedConfigurationsTest.java
@@ -25,13 +25,16 @@
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 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.TransitionFactories;
 import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
@@ -71,37 +74,53 @@
 
   private static class NoopSplitTransition implements SplitTransition {
     @Override
-    public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
-      return ImmutableMap.of("noop", buildOptions);
+    public Map<String, BuildOptions> split(
+        BuildOptionsView buildOptions, EventHandler eventHandler) {
+      return ImmutableMap.of("noop", buildOptions.underlying());
     }
   }
 
   private static class SetsHostCpuSplitTransition implements SplitTransition {
     @Override
-    public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
-      BuildOptions result = buildOptions.clone();
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(CoreOptions.class);
+    }
+
+    @Override
+    public Map<String, BuildOptions> split(
+        BuildOptionsView buildOptions, EventHandler eventHandler) {
+      BuildOptionsView result = buildOptions.clone();
       result.get(CoreOptions.class).hostCpu = "SET BY SPLIT";
-      return ImmutableMap.of("hostCpu", result);
+      return ImmutableMap.of("hostCpu", result.underlying());
     }
   }
 
   private static class SetsCpuSplitTransition implements SplitTransition {
+    @Override
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(CoreOptions.class);
+    }
 
     @Override
-    public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
-      BuildOptions result = buildOptions.clone();
+    public Map<String, BuildOptions> split(
+        BuildOptionsView buildOptions, EventHandler eventHandler) {
+      BuildOptionsView result = buildOptions.clone();
       result.get(CoreOptions.class).cpu = "SET BY SPLIT";
-      return ImmutableMap.of("cpu", result);
+      return ImmutableMap.of("cpu", result.underlying());
     }
   }
 
   private static class SetsCpuPatchTransition implements PatchTransition {
+    @Override
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(CoreOptions.class);
+    }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-      BuildOptions result = options.clone();
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+      BuildOptionsView result = options.clone();
       result.get(CoreOptions.class).cpu = "SET BY PATCH";
-      return result;
+      return result.underlying();
     }
   }
 
@@ -152,10 +171,15 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-      BuildOptions result = options.clone();
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestConfiguration.TestOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+      BuildOptionsView result = options.clone();
       result.get(TestConfiguration.TestOptions.class).testFilter = "SET BY PATCH FACTORY: " + value;
-      return result;
+      return result.underlying();
     }
   }
 
@@ -195,16 +219,21 @@
     }
 
     @Override
-    public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
+    public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+      return ImmutableSet.of(TestConfiguration.TestOptions.class);
+    }
+
+    @Override
+    public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
       if (!options.contains(TestConfiguration.TestOptions.class)) {
-        return options;
+        return options.underlying();
       }
 
-      BuildOptions result = options.clone();
+      BuildOptionsView result = options.clone();
       TestConfiguration.TestOptions testOpts = result.get(TestConfiguration.TestOptions.class);
       testOpts.testArguments =
           new ImmutableList.Builder<String>().addAll(testOpts.testArguments).add(argument).build();
-      return result;
+      return result.underlying();
     }
   }
 
@@ -551,12 +580,17 @@
   private static PatchTransition newPatchTransition(final String value) {
     return new PatchTransition() {
       @Override
-      public BuildOptions patch(BuildOptions options, EventHandler eventHandler) {
-        BuildOptions toOptions = options.clone();
+      public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+        return ImmutableSet.of(TestConfiguration.TestOptions.class);
+      }
+
+      @Override
+      public BuildOptions patch(BuildOptionsView options, EventHandler eventHandler) {
+        BuildOptionsView toOptions = options.clone();
         TestConfiguration.TestOptions baseOptions =
             toOptions.get(TestConfiguration.TestOptions.class);
         baseOptions.testFilter = nullToEmpty(baseOptions.testFilter) + value;
-        return toOptions;
+        return toOptions.underlying();
       }
     };
   }
@@ -569,15 +603,21 @@
   private static SplitTransition newSplitTransition(final String prefix) {
     return new SplitTransition() {
       @Override
-      public Map<String, BuildOptions> split(BuildOptions buildOptions, EventHandler eventHandler) {
+      public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+        return ImmutableSet.of(TestConfiguration.TestOptions.class);
+      }
+
+      @Override
+      public ImmutableMap<String, BuildOptions> split(
+          BuildOptionsView buildOptions, EventHandler eventHandler) {
         ImmutableMap.Builder<String, BuildOptions> result = ImmutableMap.builder();
         for (int index = 1; index <= 2; index++) {
-          BuildOptions toOptions = buildOptions.clone();
+          BuildOptionsView toOptions = buildOptions.clone();
           TestConfiguration.TestOptions baseOptions =
               toOptions.get(TestConfiguration.TestOptions.class);
           baseOptions.testFilter =
               (baseOptions.testFilter == null ? "" : baseOptions.testFilter) + prefix + index;
-          result.put(prefix + index, toOptions);
+          result.put(prefix + index, toOptions.underlying());
         }
         return result.build();
       }
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/trimming/TrimmableTestConfigurationFragments.java b/src/test/java/com/google/devtools/build/lib/skyframe/trimming/TrimmableTestConfigurationFragments.java
index 8f89afb..f65e770 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/trimming/TrimmableTestConfigurationFragments.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/trimming/TrimmableTestConfigurationFragments.java
@@ -35,6 +35,7 @@
 import com.google.devtools.build.lib.analysis.TransitionMode;
 import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
 import com.google.devtools.build.lib.analysis.config.ConfigurationFragmentFactory;
 import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.Fragment;
@@ -613,8 +614,19 @@
       }
 
       @Override
-      public BuildOptions patch(BuildOptions target, EventHandler eventHandler) {
-        BuildOptions output = target.clone();
+      public ImmutableSet<Class<? extends FragmentOptions>> requiresOptionFragments() {
+        return ImmutableSet.of(
+            AOptions.class,
+            BOptions.class,
+            COptions.class,
+            DOptions.class,
+            EOptions.class,
+            PlatformOptions.class);
+      }
+
+      @Override
+      public BuildOptions patch(BuildOptionsView target, EventHandler eventHandler) {
+        BuildOptionsView output = target.clone();
         if (alpha != null) {
           output.get(AOptions.class).alpha = alpha;
         }
@@ -639,7 +651,7 @@
         if (extraToolchains != null) {
           output.get(PlatformOptions.class).extraToolchains = extraToolchains;
         }
-        return output;
+        return output.underlying();
       }
     }