Merge CppDebugFileProvider with CcInfo

.dwo files were previously propagated in a separate provider, and this provider cannot be accessed from Starlark. We had 2 options:

* expose the provider in Starlark
* merge it with CcInfo

We went with unification with CcInfo, as it simplifies Starlark rules, and CppDebugFileProvider is not used by other languages anyway.

While at it, I realized we don't need the DwoArtifactsCollector to collect both pic and nopic dwos just for cc binary to then throw one of them away. Thus I removed the collector. And I changed unit tests to access dwo through action inputs, not by calling the same methods as the production code calls.

RELNOTES: None.
PiperOrigin-RevId: 257601965
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index 330740c..ee2b510 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -540,18 +540,18 @@
     CppHelper.createStripAction(
         ruleContext, ccToolchain, cppConfiguration, binary, strippedFile, featureConfiguration);
 
-    DwoArtifactsCollector dwoArtifacts =
+    NestedSet<Artifact> dwoFiles =
         collectTransitiveDwoArtifacts(
-            ruleContext,
             ccCompilationOutputs,
+            CppHelper.mergeCcDebugInfoContexts(
+                compilationInfo.getCcCompilationOutputs(),
+                AnalysisUtils.getProviders(deps, CcInfo.PROVIDER)),
             linkingMode,
-            ccToolchain.shouldCreatePerObjectDebugInfo(featureConfiguration, cppConfiguration),
             usePic,
             ccLinkingOutputsBinary.getAllLtoArtifacts());
     Artifact dwpFile =
         ruleContext.getImplicitOutputArtifact(CppRuleClasses.CC_BINARY_DEBUG_PACKAGE);
-    createDebugPackagerActions(
-        ruleContext, ccToolchain, cppConfiguration, featureConfiguration, dwpFile, dwoArtifacts);
+    createDebugPackagerActions(ruleContext, ccToolchain, dwpFile, dwoFiles);
 
     // The debug package should include the dwp file only if it was explicitly requested.
     Artifact explicitDwpFile = dwpFile;
@@ -619,7 +619,6 @@
         ccCompilationOutputs,
         ccCompilationContext,
         libraries,
-        dwoArtifacts,
         fake);
 
     // Support test execution on darwin.
@@ -859,33 +858,31 @@
    * dynamic linking, dependencies are separately linked into their own shared libraries, so we
    * don't need them here.
    */
