Skip to content

Commit 4a6e602

Browse files
committed
Allow automatically detect the rustc-src directory (fixes #3517).
If the configured rustcSource is set to "discover", try to automatically detect a source from the sysroot rustc directory.
1 parent 2967e78 commit 4a6e602

File tree

7 files changed

+67
-20
lines changed

7 files changed

+67
-20
lines changed

crates/project_model/src/cargo_workspace.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,15 @@ impl ops::Index<Target> for CargoWorkspace {
4444
}
4545
}
4646

47+
/// Describes how to set the rustc source directory.
48+
#[derive(Clone, Debug, PartialEq, Eq)]
49+
pub enum RustcSource {
50+
/// Explicit path for the rustc source directory.
51+
Path(AbsPathBuf),
52+
/// Try to automatically detect where the rustc source directory is.
53+
Discover,
54+
}
55+
4756
#[derive(Default, Clone, Debug, PartialEq, Eq)]
4857
pub struct CargoConfig {
4958
/// Do not activate the `default` feature.
@@ -64,7 +73,7 @@ pub struct CargoConfig {
6473
pub no_sysroot: bool,
6574

6675
/// rustc private crate source
67-
pub rustc_source: Option<AbsPathBuf>,
76+
pub rustc_source: Option<RustcSource>,
6877
}
6978

7079
pub type Package = Idx<PackageData>;

crates/project_model/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use rustc_hash::FxHashSet;
2121
pub use crate::{
2222
build_data::{BuildDataCollector, BuildDataResult},
2323
cargo_workspace::{
24-
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, Target, TargetData,
25-
TargetKind,
24+
CargoConfig, CargoWorkspace, Package, PackageData, PackageDependency, RustcSource, Target,
25+
TargetData, TargetKind,
2626
},
2727
project_json::{ProjectJson, ProjectJsonData},
2828
sysroot::Sysroot,

crates/project_model/src/sysroot.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,18 @@ impl Sysroot {
5151
pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
5252
log::debug!("Discovering sysroot for {}", cargo_toml.display());
5353
let current_dir = cargo_toml.parent().unwrap();
54-
let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
54+
let sysroot_dir = discover_sysroot_dir(current_dir)?;
55+
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir, current_dir)?;
5556
let res = Sysroot::load(&sysroot_src_dir)?;
5657
Ok(res)
5758
}
5859

60+
pub fn discover_rustc(cargo_toml: &AbsPath) -> Option<AbsPathBuf> {
61+
log::debug!("Discovering rustc source for {}", cargo_toml.display());
62+
let current_dir = cargo_toml.parent().unwrap();
63+
discover_sysroot_dir(current_dir).ok().and_then(|sysroot_dir| get_rustc_src(&sysroot_dir))
64+
}
65+
5966
pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
6067
let mut sysroot = Sysroot { crates: Arena::default() };
6168

@@ -110,7 +117,18 @@ impl Sysroot {
110117
}
111118
}
112119

113-
fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
120+
fn discover_sysroot_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
121+
let mut rustc = Command::new(toolchain::rustc());
122+
rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
123+
log::debug!("Discovering sysroot by {:?}", rustc);
124+
let stdout = utf8_stdout(rustc)?;
125+
Ok(AbsPathBuf::assert(PathBuf::from(stdout)))
126+
}
127+
128+
fn discover_sysroot_src_dir(
129+
sysroot_path: &AbsPathBuf,
130+
current_dir: &AbsPath,
131+
) -> Result<AbsPathBuf> {
114132
if let Ok(path) = env::var("RUST_SRC_PATH") {
115133
let path = AbsPathBuf::try_from(path.as_str())
116134
.map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
@@ -122,14 +140,6 @@ fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
122140
log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
123141
}
124142

125-
let sysroot_path = {
126-
let mut rustc = Command::new(toolchain::rustc());
127-
rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
128-
log::debug!("Discovering sysroot by {:?}", rustc);
129-
let stdout = utf8_stdout(rustc)?;
130-
AbsPathBuf::assert(PathBuf::from(stdout))
131-
};
132-
133143
get_rust_src(&sysroot_path)
134144
.or_else(|| {
135145
let mut rustup = Command::new(toolchain::rustup());
@@ -149,6 +159,16 @@ try installing the Rust source the same way you installed rustc",
149159
})
150160
}
151161

