[rust-project] Remove the emitting of sysroot crates

Now that rust-analyzer is able to automatically add the sysroot
crates, if a 'sysroot' value is specified in the file, remove
the addition of the sysroot crates, and let rust-analyzer find
the crates from within the sysroot path specified.

This is more maintainable over time (doesn't duplicate the logic
of finding the sysroot crates), and removes the current double-
addition of the sysroot crates which is breaking rust-analyzer's
ability to locate the implementations of items like Deref<>.

Change-Id: I84db1591525e8b7a5c46952a9d076990eb9c3540
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/14800
Reviewed-by: Dan Johnson <computerdruid@google.com>
Reviewed-by: Brett Wilson <brettw@chromium.org>
Commit-Queue: Aaron Wood <aaronwood@google.com>
diff --git a/src/gn/rust_project_writer.cc b/src/gn/rust_project_writer.cc
index 0eb2a53..8bcd495 100644
--- a/src/gn/rust_project_writer.cc
+++ b/src/gn/rust_project_writer.cc
@@ -29,7 +29,7 @@
 // Current structure of rust-project.json output file
 //
 // {
-//    "sysroot": "path/to/rust/sysroot",  // if there is only one sysroot found
+//    "sysroot": "path/to/rust/sysroot",
 //    "crates": [
 //        {
 //            "deps": [
@@ -45,7 +45,7 @@
 //                ],
 //                "exclude_dirs": []
 //            },
-//            "edition": "2018", // edition of crate
+//            "edition": "2021", // edition of crate
 //            "cfg": [
 //              "unix", // "atomic" value config options
 //              "rust_panic=\"abort\""", // key="value" config options
@@ -162,99 +162,9 @@
   return values;
 }
 
