Expose aspect actions from Skylark.

Like with providers, consumers get a merged view of all actions from the merged configured target (all other aspects + the base target).

I had to rejig the aspect value / configured aspect to be symmetric with rule configured targets.

I do not expect significant memory bloat from this. All lists / maps already existed, only extra fields have been added.

RELNOTES: Expose aspect actions provider to Skylark.
PiperOrigin-RevId: 201697923
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspect.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspect.java
index a33e6fe..e99d134 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspect.java
@@ -18,10 +18,14 @@
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.Actions;
+import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
@@ -57,12 +61,20 @@
 @Immutable
 @AutoCodec
 public final class ConfiguredAspect {
-  private final TransitiveInfoProviderMap providers;
   private final AspectDescriptor descriptor;
+  private final ImmutableList<ActionAnalysisMetadata> actions;
+  private final ImmutableMap<Artifact, Integer> generatingActionIndex;
+  private final TransitiveInfoProviderMap providers;
 
   @AutoCodec.VisibleForSerialization
-  ConfiguredAspect(AspectDescriptor descriptor, TransitiveInfoProviderMap providers) {
+  ConfiguredAspect(
+      AspectDescriptor descriptor,
+      ImmutableList<ActionAnalysisMetadata> actions,
+      ImmutableMap<Artifact, Integer> generatingActionIndex,
+      TransitiveInfoProviderMap providers) {
     this.descriptor = descriptor;
+    this.actions = actions;
+    this.generatingActionIndex = generatingActionIndex;
     this.providers = providers;
   }
 
@@ -80,6 +92,18 @@
     return descriptor;
   }
 
+  public ImmutableList<ActionAnalysisMetadata> getActions() {
+    return actions;
+  }
+
+  /**
+   * Returns a map where keys are artifacts that are action outputs of this rule, and values are the
+   * index of the action that generates that artifact.
+   */
+  public ImmutableMap<Artifact, Integer> getGeneratingActionIndex() {
+    return generatingActionIndex;
+  }
+
   /** Returns the providers created by the aspect. */
   public TransitiveInfoProviderMap getProviders() {
     return providers;
@@ -112,11 +136,16 @@
   }
 
   public static ConfiguredAspect forAlias(ConfiguredAspect real) {
-    return new ConfiguredAspect(real.descriptor, real.getProviders());
+    return new ConfiguredAspect(
+        real.descriptor, real.getActions(), real.getGeneratingActionIndex(), real.getProviders());
   }
 
   public static ConfiguredAspect forNonapplicableTarget(AspectDescriptor descriptor) {
-    return new ConfiguredAspect(descriptor, new TransitiveInfoProviderMapBuilder().add().build());
+    return new ConfiguredAspect(
+        descriptor,
+        ImmutableList.of(),
+        ImmutableMap.of(),
+        new TransitiveInfoProviderMapBuilder().add().build());
   }
 
   public static Builder builder(
@@ -230,8 +259,7 @@
       return this;
     }
 
-
-    public ConfiguredAspect build() {
+    public ConfiguredAspect build() throws ActionConflictException {
       if (!outputGroupBuilders.isEmpty()) {
         ImmutableMap.Builder<String, NestedSet<Artifact>> outputGroups = ImmutableMap.builder();
         for (Map.Entry<String, NestedSetBuilder<Artifact>> entry : outputGroupBuilders.entrySet()) {
@@ -250,7 +278,17 @@
               /* actionsWithoutExtraAction= */ ImmutableSet.<ActionAnalysisMetadata>of(),
               ruleContext));
 
-      return new ConfiguredAspect(descriptor, providers.build());
+      AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment();
+      GeneratingActions generatingActions =
+          Actions.filterSharedActionsAndThrowActionConflict(
+              analysisEnvironment.getActionKeyContext(),
+              analysisEnvironment.getRegisteredActions());
+
+      return new ConfiguredAspect(
+          descriptor,
+          generatingActions.getActions(),
+          generatingActions.getGeneratingActionIndex(),
+          providers.build());
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspectFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspectFactory.java
index 18462fb..a613ec6 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspectFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredAspectFactory.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.analysis;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.packages.AspectParameters;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
 
@@ -30,5 +31,5 @@
    */
   ConfiguredAspect create(
       ConfiguredTargetAndData ctadBase, RuleContext context, AspectParameters parameters)
-      throws InterruptedException;
+      throws ActionConflictException, InterruptedException;
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index 456c6a1..c04365a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -64,6 +64,7 @@
 import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.profiler.memory.CurrentRuleTracker;
+import com.google.devtools.build.lib.skyframe.AspectFunction.AspectFunctionException;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.util.OrderedSetMultimap;
@@ -389,7 +390,7 @@
       @Nullable ToolchainContext toolchainContext,
       BuildConfiguration aspectConfiguration,
       BuildConfiguration hostConfiguration)
-      throws InterruptedException {
+      throws AspectFunctionException, InterruptedException {
 
     // Load the requested toolchains into the ToolchainContext.
     if (toolchainContext != null) {
@@ -424,8 +425,13 @@
       return null;
     }
 
-    ConfiguredAspect configuredAspect =
-        aspectFactory.create(associatedTarget, ruleContext, aspect.getParameters());
+    ConfiguredAspect configuredAspect;
+    try {
+      configuredAspect =
+          aspectFactory.create(associatedTarget, ruleContext, aspect.getParameters());
+    } catch (ActionConflictException e) {
+      throw new AspectFunctionException(e);
+    }
     if (configuredAspect != null) {
       validateAdvertisedProviders(
           configuredAspect, aspect.getDefinition().getAdvertisedProviders(),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
index bb1e908..1e60f64 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/MergedConfiguredTarget.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
 import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.ConfiguredAspect;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -39,6 +40,7 @@
  */
 public final class MergedConfiguredTarget extends AbstractConfiguredTarget {
   private final ConfiguredTarget base;
+  private final ImmutableList<ConfiguredAspect> aspects;
   private final TransitiveInfoProviderMap providers;
 
   /**
@@ -52,9 +54,13 @@
     }
   }
 
-  private MergedConfiguredTarget(ConfiguredTarget base, TransitiveInfoProviderMap providers) {
+  private MergedConfiguredTarget(
+      ConfiguredTarget base,
+      Iterable<ConfiguredAspect> aspects,
+      TransitiveInfoProviderMap providers) {
     super(base.getLabel(), base.getConfigurationKey());
     this.base = base;
+    this.aspects = ImmutableList.copyOf(aspects);
     this.providers = providers;
   }
 
@@ -81,6 +87,7 @@
         result.accept((String) classAt);
       }
     }
+    result.accept(RuleConfiguredTarget.ACTIONS_FIELD_NAME);
   }
 
   @Override
@@ -94,6 +101,16 @@
 
   @Override
   protected Object rawGetSkylarkProvider(String providerKey) {
+    if (providerKey.equals(RuleConfiguredTarget.ACTIONS_FIELD_NAME)) {
+      ImmutableList.Builder<ActionAnalysisMetadata> actions = ImmutableList.builder();
+      for (ConfiguredAspect aspect : aspects) {
+        actions.addAll(aspect.getActions());
+      }
+      if (base instanceof RuleConfiguredTarget) {
+        actions.addAll(((RuleConfiguredTarget) base).getActions());
+      }
+      return actions.build();
+    }
     Object provider = providers.getProvider(providerKey);
     if (provider == null) {
       provider = base.get(providerKey);
@@ -159,7 +176,7 @@
         }
       }
     }
-    return new MergedConfiguredTarget(base, aspectProviders.build());
+    return new MergedConfiguredTarget(base, aspects, aspectProviders.build());
   }
 
   private static ImmutableList<OutputGroupInfo> getAllOutputGroupProviders(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
index bea36d8..2f668f6 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
@@ -60,7 +60,13 @@
  */
 @AutoCodec(checkClassExplicitlyAllowed = true)
 public final class RuleConfiguredTarget extends AbstractConfiguredTarget {
-  private static final String ACTIONS_FIELD_NAME = "actions";
+  /**
+   * The name of the key for the 'actions' synthesized provider.
+   *
+   * <p>If you respond to this key you are expected to return a list of actions belonging to this
+   * configured target.
+   */
+  public static final String ACTIONS_FIELD_NAME = "actions";
 
   /**
    * The configuration transition for an attribute through which a prerequisite