162+
fn get_rustc_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
163+
let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
164+
log::debug!("Checking for rustc source code: {}", rustc_src.display());
165+
if rustc_src.exists() {
166+
Some(rustc_src)
167+
} else {
168+
None
169+
}
170+
}
171+
152172
fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
153173
// Try the new path first since the old one still exists.
154174
let rust_src = sysroot_path.join("lib/rustlib/src/rust");

crates/project_model/src/workspace.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ impl ProjectWorkspace {
114114
cargo_version
115115
)
116116
})?;
117+
117118
let sysroot = if config.no_sysroot {
118119
Sysroot::default()
119120
} else {
@@ -125,7 +126,17 @@ impl ProjectWorkspace {
125126
})?
126127
};
127128

128-
let rustc = if let Some(rustc_dir) = &config.rustc_source {
129+
let rustc_dir = if let Some(rustc_source) = &config.rustc_source {
130+
use cargo_workspace::RustcSource;
131+
match rustc_source {
132+
RustcSource::Path(path) => Some(path.clone()),
133+
RustcSource::Discover => Sysroot::discover_rustc(&cargo_toml),
134+
}
135+
} else {
136+
None
137+
};
138+
139+
let rustc = if let Some(rustc_dir) = rustc_dir {
129140
Some(
130141
CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
131142
.with_context(|| {

crates/rust-analyzer/src/config.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use ide_db::helpers::{
1818
};
1919
use itertools::Itertools;
2020
use lsp_types::{ClientCapabilities, MarkupKind};
21-
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest};
21+
use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource};
2222
use rustc_hash::FxHashSet;
2323
use serde::{de::DeserializeOwned, Deserialize};
2424
use vfs::AbsPathBuf;
@@ -177,8 +177,9 @@ config_data! {
177177
/// tests or binaries.\nFor example, it may be `--release`.
178178
runnables_cargoExtraArgs: Vec<String> = "[]",
179179

180-
/// Path to the rust compiler sources, for usage in rustc_private projects.
181-
rustcSource : Option<PathBuf> = "null",
180+
/// Path to the rust compiler sources, for usage in rustc_private projects, or "discover"
181+
/// to try to automatically find it.
182+
rustcSource : Option<String> = "null",
182183

183184
/// Additional arguments to `rustfmt`.
184185
rustfmt_extraArgs: Vec<String> = "[]",
@@ -473,7 +474,13 @@ impl Config {
473474
self.data.cargo_loadOutDirsFromCheck
474475
}
475476
pub fn cargo(&self) -> CargoConfig {
476-
let rustc_source = self.data.rustcSource.as_ref().map(|it| self.root_path.join(&it));
477+
let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| {
478+
if rustc_src == "discover" {
479+
RustcSource::Discover
480+
} else {
481+
RustcSource::Path(self.root_path.join(rustc_src))
482+
}
483+
});
477484

478485
CargoConfig {
479486
no_default_features: self.data.cargo_noDefaultFeatures,

docs/user/generated_config.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@
105105
[[rust-analyzer.runnables.cargoExtraArgs]]rust-analyzer.runnables.cargoExtraArgs (default: `[]`)::
106106
Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be `--release`.
107107
[[rust-analyzer.rustcSource]]rust-analyzer.rustcSource (default: `null`)::
108-
Path to the rust compiler sources, for usage in rustc_private projects.
108+
Path to the rust compiler sources, for usage in rustc_private projects, or "discover" to try to automatically find it.
109109
[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
110110
Additional arguments to `rustfmt`.
111111
[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::

editors/code/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@
707707
}
708708
},
709709
"rust-analyzer.rustcSource": {
710-
"markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects.",
710+
"markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects, or \"discover\" to try to automatically find it.",
711711
"default": null,
712712
"type": [
713713
"null",

0 commit comments

Comments
 (0)