Add ResolvedTargetData class.

This class will be used to compute and cache values over
the transitive dependency tree of resolved targets. This
CL is minimal and only implements the conversion of dependencies
into a ResolvedTargetDeps instance.

Future CLs will use this in Ninja target writers calls, then
will gradually move computations performed in Target::OnResolved()
to this class to speed up computations.

Bug: 331
Change-Id: I3af49cce4252dc44733c0d47afb263023c7b50db
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/15320
Commit-Queue: David Turner <digit@google.com>
Reviewed-by: Takuto Ikuta <tikuta@google.com>
diff --git a/build/gen.py b/build/gen.py
index 2d109ed..76fddfb 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -688,6 +688,7 @@
         'src/gn/pattern.cc',
         'src/gn/pool.cc',
         'src/gn/qt_creator_writer.cc',
+        'src/gn/resolved_target_data.cc',
         'src/gn/runtime_deps.cc',
         'src/gn/rust_substitution_type.cc',
         'src/gn/rust_tool.cc',
@@ -807,6 +808,7 @@
         'src/gn/path_output_unittest.cc',
         'src/gn/pattern_unittest.cc',
         'src/gn/pointer_set_unittest.cc',
+        'src/gn/resolved_target_data_unittest.cc',
         'src/gn/resolved_target_deps_unittest.cc',
         'src/gn/runtime_deps_unittest.cc',
         'src/gn/scope_per_file_provider_unittest.cc',
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc
new file mode 100644
index 0000000..742a4cc
--- /dev/null
+++ b/src/gn/resolved_target_data.cc
@@ -0,0 +1,14 @@
+// Copyright 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/resolved_target_data.h"
+
+ResolvedTargetData::TargetInfo* ResolvedTargetData::GetTargetInfo(
+    const Target* target) const {
+  auto ret = targets_.PushBackWithIndex(target);
+  if (ret.first) {
+    infos_.push_back(std::make_unique<TargetInfo>(target));
+  }
+  return infos_[ret.second].get();
+}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h
new file mode 100644
index 0000000..510d6f6
--- /dev/null
+++ b/src/gn/resolved_target_data.h
@@ -0,0 +1,90 @@
+// Copyright 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TOOLS_GN_RESOLVED_TARGET_DATA_H_
+#define TOOLS_GN_RESOLVED_TARGET_DATA_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/containers/span.h"
+#include "gn/lib_file.h"
+#include "gn/resolved_target_deps.h"
+#include "gn/source_dir.h"
+#include "gn/target.h"
+#include "gn/target_public_pair.h"
+#include "gn/unique_vector.h"
+
+// A class used to compute target-specific data by collecting information
+// from its tree of dependencies.
+//
+// For example, linkable targets can call GetLinkedLibraries() and
+// GetLinkedLibraryDirs() to find the library files and library search
+// paths to add to their final linker command string, based on the
+// definitions of the `libs` and `lib_dirs` config values of their
+// transitive dependencies.
+//
+// Values are computed on demand, but memorized by the class instance in order
+// to speed up multiple queries for targets that share dependencies.
+//
+// Usage is:
+//
+//  1) Create instance.
+//
+//  2) Call any of the methods to retrieve the value of the corresponding
+//     data. For all methods, the input Target instance passed as argument
+//     must have been fully resolved (meaning that Target::OnResolved()
+//     must have been called and completed). Input target pointers are
+//     const and thus are never modified. This allows using multiple
+//     ResolvedTargetData instances from the same input graph in multiple
+//     threads safely.
+//
+class ResolvedTargetData {
+ public:
+  // Return the public/private/data/dependencies of a given target
+  // as a ResolvedTargetDeps instance.
+  const ResolvedTargetDeps& GetTargetDeps(const Target* target) const {
+    return GetTargetInfo(target)->deps;
+  }
+
+  // Return the data dependencies of a given target.
+  // Convenience shortcut for GetTargetDeps(target).data_deps().
+  base::span<const Target*> GetDataDeps(const Target* target) const {
+    return GetTargetDeps(target).data_deps();
+  }
+
+  // Return the public and private dependencies of a given target.
+  // Convenience shortcut for GetTargetDeps(target).linked_deps().
+  base::span<const Target*> GetLinkedDeps(const Target* target) const {
+    return GetTargetDeps(target).linked_deps();
+  }
+
+ private:
+  // The information associated with a given Target pointer.
+  struct TargetInfo {
+    TargetInfo() = default;
+
+    TargetInfo(const Target* target)
+        : target(target),
+          deps(target->public_deps(),
+               target->private_deps(),
+               target->data_deps()) {}
+
+    const Target* target = nullptr;
+    ResolvedTargetDeps deps;
+  };
+
+  // Retrieve TargetInfo value associated with |target|. Create
+  // a new empty instance on demand if none is already available.
+  TargetInfo* GetTargetInfo(const Target* target) 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
+  // instances for best performance.
+  mutable UniqueVector<const Target*> targets_;
+  mutable std::vector<std::unique_ptr<TargetInfo>> infos_;
+};
+
+#endif  // TOOLS_GN_RESOLVED_TARGET_DATA_H_
diff --git a/src/gn/resolved_target_data_unittest.cc b/src/gn/resolved_target_data_unittest.cc
new file mode 100644
index 0000000..03cd28b
--- /dev/null
+++ b/src/gn/resolved_target_data_unittest.cc
@@ -0,0 +1,53 @@
+// Copyright 2023 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gn/resolved_target_data.h"
+
+#include "gn/test_with_scope.h"
+#include "util/test/test.h"
+
+// Tests that lib[_dir]s are inherited across deps boundaries for static
+// libraries but not executables.
+TEST(ResolvedTargetDataTest, GetTargetDeps) {
+  TestWithScope setup;
+  Err err;
+
+  TestTarget a(setup, "//foo:a", Target::GROUP);
+  TestTarget b(setup, "//foo:b", Target::GROUP);
+  TestTarget c(setup, "//foo:c", Target::GROUP);
+  TestTarget d(setup, "//foo:d", Target::GROUP);
+  TestTarget e(setup, "//foo:e", Target::GROUP);
+
+  a.private_deps().push_back(LabelTargetPair(&b));
+  a.private_deps().push_back(LabelTargetPair(&c));
+  a.public_deps().push_back(LabelTargetPair(&d));
+  a.data_deps().push_back(LabelTargetPair(&e));
+
+  b.private_deps().push_back(LabelTargetPair(&e));
+
+  ASSERT_TRUE(e.OnResolved(&err));
+  ASSERT_TRUE(d.OnResolved(&err));
+  ASSERT_TRUE(c.OnResolved(&err));
+  ASSERT_TRUE(b.OnResolved(&err));
+  ASSERT_TRUE(a.OnResolved(&err));
+
+  ResolvedTargetData resolved;
+
+  const auto& a_deps = resolved.GetTargetDeps(&a);
+  EXPECT_EQ(a_deps.size(), 4u);
+  EXPECT_EQ(a_deps.private_deps().size(), 2u);
+  EXPECT_EQ(a_deps.private_deps()[0], &b);
+  EXPECT_EQ(a_deps.private_deps()[1], &c);
+  EXPECT_EQ(a_deps.public_deps().size(), 1u);
+  EXPECT_EQ(a_deps.public_deps()[0], &d);
+  EXPECT_EQ(a_deps.data_deps().size(), 1u);
+  EXPECT_EQ(a_deps.data_deps()[0], &e);
+
+  const auto& b_deps = resolved.GetTargetDeps(&b);
+  EXPECT_EQ(b_deps.size(), 1u);
+  EXPECT_EQ(b_deps.private_deps().size(), 1u);
+  EXPECT_EQ(b_deps.private_deps()[0], &e);
+  EXPECT_EQ(b_deps.public_deps().size(), 0u);
+  EXPECT_EQ(b_deps.data_deps().size(), 0u);
+}