Add ResolvedTargetData::GetRustInheritedLibraries()

This CL removes Target::rust_transitive_inherited_libs()
and moves the computation of the corresponding value to
the ResolvedTargetData class, where it will be created
on demand by the GetRustInheritedLibraries() method.

Bug: 331
Change-Id: I7fcfaee61242aeddfb9284e2270f2882712cdb81
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15327
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/gn/ninja_rust_binary_target_writer.cc b/src/gn/ninja_rust_binary_target_writer.cc
index 6b9c2dc..06bce2f 100644
--- a/src/gn/ninja_rust_binary_target_writer.cc
+++ b/src/gn/ninja_rust_binary_target_writer.cc
@@ -180,8 +180,9 @@
   // on, and the public flag represents if the target has direct access to the
   // dependency through a chain of public_deps.
   std::vector<ExternCrate> transitive_crates;
-  for (const auto& [dep, has_direct_access] :
-       target_->rust_transitive_inherited_libs().GetOrderedAndPublicFlag()) {
+  for (const auto& inherited : resolved().GetRustInheritedLibraries(target_)) {
+    const Target* dep = inherited.target();
+    bool has_direct_access = inherited.is_public();
     // We will tell rustc to look for crate metadata for any rust crate
     // dependencies except cdylibs, as they have no metadata present.
     if (dep->source_types_used().RustSourceUsed() &&
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index d944123..b2692e7 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -171,3 +171,55 @@
     }
   }
 }
+
+void ResolvedTargetData::ComputeRustLibs(TargetInfo* info) const {
+  RustLibsBuilder rust_libs;
+
+  ComputeRustLibsFor(info->deps.public_deps(), true, &rust_libs);
+  ComputeRustLibsFor(info->deps.private_deps(), false, &rust_libs);
+
+  info->rust_inherited_libs = rust_libs.inherited.Build();
+  info->rust_inheritable_libs = rust_libs.inheritable.Build();
+  info->has_rust_libs = true;
+}
+
+void ResolvedTargetData::ComputeRustLibsFor(base::span<const Target*> deps,
+                                            bool is_public,
+                                            RustLibsBuilder* rust_libs) const {
+  for (const Target* dep : deps) {
+    // Collect Rust libraries that are accessible from the current target, or
+    // transitively part of the current target.
+    if (dep->output_type() == Target::STATIC_LIBRARY ||
+        dep->output_type() == Target::SHARED_LIBRARY ||
+        dep->output_type() == Target::SOURCE_SET ||
+        dep->output_type() == Target::RUST_LIBRARY ||
+        dep->output_type() == Target::GROUP) {
+      // Here we have: `this` --[depends-on]--> `dep`
+      //
+      // The `this` target has direct access to `dep` since its a direct
+      // dependency, regardless of the edge being a public_dep or not, so we
+      // pass true for public-ness. Whereas, anything depending on `this` can
+      // only gain direct access to `dep` if the edge between `this` and `dep`
+      // is public, so we pass `is_public`.
+      //
+      // TODO(danakj): We should only need to track Rust rlibs or dylibs here,
+      // as it's used for passing to rustc with --extern. We currently track
+      // everything then drop non-Rust libs in
+      // ninja_rust_binary_target_writer.cc.
+      rust_libs->inherited.Append(dep, true);
+      rust_libs->inheritable.Append(dep, is_public);
+
+      const TargetInfo* dep_info = GetTargetRustLibs(dep);
+      rust_libs->inherited.AppendInherited(dep_info->rust_inheritable_libs,
+                                           true);
+      rust_libs->inheritable.AppendInherited(dep_info->rust_inheritable_libs,
+                                             is_public);
+    } else if (dep->output_type() == Target::RUST_PROC_MACRO) {
+      // Proc-macros are inherited as a transitive dependency, but the things
+      // they depend on can't be used elsewhere, as the proc macro is not
+      // linked into the target (as it's only used during compilation).
+      rust_libs->inherited.Append(dep, true);
+      rust_libs->inheritable.Append(dep, is_public);
+    }
+  }
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
index 0dc36be..f8f6458 100644
--- a/src/gn/resolved_target_data.h
+++ b/src/gn/resolved_target_data.h
@@ -110,6 +110,13 @@
     return GetTargetInheritedLibs(target)->inherited_libs;
   }
 
