For all top-level artifacts, track the labels that own them when that is available.

The owning labels are the labels of the top-level configured targets that requested this artifact to be built (there may be many such targets). In cases where the artifact is added not through a configured target (build-info artifacts and coverage artifacts), the label of the artifact's owner is used.

PiperOrigin-RevId: 204432951
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
index 4015513..ff8dbe4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisResult.java
@@ -16,10 +16,12 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.SetMultimap;
 import com.google.devtools.build.lib.actions.ActionGraph;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.PackageRoots;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.skyframe.AspectValue;
 import java.util.Collection;
 import java.util.List;
@@ -35,7 +37,7 @@
   private final ImmutableSet<ConfiguredTarget> targetsToSkip;
   @Nullable private final String error;
   private final ActionGraph actionGraph;
-  private final ImmutableSet<Artifact> artifactsToBuild;
+  private final SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels;
   private final ImmutableSet<ConfiguredTarget> parallelTests;
   private final ImmutableSet<ConfiguredTarget> exclusiveTests;
   @Nullable private final TopLevelArtifactContext topLevelContext;
@@ -52,7 +54,7 @@
       Collection<ConfiguredTarget> targetsToSkip,
       @Nullable String error,
       ActionGraph actionGraph,
-      Collection<Artifact> artifactsToBuild,
+      SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels,
       Collection<ConfiguredTarget> parallelTests,
       Collection<ConfiguredTarget> exclusiveTests,
       TopLevelArtifactContext topLevelContext,
@@ -66,7 +68,7 @@
     this.targetsToSkip = ImmutableSet.copyOf(targetsToSkip);
     this.error = error;
     this.actionGraph = actionGraph;
-    this.artifactsToBuild = ImmutableSet.copyOf(artifactsToBuild);
+    this.topLevelArtifactsToOwnerLabels = topLevelArtifactsToOwnerLabels;
     this.parallelTests = ImmutableSet.copyOf(parallelTests);
     this.exclusiveTests = ImmutableSet.copyOf(exclusiveTests);
     this.topLevelContext = topLevelContext;
@@ -120,8 +122,8 @@
     return targetsToSkip;
   }
 
-  public ImmutableSet<Artifact> getAdditionalArtifactsToBuild() {
-    return artifactsToBuild;
+  public SetMultimap<Artifact, Label> getTopLevelArtifactsToOwnerLabels() {
+    return topLevelArtifactsToOwnerLabels;
   }
 
   public ImmutableSet<ConfiguredTarget> getExclusiveTests() {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
index 2143efa..caca6a7 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
@@ -14,18 +14,17 @@
 
 package com.google.devtools.build.lib.analysis;
 
-import static com.google.common.collect.Iterables.concat;
-
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
 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.common.collect.Lists;
 import com.google.common.collect.Multimap;
+import com.google.common.collect.SetMultimap;
 import com.google.common.collect.Sets;
 import com.google.common.eventbus.EventBus;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
@@ -378,7 +377,7 @@
       allTargetsToTest = filterTestsByTargets(configuredTargets, testsToRun);
     }
 
-    Set<Artifact> artifactsToBuild = new HashSet<>();
+    SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels = HashMultimap.create();
     Set<ConfiguredTarget> parallelTests = new HashSet<>();
     Set<ConfiguredTarget> exclusiveTests = new HashSet<>();
 
@@ -386,15 +385,15 @@
     Collection<Artifact> buildInfoArtifacts =
         skyframeExecutor.getWorkspaceStatusArtifacts(eventHandler);
     Preconditions.checkState(buildInfoArtifacts.size() == 2, buildInfoArtifacts);
-    artifactsToBuild.addAll(buildInfoArtifacts);
+    addArtifactsWithNoOwner(buildInfoArtifacts, topLevelArtifactsToOwnerLabels);
 
     // Extra actions
     addExtraActionsIfRequested(
-        viewOptions, configuredTargets, aspects, artifactsToBuild, eventHandler);
+        viewOptions, configuredTargets, aspects, topLevelArtifactsToOwnerLabels, eventHandler);
 
     // Coverage
