Add ResolvedTargetData:GetSwiftModuleDependencies()

This moves the SwiftValues::modules_ and SwiftValues::public_modules_
values to the ResolvedTargetData class to compute them on demand,
instead of unconditionally.

Bug: 331
Change-Id: Icc894415cb556c9b750227dd8cf7a493982d77b9
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15328
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/ninja_c_binary_target_writer.cc b/src/gn/ninja_c_binary_target_writer.cc
index 9978b63..da27df6 100644
--- a/src/gn/ninja_c_binary_target_writer.cc
+++ b/src/gn/ninja_c_binary_target_writer.cc
@@ -564,7 +564,8 @@
     swift_order_only_deps.Append(order_only_deps.begin(),
                                  order_only_deps.end());
 
-    for (const Target* swiftmodule : target_->swift_values().modules())
+    for (const Target* swiftmodule :
+         resolved().GetSwiftModuleDependencies(target_))
       swift_order_only_deps.push_back(swiftmodule->dependency_output_file());
 
     WriteCompilerBuildLine(target_->sources(), input_deps,
diff --git a/src/gn/ninja_target_writer.cc b/src/gn/ninja_target_writer.cc
index ea39822..2f7ec38 100644
--- a/src/gn/ninja_target_writer.cc
+++ b/src/gn/ninja_target_writer.cc
@@ -346,7 +346,7 @@
       // Uniquify the list of swiftmodule dirs (in case multiple swiftmodules
       // are generated in the same directory).
       UniqueVector<SourceDir> swiftmodule_dirs;
-      for (const Target* dep : target_->swift_values().modules())
+      for (const Target* dep : resolved().GetSwiftModuleDependencies(target_))
         swiftmodule_dirs.push_back(dep->swift_values().module_output_dir());
 
       if (indent)
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
index b2692e7..7c3e79f 100644
--- a/src/gn/resolved_target_data.cc
+++ b/src/gn/resolved_target_data.cc
@@ -223,3 +223,43 @@
     }
   }
 }
+
+void ResolvedTargetData::ComputeSwiftValues(TargetInfo* info) const {
+  UniqueVector<const Target*> modules;
+  UniqueVector<const Target*> public_modules;
+  const Target* target = info->target;
+
+  for (const Target* dep : info->deps.public_deps()) {
+    if (dep->toolchain() != target->toolchain() &&
+        !dep->toolchain()->propagates_configs()) {
+      continue;
+    }
+
+    const TargetInfo* dep_info = GetTargetSwiftValues(dep);
+    if (dep_info->swift_values.get()) {
+      const auto& public_deps = dep_info->swift_values->public_modules;
+      modules.Append(public_deps);
+      public_modules.Append(public_deps);
+    }
+  }
+
+  for (const Target* dep : info->deps.private_deps()) {
+    if (dep->toolchain() != target->toolchain() &&
+        !dep->toolchain()->propagates_configs()) {
+      continue;
+    }
+    const TargetInfo* dep_info = GetTargetSwiftValues(dep);
+    if (dep_info->swift_values.get()) {
+      modules.Append(dep_info->swift_values->public_modules);
+    }
+  }
+
+  if (target->builds_swift_module())
+    public_modules.push_back(target);
+
+  if (!modules.empty() || !public_modules.empty()) {
+    info->swift_values = std::make_unique<TargetInfo::SwiftValues>(
+        modules.release(), public_modules.release());
+  }
+  info->has_swift_values = true;
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
index f8f6458..61483bf 100644
--- a/src/gn/resolved_target_data.h
+++ b/src/gn/resolved_target_data.h
@@ -117,6 +117,17 @@
     return GetTargetRustLibs(target)->rust_inherited_libs;
   }
 
+  // List of dependent target that generate a .swiftmodule. The current target
+  // is assumed to depend on those modules, and will add them to the module
+  // search path.
+  base::span<const Target*> GetSwiftModuleDependencies(
+      const Target* target) const {
+    const TargetInfo* info = GetTargetSwiftValues(target);
+    if (!info->swift_values.get())
+      return {};
+    return info->swift_values->modules;
+  }
+
  private:
   // The information associated with a given Target pointer.
   struct TargetInfo {
@@ -136,6 +147,7 @@
     bool has_hard_deps = false;
     bool has_inherited_libs = false;
     bool has_rust_libs = false;
+    bool has_swift_values = false;
 
     // Only valid if |has_lib_info| is true.
     std::vector<SourceDir> lib_dirs;
@@ -155,6 +167,21 @@
     // Only valid if |has_rust_libs| is true.
     std::vector<TargetPublicPair> rust_inherited_libs;
     std::vector<TargetPublicPair> rust_inheritable_libs;
+
+    // Only valid if |has_swift_values| is true.
+    // Most targets will not have Swift dependencies, so only
+    // allocate a SwiftValues struct when needed. A null pointer
+    // indicates empty lists.
+    struct SwiftValues {
+      std::vector<const Target*> modules;
+      std::vector<const Target*> public_modules;
+
+      SwiftValues(std::vector<const Target*> modules,
+                  std::vector<const Target*> public_modules)
+          : modules(std::move(modules)),
+            public_modules(std::move(public_modules)) {}
+    };
+    std::unique_ptr<SwiftValues> swift_values;
   };
 
   // Retrieve TargetInfo value associated with |target|. Create