-  private static DwoArtifactsCollector collectTransitiveDwoArtifacts(
-      RuleContext context,
+  private static NestedSet<Artifact> collectTransitiveDwoArtifacts(
       CcCompilationOutputs compilationOutputs,
-      Link.LinkingMode linkingMode,
-      boolean generateDwo,
-      boolean ltoBackendArtifactsUsePic,
+      CcDebugInfoContext ccDebugInfoContext,
+      LinkingMode linkingMode,
+      boolean usePic,
       Iterable<LtoBackendArtifacts> ltoBackendArtifacts) {
-    if (linkingMode == LinkingMode.DYNAMIC) {
-      return DwoArtifactsCollector.directCollector(
-          compilationOutputs, generateDwo, ltoBackendArtifactsUsePic, ltoBackendArtifacts);
-    } else {
-      return CcCommon.collectTransitiveDwoArtifacts(
-          context, compilationOutputs, generateDwo, ltoBackendArtifactsUsePic, ltoBackendArtifacts);
-    }
-  }
+    NestedSetBuilder<Artifact> dwoFiles = NestedSetBuilder.stableOrder();
+    dwoFiles.addAll(
+        usePic ? compilationOutputs.getPicDwoFiles() : compilationOutputs.getDwoFiles());
 
-  @VisibleForTesting
-  public static Iterable<Artifact> getDwpInputs(
-      RuleContext context,
-      CcToolchainProvider toolchain,
-      CppConfiguration cppConfiguration,
-      FeatureConfiguration featureConfiguration,
-      NestedSet<Artifact> picDwoArtifacts,
-      NestedSet<Artifact> dwoArtifacts) {
-    return usePic(context, toolchain, cppConfiguration, featureConfiguration)
-        ? picDwoArtifacts
-        : dwoArtifacts;
+    if (ltoBackendArtifacts != null) {
+      for (LtoBackendArtifacts ltoBackendArtifact : ltoBackendArtifacts) {
+        if (ltoBackendArtifact.getDwoFile() != null) {
+          dwoFiles.add(ltoBackendArtifact.getDwoFile());
+        }
+      }
+    }
+
+    if (linkingMode != LinkingMode.DYNAMIC) {
+      dwoFiles.addTransitive(
+          usePic
+              ? ccDebugInfoContext.getTransitivePicDwoFiles()
+              : ccDebugInfoContext.getTransitiveDwoFiles());
+    }
+    return dwoFiles.build();
   }
 
   /**
@@ -894,27 +891,16 @@
   private static void createDebugPackagerActions(
       RuleContext context,
       CcToolchainProvider toolchain,
-      CppConfiguration cppConfiguration,
-      FeatureConfiguration featureConfiguration,
       Artifact dwpOutput,
-      DwoArtifactsCollector dwoArtifactsCollector)
+      NestedSet<Artifact> dwoFiles)
       throws RuleErrorException {
-    Iterable<Artifact> allInputs =
-        getDwpInputs(
-            context,
-            toolchain,
-            cppConfiguration,
-            featureConfiguration,
-            dwoArtifactsCollector.getPicDwoArtifacts(),
-            dwoArtifactsCollector.getDwoArtifacts());
-
     // No inputs? Just generate a trivially empty .dwp.
     //
     // Note this condition automatically triggers for any build where fission is disabled.
     // Because rules referencing .dwp targets may be invoked with or without fission, we need
     // to support .dwp generation even when fission is disabled. Since no actual functionality
     // is expected then, an empty file is appropriate.
-    if (Iterables.isEmpty(allInputs)) {
+    if (Iterables.isEmpty(dwoFiles)) {
       context.registerAction(FileWriteAction.create(context, dwpOutput, "", false));
       return;
     }
@@ -938,7 +924,7 @@
     // at the leaves than the root, but that both increases parallelism and reduces the final
     // action's input size.
     Packager packager =
-        createIntermediateDwpPackagers(context, dwpOutput, toolchain, dwpFiles, allInputs, 1);
+        createIntermediateDwpPackagers(context, dwpOutput, toolchain, dwpFiles, dwoFiles, 1);
     packager.spawnAction.setMnemonic("CcGenerateDwp").addOutput(dwpOutput);
     packager.commandLine.addExecPath("-o", dwpOutput);
     context.registerAction(packager.build(context));
@@ -963,25 +949,25 @@
       RuleContext context,
       Artifact dwpOutput,
       CcToolchainProvider toolchain,
-      NestedSet<Artifact> dwpTools,
-      Iterable<Artifact> inputs,
+      NestedSet<Artifact> dwpFiles,
+      Iterable<Artifact> dwoFiles,
       int intermediateDwpCount)
       throws RuleErrorException {
     List<Packager> packagers = new ArrayList<>();
 
     // Step 1: generate our batches. We currently break into arbitrary batches of fixed maximum
     // input counts, but we can always apply more intelligent heuristics if the need arises.
-    Packager currentPackager = newDwpAction(context, toolchain, dwpTools);
+    Packager currentPackager = newDwpAction(context, toolchain, dwpFiles);
     int inputsForCurrentPackager = 0;
 
-    for (Artifact dwoInput : inputs) {
+    for (Artifact dwoFile : dwoFiles) {
       if (inputsForCurrentPackager == MAX_INPUTS_PER_DWP_ACTION) {
         packagers.add(currentPackager);
-        currentPackager = newDwpAction(context, toolchain, dwpTools);
+        currentPackager = newDwpAction(context, toolchain, dwpFiles);
         inputsForCurrentPackager = 0;
       }
-      currentPackager.spawnAction.addInput(dwoInput);
-      currentPackager.commandLine.addExecPath(dwoInput);
+      currentPackager.spawnAction.addInput(dwoFile);
+      currentPackager.commandLine.addExecPath(dwoFile);
       inputsForCurrentPackager++;
     }
     packagers.add(currentPackager);
@@ -1000,7 +986,7 @@
         intermediateOutputs.add(intermediateOutput);
       }
       return createIntermediateDwpPackagers(
-          context, dwpOutput, toolchain, dwpTools, intermediateOutputs, intermediateDwpCount);
+          context, dwpOutput, toolchain, dwpFiles, intermediateOutputs, intermediateDwpCount);
     }
     return Iterables.getOnlyElement(packagers);
   }
@@ -1084,7 +1070,6 @@
       CcCompilationOutputs ccCompilationOutputs,
       CcCompilationContext ccCompilationContext,
       List<LibraryToLink> libraries,
-      DwoArtifactsCollector dwoArtifacts,
       boolean fake)
       throws RuleErrorException {
     List<Artifact> instrumentedObjectFiles = new ArrayList<>();
@@ -1117,10 +1102,6 @@
             CcNativeLibraryProvider.class,
             new CcNativeLibraryProvider(collectTransitiveCcNativeLibraries(ruleContext, libraries)))
         .addNativeDeclaredProvider(instrumentedFilesProvider)
-        .addProvider(
-            CppDebugFileProvider.class,
-            new CppDebugFileProvider(
-                dwoArtifacts.getDwoArtifacts(), dwoArtifacts.getPicDwoArtifacts()))
         // For CcBinary targets, we only want to ensure that we process headers in dependencies and
         // thus only add header tokens to HIDDEN_TOP_LEVEL. If we add all HIDDEN_TOP_LEVEL artifacts
         // from dependent CcLibrary targets, we'd be building .pic.o files in nopic builds.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
index 89413e3..fac7cb2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCommon.java
@@ -276,30 +276,6 @@
     return ruleContext.attributes().has(name, type);
   }
 
-  /** Collects all .dwo artifacts in this target's transitive closure. */
-  public static DwoArtifactsCollector collectTransitiveDwoArtifacts(
-      RuleContext ruleContext,
-      CcCompilationOutputs compilationOutputs,
-      boolean generateDwo,
-      boolean ltoBackendArtifactsUsePic,
-      Iterable<LtoBackendArtifacts> ltoBackendArtifacts) {
-    ImmutableList.Builder<TransitiveInfoCollection> deps =
-        ImmutableList.<TransitiveInfoCollection>builder();
-
-    deps.addAll(ruleContext.getPrerequisites("deps", Mode.TARGET));
-
-    if (ruleContext.attributes().has("malloc", BuildType.LABEL)) {
-      deps.add(CppHelper.mallocForTarget(ruleContext));
-    }
-
-    return DwoArtifactsCollector.transitiveCollector(
-        compilationOutputs,
-        deps.build(),
-        generateDwo,
-        ltoBackendArtifactsUsePic,
-        ltoBackendArtifacts);
-  }
-
   /**
    * Returns a list of ({@link Artifact}, {@link Label}) pairs. Each pair represents an input source
    * file and the label of the rule that generates it (or the label of the source file itself if it
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
index 8eee474..0e84756 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
@@ -543,7 +543,6 @@
         ActionConstructionContext actionConstructionContext,
         BuildConfiguration configuration,
         Label label) {
-      // private to avoid class initialization deadlock between this class and its outer class
       this.actionConstructionContext = actionConstructionContext;
       this.configuration = configuration;
       this.label = label;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
index 5428a78..62fdb9c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationHelper.java
@@ -709,20 +709,6 @@
     return outputGroups;
   }
 
-  public static CppDebugFileProvider buildCppDebugFileProvider(
-      CcCompilationOutputs ccCompilationOutputs, Iterable<TransitiveInfoCollection> deps) {
-    DwoArtifactsCollector dwoArtifacts =
-        DwoArtifactsCollector.transitiveCollector(
-            ccCompilationOutputs,
-            deps,
-            /*generateDwo=*/ false,
-            /*ltoBackendArtifactsUsePic=*/ false,
-            /*ltoBackendArtifacts=*/ ImmutableList.of());
-    CppDebugFileProvider cppDebugFileProvider =
-        new CppDebugFileProvider(dwoArtifacts.getDwoArtifacts(), dwoArtifacts.getPicDwoArtifacts());
-    return cppDebugFileProvider;
-  }
-
   public static Map<String, NestedSet<Artifact>> buildOutputGroupsForEmittingCompileProviders(
       CcCompilationOutputs ccCompilationOutputs,
       CcCompilationContext ccCompilationContext,
@@ -1259,8 +1245,7 @@
       }
     }
 