-    NestedSet<Artifact> baselineCoverageArtifacts = getBaselineCoverageArtifacts(configuredTargets);
-    Iterables.addAll(artifactsToBuild, baselineCoverageArtifacts);
+    NestedSet<Artifact> baselineCoverageArtifacts =
+        getBaselineCoverageArtifacts(configuredTargets, topLevelArtifactsToOwnerLabels);
     if (coverageReportActionFactory != null) {
       CoverageReportActionsWrapper actionsWrapper;
       actionsWrapper =
@@ -409,7 +408,8 @@
       if (actionsWrapper != null) {
         ImmutableList<ActionAnalysisMetadata> actions = actionsWrapper.getActions();
         skyframeExecutor.injectCoverageReportData(actions);
-        artifactsToBuild.addAll(actionsWrapper.getCoverageOutputs());
+        addArtifactsWithNoOwner(
+            actionsWrapper.getCoverageOutputs(), topLevelArtifactsToOwnerLabels);
       }
     }
 
@@ -453,7 +453,7 @@
         targetsToSkip,
         error,
         actionGraph,
-        artifactsToBuild,
+        topLevelArtifactsToOwnerLabels,
         parallelTests,
         exclusiveTests,
         topLevelOptions,
@@ -462,6 +462,11 @@
         topLevelTargetsWithConfigs);
   }
 
+  private static void addArtifactsWithNoOwner(
+      Collection<Artifact> artifacts, SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels) {
+    artifacts.forEach((a) -> topLevelArtifactsToOwnerLabels.put(a, a.getOwnerLabel()));
+  }
+
   @Nullable
   public static String createErrorMessage(
       LoadingResult loadingResult, @Nullable SkyframeAnalysisResult skyframeAnalysisResult) {
@@ -476,11 +481,17 @@
   }
 
   private static NestedSet<Artifact> getBaselineCoverageArtifacts(
-      Collection<ConfiguredTarget> configuredTargets) {
+      Collection<ConfiguredTarget> configuredTargets,
+      SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels) {
     NestedSetBuilder<Artifact> baselineCoverageArtifacts = NestedSetBuilder.stableOrder();
     for (ConfiguredTarget target : configuredTargets) {
       InstrumentedFilesProvider provider = target.getProvider(InstrumentedFilesProvider.class);
       if (provider != null) {
+        TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+            provider.getBaselineCoverageArtifacts(),
+            null,
+            target.getLabel(),
+            topLevelArtifactsToOwnerLabels);
         baselineCoverageArtifacts.addTransitive(provider.getBaselineCoverageArtifacts());
       }
     }
@@ -491,28 +502,9 @@
       AnalysisOptions viewOptions,
       Collection<ConfiguredTarget> configuredTargets,
       Collection<AspectValue> aspects,