-// TODO(bwb) Parse sysroot structure from toml files. This is fragile and
-// might break if upstream changes the dependency structure.
-const std::string_view sysroot_crates[] = {"std",
-                                           "core",
-                                           "alloc",
-                                           "panic_unwind",
-                                           "proc_macro",
-                                           "test",
-                                           "panic_abort",
-                                           "unwind"};
-
-// Multiple sysroot crates have dependenices on each other.  This provides a
-// mechanism for specifying that in an extendible manner.
-const std::unordered_map<std::string_view, std::vector<std::string_view>>
-    sysroot_deps_map = {{"alloc", {"core"}},
-                        {"std", {"alloc", "core", "panic_abort", "unwind"}}};
-
-// Add each of the crates a sysroot has, including their dependencies.
-void AddSysrootCrate(const BuildSettings* build_settings,
-                     std::string_view crate,
-                     std::string_view current_sysroot,
-                     SysrootCrateIndexMap& sysroot_crate_lookup,
-                     CrateList& crate_list) {
-  if (sysroot_crate_lookup.find(crate) != sysroot_crate_lookup.end()) {
-    // If this sysroot crate is already in the lookup, we don't add it again.
-    return;
-  }
-
-  // Add any crates that this sysroot crate depends on.
-  auto deps_lookup = sysroot_deps_map.find(crate);
-  if (deps_lookup != sysroot_deps_map.end()) {
-    auto deps = (*deps_lookup).second;
-    for (auto dep : deps) {
-      AddSysrootCrate(build_settings, dep, current_sysroot,
-                      sysroot_crate_lookup, crate_list);
-    }
-  }
-
-  size_t crate_index = crate_list.size();
-  sysroot_crate_lookup.insert(std::make_pair(crate, crate_index));
-
-  base::FilePath rebased_out_dir =
-      build_settings->GetFullPath(build_settings->build_dir());
-  auto crate_path =
-      FilePathToUTF8(rebased_out_dir) + std::string(current_sysroot) +
-      "/lib/rustlib/src/rust/library/" + std::string(crate) + "/src/lib.rs";
-
-  Crate sysroot_crate = Crate(SourceFile(crate_path), std::nullopt, crate_index,
-                              std::string(crate), "2018");
-
-  sysroot_crate.AddConfigItem("debug_assertions");
-
-  if (deps_lookup != sysroot_deps_map.end()) {
-    auto deps = (*deps_lookup).second;
-    for (auto dep : deps) {
-      auto idx = sysroot_crate_lookup[dep];
-      sysroot_crate.AddDependency(idx, std::string(dep));
-    }
-  }
-
-  crate_list.push_back(sysroot_crate);
-}
-
-// Add the given sysroot to the project, if it hasn't already been added.
-void AddSysroot(const BuildSettings* build_settings,
-                std::string_view sysroot,
-                SysrootIndexMap& sysroot_lookup,
-                CrateList& crate_list) {
-  // If this sysroot is already in the lookup, we don't add it again.
-  if (sysroot_lookup.find(sysroot) != sysroot_lookup.end()) {
-    return;
-  }
-
-  // Otherwise, add all of its crates
-  for (auto crate : sysroot_crates) {
-    AddSysrootCrate(build_settings, crate, sysroot, sysroot_lookup[sysroot],
-                    crate_list);
-  }
-}
-
-void AddSysrootDependencyToCrate(Crate* crate,
-                                 const SysrootCrateIndexMap& sysroot,
-                                 std::string_view crate_name) {
-  if (const auto crate_idx = sysroot.find(crate_name);
-      crate_idx != sysroot.end()) {
-    crate->AddDependency(crate_idx->second, std::string(crate_name));
-  }
-}
-
 void AddTarget(const BuildSettings* build_settings,
                const Target* target,
                TargetIndexMap& lookup,
-               SysrootIndexMap& sysroot_lookup,
                CrateList& crate_list) {
   if (lookup.find(target) != lookup.end()) {
     // If target is already in the lookup, we don't add it again.
@@ -263,21 +173,11 @@
 
   auto compiler_args = ExtractCompilerArgs(target);
   auto compiler_target = FindArgValue("--target", compiler_args);
-
-  // Check what sysroot this target needs.  Add it to the crate list if it
-  // hasn't already been added.
-  auto rust_tool =
-      target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
-  auto current_sysroot = rust_tool->GetSysroot();
-  if (current_sysroot != "" && sysroot_lookup.count(current_sysroot) == 0) {
-    AddSysroot(build_settings, current_sysroot, sysroot_lookup, crate_list);
-  }
-
   auto crate_deps = GetRustDeps(target);
 
   // Add all dependencies of this crate, before this crate.
   for (const auto& dep : crate_deps) {
-    AddTarget(build_settings, dep, lookup, sysroot_lookup, crate_list);
+    AddTarget(build_settings, dep, lookup, crate_list);
   }
 
   // The index of a crate is its position (0-based) in the list of crates.
@@ -314,21 +214,9 @@
     crate.AddConfigItem(cfg);
   }
 
-  // Add the sysroot dependencies, if there is one.
-  if (current_sysroot != "") {
-    const auto& sysroot = sysroot_lookup[current_sysroot];
-    AddSysrootDependencyToCrate(&crate, sysroot, "core");
-    AddSysrootDependencyToCrate(&crate, sysroot, "alloc");
-    AddSysrootDependencyToCrate(&crate, sysroot, "std");
-
-    // Proc macros have the proc_macro crate as a direct dependency
-    if (std::string_view(rust_tool->name()) ==
-        std::string_view(RustTool::kRsToolMacro)) {
-      AddSysrootDependencyToCrate(&crate, sysroot, "proc_macro");
-    }
-  }
-
   // If it's a proc macro, record its output location so IDEs can invoke it.
+  auto rust_tool =
+      target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
   if (std::string_view(rust_tool->name()) ==
       std::string_view(RustTool::kRsToolMacro)) {
     auto outputs = target->computed_outputs();
@@ -359,19 +247,18 @@
 
 void WriteCrates(const BuildSettings* build_settings,
                  CrateList& crate_list,
-                 SysrootIndexMap& sysroots,
+                 std::optional<std::string>& sysroot,
                  std::ostream& rust_project) {
   rust_project << "{" NEWLINE;
 
-  // If there is one, and only one, sysroot found, then that can be used to tell
-  // rust-analyzer where to find the sysroot (and associated tools like the
+  // If a sysroot was found, then that can be used to tell rust-analyzer where
+  // to find the sysroot (and associated tools like the
   // 'rust-analyzer-proc-macro-srv` proc-macro server that matches the abi used
   // by 'rustc'
-  if (sysroots.size() == 1) {
-    auto sysroot = sysroots.begin()->first;
+  if (sysroot.has_value()) {
     base::FilePath rebased_out_dir =
         build_settings->GetFullPath(build_settings->build_dir());
-    auto sysroot_path = FilePathToUTF8(rebased_out_dir) + std::string(sysroot);
+    auto sysroot_path = FilePathToUTF8(rebased_out_dir) + sysroot.value();
     rust_project << "  \"sysroot\": \"" << sysroot_path << "\"," NEWLINE;
   }
 
@@ -503,16 +390,25 @@
                                    std::vector<const Target*>& all_targets,
                                    std::ostream& rust_project) {
   TargetIndexMap lookup;
-  SysrootIndexMap sysroot_lookup;
   CrateList crate_list;
+  std::optional<std::string> rust_sysroot;
 
   // All the crates defined in the project.
   for (const auto* target : all_targets) {
     if (!target->IsBinary() || !target->source_types_used().RustSourceUsed())
       continue;
 
-    AddTarget(build_settings, target, lookup, sysroot_lookup, crate_list);
+    AddTarget(build_settings, target, lookup, crate_list);
+
+    // If a sysroot hasn't been found, see if we can find one using this target.
+    if (!rust_sysroot.has_value()) {
+      auto rust_tool =
+          target->toolchain()->GetToolForTargetFinalOutputAsRust(target);
+      auto sysroot = rust_tool->GetSysroot();
+      if (sysroot != "")
+        rust_sysroot = sysroot;
+    }
   }
 
-  WriteCrates(build_settings, crate_list, sysroot_lookup, rust_project);
+  WriteCrates(build_settings, crate_list, rust_sysroot, rust_project);
 }
diff --git a/src/gn/rust_project_writer_helpers.h b/src/gn/rust_project_writer_helpers.h
index aba1388..31efd40 100644
--- a/src/gn/rust_project_writer_helpers.h
+++ b/src/gn/rust_project_writer_helpers.h
@@ -125,26 +125,11 @@
 
 using CrateList = std::vector<Crate>;
 
-// Mapping of a sysroot crate (path) to it's index in the crates list.
-using SysrootCrateIndexMap = std::unordered_map<std::string_view, CrateIndex>;
-
-// Mapping of a sysroot (path) to the mapping of each of the sysroot crates to
-// their index in the crates list.
-using SysrootIndexMap =
-    std::unordered_map<std::string_view, SysrootCrateIndexMap>;
-
-// Add all of the crates for a sysroot (path) to the rust_project ostream.
-// Add the given sysroot to the project, if it hasn't already been added.
-void AddSysroot(const BuildSettings* build_settings,
-                std::string_view sysroot,
-                SysrootIndexMap& sysroot_lookup,
-                CrateList& crate_list);
-
 // Write the entire rust-project.json file contents into the given stream, based
 // on the the given crates list.
 void WriteCrates(const BuildSettings* build_settings,
                  CrateList& crate_list,
-                 SysrootIndexMap& sysroot_lookup,
+                 std::optional<std::string>& sysroot,
                  std::ostream& rust_project);
 
 // Assemble the compiler arguments for the given GN Target.
diff --git a/src/gn/rust_project_writer_helpers_unittest.cc b/src/gn/rust_project_writer_helpers_unittest.cc
index df07c77..14d5c35 100644
--- a/src/gn/rust_project_writer_helpers_unittest.cc
+++ b/src/gn/rust_project_writer_helpers_unittest.cc
@@ -26,7 +26,7 @@
 TEST_F(RustProjectWriterHelper, WriteCrates) {
   TestWithScope setup;
 
-  SysrootIndexMap sysroot_lookup;
+  std::optional<std::string> sysroot;
 
   CrateList crates;
   Crate dep = Crate(SourceFile("/root/tortoise/lib.rs"), std::nullopt, 0,
@@ -41,7 +41,7 @@
   crates.push_back(target);
 
   std::ostringstream stream;
-  WriteCrates(setup.build_settings(), crates, sysroot_lookup, stream);
+  WriteCrates(setup.build_settings(), crates, sysroot, stream);
   std::string out = stream.str();
 #if defined(OS_WIN)
   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
@@ -98,13 +98,11 @@
   TestWithScope setup;
   setup.build_settings()->SetRootPath(UTF8ToFilePath("/root"));
 
-  SysrootIndexMap sysroot_lookup;
+  std::optional<std::string> sysroot = "sysroot";
   CrateList crates;
 
-  AddSysroot(setup.build_settings(), "sysroot", sysroot_lookup, crates);
-
   std::ostringstream stream;
-  WriteCrates(setup.build_settings(), crates, sysroot_lookup, stream);
+  WriteCrates(setup.build_settings(), crates, sysroot, stream);
   std::string out = stream.str();
 #if defined(OS_WIN)
   base::ReplaceSubstringsAfterOffset(&out, 0, "\r\n", "\n");
@@ -114,189 +112,6 @@
       "{\n"
       "  \"sysroot\": \"/root/out/Debug/sysroot\",\n"
       "  \"crates\": [\n"
-      "    {\n"
-      "      \"crate_id\": 0,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/core/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"core\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/core/src/\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 1,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/alloc/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"alloc\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/alloc/src/\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "        {\n"
-      "          \"crate\": 0,\n"
-      "          \"name\": \"core\"\n"
-      "        }\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 2,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_abort/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"panic_abort\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_abort/src/"
-      "\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 3,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/unwind/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"unwind\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/unwind/src/\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 4,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/std/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"std\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/std/src/\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "        {\n"
-      "          \"crate\": 1,\n"
-      "          \"name\": \"alloc\"\n"
-      "        },\n"
-      "        {\n"
-      "          \"crate\": 0,\n"
-      "          \"name\": \"core\"\n"
-      "        },\n"
-      "        {\n"
-      "          \"crate\": 2,\n"
-      "          \"name\": \"panic_abort\"\n"
-      "        },\n"
-      "        {\n"
-      "          \"crate\": 3,\n"
-      "          \"name\": \"unwind\"\n"
-      "        }\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 5,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_unwind/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"panic_unwind\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/panic_unwind/src/"
-      "\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 6,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/proc_macro/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"proc_macro\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/proc_macro/src/"
-      "\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    },\n"
-      "    {\n"
-      "      \"crate_id\": 7,\n"
-      "      \"root_module\": "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/test/src/"
-      "lib.rs\",\n"
-      "      \"label\": \"test\",\n"
-      "      \"source\": {\n"
-      "          \"include_dirs\": [\n"
-      "               "
-      "\"/root/out/Debug/sysroot/lib/rustlib/src/rust/library/test/src/\"\n"
-      "          ],\n"
-      "          \"exclude_dirs\": []\n"
-      "      },\n"
-      "      \"deps\": [\n"
-      "      ],\n"
-      "      \"edition\": \"2018\",\n"
-      "      \"cfg\": [\n"
-      "        \"debug_assertions\"\n"
-      "      ]\n"
-      "    }\n"
       "  ]\n"
       "}\n";