Add --file_relation to gn refs command

Allows users to filter targets by how they relate
to the input file.

Bug: 458444125
Change-Id: Icdedf5126b86558794370c5869070a54fa48e3a2
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/20180
Commit-Queue: Dan Harrington <harringtond@google.com>
Reviewed-by: Andrew Grieve <agrieve@google.com>
diff --git a/docs/reference.md b/docs/reference.md
index 81be9b3..489dfbb 100644
--- a/docs/reference.md
+++ b/docs/reference.md
@@ -1322,6 +1322,11 @@
           source_set|static_library)
       Restrict outputs to targets matching the given type. If
       unspecified, no filtering will be performed.
+
+  --relation=(source|public|input|data|script|output)
+      Restricts output to targets which refer to input files by a specific
+      relation. Defaults to any relation. Can be provided multiple times to
+      include multiple relations.
 ```
 
 #### **Examples (target input)**
diff --git a/src/gn/command_refs.cc b/src/gn/command_refs.cc
index b751035..e2bcdb5 100644
--- a/src/gn/command_refs.cc
+++ b/src/gn/command_refs.cc
@@ -21,6 +21,7 @@
 #include "gn/standard_out.h"
 #include "gn/switches.h"
 #include "gn/target.h"
+#include "gn/unique_vector.h"
 
 namespace commands {
 
@@ -296,6 +297,13 @@
     TARGET_TYPE_FILTER_COMMAND_LINE_HELP
 
     R"(
+  --relation=(source|public|input|data|script|output)
+      Restricts output to targets which refer to input files by a specific
+      relation. Defaults to any relation. Can be provided multiple times to
+      include multiple relations.
+    )"
+
+    R"(
 
 Examples (target input)
 
@@ -349,6 +357,25 @@
   const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
   bool tree = cmdline->HasSwitch("tree");
   bool all = cmdline->HasSwitch("all");
+  UniqueVector<HowTargetContainsFile> include_relations;
+  for (const std::string& relation : cmdline->GetSwitchValueStrings("relation")){
+    if (relation == "source"){
+      include_relations.push_back(HowTargetContainsFile::kSources);
+    } else if (relation == "public"){
+      include_relations.push_back(HowTargetContainsFile::kPublic);
+    } else if (relation == "input"){
+      include_relations.push_back(HowTargetContainsFile::kInputs);
+    } else if (relation == "data"){
+      include_relations.push_back(HowTargetContainsFile::kData);
+    } else if (relation == "script"){
+      include_relations.push_back(HowTargetContainsFile::kScript);
+    } else if (relation == "output"){
+      include_relations.push_back(HowTargetContainsFile::kOutput);
+    } else {
+      Err(Location(), "Unknown relation: " + relation).PrintToStdout();
+      return 1;
+    }
+  }
   bool default_toolchain_only = cmdline->HasSwitch(switches::kDefaultToolchain);
 
   // Deliberately leaked to avoid expensive process teardown.
@@ -404,8 +431,13 @@
                              &target_containing);
 
     // Extract just the Target*.
-    for (const TargetContainingFile& pair : target_containing)
+    for (const TargetContainingFile& pair : target_containing) {
+      if (!include_relations.empty() &&
+          !include_relations.Contains(pair.second)) {
+        continue;
+      }
       explicit_target_matches.push_back(pair.first);
+    }
   }
   for (auto* config : config_matches) {
     GetTargetsReferencingConfig(setup, all_targets, config,