@@ -206,6 +233,15 @@
     return info;
   }
 
+  const TargetInfo* GetTargetSwiftValues(const Target* target) const {
+    TargetInfo* info = GetTargetInfo(target);
+    if (!info->has_swift_values) {
+      ComputeSwiftValues(info);
+      DCHECK(info->has_swift_values);
+    }
+    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.
@@ -214,6 +250,7 @@
   void ComputeHardDeps(TargetInfo* info) const;
   void ComputeInheritedLibs(TargetInfo* info) const;
   void ComputeRustLibs(TargetInfo* info) const;
+  void ComputeSwiftValues(TargetInfo* info) const;
 
   // Helper function used by ComputeInheritedLibs().
   void ComputeInheritedLibsFor(
diff --git a/src/gn/swift_values.cc b/src/gn/swift_values.cc
index 85a49ad..6065478 100644
--- a/src/gn/swift_values.cc
+++ b/src/gn/swift_values.cc
@@ -16,40 +16,7 @@
 
 // static
 bool SwiftValues::OnTargetResolved(Target* target, Err* err) {
-  if (!FillModuleOutputFile(target, err))
-    return false;
-
-  FillModuleDependencies(target);
-  return true;
-}
-
-// static
-void SwiftValues::FillModuleDependencies(Target* target) {
-  for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
-    if (!pair.ptr->has_swift_values())
-      continue;
-
-    if (pair.ptr->toolchain() == target->toolchain() ||
-        pair.ptr->toolchain()->propagates_configs()) {
-      target->swift_values().modules_.Append(
-          pair.ptr->swift_values().public_modules().begin(),
-          pair.ptr->swift_values().public_modules().end());
-    }
-  }
-
-  for (const auto& pair : target->public_deps()) {
-    if (!pair.ptr->has_swift_values())
-      continue;
-
-    if (pair.ptr->toolchain() == target->toolchain() ||
-        pair.ptr->toolchain()->propagates_configs())
-      target->swift_values().public_modules_.Append(
-          pair.ptr->swift_values().public_modules().begin(),
-          pair.ptr->swift_values().public_modules().end());
-  }
-
-  if (target->builds_swift_module())
-    target->swift_values().public_modules_.push_back(target);
+  return FillModuleOutputFile(target, err);
 }
 
 // static
diff --git a/src/gn/swift_values.h b/src/gn/swift_values.h
index 91ec066..198ca85 100644
--- a/src/gn/swift_values.h
+++ b/src/gn/swift_values.h
@@ -43,25 +43,10 @@
   // Computed when the target is resolved.
   const SourceDir& module_output_dir() const { return module_output_dir_; }
 
-  // List of dependent target that generate a .swiftmodule. The current target
-  // is assumed to depend on those modules, and will add them to the module
-  // search path.
-  const UniqueVector<const Target*>& modules() const { return modules_; }
-
-  // List of dependent target that generate a .swiftmodule that are publicly
-  // exported by the current target. This will include the current target if
-  // it generates a .swiftmodule.
-  const UniqueVector<const Target*>& public_modules() const {
-    return public_modules_;
-  }
-
  private:
   // Fill informations about .swiftmodule generated by this target.
   static bool FillModuleOutputFile(Target* target, Err* err);
 
-  // Fill dependencies information on other target generating .swiftmodules.
-  static void FillModuleDependencies(Target* target);
-
   // Name of the optional bridge header used to import Objective-C classes.
   // Filled from the target, may be empty even if the target include .swift
   // source files.
@@ -77,12 +62,6 @@
   // Path of the directory containing the .swiftmodule generated by this
   // target. Will be null if the target does not include .swift sources.
   SourceDir module_output_dir_;
-
-  // For modules() and public_modules() function. Will be filled when the
-  // target is resolved (can be non-empty even if the target does not build
-  // .swift sources due to transitive dependencies).
-  UniqueVector<const Target*> modules_;
-  UniqueVector<const Target*> public_modules_;
 };
 
 #endif  // TOOLS_GN_SWIFT_TARGET_VALUES_H_