about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/project_model/src/project_json.rs4
-rw-r--r--crates/project_model/src/tests.rs551
-rw-r--r--crates/project_model/src/workspace.rs12
-rw-r--r--crates/project_model/test_data/fake-sysroot/alloc/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/core/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/panic_abort/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/panic_unwind/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/proc_macro/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/profiler_builtins/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/std/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/term/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/test/src/lib.rs0
-rw-r--r--crates/project_model/test_data/fake-sysroot/unwind/src/lib.rs0
-rw-r--r--crates/project_model/test_data/hello-world-project.json12
-rw-r--r--crates/project_model/test_data/is-proc-macro-project.json13
-rw-r--r--docs/user/manual.adoc4
17 files changed, 569 insertions, 27 deletions
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index e8f1aca61b3..5db1aa1b4f3 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -37,6 +37,7 @@ pub struct Crate {
     pub(crate) is_workspace_member: bool,
     pub(crate) include: Vec<AbsPathBuf>,
     pub(crate) exclude: Vec<AbsPathBuf>,
+    pub(crate) is_proc_macro: bool,
 }
 
 impl ProjectJson {
@@ -96,6 +97,7 @@ impl ProjectJson {
                         is_workspace_member,
                         include,
                         exclude,
+                        is_proc_macro: crate_data.is_proc_macro,
                     }
                 })
                 .collect::<Vec<_>>(),
@@ -135,6 +137,8 @@ struct CrateData {
     proc_macro_dylib_path: Option<PathBuf>,
     is_workspace_member: Option<bool>,
     source: Option<CrateSource>,
+    #[serde(default)]
+    is_proc_macro: bool,
 }
 
 #[derive(Deserialize, Debug, Clone)]
diff --git a/crates/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index 302a000d70e..b50db6f3b85 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -1,12 +1,20 @@
-use std::path::PathBuf;
+use std::{
+    ops::Deref,
+    path::{Path, PathBuf},
+};
 
-use base_db::FileId;
+use base_db::{CrateGraph, FileId};
 use expect_test::{expect, Expect};
+use paths::AbsPath;
+use serde::de::DeserializeOwned;
 
-use crate::{CargoWorkspace, CfgOverrides, ProjectWorkspace, Sysroot, WorkspaceBuildScripts};
+use crate::{
+    CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
+    WorkspaceBuildScripts,
+};
 