-      Set<Artifact> artifactsToBuild,
+      SetMultimap<Artifact, Label> artifactsToTopLevelLabelsMap,
       ExtendedEventHandler eventHandler) {
-    Iterable<Artifact> extraActionArtifacts =
-        concat(
-            addExtraActionsFromTargets(viewOptions, configuredTargets, eventHandler),
-            addExtraActionsFromAspects(viewOptions, aspects));
-
     RegexFilter filter = viewOptions.extraActionFilter;
-    for (Artifact artifact : extraActionArtifacts) {
-      boolean filterMatches =
-          filter == null || filter.isIncluded(artifact.getOwnerLabel().toString());
-      if (filterMatches) {
-        artifactsToBuild.add(artifact);
-      }
-    }
-  }
-
-  private NestedSet<Artifact> addExtraActionsFromTargets(
-      AnalysisOptions viewOptions,
-      Collection<ConfiguredTarget> configuredTargets,
-      ExtendedEventHandler eventHandler) {
-    NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder();
     for (ConfiguredTarget target : configuredTargets) {
       ExtraActionArtifactsProvider provider =
           target.getProvider(ExtraActionArtifactsProvider.class);
@@ -530,17 +522,46 @@
           for (Attribute attr : actualTarget.getAssociatedRule().getAttributes()) {
             aspectClasses.addAll(attr.getAspectClasses());
           }
-
-          builder.addTransitive(provider.getExtraActionArtifacts());
+          TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+              provider.getExtraActionArtifacts(),
+              filter,
+              target.getLabel(),
+              artifactsToTopLevelLabelsMap);
           if (!aspectClasses.isEmpty()) {
-            builder.addAll(filterTransitiveExtraActions(provider, aspectClasses));
+            TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+                filterTransitiveExtraActions(provider, aspectClasses),
+                filter,
+                target.getLabel(),
+                artifactsToTopLevelLabelsMap);
           }
         } else {
-          builder.addTransitive(provider.getTransitiveExtraActionArtifacts());
+          TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+              provider.getTransitiveExtraActionArtifacts(),
+              filter,
+              target.getLabel(),
+              artifactsToTopLevelLabelsMap);
         }
       }
     }
-    return builder.build();
+    for (AspectValue aspect : aspects) {
+      ExtraActionArtifactsProvider provider =
+          aspect.getConfiguredAspect().getProvider(ExtraActionArtifactsProvider.class);
+      if (provider != null) {
+        if (viewOptions.extraActionTopLevelOnly) {
+          TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+              provider.getExtraActionArtifacts(),
+              filter,
+              aspect.getLabel(),
+              artifactsToTopLevelLabelsMap);
+        } else {
+          TopLevelArtifactHelper.addArtifactsWithOwnerLabel(
+              provider.getTransitiveExtraActionArtifacts(),
+              filter,
+              aspect.getLabel(),
+              artifactsToTopLevelLabelsMap);
+        }
+      }
+    }
   }
 
   /**
@@ -563,23 +584,6 @@
     return artifacts.build();
   }
 
-  private NestedSet<Artifact> addExtraActionsFromAspects(
-      AnalysisOptions viewOptions, Collection<AspectValue> aspects) {
-    NestedSetBuilder<Artifact> builder = NestedSetBuilder.stableOrder();
-    for (AspectValue aspect : aspects) {
-      ExtraActionArtifactsProvider provider =
-          aspect.getConfiguredAspect().getProvider(ExtraActionArtifactsProvider.class);
-      if (provider != null) {
-        if (viewOptions.extraActionTopLevelOnly) {
-          builder.addTransitive(provider.getExtraActionArtifacts());
-        } else {
-          builder.addTransitive(provider.getTransitiveExtraActionArtifacts());
-        }
-      }
-    }
-    return builder.build();
-  }
-
   private static void scheduleTestsIfRequested(
       Collection<ConfiguredTarget> targetsToTest,
       Collection<ConfiguredTarget> targetsToTestExclusive,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
index bb71490..7730719 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/TopLevelArtifactHelper.java
@@ -16,14 +16,17 @@
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.collect.ImmutableCollection;
-import com.google.common.collect.ImmutableList;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.SetMultimap;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.test.TestProvider;
+import com.google.devtools.build.lib.cmdline.Label;
 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;
 import com.google.devtools.build.lib.skyframe.AspectValue;
+import com.google.devtools.build.lib.util.RegexFilter;
 import javax.annotation.Nullable;
 
 /**
@@ -115,47 +118,50 @@
     // Prevent instantiation.
   }
 
-  /**
-   * Utility function to form a list of all test output Artifacts of the given targets to test.
-   */
-  public static ImmutableCollection<Artifact> getAllArtifactsToTest(
-      Iterable<? extends TransitiveInfoCollection> targets) {
-    if (targets == null) {
-      return ImmutableList.of();
+  @VisibleForTesting
+  public static SetMultimap<Artifact, Label> makeTopLevelArtifactsToOwnerLabels(
+      AnalysisResult analysisResult, Iterable<AspectValue> aspects) {
+    SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels =
+        HashMultimap.create(analysisResult.getTopLevelArtifactsToOwnerLabels());
+    TopLevelArtifactContext artifactContext = analysisResult.getTopLevelContext();
+    for (ConfiguredTarget target : analysisResult.getTargetsToBuild()) {
+      addArtifactsWithOwnerLabel(
+          getAllArtifactsToBuild(target, artifactContext).getAllArtifacts(),
+          null,
+          target.getLabel(),
+          topLevelArtifactsToOwnerLabels);
     }
-    ImmutableList.Builder<Artifact> allTestArtifacts = ImmutableList.builder();
-    for (TransitiveInfoCollection target : targets) {
-      allTestArtifacts.addAll(TestProvider.getTestStatusArtifacts(target));
-    }
-    return allTestArtifacts.build();
-  }
-
-  /**
-   * Utility function to form a NestedSet of all top-level Artifacts of the given targets.
-   */
-  public static ArtifactsToBuild getAllArtifactsToBuild(
-      Iterable<? extends TransitiveInfoCollection> targets, TopLevelArtifactContext context) {
-    NestedSetBuilder<ArtifactsInOutputGroup> artifacts = NestedSetBuilder.stableOrder();
-    for (TransitiveInfoCollection target : targets) {
-      ArtifactsToBuild targetArtifacts = getAllArtifactsToBuild(target, context);
-      artifacts.addTransitive(targetArtifacts.getAllArtifactsByOutputGroup());
-    }
-    return new ArtifactsToBuild(artifacts.build());
-  }
-
-  /**
-   * Utility function to form a NestedSet of all top-level Artifacts of the given targets.
-   */
-  public static ArtifactsToBuild getAllArtifactsToBuildFromAspects(
-      Iterable<AspectValue> aspects, TopLevelArtifactContext context) {
-    NestedSetBuilder<ArtifactsInOutputGroup> artifacts = NestedSetBuilder.stableOrder();
     for (AspectValue aspect : aspects) {
-      ArtifactsToBuild aspectArtifacts = getAllArtifactsToBuild(aspect, context);
-      artifacts.addTransitive(aspectArtifacts.getAllArtifactsByOutputGroup());
+      addArtifactsWithOwnerLabel(
+          getAllArtifactsToBuild(aspect, artifactContext).getAllArtifacts(),
+          null,
+          aspect.getLabel(),
+          topLevelArtifactsToOwnerLabels);
     }
-    return new ArtifactsToBuild(artifacts.build());
+    if (analysisResult.getTargetsToTest() != null) {
+      for (ConfiguredTarget target : analysisResult.getTargetsToTest()) {
+        addArtifactsWithOwnerLabel(
+            TestProvider.getTestStatusArtifacts(target),
+            null,
+            target.getLabel(),
+            topLevelArtifactsToOwnerLabels);
+      }
+    }
+    // TODO(dslomov): Artifacts to test from aspects?
+    return topLevelArtifactsToOwnerLabels;
   }
 
+  public static void addArtifactsWithOwnerLabel(
+      Iterable<Artifact> artifacts,
+      @Nullable RegexFilter filter,
+      Label ownerLabel,
+      SetMultimap<Artifact, Label> artifactToTopLevelLabels) {
+    for (Artifact artifact : artifacts) {
+      if (filter == null || filter.isIncluded(artifact.getOwnerLabel().toString())) {
+        artifactToTopLevelLabels.put(artifact, ownerLabel);
+      }
+    }
+  }
 
   /**
    * Returns all artifacts to build if this target is requested as a top-level target. The resulting
@@ -184,7 +190,7 @@
         context);
   }
 
-  public static ArtifactsToBuild getAllArtifactsToBuild(
+  static ArtifactsToBuild getAllArtifactsToBuild(
       @Nullable OutputGroupInfo outputGroupInfo,
       @Nullable FileProvider fileProvider,
       TopLevelArtifactContext context) {
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
index 2e61ef8..d31e0d1 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/ExecutionTool.java
@@ -21,7 +21,7 @@
 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.common.collect.SetMultimap;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.ActionCacheChecker;
 import com.google.devtools.build.lib.actions.ActionGraph;
@@ -49,6 +49,7 @@
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.buildtool.buildevent.ExecutionPhaseCompleteEvent;
 import com.google.devtools.build.lib.buildtool.buildevent.ExecutionStartingEvent;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.PackageIdentifier;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
@@ -226,8 +227,6 @@
 
     ActionGraph actionGraph = analysisResult.getActionGraph();
 
-    // Get top-level artifacts.
-    ImmutableSet<Artifact> additionalArtifacts = analysisResult.getAdditionalArtifactsToBuild();
 
     OutputService outputService = env.getOutputService();
     ModifiedFileSet modifiedOutputFiles = ModifiedFileSet.EVERYTHING_MODIFIED;
@@ -303,18 +302,8 @@
     Set<AspectKey> builtAspects = new HashSet<>();
     Collection<AspectValue> aspects = analysisResult.getAspects();
 
-    Iterable<Artifact> allArtifactsForProviders =
-        Iterables.concat(
-            additionalArtifacts,
-            TopLevelArtifactHelper.getAllArtifactsToBuild(
-                    analysisResult.getTargetsToBuild(), analysisResult.getTopLevelContext())
-                .getAllArtifacts(),
-            TopLevelArtifactHelper.getAllArtifactsToBuildFromAspects(
-                    aspects, analysisResult.getTopLevelContext())
-                .getAllArtifacts(),
-            //TODO(dslomov): Artifacts to test from aspects?
-            TopLevelArtifactHelper.getAllArtifactsToTest(analysisResult.getTargetsToTest()));
-
+    SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels =
+        TopLevelArtifactHelper.makeTopLevelArtifactsToOwnerLabels(analysisResult, aspects);
     if (request.isRunningInEmacs()) {
       // The syntax of this message is tightly constrained by lisp/progmodes/compile.el in emacs
       request
@@ -327,7 +316,7 @@
       for (ActionContextProvider actionContextProvider : actionContextProviders) {
         try (SilentCloseable c =
             Profiler.instance().profile(actionContextProvider + ".executionPhaseStarting")) {
-          actionContextProvider.executionPhaseStarting(actionGraph, allArtifactsForProviders);
+          actionContextProvider.executionPhaseStarting(actionGraph, topLevelArtifactsToOwnerLabels);
         }
       }
       executor.executionPhaseStarting();
@@ -350,7 +339,7 @@
 
       builder.buildArtifacts(
           env.getReporter(),
-          additionalArtifacts,
+          analysisResult.getTopLevelArtifactsToOwnerLabels().keySet(),
           analysisResult.getParallelTests(),
           analysisResult.getExclusiveTests(),
           analysisResult.getTargetsToBuild(),
diff --git a/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
index 0afdb13..909f36a 100644
--- a/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/exec/ActionContextProvider.java
@@ -13,11 +13,13 @@
 // limitations under the License.
 package com.google.devtools.build.lib.exec;
 
+import com.google.common.collect.SetMultimap;
 import com.google.devtools.build.lib.actions.ActionContext;
 import com.google.devtools.build.lib.actions.ActionGraph;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ExecutorInitException;
 import com.google.devtools.build.lib.actions.MetadataProvider;
+import com.google.devtools.build.lib.cmdline.Label;
 
 /**
  * An object that provides execution strategies to {@link BlazeExecutor}.
@@ -50,8 +52,7 @@
 
   /** Called when the execution phase is started. */
   public void executionPhaseStarting(
-      ActionGraph actionGraph,
-      Iterable<Artifact> topLevelArtifacts)
+      ActionGraph actionGraph, SetMultimap<Artifact, Label> topLevelArtifactsToOwnerLabels)
       throws ExecutorInitException, InterruptedException {}
 
   /**