Avoid clashes of include_dir in rust-project.json.
In the event of a BUILD.gn file containing multiple crates:
```
# path/to/BUILD.gn
rust_library("foo") {
sources = [..., "//gen/path/to/foo/foo.rs"]
}
rust_library("bar") {
sources = [..., "//gen/path/to/bar/bar.rs"]
}
```
It would previously generate a rust-project.json containing an include
dir of `gen/path/to`. This means that rust-analyzer thought that foo
contains bar.rs and vice versa.
Now we generate the include_dir of `gen/path/to/foo` instead.
Change-Id: Iac4f87c42aa09339ebe01425fed6ed5b39c22747
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/19801
Reviewed-by: Takuto Ikuta <tikuta@google.com>
Commit-Queue: Takuto Ikuta <tikuta@google.com>
diff --git a/src/gn/rust_project_writer.cc b/src/gn/rust_project_writer.cc
index 6c9aef8..c5b4590 100644
--- a/src/gn/rust_project_writer.cc
+++ b/src/gn/rust_project_writer.cc
@@ -4,10 +4,10 @@
#include "gn/rust_project_writer.h"
-#include <fstream>
+#include <algorithm>
#include <optional>
-#include <sstream>
-#include <tuple>
+#include <ranges>
+#include <vector>
#include "base/json/string_escape.h"
#include "base/strings/string_split.h"
@@ -195,9 +195,33 @@
edition = FindArgValue("--edition", compiler_args);
}
- auto gen_dir = GetBuildDirForTargetAsOutputFile(target, BuildDirType::GEN);
+ auto source_root = build_settings->root_path();
+ // Generated sources also need to be added to include dirs. However, we can't
+ // naively add the top-level build dir for this target as an include dir.
+ // It's possible to define multiple crates in the same buildfile, and the
+ // default build dir corresponds to the buildfile's containing directory.
+ // Hence they would incorrectly share the same include dir, despite being
+ // separate crates.
+ // Unfortunately this doesn't help if the buildfile author places unrelated
+ // generated sources for multiple crates in the same directory, but that's
+ // impossible to solve anyway.
+ auto gen_dir = GetBuildDirForTargetAsSourceDir(target, BuildDirType::GEN)
+ .Resolve(source_root);
+ std::vector<SourceDir> include_dirs;
+ for (const SourceFile& source : target->sources()) {
+ if (gen_dir.IsParent(source.Resolve(source_root))) {
+ include_dirs.push_back(source.GetDir());
+ }
+ }
+ // Remove duplicates. We could use a set-like structure, but chances are
+ // there's very few elements.
+ std::ranges::sort(include_dirs, [](const auto& lhs, const auto& rhs) {
+ return lhs.value() < rhs.value();
+ });
+ include_dirs.erase(std::ranges::unique(include_dirs).begin(),
+ include_dirs.end());
- Crate crate = Crate(crate_root, gen_dir, crate_id, crate_label,
+ Crate crate = Crate(crate_root, include_dirs, crate_id, crate_label,
edition.value_or("2015"));
crate.SetCompilerArgs(compiler_args);
@@ -284,16 +308,12 @@
<< FilePathToUTF8(
build_settings->GetFullPath(crate.root().GetDir()))
<< "\"";
- auto gen_dir = crate.gen_dir();
- if (gen_dir.has_value()) {
- auto gen_dir_path = FilePathToUTF8(
- build_settings->GetFullPath(gen_dir->AsSourceDir(build_settings)));
- rust_project << "," NEWLINE << " \"" << gen_dir_path
- << "\"" NEWLINE;
- } else {
- rust_project << NEWLINE;
+
+ for (const auto& include_dir : crate.extra_include_dirs()) {
+ auto path = FilePathToUTF8(build_settings->GetFullPath(include_dir));
+ rust_project << "," << NEWLINE << " \"" << path << "\"";
}
- rust_project << " ]," NEWLINE
+ rust_project << NEWLINE " ]," NEWLINE
<< " \"exclude_dirs\": []" NEWLINE
<< " }," NEWLINE;
diff --git a/src/gn/rust_project_writer_helpers.h b/src/gn/rust_project_writer_helpers.h
index 3073fd5..4feff94 100644
--- a/src/gn/rust_project_writer_helpers.h
+++ b/src/gn/rust_project_writer_helpers.h
@@ -5,13 +5,9 @@
#ifndef TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
#define TOOLS_GN_RUST_PROJECT_WRITER_HELPERS_H_
-#include <fstream>
#include <optional>
-#include <sstream>
#include <string>
-#include <string_view>
-#include <tuple>
-#include <unordered_map>
+#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
@@ -35,12 +31,12 @@
class Crate {
public:
Crate(SourceFile root,
- std::optional<OutputFile> gen_dir,
+ std::vector<SourceDir> extra_include_dirs,
CrateIndex index,
std::string label,
std::string edition)
: root_(root),
- gen_dir_(gen_dir),
+ extra_include_dirs_(std::move(extra_include_dirs)),
index_(index),
label_(label),
edition_(edition) {}
@@ -74,8 +70,8 @@
// Returns the root file for the crate.
SourceFile& root() { return root_; }
- // Returns the root file for the crate.
- std::optional<OutputFile>& gen_dir() { return gen_dir_; }
+ // Extra include dirs in addition to the directory containing the crate root.
+ std::vector<SourceDir>& extra_include_dirs() { return extra_include_dirs_; }
// Returns the crate index.
CrateIndex index() { return index_; }
@@ -111,7 +107,7 @@
private:
SourceFile root_;
- std::optional<OutputFile> gen_dir_;
+ std::vector<SourceDir> extra_include_dirs_;
CrateIndex index_;
std::string label_;
std::string edition_;
diff --git a/src/gn/rust_project_writer_helpers_unittest.cc b/src/gn/rust_project_writer_helpers_unittest.cc
index 87ccd83..c37f215 100644
--- a/src/gn/rust_project_writer_helpers_unittest.cc
+++ b/src/gn/rust_project_writer_helpers_unittest.cc
@@ -29,10 +29,11 @@
std::optional<std::string> sysroot;
CrateList crates;
- Crate dep = Crate(SourceFile("/root/tortoise/lib.rs"), std::nullopt, 0,
+ Crate dep = Crate(SourceFile("/root/tortoise/lib.rs"), {}, 0,
"//tortoise:bar", "2015");
- Crate target = Crate(SourceFile("/root/hare/lib.rs"),
- OutputFile("gendir/hare/"), 1, "//hare:bar", "2015");
+ Crate target =
+ Crate(SourceFile("/root/hare/lib.rs"),
+ {SourceDir("//out/Debug/gendir/hare")}, 1, "//hare:bar", "2015");
target.AddDependency(0, "tortoise");
target.AddConfigItem("unix");
target.AddConfigItem("feature=\"test\"");
diff --git a/src/gn/rust_project_writer_unittest.cc b/src/gn/rust_project_writer_unittest.cc
index f0b806b..8f80824 100644
--- a/src/gn/rust_project_writer_unittest.cc
+++ b/src/gn/rust_project_writer_unittest.cc
@@ -34,6 +34,10 @@
target.visibility().SetPublic();
SourceFile lib("//foo/lib.rs");
target.sources().push_back(lib);
+ target.sources().push_back(
+ SourceFile("//out/Debug/gen/foo/bar/generated.rs"));
+ target.sources().push_back(
+ SourceFile("//out/Debug/gen/foo/bar/generated2.rs"));
target.source_types_used().Set(SourceFile::SOURCE_RS);
target.rust_values().set_crate_root(lib);
target.rust_values().crate_name() = "foo";
@@ -59,7 +63,7 @@
" \"source\": {\n"
" \"include_dirs\": [\n"
" \"path/foo/\",\n"
- " \"path/out/Debug/gen/foo/\"\n"
+ " \"path/out/Debug/gen/foo/bar/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -123,8 +127,7 @@
" \"label\": \"//tortoise:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"tortoise/\",\n"
- " \"out/Debug/gen/tortoise/\"\n"
+ " \"tortoise/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -142,8 +145,7 @@
" \"label\": \"//hare:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"hare/\",\n"
- " \"out/Debug/gen/hare/\"\n"
+ " \"hare/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -221,8 +223,7 @@
" \"label\": \"//tortoise:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"tortoise/\",\n"
- " \"out/Debug/gen/tortoise/\"\n"
+ " \"tortoise/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -240,8 +241,7 @@
" \"label\": \"//achilles:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"achilles/\",\n"
- " \"out/Debug/gen/achilles/\"\n"
+ " \"achilles/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -259,8 +259,7 @@
" \"label\": \"//hare:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"hare/\",\n"
- " \"out/Debug/gen/hare/\"\n"
+ " \"hare/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -358,8 +357,7 @@
" \"label\": \"//tortoise:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"tortoise/\",\n"
- " \"out/Debug/gen/tortoise/\"\n"
+ " \"tortoise/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -377,8 +375,7 @@
" \"label\": \"//tortoise:macro\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"tortoise/macro/\",\n"
- " \"out/Debug/gen/tortoise/\"\n"
+ " \"tortoise/macro/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -399,8 +396,7 @@
" \"label\": \"//hare:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"hare/\",\n"
- " \"out/Debug/gen/hare/\"\n"
+ " \"hare/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -461,8 +457,7 @@
" \"label\": \"//foo:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"path/foo/\",\n"
- " \"path/out/Debug/gen/foo/\"\n"
+ " \"path/foo/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -516,8 +511,7 @@
" \"label\": \"//foo:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"path/foo/\",\n"
- " \"path/out/Debug/gen/foo/\"\n"
+ " \"path/foo/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -571,8 +565,7 @@
" \"label\": \"//foo:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"path/foo/\",\n"
- " \"path/out/Debug/gen/foo/\"\n"
+ " \"path/foo/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"
@@ -627,8 +620,7 @@
" \"label\": \"//foo:bar\",\n"
" \"source\": {\n"
" \"include_dirs\": [\n"
- " \"path/foo/\",\n"
- " \"path/out/Debug/gen/foo/\"\n"
+ " \"path/foo/\"\n"
" ],\n"
" \"exclude_dirs\": []\n"
" },\n"