-fn check(file: &str, expect: Expect) {
-    let meta = get_test_metadata(file);
+fn load_cargo(file: &str) -> CrateGraph {
+    let meta = get_test_json_file(file);
     let cargo_workspace = CargoWorkspace::new(meta);
     let project_workspace = ProjectWorkspace::Cargo {
         cargo: cargo_workspace,
@@ -16,23 +24,21 @@ fn check(file: &str, expect: Expect) {
         rustc_cfg: Vec::new(),
         cfg_overrides: CfgOverrides::default(),
     };
+    to_crate_graph(project_workspace)
+}
 
-    let crate_graph = project_workspace.to_crate_graph(None, {
-        let mut counter = 0;
-        &mut move |_path| {
-            counter += 1;
-            Some(FileId(counter))
-        }
-    });
-
-    let mut crate_graph = format!("{:#?}", crate_graph);
-    replace_root(&mut crate_graph, false);
-
-    expect.assert_eq(&crate_graph);
+fn load_rust_project(file: &str) -> CrateGraph {
+    let data = get_test_json_file(file);
+    let project = rooted_project_json(data);
+    let sysroot = Some(get_fake_sysroot());
+    let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() };
+    to_crate_graph(project_workspace)
 }
 
-fn get_test_metadata(file: &str) -> cargo_metadata::Metadata {
-    let mut json = get_test_data(file).parse::<serde_json::Value>().unwrap();
+fn get_test_json_file<T: DeserializeOwned>(file: &str) -> T {
+    let file = get_test_path(file);
+    let data = std::fs::read_to_string(file).unwrap();
+    let mut json = data.parse::<serde_json::Value>().unwrap();
     fixup_paths(&mut json);
     return serde_json::from_value(json).unwrap();
 
@@ -58,16 +64,46 @@ fn replace_root(s: &mut String, direction: bool) {
     }
 }
 
-fn get_test_data(file: &str) -> String {
+fn get_test_path(file: &str) -> PathBuf {
     let base = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    let file = base.join("test_data").join(file);
-    std::fs::read_to_string(file).unwrap()
+    base.join("test_data").join(file)
+}
+
+fn get_fake_sysroot() -> Sysroot {
+    let sysroot_path = get_test_path("fake-sysroot");
+    let sysroot_src_dir = AbsPath::assert(&sysroot_path);
+    Sysroot::load(&sysroot_src_dir).unwrap()
+}
+
+fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
+    let mut root = "$ROOT$".to_string();
+    replace_root(&mut root, true);
+    let path = Path::new(&root);
+    let base = AbsPath::assert(path);
+    ProjectJson::new(base, data)
+}
+
+fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph {
+    project_workspace.to_crate_graph(None, {
+        let mut counter = 0;
+        &mut move |_path| {
+            counter += 1;
+            Some(FileId(counter))
+        }
+    })
+}
+
+fn check_crate_graph(crate_graph: CrateGraph, expect: Expect) {
+    let mut crate_graph = format!("{:#?}", crate_graph);
+    replace_root(&mut crate_graph, false);
+    expect.assert_eq(&crate_graph);
 }
 
 #[test]
-fn hello_world_project_model() {
-    check(
-        "hello-world-metadata.json",
+fn cargo_hello_world_project_model() {
+    let crate_graph = load_cargo("hello-world-metadata.json");
+    check_crate_graph(
+        crate_graph,
         expect![[r#"
             CrateGraph {
                 arena: {
@@ -514,3 +550,468 @@ fn hello_world_project_model() {
             }"#]],
     )
 }
+
+#[test]
+fn rust_project_hello_world_project_model() {
+    let crate_graph = load_rust_project("hello-world-project.json");
+    check_crate_graph(
+        crate_graph,
+        expect![[r#"
+            CrateGraph {
+                arena: {
+                    CrateId(
+                        0,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            1,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "alloc",
+                                ),
+                                canonical_name: "alloc",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    1,
+                                ),
+                                name: CrateName(
+                                    "core",
+                                ),
+                            },
+                        ],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        10,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            11,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "unwind",
+                                ),
+                                canonical_name: "unwind",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        7,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            8,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "std_detect",
+                                ),
+                                canonical_name: "std_detect",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        4,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            5,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "proc_macro",
+                                ),
+                                canonical_name: "proc_macro",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    6,
+                                ),
+                                name: CrateName(
+                                    "std",
+                                ),
+                            },
+                        ],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        1,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            2,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "core",
+                                ),
+                                canonical_name: "core",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        11,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            12,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "hello_world",
+                                ),
+                                canonical_name: "hello_world",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    1,
+                                ),
+                                name: CrateName(
+                                    "core",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    0,
+                                ),
+                                name: CrateName(
+                                    "alloc",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    6,
+                                ),
+                                name: CrateName(
+                                    "std",
+                                ),
+                            },
+                        ],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        8,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            9,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "term",
+                                ),
+                                canonical_name: "term",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        5,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            6,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "profiler_builtins",
+                                ),
+                                canonical_name: "profiler_builtins",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        2,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            3,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "panic_abort",
+                                ),
+                                canonical_name: "panic_abort",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        9,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            10,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "test",
+                                ),
+                                canonical_name: "test",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        6,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            7,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "std",
+                                ),
+                                canonical_name: "std",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [
+                            Dependency {
+                                crate_id: CrateId(
+                                    0,
+                                ),
+                                name: CrateName(
+                                    "alloc",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    1,
+                                ),
+                                name: CrateName(
+                                    "core",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    2,
+                                ),
+                                name: CrateName(
+                                    "panic_abort",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    3,
+                                ),
+                                name: CrateName(
+                                    "panic_unwind",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    5,
+                                ),
+                                name: CrateName(
+                                    "profiler_builtins",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    7,
+                                ),
+                                name: CrateName(
+                                    "std_detect",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    8,
+                                ),
+                                name: CrateName(
+                                    "term",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    9,
+                                ),
+                                name: CrateName(
+                                    "test",
+                                ),
+                            },
+                            Dependency {
+                                crate_id: CrateId(
+                                    10,
+                                ),
+                                name: CrateName(
+                                    "unwind",
+                                ),
+                            },
+                        ],
+                        proc_macro: [],
+                    },
+                    CrateId(
+                        3,
+                    ): CrateData {
+                        root_file_id: FileId(
+                            4,
+                        ),
+                        edition: Edition2018,
+                        display_name: Some(
+                            CrateDisplayName {
+                                crate_name: CrateName(
+                                    "panic_unwind",
+                                ),
+                                canonical_name: "panic_unwind",
+                            },
+                        ),
+                        cfg_options: CfgOptions(
+                            [],
+                        ),
+                        potential_cfg_options: CfgOptions(
+                            [],
+                        ),
+                        env: Env {
+                            entries: {},
+                        },
+                        dependencies: [],
+                        proc_macro: [],
+                    },
+                },
+            }"#]],
+    );
+}
+
+#[test]
+fn rust_project_is_proc_macro_has_proc_macro_dep() {
+    let crate_graph = load_rust_project("is-proc-macro-project.json");
+    // Since the project only defines one crate (outside the sysroot crates),
+    // it should be the one with the biggest Id.
+    let crate_id = crate_graph.iter().max().unwrap();
+    let crate_data = &crate_graph[crate_id];
+    // Assert that the project crate with `is_proc_macro` has a dependency
+    // on the proc_macro sysroot crate.
+    crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap();
+}
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 41bd668e476..bfc0f144aac 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -446,10 +446,20 @@ fn project_json_to_crate_graph(
 
     for (from, krate) in project.crates() {
         if let Some(&from) = crates.get(&from) {
-            if let Some((public_deps, _proc_macro)) = &sysroot_deps {
+            if let Some((public_deps, libproc_macro)) = &sysroot_deps {
                 for (name, to) in public_deps.iter() {
                     add_dep(&mut crate_graph, from, name.clone(), *to)
                 }
+                if krate.is_proc_macro {
+                    if let Some(proc_macro) = libproc_macro {
+                        add_dep(
+                            &mut crate_graph,
+                            from,
+                            CrateName::new("proc_macro").unwrap(),
+                            *proc_macro,
+                        );
+                    }
+                }
             }
 
             for dep in &krate.deps {
diff --git a/crates/project_model/test_data/fake-sysroot/alloc/src/lib.rs b/crates/project_model/test_data/fake-sysroot/alloc/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/alloc/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/core/src/lib.rs b/crates/project_model/test_data/fake-sysroot/core/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/core/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/panic_abort/src/lib.rs b/crates/project_model/test_data/fake-sysroot/panic_abort/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/panic_abort/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/panic_unwind/src/lib.rs b/crates/project_model/test_data/fake-sysroot/panic_unwind/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/panic_unwind/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/proc_macro/src/lib.rs b/crates/project_model/test_data/fake-sysroot/proc_macro/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/proc_macro/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/profiler_builtins/src/lib.rs b/crates/project_model/test_data/fake-sysroot/profiler_builtins/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/profiler_builtins/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/std/src/lib.rs b/crates/project_model/test_data/fake-sysroot/std/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/std/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs b/crates/project_model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/stdarch/crates/std_detect/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/term/src/lib.rs b/crates/project_model/test_data/fake-sysroot/term/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/term/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/test/src/lib.rs b/crates/project_model/test_data/fake-sysroot/test/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/test/src/lib.rs
diff --git a/crates/project_model/test_data/fake-sysroot/unwind/src/lib.rs b/crates/project_model/test_data/fake-sysroot/unwind/src/lib.rs
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/crates/project_model/test_data/fake-sysroot/unwind/src/lib.rs
diff --git a/crates/project_model/test_data/hello-world-project.json b/crates/project_model/test_data/hello-world-project.json
new file mode 100644
index 00000000000..b27ab1f42b5
--- /dev/null
+++ b/crates/project_model/test_data/hello-world-project.json
@@ -0,0 +1,12 @@
+{
+    "sysroot_src": null,
+    "crates": [
+        {
+            "display_name": "hello_world",
+            "root_module": "$ROOT$src/lib.rs",
+            "edition": "2018",
+            "deps": [],
+            "is_workspace_member": true
+        }
+    ]
+}
diff --git a/crates/project_model/test_data/is-proc-macro-project.json b/crates/project_model/test_data/is-proc-macro-project.json
new file mode 100644
index 00000000000..5d500a4729f
--- /dev/null
+++ b/crates/project_model/test_data/is-proc-macro-project.json
@@ -0,0 +1,13 @@
+{
+    "sysroot_src": null,
+    "crates": [
+        {
+            "display_name": "is_proc_macro",
+            "root_module": "$ROOT$src/lib.rs",
+            "edition": "2018",
+            "deps": [],
+            "is_workspace_member": true,
+            "is_proc_macro": true
+        }
+    ]
+}
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 000a95b1003..6f00da3178a 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -578,6 +578,8 @@ interface Crate {
     /// the `env!` macro
     env: : { [key: string]: string; },
 
+    /// Whether the crate is a proc-macro crate.
+    is_proc_macro: bool;
     /// For proc-macro crates, path to compiled
     /// proc-macro (.so file).
     proc_macro_dylib_path?: string;
@@ -597,7 +599,7 @@ Specifically, the `roots` setup will be different eventually.
 
 There are three ways to feed `rust-project.json` to rust-analyzer:
 
-* Place `rust-project.json` file at the root of the project, and rust-anlayzer will discover it.
+* Place `rust-project.json` file at the root of the project, and rust-analyzer will discover it.
 * Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request).
 * Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline.