Make sure abs-path gn labels have separate target_gen_dirs

Use gen/ABS_PATH/... for target_gen_dir of build files outside of the
source tree, to mimic obj/ABS_PATH that's used for object directories
for such build files.

Previously, all build files outside of the source tree would use
root_gen_dir (e.g. out/Default/gen) as target_gen_dir. This broke the
"target_gen_dir is unique between different BUILD.gn files" assumption,
causing strange behavior and "ninja: multiple targets generate ..."
warnings for users of absolute path BUILD.gn files outside of //.

BUG=445454
R=brettw@chromium.org

Review URL: https://codereview.chromium.org/1420973003

Cr-Original-Commit-Position: refs/heads/master@{#356011}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 5b6813c06deae18ca309fba9913ee18e28150122
diff --git a/tools/gn/filesystem_utils.cc b/tools/gn/filesystem_utils.cc
index 44de5ad..a3455fd 100644
--- a/tools/gn/filesystem_utils.cc
+++ b/tools/gn/filesystem_utils.cc
@@ -686,6 +686,32 @@
       settings->toolchain_label(), settings->is_default());
 }
 
+void AppendFixedAbsolutePathSuffix(const BuildSettings* build_settings,
+                                   const SourceDir& source_dir,
+                                   OutputFile* result) {
+  const std::string& build_dir = build_settings->build_dir().value();
+
+  if (base::StartsWith(source_dir.value(), build_dir,
+                       base::CompareCase::SENSITIVE)) {
+    size_t build_dir_size = build_dir.size();
+    result->value().append(&source_dir.value()[build_dir_size],
+                           source_dir.value().size() - build_dir_size);
+  } else {
+    result->value().append("ABS_PATH");
+#if defined(OS_WIN)
+    // Windows absolute path contains ':' after drive letter. Remove it to
+    // avoid inserting ':' in the middle of path (eg. "ABS_PATH/C:/").
+    std::string src_dir_value = source_dir.value();
+    const auto colon_pos = src_dir_value.find(':');
+    if (colon_pos != std::string::npos)
+      src_dir_value.erase(src_dir_value.begin() + colon_pos);
+#else
+    const std::string& src_dir_value = source_dir.value();
+#endif
+    result->value().append(src_dir_value);
+  }
+}
+
 SourceDir GetOutputDirForSourceDir(
     const BuildSettings* build_settings,
     const SourceDir& source_dir,
@@ -711,27 +737,7 @@
                           source_dir.value().size() - 2);
   } else {
     // System-absolute.
-    const std::string& build_dir = build_settings->build_dir().value();
-
-    if (base::StartsWith(source_dir.value(), build_dir,
-                         base::CompareCase::SENSITIVE)) {
-      size_t build_dir_size = build_dir.size();
-      result.value().append(&source_dir.value()[build_dir_size],
-                            source_dir.value().size() - build_dir_size);
-    } else {
-      result.value().append("ABS_PATH");
-#if defined(OS_WIN)
-      // Windows absolute path contains ':' after drive letter. Remove it to
-      // avoid inserting ':' in the middle of path (eg. "ABS_PATH/C:/").
-      std::string src_dir_value = source_dir.value();
-      const auto colon_pos = src_dir_value.find(':');
-      if (colon_pos != std::string::npos)
-        src_dir_value.erase(src_dir_value.begin() + colon_pos);
-#else
-      const std::string& src_dir_value = source_dir.value();
-#endif
-      result.value().append(src_dir_value);
-    }
+    AppendFixedAbsolutePathSuffix(build_settings, source_dir, &result);
   }
   return result;
 }
@@ -759,6 +765,10 @@
     DCHECK(source_dir.is_source_absolute());
     result.value().append(&source_dir.value()[2],
                           source_dir.value().size() - 2);
+  } else {
+    // System-absolute.
+    AppendFixedAbsolutePathSuffix(settings->build_settings(), source_dir,
+                                  &result);
   }
   return result;
 }
diff --git a/tools/gn/function_get_path_info_unittest.cc b/tools/gn/function_get_path_info_unittest.cc
index 306c57e..5a8c455 100644
--- a/tools/gn/function_get_path_info_unittest.cc
+++ b/tools/gn/function_get_path_info_unittest.cc
@@ -110,6 +110,10 @@
   EXPECT_EQ("//out/Debug/gen/src/foo", Call(".", "gen_dir"));
   EXPECT_EQ("//out/Debug/gen/src/foo", Call("bar", "gen_dir"));
   EXPECT_EQ("//out/Debug/gen/foo", Call("//foo/bar.txt", "gen_dir"));
-  // System paths go into the root obj directory.
-  EXPECT_EQ("//out/Debug/gen", Call("/foo/bar.txt", "gen_dir"));
+  // System paths go into the ABS_PATH gen directory
+  EXPECT_EQ("//out/Debug/gen/ABS_PATH/foo", Call("/foo/bar.txt", "gen_dir"));
+#if defined(OS_WIN)
+  EXPECT_EQ("//out/Debug/gen/ABS_PATH/C/foo",
+            Call("/C:/foo/bar.txt", "out_dir"));
+#endif
 }
diff --git a/tools/gn/substitution_writer_unittest.cc b/tools/gn/substitution_writer_unittest.cc
index f5dcb78..6ae28ec 100644
--- a/tools/gn/substitution_writer_unittest.cc
+++ b/tools/gn/substitution_writer_unittest.cc
@@ -160,10 +160,13 @@
   // Operations on an absolute path.
   EXPECT_EQ("/baz.txt", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE));
   EXPECT_EQ("/.", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_DIR));
-  EXPECT_EQ("gen", GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
+  EXPECT_EQ("gen/ABS_PATH",
+            GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
   EXPECT_EQ("obj/ABS_PATH",
             GetRelSubst("/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
 #if defined(OS_WIN)
+  EXPECT_EQ("gen/ABS_PATH/C",
+            GetRelSubst("/C:/baz.txt", SUBSTITUTION_SOURCE_GEN_DIR));
   EXPECT_EQ("obj/ABS_PATH/C",
             GetRelSubst("/C:/baz.txt", SUBSTITUTION_SOURCE_OUT_DIR));
 #endif