-    ImmutableMap<Artifact, String> outputNameMap = null;
-
+    ImmutableMap<Artifact, String> outputNameMap;
     String outputNamePrefixDir = null;
     // purpose is only used by objc rules, it ends with either "_non_objc_arc" or "_objc_arc".
     // Here we use it to distinguish arc and non-arc compilation.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcDebugInfoContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcDebugInfoContext.java
new file mode 100644
index 0000000..ffc9abe
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcDebugInfoContext.java
@@ -0,0 +1,98 @@
+// Copyright 2014 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.rules.cpp;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import java.util.Objects;
+
+/**
+ * A struct that stores .dwo files which can be combined into a .dwp in the packaging step. See
+ * https://gcc.gnu.org/wiki/DebugFission for details.
+ */
+@Immutable
+public final class CcDebugInfoContext {
+
+  public static final CcDebugInfoContext EMPTY =
+      new CcDebugInfoContext(
+          /* transitiveDwoFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
+          /* transitivePicDwoFiles= */ NestedSetBuilder.emptySet(Order.STABLE_ORDER));
+  private final NestedSet<Artifact> transitiveDwoFiles;
+  private final NestedSet<Artifact> transitivePicDwoFiles;
+
+  public CcDebugInfoContext(
+      NestedSet<Artifact> transitiveDwoFiles, NestedSet<Artifact> transitivePicDwoFiles) {
+    this.transitiveDwoFiles = transitiveDwoFiles;
+    this.transitivePicDwoFiles = transitivePicDwoFiles;
+  }
+
+  /** Merge multiple {@link CcDebugInfoContext}s into one. */
+  public static CcDebugInfoContext merge(ImmutableList<CcDebugInfoContext> contexts) {
+    NestedSetBuilder<Artifact> transitiveDwoFiles = NestedSetBuilder.stableOrder();
+    NestedSetBuilder<Artifact> transitivePicDwoFiles = NestedSetBuilder.stableOrder();
+
+    for (CcDebugInfoContext context : contexts) {
+      transitiveDwoFiles.addTransitive(context.getTransitiveDwoFiles());
+      transitivePicDwoFiles.addTransitive(context.getTransitivePicDwoFiles());
+    }
+
+    return new CcDebugInfoContext(transitiveDwoFiles.build(), transitivePicDwoFiles.build());
+  }
+
+  public static CcDebugInfoContext from(CcCompilationOutputs outputs) {
+    return new CcDebugInfoContext(
+        NestedSetBuilder.wrap(Order.STABLE_ORDER, outputs.getDwoFiles()),
+        NestedSetBuilder.wrap(Order.STABLE_ORDER, outputs.getPicDwoFiles()));
+  }
+
+  /**
+   * Returns the .dwo files that should be included in this target's .dwp packaging (if this
+   * target is linked) or passed through to a dependant's .dwp packaging (e.g. if this is a
+   * cc_library depended on by a statically linked cc_binary).
+   *
+   * Assumes the corresponding link consumes .o files (vs. .pic.o files).
+   */
+  public NestedSet<Artifact> getTransitiveDwoFiles() {
+    return transitiveDwoFiles;
+  }
+
+  /**
+   * Same as above, but assumes the corresponding link consumes pic.o files.
+   */
+  public NestedSet<Artifact> getTransitivePicDwoFiles() {
+    return transitivePicDwoFiles;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+    CcDebugInfoContext that = (CcDebugInfoContext) o;
+    return Objects.equals(transitiveDwoFiles, that.transitiveDwoFiles)
+        && Objects.equals(transitivePicDwoFiles, that.transitivePicDwoFiles);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(transitiveDwoFiles, transitivePicDwoFiles);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
index 152768a..e9986bf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.rules.cpp;
 
 import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -167,18 +166,16 @@
             .setCodeCoverageEnabled(CcCompilationHelper.isCodeCoverageEnabled(ruleContext))
             .compile();
 
-    CppDebugFileProvider cppDebugFileProvider =
-        CcCompilationHelper.buildCppDebugFileProvider(
-            compilationInfo.getCcCompilationOutputs(), ImmutableList.of());
     Map<String, NestedSet<Artifact>> outputGroups =
         CcCompilationHelper.buildOutputGroups(compilationInfo.getCcCompilationOutputs());
     RuleConfiguredTargetBuilder result =
         new RuleConfiguredTargetBuilder(ruleContext)
-            .addProvider(cppDebugFileProvider)
             .addNativeDeclaredProvider(
                 CcInfo.builder()
                     .setCcCompilationContext(compilationInfo.getCcCompilationContext())
                     .setCcLinkingContext(ccLinkingContext)
+                    .setCcDebugInfoContext(
+                        CcDebugInfoContext.from(compilationInfo.getCcCompilationOutputs()))
                     .build())
             .addOutputGroups(outputGroups)
             .addProvider(RunfilesProvider.class, RunfilesProvider.simple(Runfiles.EMPTY));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcInfo.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcInfo.java
index ab6ebf7..b68c30b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcInfo.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcInfo.java
@@ -37,11 +37,16 @@
 
   private final CcCompilationContext ccCompilationContext;
   private final CcLinkingContext ccLinkingContext;
+  private final CcDebugInfoContext ccDebugInfoContext;
 
-  public CcInfo(CcCompilationContext ccCompilationContext, CcLinkingContext ccLinkingContext) {
+  public CcInfo(
+      CcCompilationContext ccCompilationContext,
+      CcLinkingContext ccLinkingContext,
+      CcDebugInfoContext ccDebugInfoContext) {
     super(PROVIDER);
     this.ccCompilationContext = ccCompilationContext;
     this.ccLinkingContext = ccLinkingContext;
+    this.ccDebugInfoContext = ccDebugInfoContext;
   }
 
   @Override
@@ -54,12 +59,19 @@
     return ccLinkingContext;
   }
 
+  public CcDebugInfoContext getCcDebugInfoContext() {
+    return ccDebugInfoContext;
+  }
+
   public static CcInfo merge(Collection<CcInfo> ccInfos) {
     ImmutableList.Builder<CcCompilationContext> ccCompilationContexts = ImmutableList.builder();
     ImmutableList.Builder<CcLinkingContext> ccLinkingContexts = ImmutableList.builder();
+    ImmutableList.Builder<CcDebugInfoContext> ccDebugInfoContexts = ImmutableList.builder();
+
     for (CcInfo ccInfo : ccInfos) {
       ccCompilationContexts.add(ccInfo.getCcCompilationContext());
       ccLinkingContexts.add(ccInfo.getCcLinkingContext());
+      ccDebugInfoContexts.add(ccInfo.getCcDebugInfoContext());
     }
     CcCompilationContext.Builder builder =
         CcCompilationContext.builder(
@@ -67,7 +79,8 @@
 
     return new CcInfo(
         builder.mergeDependentCcCompilationContexts(ccCompilationContexts.build()).build(),
-        CcLinkingContext.merge(ccLinkingContexts.build()));
+        CcLinkingContext.merge(ccLinkingContexts.build()),
+        CcDebugInfoContext.merge(ccDebugInfoContexts.build()));
   }
 
   @Override
@@ -80,6 +93,7 @@
       return true;
     }
     if (!this.ccCompilationContext.equals(other.ccCompilationContext)
+        || !this.ccDebugInfoContext.equals(other.ccDebugInfoContext)
         || !this.getCcLinkingContext().equals(other.getCcLinkingContext())) {
       return false;
     }
@@ -88,7 +102,7 @@
 
   @Override
   public int hashCode() {
-    return Objects.hashCode(ccCompilationContext, ccLinkingContext);
+    return Objects.hashCode(ccCompilationContext, ccLinkingContext, ccDebugInfoContext);
   }
 
   public static Builder builder() {
@@ -100,6 +114,7 @@
   public static class Builder {
     private CcCompilationContext ccCompilationContext;
     private CcLinkingContext ccLinkingContext;
+    private CcDebugInfoContext ccDebugInfoContext;
 
     private Builder() {}
 
@@ -115,6 +130,12 @@
       return this;
     }
 
+    public CcInfo.Builder setCcDebugInfoContext(CcDebugInfoContext ccDebugInfoContext) {
+      Preconditions.checkState(this.ccDebugInfoContext == null);
+      this.ccDebugInfoContext = ccDebugInfoContext;
+      return this;
+    }
+
     public CcInfo build() {
       if (ccCompilationContext == null) {
         ccCompilationContext = CcCompilationContext.EMPTY;
@@ -122,7 +143,10 @@
       if (ccLinkingContext == null) {
         ccLinkingContext = CcLinkingContext.EMPTY;
       }
-      return new CcInfo(ccCompilationContext, ccLinkingContext);
+      if (ccDebugInfoContext == null) {
+        ccDebugInfoContext = CcDebugInfoContext.EMPTY;
+      }
+      return new CcInfo(ccCompilationContext, ccLinkingContext, ccDebugInfoContext);
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index 1b799bc..1f15172 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -145,6 +145,7 @@
     if (ruleContext.hasErrors()) {
       return;
     }
+    Iterable<CcInfo> ccInfosFromDeps = AnalysisUtils.getProviders(deps, CcInfo.PROVIDER);
     CcCompilationHelper compilationHelper =
         new CcCompilationHelper(
                 ruleContext,
@@ -161,7 +162,7 @@
             .addPublicHeaders(common.getHeaders())
             .setCodeCoverageEnabled(CcCompilationHelper.isCodeCoverageEnabled(ruleContext))
             .addCcCompilationContexts(
-                Streams.stream(AnalysisUtils.getProviders(deps, CcInfo.PROVIDER))
+                Streams.stream(ccInfosFromDeps)
                     .map(CcInfo::getCcCompilationContext)
                     .collect(ImmutableList.toImmutableList()))
             .addCcCompilationContexts(
@@ -443,11 +444,6 @@
                 LibraryToLink.getDynamicLibrariesForRuntime(
                     /* linkingStatically= */ false, libraryToLinks));
 
-    @SuppressWarnings("unchecked")
-    CppDebugFileProvider cppDebugFileProvider =
-        CcCompilationHelper.buildCppDebugFileProvider(
-            compilationInfo.getCcCompilationOutputs(),
-            (List<TransitiveInfoCollection>) ruleContext.getPrerequisites("deps", Mode.TARGET));
     Map<String, NestedSet<Artifact>> currentOutputGroups =
         CcCompilationHelper.buildOutputGroupsForEmittingCompileProviders(
             compilationInfo.getCcCompilationOutputs(),
@@ -459,12 +455,14 @@
     CcSkylarkApiProvider.maybeAdd(ruleContext, targetBuilder);
     targetBuilder
         .setFilesToBuild(filesToBuild)
-        .addProvider(cppDebugFileProvider)
         .addProvider(ccNativeLibraryProvider)
         .addNativeDeclaredProvider(
             CcInfo.builder()
                 .setCcCompilationContext(compilationInfo.getCcCompilationContext())
                 .setCcLinkingContext(ccLinkingContext)
+                .setCcDebugInfoContext(
+                    CppHelper.mergeCcDebugInfoContexts(
+                        compilationInfo.getCcCompilationOutputs(), ccInfosFromDeps))
                 .build())
         .addOutputGroups(
             CcCommon.mergeOutputGroups(ImmutableList.of(currentOutputGroups, outputGroups.build())))
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
index cf054d1..c018ccd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainProvider.java
@@ -33,7 +33,6 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchain.AdditionalBuildVariablesComputer;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration.Tool;
-import com.google.devtools.build.lib.rules.cpp.LibraryToLink.CcLinkingContext;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.skylarkbuildapi.cpp.CcToolchainProviderApi;
 import com.google.devtools.build.lib.syntax.EvalException;
@@ -244,7 +243,6 @@
     this.ccInfo =
         CcInfo.builder()
             .setCcCompilationContext(Preconditions.checkNotNull(ccCompilationContext))
-            .setCcLinkingContext(CcLinkingContext.EMPTY)
             .build();
     this.supportsParamFiles = supportsParamFiles;
     this.supportsHeaderParsing = supportsHeaderParsing;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppDebugFileProvider.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppDebugFileProvider.java
deleted file mode 100644
index 5b1ec70..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppDebugFileProvider.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 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.rules.cpp;
-
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-
-/**
- * A target that provides .dwo files which can be combined into a .dwp packaging step. See
- * https://gcc.gnu.org/wiki/DebugFission for details.
- */
-@Immutable
-@AutoCodec
-public final class CppDebugFileProvider implements TransitiveInfoProvider {
-  private final NestedSet<Artifact> transitiveDwoFiles;
-  private final NestedSet<Artifact> transitivePicDwoFiles;
-
-  @AutoCodec.Instantiator
-  public CppDebugFileProvider(
-      NestedSet<Artifact> transitiveDwoFiles, NestedSet<Artifact> transitivePicDwoFiles) {
-    this.transitiveDwoFiles = transitiveDwoFiles;
-    this.transitivePicDwoFiles = transitivePicDwoFiles;
-  }
-
-  /**
-   * Returns the .dwo files that should be included in this target's .dwp packaging (if this
-   * target is linked) or passed through to a dependant's .dwp packaging (e.g. if this is a
-   * cc_library depended on by a statically linked cc_binary).
-   *
-   * Assumes the corresponding link consumes .o files (vs. .pic.o files).
-   */
-  public NestedSet<Artifact> getTransitiveDwoFiles() {
-    return transitiveDwoFiles;
-  }
-
-  /**
-   * Same as above, but assumes the corresponding link consumes pic.o files.
-   */
-  public NestedSet<Artifact> getTransitivePicDwoFiles() {
-    return transitivePicDwoFiles;
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
index 5d44369..4dd4aaa 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppHelper.java
@@ -961,6 +961,16 @@
         .collect(ImmutableList.toImmutableList());
   }
 
+  public static CcDebugInfoContext mergeCcDebugInfoContexts(
+      CcCompilationOutputs compilationOutputs, Iterable<CcInfo> deps) {
+    ImmutableList.Builder<CcDebugInfoContext> contexts = ImmutableList.builder();
+    for (CcInfo ccInfo : deps) {
+      contexts.add(ccInfo.getCcDebugInfoContext());
+    }
+    contexts.add(CcDebugInfoContext.from(compilationOutputs));
+    return CcDebugInfoContext.merge(contexts.build());
+  }
+
   public static ImmutableList<CcLinkingContext> getLinkingContextsFromDeps(
       ImmutableList<TransitiveInfoCollection> deps) {
     return Streams.stream(AnalysisUtils.getProviders(deps, CcInfo.PROVIDER))
@@ -968,6 +978,13 @@
         .collect(ImmutableList.toImmutableList());
   }
 
+  public static ImmutableList<CcDebugInfoContext> getDebugInfoContextsFromDeps(
+      List<TransitiveInfoCollection> deps) {
+    return Streams.stream(AnalysisUtils.getProviders(deps, CcInfo.PROVIDER))
+        .map(CcInfo::getCcDebugInfoContext)
+        .collect(ImmutableList.toImmutableList());
+  }
+
   public static Artifact getGrepIncludes(RuleContext ruleContext) {
     return ruleContext.attributes().has("$grep_includes")
         ? ruleContext.getPrerequisiteArtifact("$grep_includes", Mode.HOST)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/DwoArtifactsCollector.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/DwoArtifactsCollector.java
deleted file mode 100644
index 85348ac..0000000
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/DwoArtifactsCollector.java
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2014 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.rules.cpp;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.Artifact;
-import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
-import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
-import com.google.devtools.build.lib.collect.nestedset.Order;
-
-/**
- * Provides generic functionality for collecting the .dwo artifacts produced by any target
- * that compiles C++ files. Supports both transitive and "only direct outputs" collection.
- * Provides accessors for both PIC and non-PIC compilation modes.
- */
-public class DwoArtifactsCollector {
-
-  /**
-   * The .dwo files collected by this target in non-PIC compilation mode (i.e. myobject.dwo).
-   */
-  private final NestedSet<Artifact> dwoArtifacts;
-
-  /**
-   * The .dwo files collected by this target in PIC compilation mode (i.e. myobject.pic.dwo).
-   */
-  private final NestedSet<Artifact> picDwoArtifacts;
-
-  /** Instantiates a "real" collector on meaningful data. */
-  private DwoArtifactsCollector(
-      CcCompilationOutputs compilationOutputs,
-      Iterable<TransitiveInfoCollection> deps,
-      boolean generateDwo,
-      boolean ltoBackendArtifactsUsePic,
-      Iterable<LtoBackendArtifacts> ltoBackendArtifacts) {
-
-    Preconditions.checkNotNull(compilationOutputs);
-    Preconditions.checkNotNull(deps);
-
-    // Note: .dwo collection works fine with any order, but tests may assume a
-    // specific order for readability / simplicity purposes. See
-    // DebugInfoPackagingTest for details.
-    NestedSetBuilder<Artifact> dwoBuilder = NestedSetBuilder.compileOrder();
-    NestedSetBuilder<Artifact> picDwoBuilder = NestedSetBuilder.compileOrder();
-
-    dwoBuilder.addAll(compilationOutputs.getDwoFiles());
-    picDwoBuilder.addAll(compilationOutputs.getPicDwoFiles());
-
-    // If we are generating .dwo, add any generated for LtoBackendArtifacts.
-    if (generateDwo && ltoBackendArtifacts != null) {
-      for (LtoBackendArtifacts ltoBackendArtifact : ltoBackendArtifacts) {
-        Artifact dwoFile = ltoBackendArtifact.getDwoFile();
-        if (ltoBackendArtifactsUsePic) {
-          picDwoBuilder.add(dwoFile);
-        } else {
-          dwoBuilder.add(dwoFile);
-        }
-      }
-    }
-
-    for (TransitiveInfoCollection info : deps) {
-      CppDebugFileProvider provider = info.getProvider(CppDebugFileProvider.class);
-      if (provider != null) {
-        dwoBuilder.addTransitive(provider.getTransitiveDwoFiles());
-        picDwoBuilder.addTransitive(provider.getTransitivePicDwoFiles());
-      }
-    }
-
-    dwoArtifacts = dwoBuilder.build();
-    picDwoArtifacts = picDwoBuilder.build();
-  }
-
-  /**
-   * Instantiates an empty collector.
-   */
-  private DwoArtifactsCollector() {
-    dwoArtifacts = NestedSetBuilder.<Artifact>emptySet(Order.COMPILE_ORDER);
-    picDwoArtifacts = NestedSetBuilder.<Artifact>emptySet(Order.COMPILE_ORDER);
-  }
-
-  /**
-   * Returns a new instance that collects direct outputs and transitive dependencies.
-   *
-   * @param compilationOutputs the {@code CcCompilationOutputs} for the owning target
-   * @param deps which of the target's transitive info collections should be visited
-   */
-  public static DwoArtifactsCollector transitiveCollector(
-      CcCompilationOutputs compilationOutputs,
-      Iterable<TransitiveInfoCollection> deps,
-      boolean generateDwo,
-      boolean ltoBackendArtifactsUsePic,
-      Iterable<LtoBackendArtifacts> ltoBackendArtifacts) {
-    return new DwoArtifactsCollector(
-        compilationOutputs,
-        deps,
-        generateDwo,
-        ltoBackendArtifactsUsePic,
-        ltoBackendArtifacts);
-  }
-
-  /**
-   * Returns a new instance that collects direct outputs only.
-   *
-   * @param compilationOutputs the output {@code CcCompilationOutputs} for the owning target
-   */
-  public static DwoArtifactsCollector directCollector(
-      CcCompilationOutputs compilationOutputs,
-      boolean generateDwo,
-      boolean ltoBackendArtifactsUsePic,
-      Iterable<LtoBackendArtifacts> ltoBackendArtifacts) {
-    return new DwoArtifactsCollector(
-        compilationOutputs,
-        ImmutableList.<TransitiveInfoCollection>of(),
-        generateDwo,
-        ltoBackendArtifactsUsePic,
-        ltoBackendArtifacts);
-  }
-
-  /**
-   * Returns a new instance that doesn't collect anything (its artifact sets are empty).
-   */
-  public static DwoArtifactsCollector emptyCollector() {
-    return new DwoArtifactsCollector();
-  }
-
-  /**
-   * Returns the .dwo files applicable to non-PIC compilation mode (i.e. myobject.dwo).
-   */
-  public NestedSet<Artifact> getDwoArtifacts() {
-    return dwoArtifacts;
-  }
-
-  /**
-   * Returns the .dwo files applicable to PIC compilation mode (i.e. myobject.pic.dwo).
-   */
-  public NestedSet<Artifact> getPicDwoArtifacts() {
-    return picDwoArtifacts;
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
index 69d1464..9e86685 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoAspect.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
+import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.ConfiguredAspect;
 import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -53,7 +54,6 @@
 import com.google.devtools.build.lib.rules.cpp.CcToolchainFeatures.FeatureConfiguration;
 import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
-import com.google.devtools.build.lib.rules.cpp.CppDebugFileProvider;
 import com.google.devtools.build.lib.rules.cpp.CppHelper;
 import com.google.devtools.build.lib.rules.cpp.CppRuleClasses;
 import com.google.devtools.build.lib.rules.cpp.CppSemantics;
@@ -225,16 +225,16 @@
           ccLinkingHelper.buildCcLinkingContextFromLibrariesToLink(
               libraryToLink, compilationInfo.getCcCompilationContext());
 
-      CppDebugFileProvider cppDebugFileProvider =
-          CcCompilationHelper.buildCppDebugFileProvider(
-              compilationInfo.getCcCompilationOutputs(), deps);
       ccLibraryProviders =
           new TransitiveInfoProviderMapBuilder()
-              .add(cppDebugFileProvider)
               .put(
                   CcInfo.builder()
                       .setCcCompilationContext(compilationInfo.getCcCompilationContext())
                       .setCcLinkingContext(ccLinkingContext)
+                      .setCcDebugInfoContext(
+                          CppHelper.mergeCcDebugInfoContexts(
+                              compilationInfo.getCcCompilationOutputs(),
+                              AnalysisUtils.getProviders(deps, CcInfo.PROVIDER)))
                       .build())
               .add(ccNativeLibraryProvider)
               .build();