Add ResolvedTargetData::GetHardDeps()

This CL removes Target::recursive_hard_deps() and moves the
computation of the corresponding value to the
ResolvedTargetData class, which creates it on demand
with the GetHardDeps() method.

Bug: 331
Change-Id: I8aec15ab047533b2fe80ff853850de3a57dc898d
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15325
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/ninja_target_writer.cc b/src/gn/ninja_target_writer.cc
index 416d62e..ea39822 100644
--- a/src/gn/ninja_target_writer.cc
+++ b/src/gn/ninja_target_writer.cc
@@ -434,7 +434,7 @@
 
   // Hard dependencies that are direct or indirect dependencies.
   // These are large (up to 100s), hence why we check other
-  const TargetSet& hard_deps(target_->recursive_hard_deps());
+  const TargetSet& hard_deps = resolved().GetHardDeps(target_);
   for (const Target* target : hard_deps) {
     // BUNDLE_DATA should normally be treated as a data-only dependency
     // (see Target::IsDataOnly()). Only the CREATE_BUNDLE target, that actually
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index 3208f04..467e2fb 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -62,3 +62,29 @@
   info->weak_frameworks = all_weak_frameworks.release();
   info->has_framework_info = true;
 }
+
+void ResolvedTargetData::ComputeHardDeps(TargetInfo* info) const {
+  TargetSet all_hard_deps;
+  for (const Target* dep : info->deps.linked_deps()) {
+    // Direct hard dependencies
+    if (info->target->hard_dep() || dep->hard_dep()) {
+      all_hard_deps.insert(dep);
+      continue;
+    }
+    // If |dep| is binary target and |dep| has no public header,
+    // |this| target does not need to have |dep|'s hard_deps as its
+    // hard_deps to start compiles earlier. Unless the target compiles a
+    // Swift module (since they also generate a header that can be used
+    // by the current target).
+    if (dep->IsBinary() && !dep->all_headers_public() &&
+        dep->public_headers().empty() && !dep->builds_swift_module()) {
+      continue;
+    }
+
+    // Recursive hard dependencies of all dependencies.
+    const TargetInfo* dep_info = GetTargetHardDeps(dep);
+    all_hard_deps.insert(dep_info->hard_deps);
+  }
+  info->hard_deps = std::move(all_hard_deps);
+  info->has_hard_deps = true;
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
index 754abc2..bc992a1 100644
--- a/src/gn/resolved_target_data.h
+++ b/src/gn/resolved_target_data.h
@@ -96,6 +96,13 @@
     return GetTargetFrameworkInfo(target)->weak_frameworks;
   }
 
+  // Retrieves a set of hard dependencies for this target.
+  // All hard deps from this target and all dependencies, but not the
+  // target itself.
+  const TargetSet& GetHardDeps(const Target* target) const {
+    return GetTargetHardDeps(target)->hard_deps;
+  }
+
  private:
   // The information associated with a given Target pointer.
   struct TargetInfo {
@@ -112,6 +119,7 @@
 
     bool has_lib_info = false;
     bool has_framework_info = false;
+    bool has_hard_deps = false;
 
     // Only valid if |has_lib_info| is true.
     std::vector<SourceDir> lib_dirs;
@@ -121,6 +129,9 @@
     std::vector<SourceDir> framework_dirs;
     std::vector<std::string> frameworks;
     std::vector<std::string> weak_frameworks;
+
+    // Only valid if |has_hard_deps| is true.
+    TargetSet hard_deps;
   };
 
   // Retrieve TargetInfo value associated with |target|. Create
@@ -145,11 +156,21 @@
     return info;
   }
 
+  const TargetInfo* GetTargetHardDeps(const Target* target) const {
+    TargetInfo* info = GetTargetInfo(target);
+    if (!info->has_hard_deps) {
+      ComputeHardDeps(info);
+      DCHECK(info->has_hard_deps);
+    }
+    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.
   void ComputeLibInfo(TargetInfo* info) const;
   void ComputeFrameworkInfo(TargetInfo* info) const;
+  void ComputeHardDeps(TargetInfo* info) const;
 
   // A { Target* -> TargetInfo } map that will create entries
   // on demand (hence the mutable qualifier). Implemented with a
diff --git a/src/gn/target.cc b/src/gn/target.cc
index 0ad2dd2..84cfbfa 100644
--- a/src/gn/target.cc
+++ b/src/gn/target.cc
@@ -485,7 +485,6 @@
 
   PullRecursiveBundleData();
   PullDependentTargetLibs();
-  PullRecursiveHardDeps();
   if (!ResolvePrecompiledHeaders(err))
     return false;
 
@@ -848,31 +847,6 @@
     PullDependentTargetLibsFrom(dep.ptr, false);
 }
 
-void Target::PullRecursiveHardDeps() {
-  for (const auto& pair : GetDeps(DEPS_LINKED)) {
-    // Direct hard dependencies.
-    if (hard_dep() || pair.ptr->hard_dep()) {
-      recursive_hard_deps_.insert(pair.ptr);
-      continue;
-    }
-
-    // If |pair.ptr| is binary target and |pair.ptr| has no public header,
-    // |this| target does not need to have |pair.ptr|'s hard_deps as its
-    // hard_deps to start compiles earlier. Unless the target compiles a
-    // Swift module (since they also generate a header that can be used
-    // by the current target).
-    if (pair.ptr->IsBinary() && !pair.ptr->all_headers_public() &&
-        pair.ptr->public_headers().empty() &&
-        !pair.ptr->builds_swift_module()) {
-      continue;
-    }
-
-    // Recursive hard dependencies of all dependencies.
-    recursive_hard_deps_.insert(pair.ptr->recursive_hard_deps().begin(),
-                                pair.ptr->recursive_hard_deps().end());
-  }
-}
-
 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 899e06b..d672985 100644
--- a/src/gn/target.h
+++ b/src/gn/target.h
@@ -332,8 +332,6 @@
     return rust_transitive_inheritable_libs_;
   }
 
-  const TargetSet& recursive_hard_deps() const { return recursive_hard_deps_; }
-
   std::vector<LabelPattern>& friends() { return friends_; }
   const std::vector<LabelPattern>& friends() const { return friends_; }
 
@@ -491,10 +489,6 @@
   // that need to be linked.
   InheritedLibraries inherited_libraries_;
 
-  // All hard deps from this target and all dependencies. Filled in when this
-  // target is marked resolved. This will not include the current target.
-  TargetSet recursive_hard_deps_;
-
   std::vector<LabelPattern> friends_;
   std::vector<LabelPattern> assert_no_deps_;