about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/project-model/src/cargo_workspace.rs1
-rw-r--r--crates/project-model/src/sysroot.rs11
-rw-r--r--crates/project-model/src/workspace.rs41
-rw-r--r--crates/rust-analyzer/src/config.rs8
-rw-r--r--docs/user/generated_config.adoc8
-rw-r--r--editors/code/package.json8
6 files changed, 68 insertions, 9 deletions
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index 467cf091787..fdc7859eb90 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -96,6 +96,7 @@ pub struct CargoConfig {
     pub target: Option<String>,
     /// Sysroot loading behavior
     pub sysroot: Option<RustcSource>,
+    pub sysroot_src: Option<AbsPathBuf>,
     /// rustc private crate source
     pub rustc_source: Option<RustcSource>,
     /// crates to disable `#[cfg(test)]` on
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index e1dde12bad8..328d2fbcf31 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -76,6 +76,7 @@ impl Sysroot {
     }
 }
 
+// FIXME: Expose a builder api as loading the sysroot got way too modular and complicated.
 impl Sysroot {
     /// Attempts to discover the toolchain's sysroot from the given `dir`.
     pub fn discover(dir: &AbsPath, extra_env: &FxHashMap<String, String>) -> Result<Sysroot> {
@@ -86,6 +87,16 @@ impl Sysroot {
         Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
     }
 
+    pub fn discover_with_src_override(
+        dir: &AbsPath,
+        extra_env: &FxHashMap<String, String>,
+        src: AbsPathBuf,
+    ) -> Result<Sysroot> {
+        tracing::debug!("discovering sysroot for {}", dir.display());
+        let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
+        Ok(Sysroot::load(sysroot_dir, src))
+    }
+
     pub fn discover_rustc(
         cargo_toml: &ManifestPath,
         extra_env: &FxHashMap<String, String>,
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index d784d3d0e9a..2a11f1e8eb8 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -190,8 +190,8 @@ impl ProjectWorkspace {
                 })?;
                 let cargo = CargoWorkspace::new(meta);
 
-                let sysroot = match &config.sysroot {
-                    Some(RustcSource::Path(path)) => {
+                let sysroot = match (&config.sysroot, &config.sysroot_src) {
+                    (Some(RustcSource::Path(path)), None) => {
                         match Sysroot::with_sysroot_dir(path.clone()) {
                             Ok(it) => Some(it),
                             Err(e) => {
@@ -200,7 +200,7 @@ impl ProjectWorkspace {
                             }
                         }
                     }
-                    Some(RustcSource::Discover) => {
+                    (Some(RustcSource::Discover), None) => {
                         match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
                             Ok(it) => Some(it),
                             Err(e) => {
@@ -213,8 +213,29 @@ impl ProjectWorkspace {
                             }
                         }
                     }
-                    None => None,
+                    (Some(RustcSource::Path(sysroot)), Some(sysroot_src)) => {
+                        Some(Sysroot::load(sysroot.clone(), sysroot_src.clone()))
+                    }
+                    (Some(RustcSource::Discover), Some(sysroot_src)) => {
+                        match Sysroot::discover_with_src_override(
+                            cargo_toml.parent(),
+                            &config.extra_env,
+                            sysroot_src.clone(),
+                        ) {
+                            Ok(it) => Some(it),
+                            Err(e) => {
+                                tracing::error!(
+                                    %e,
+                                    "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
+                                    cargo_toml.display()
+                                );
+                                None
+                            }
+                        }
+                    }
+                    (None, _) => None,
                 };
+
                 if let Some(sysroot) = &sysroot {
                     tracing::info!(src_root = %sysroot.src_root().display(), root = %sysroot.root().display(), "Using sysroot");
                 }
@@ -440,9 +461,11 @@ impl ProjectWorkspace {
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
     pub fn to_roots(&self) -> Vec<PackageRoot> {
-        let mk_sysroot = |sysroot: Option<&Sysroot>| {
+        let mk_sysroot = |sysroot: Option<&Sysroot>, project_root: Option<&AbsPath>| {
             sysroot.map(|sysroot| PackageRoot {
-                is_local: false,
+                // mark the sysroot as mutable if it is located inside of the project
+                is_local: project_root
+                    .map_or(false, |project_root| sysroot.src_root().starts_with(project_root)),
                 include: vec![sysroot.src_root().to_path_buf()],
                 exclude: Vec::new(),
             })
@@ -457,7 +480,7 @@ impl ProjectWorkspace {
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot(sysroot.as_ref(), Some(project.path())))
                 .collect::<Vec<_>>(),
             ProjectWorkspace::Cargo {
                 cargo,
@@ -507,7 +530,7 @@ impl ProjectWorkspace {
                         }
                         PackageRoot { is_local, include, exclude }
                     })
-                    .chain(mk_sysroot(sysroot.as_ref()))
+                    .chain(mk_sysroot(sysroot.as_ref(), Some(cargo.workspace_root())))
                     .chain(rustc.iter().flat_map(|rustc| {
                         rustc.packages().map(move |krate| PackageRoot {
                             is_local: false,
@@ -524,7 +547,7 @@ impl ProjectWorkspace {
                     include: vec![detached_file.clone()],
                     exclude: Vec::new(),
                 })
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot(sysroot.as_ref(), None))
                 .collect(),
         }
     }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 8ea161dbdc4..c8075aefbbe 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -117,6 +117,11 @@ config_data! {
         ///
         /// This option does not take effect until rust-analyzer is restarted.
         cargo_sysroot: Option<String>    = "\"discover\"",
+        /// Relative path to the sysroot library sources. If left unset, this will default to
+        /// `{cargo.sysroot}/lib/rustlib/src/rust/library`.
+        ///
+        /// This option does not take effect until rust-analyzer is restarted.
+        cargo_sysrootSrc: Option<String>    = "null",
         /// Compilation target override (target triple).
         // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
         // than `checkOnSave_target`
@@ -1103,6 +1108,8 @@ impl Config {
                 RustcSource::Path(self.root_path.join(sysroot))
             }
         });
+        let sysroot_src =
+            self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
 
         CargoConfig {
             features: match &self.data.cargo_features {
@@ -1114,6 +1121,7 @@ impl Config {
             },
             target: self.data.cargo_target.clone(),
             sysroot,
+            sysroot_src,
             rustc_source,
             unset_test_crates: UnsetTestCrates::Only(self.data.cargo_unsetTest.clone()),
             wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 1bfb8a917a8..d5fdedfe3af 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -99,6 +99,14 @@ Unsetting this disables sysroot loading.
 
 This option does not take effect until rust-analyzer is restarted.
 --
+[[rust-analyzer.cargo.sysrootSrc]]rust-analyzer.cargo.sysrootSrc (default: `null`)::
++
+--
+Relative path to the sysroot library sources. If left unset, this will default to
+`{cargo.sysroot}/lib/rustlib/src/rust/library`.
+
+This option does not take effect until rust-analyzer is restarted.
+--
 [[rust-analyzer.cargo.target]]rust-analyzer.cargo.target (default: `null`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 599e9c5a7bf..7160781b6f3 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -539,6 +539,14 @@
                         "string"
                     ]
                 },
+                "rust-analyzer.cargo.sysrootSrc": {
+                    "markdownDescription": "Relative path to the sysroot library sources. If left unset, this will default to\n`{cargo.sysroot}/lib/rustlib/src/rust/library`.\n\nThis option does not take effect until rust-analyzer is restarted.",
+                    "default": null,
+                    "type": [
+                        "null",
+                        "string"
+                    ]
+                },
                 "rust-analyzer.cargo.target": {
                     "markdownDescription": "Compilation target override (target triple).",
                     "default": null,