+  // Retrieves an ordered list of (target, is_public) paris for all link-time
+  // libraries for Rust-specific binary targets.
+  const std::vector<TargetPublicPair>& GetRustInheritedLibraries(
+      const Target* target) const {
+    return GetTargetRustLibs(target)->rust_inherited_libs;
+  }
+
  private:
   // The information associated with a given Target pointer.
   struct TargetInfo {
@@ -128,6 +135,7 @@
     bool has_framework_info = false;
     bool has_hard_deps = false;
     bool has_inherited_libs = false;
+    bool has_rust_libs = false;
 
     // Only valid if |has_lib_info| is true.
     std::vector<SourceDir> lib_dirs;
@@ -143,6 +151,10 @@
 
     // Only valid if |has_inherited_libs| is true.
     std::vector<TargetPublicPair> inherited_libs;
+
+    // Only valid if |has_rust_libs| is true.
+    std::vector<TargetPublicPair> rust_inherited_libs;
+    std::vector<TargetPublicPair> rust_inheritable_libs;
   };
 
   // Retrieve TargetInfo value associated with |target|. Create
@@ -185,6 +197,15 @@
     return info;
   }
 
+  const TargetInfo* GetTargetRustLibs(const Target* target) const {
+    TargetInfo* info = GetTargetInfo(target);
+    if (!info->has_rust_libs) {
+      ComputeRustLibs(info);
+      DCHECK(info->has_rust_libs);
+    }
+    return info;
+  }
+
   // Compute the portion of TargetInfo guarded by one of the |has_xxx|
   // booleans. This performs recursive and expensive computations and
   // should only be called once per TargetInfo instance.
@@ -192,13 +213,24 @@
   void ComputeFrameworkInfo(TargetInfo* info) const;
   void ComputeHardDeps(TargetInfo* info) const;
   void ComputeInheritedLibs(TargetInfo* info) const;
+  void ComputeRustLibs(TargetInfo* info) const;
 
-  // Helper function usde by ComputeInheritedLibs().
+  // Helper function used by ComputeInheritedLibs().
   void ComputeInheritedLibsFor(
       base::span<const Target*> deps,
       bool is_public,
       TargetPublicPairListBuilder* inherited_libraries) const;
 
+  // Helper data structure and function used by ComputeRustLibs().
+  struct RustLibsBuilder {
+    TargetPublicPairListBuilder inherited;
+    TargetPublicPairListBuilder inheritable;
+  };
+
+  void ComputeRustLibsFor(base::span<const Target*> deps,
+                          bool is_public,
+                          RustLibsBuilder* rust_libs) const;
+
   // A { Target* -> TargetInfo } map that will create entries
   // on demand (hence the mutable qualifier). Implemented with a
   // UniqueVector<> and a parallel vector of unique TargetInfo
diff --git a/src/gn/rust_values.h b/src/gn/rust_values.h
index d201014..52a7623 100644
--- a/src/gn/rust_values.h
+++ b/src/gn/rust_values.h
@@ -8,7 +8,6 @@
 #include <map>
 
 #include "base/containers/flat_map.h"
-#include "gn/inherited_libraries.h"
 #include "gn/label.h"
 #include "gn/source_file.h"
 
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 5bdfdef..f73cd3a 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -484,7 +484,6 @@
   }
 
   PullRecursiveBundleData();
-  PullDependentTargetLibs();
   if (!ResolvePrecompiledHeaders(err))
     return false;
 
@@ -738,47 +737,6 @@
   }
 }
 
-void Target::PullDependentTargetLibsFrom(const Target* dep, bool is_public) {
-  // Collect Rust libraries that are accessible from the current target, or
-  // transitively part of the current target.
-  if (dep->output_type() == STATIC_LIBRARY ||
-      dep->output_type() == SHARED_LIBRARY ||
-      dep->output_type() == SOURCE_SET || dep->output_type() == RUST_LIBRARY ||
-      dep->output_type() == GROUP) {
-    // Here we have: `this` --[depends-on]--> `dep`
-    //
-    // The `this` target has direct access to `dep` since its a direct
-    // dependency, regardless of the edge being a public_dep or not, so we pass
-    // true for public-ness. Whereas, anything depending on `this` can only gain
-    // direct access to `dep` if the edge between `this` and `dep` is public, so
-    // we pass `is_public`.
-    //
-    // TODO(danakj): We should only need to track Rust rlibs or dylibs here, as
-    // it's used for passing to rustc with --extern. We currently track
-    // everything then drop non-Rust libs in ninja_rust_binary_target_writer.cc.
-    rust_transitive_inherited_libs_.Append(dep, true);
-    rust_transitive_inheritable_libs_.Append(dep, is_public);
-
-    rust_transitive_inherited_libs_.AppendInherited(
-        dep->rust_transitive_inheritable_libs(), true);
-    rust_transitive_inheritable_libs_.AppendInherited(
-        dep->rust_transitive_inheritable_libs(), is_public);
-  } else if (dep->output_type() == RUST_PROC_MACRO) {
-    // Proc-macros are inherited as a transitive dependency, but the things they
-    // depend on can't be used elsewhere, as the proc macro is not linked into
-    // the target (as it's only used during compilation).
-    rust_transitive_inherited_libs_.Append(dep, true);
-    rust_transitive_inheritable_libs_.Append(dep, is_public);
-  }
-}
-
-void Target::PullDependentTargetLibs() {
-  for (const auto& dep : public_deps_)
-    PullDependentTargetLibsFrom(dep.ptr, true);
-  for (const auto& dep : private_deps_)
-    PullDependentTargetLibsFrom(dep.ptr, false);
-}
-
 void Target::PullRecursiveBundleData() {
   for (const auto& pair : GetDeps(DEPS_LINKED)) {
     // Don't propagate bundle_data once they are added to a bundle.
diff --git a/src/gn/target.h b/src/gn/target.h
index 348f49f..806d14b 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -319,14 +319,6 @@
   const RustValues& rust_values() const;
   bool has_rust_values() const { return rust_values_.get(); }
 
-  // Transitive closure of libraries that are depended on by this target
-  const InheritedLibraries& rust_transitive_inherited_libs() const {
-    return rust_transitive_inherited_libs_;
-  }
-  const InheritedLibraries& rust_transitive_inheritable_libs() const {
-    return rust_transitive_inheritable_libs_;
-  }
-
   std::vector<LabelPattern>& friends() { return friends_; }
   const std::vector<LabelPattern>& friends() const { return friends_; }
 
@@ -494,19 +486,6 @@
   // Used for Rust targets.
   std::unique_ptr<RustValues> rust_values_;
 
-  // Used by all targets, only useful to generate Rust targets though. These
-  // present 2 different views of the public flags:
-  //
-  // Lists all transitive libraries, and for each one the public bit says if
-  // there is a public chain such that this target can make direct use of the
-  // lib. For each library marked public: "I have access to these targets."
-  InheritedLibraries rust_transitive_inherited_libs_;
-  // Lists all transitive libraries, and for each one the public bit says if a
-  // target depending on this target would inherit the libraries as public too.
-  // For each library marked public: "If you depend on me, you get access to
-  // these targets."
-  InheritedLibraries rust_transitive_inheritable_libs_;
-
   // User for Swift targets.
   std::unique_ptr<SwiftValues> swift_values_;