mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-26 11:59:49 +00:00
⬆️ rust-analyzer
This commit is contained in:
parent
3e0e51c108
commit
bc45c7659a
321 changed files with 11210 additions and 9720 deletions
|
@ -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
|
||||
|
|
|
@ -25,7 +25,7 @@ mod sysroot;
|
|||
mod workspace;
|
||||
mod rustc_cfg;
|
||||
mod build_scripts;
|
||||
mod target_data_layout;
|
||||
pub mod target_data_layout;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
@ -4,6 +4,50 @@
|
|||
//! idea here is that people who do not use Cargo, can instead teach their build
|
||||
//! system to generate `rust-project.json` which can be ingested by
|
||||
//! rust-analyzer.
|
||||
//!
|
||||
//! This short file is a somewhat big conceptual piece of the architecture of
|
||||
//! rust-analyzer, so it's worth elaborating on the underlying ideas and
|
||||
//! motivation.
|
||||
//!
|
||||
//! For rust-analyzer to function, it needs some information about the project.
|
||||
//! Specifically, it maintains an in-memory data structure which lists all the
|
||||
//! crates (compilation units) and dependencies between them. This is necessary
|
||||
//! a global singleton, as we do want, eg, find usages to always search across
|
||||
//! the whole project, rather than just in the "current" crate.
|
||||
//!
|
||||
//! Normally, we get this "crate graph" by calling `cargo metadata
|
||||
//! --message-format=json` for each cargo workspace and merging results. This
|
||||
//! works for your typical cargo project, but breaks down for large folks who
|
||||
//! have a monorepo with an infinite amount of Rust code which is built with bazel or
|
||||
//! some such.
|
||||
//!
|
||||
//! To support this use case, we need to make _something_ configurable. To avoid
|
||||
//! a [midlayer mistake](https://lwn.net/Articles/336262/), we allow configuring
|
||||
//! the lowest possible layer. `ProjectJson` is essentially a hook to just set
|
||||
//! that global singleton in-memory data structure. It is optimized for power,
|
||||
//! not for convenience (you'd be using cargo anyway if you wanted nice things,
|
||||
//! right? :)
|
||||
//!
|
||||
//! `rust-project.json` also isn't necessary a file. Architecturally, we support
|
||||
//! any convenient way to specify this data, which today is:
|
||||
//!
|
||||
//! * file on disk
|
||||
//! * a field in the config (ie, you can send a JSON request with the contents
|
||||
//! of rust-project.json to rust-analyzer, no need to write anything to disk)
|
||||
//!
|
||||
//! Another possible thing we don't do today, but which would be totally valid,
|
||||
//! is to add an extension point to VS Code extension to register custom
|
||||
//! project.
|
||||
//!
|
||||
//! In general, it is assumed that if you are going to use `rust-project.json`,
|
||||
//! you'd write a fair bit of custom code gluing your build system to ra through
|
||||
//! this JSON format. This logic can take form of a VS Code extension, or a
|
||||
//! proxy process which injects data into "configure" LSP request, or maybe just
|
||||
//! a simple build system rule to generate the file.
|
||||
//!
|
||||
//! In particular, the logic for lazily loading parts of the monorepo as the
|
||||
//! user explores them belongs to that extension (it's totally valid to change
|
||||
//! rust-project.json over time via configuration request!)
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
use std::{env, fs, iter, ops, path::PathBuf, process::Command};
|
||||
|
||||
use anyhow::{format_err, Result};
|
||||
use base_db::CrateName;
|
||||
use la_arena::{Arena, Idx};
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
@ -50,14 +51,16 @@ impl Sysroot {
|
|||
&self.src_root
|
||||
}
|
||||
|
||||
pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate, bool)> + '_ {
|
||||
pub fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
|
||||
// core is added as a dependency before std in order to
|
||||
// mimic rustcs dependency order
|
||||
["core", "alloc", "std"]
|
||||
.into_iter()
|
||||
.zip(iter::repeat(true))
|
||||
.chain(iter::once(("test", false)))
|
||||
.filter_map(move |(name, prelude)| Some((name, self.by_name(name)?, prelude)))
|
||||
.filter_map(move |(name, prelude)| {
|
||||
Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn proc_macro(&self) -> Option<SysrootCrate> {
|
||||
|
@ -67,8 +70,13 @@ impl Sysroot {
|
|||
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
|
||||
self.crates.iter().map(|(id, _data)| id)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.crates.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
// 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> {
|
||||
|
@ -76,8 +84,17 @@ impl Sysroot {
|
|||
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
|
||||
let sysroot_src_dir =
|
||||
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
|
||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
||||
Ok(res)
|
||||
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(
|
||||
|
@ -94,11 +111,10 @@ impl Sysroot {
|
|||
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
|
||||
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
|
||||
})?;
|
||||
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
|
||||
Ok(res)
|
||||
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
|
||||
}
|
||||
|
||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
|
||||
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
|
||||
let mut sysroot =
|
||||
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
|
||||
|
||||
|
@ -149,14 +165,14 @@ impl Sysroot {
|
|||
} else {
|
||||
""
|
||||
};
|
||||
anyhow::bail!(
|
||||
tracing::error!(
|
||||
"could not find libcore in sysroot path `{}`{}",
|
||||
sysroot.src_root.as_path().display(),
|
||||
var_note,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(sysroot)
|
||||
sysroot
|
||||
}
|
||||
|
||||
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
//! Runs `rustc --print target-spec-json` to get the target_data_layout.
|
||||
use std::process::Command;
|
||||
|
||||
use anyhow::Result;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{utf8_stdout, ManifestPath};
|
||||
|
||||
pub(super) fn get(
|
||||
pub fn get(
|
||||
cargo_toml: Option<&ManifestPath>,
|
||||
target: Option<&str>,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Option<String> {
|
||||
) -> Result<String> {
|
||||
let output = (|| {
|
||||
if let Some(cargo_toml) = cargo_toml {
|
||||
let mut cmd = Command::new(toolchain::rustc());
|
||||
|
@ -28,13 +29,13 @@ pub(super) fn get(
|
|||
// using unstable cargo features failed, fall back to using plain rustc
|
||||
let mut cmd = Command::new(toolchain::rustc());
|
||||
cmd.envs(extra_env)
|
||||
.args(["-Z", "unstable-options", "rustc", "--print", "target-spec-json"])
|
||||
.args(["-Z", "unstable-options", "--print", "target-spec-json"])
|
||||
.env("RUSTC_BOOTSTRAP", "1");
|
||||
if let Some(target) = target {
|
||||
cmd.args(["--target", target]);
|
||||
}
|
||||
utf8_stdout(cmd)
|
||||
})()
|
||||
.ok()?;
|
||||
Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned())
|
||||
})()?;
|
||||
(|| Some(output.split_once(r#""data-layout": ""#)?.1.split_once('"')?.0.to_owned()))()
|
||||
.ok_or_else(|| anyhow::format_err!("could not fetch target-spec-json from command output"))
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
|
|||
rustc_cfg: Vec::new(),
|
||||
cfg_overrides,
|
||||
toolchain: None,
|
||||
target_layout: None,
|
||||
target_layout: Err("target_data_layout not loaded".into()),
|
||||
};
|
||||
to_crate_graph(project_workspace)
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ fn get_fake_sysroot() -> Sysroot {
|
|||
// fake sysroot, so we give them both the same path:
|
||||
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
|
||||
let sysroot_src_dir = sysroot_dir.clone();
|
||||
Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap()
|
||||
Sysroot::load(sysroot_dir, sysroot_src_dir)
|
||||
}
|
||||
|
||||
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
|
||||
|
@ -151,7 +151,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
"debug_assertions",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -221,7 +223,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
"debug_assertions",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -300,7 +304,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
"debug_assertions",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -379,7 +385,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
"debug_assertions",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -467,7 +475,9 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
|
|||
"feature=use_std",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -553,7 +563,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -625,7 +637,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -706,7 +720,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -787,7 +803,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -875,7 +893,9 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
|
|||
"feature=use_std",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -952,7 +972,9 @@ fn cargo_hello_world_project_model() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -1024,7 +1046,9 @@ fn cargo_hello_world_project_model() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -1105,7 +1129,9 @@ fn cargo_hello_world_project_model() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -1186,7 +1212,9 @@ fn cargo_hello_world_project_model() {
|
|||
"test",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -1274,7 +1302,9 @@ fn cargo_hello_world_project_model() {
|
|||
"feature=use_std",
|
||||
],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"target_data_layout not loaded",
|
||||
),
|
||||
env: Env {
|
||||
entries: {
|
||||
"CARGO_PKG_LICENSE": "",
|
||||
|
@ -1327,7 +1357,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
1,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1343,7 +1373,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1372,7 +1404,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
2,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1388,7 +1420,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1407,7 +1441,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
3,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1423,7 +1457,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1442,7 +1478,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
4,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1458,7 +1494,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1477,7 +1515,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
5,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1493,7 +1531,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1522,7 +1562,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
6,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1538,7 +1578,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1557,7 +1599,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
7,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1573,7 +1615,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1665,7 +1709,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
8,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1681,7 +1725,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1700,7 +1746,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
9,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1716,7 +1762,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1735,7 +1783,7 @@ fn rust_project_hello_world_project_model() {
|
|||
root_file_id: FileId(
|
||||
10,
|
||||
),
|
||||
edition: Edition2018,
|
||||
edition: Edition2021,
|
||||
version: None,
|
||||
display_name: Some(
|
||||
CrateDisplayName {
|
||||
|
@ -1751,7 +1799,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
@ -1786,7 +1836,9 @@ fn rust_project_hello_world_project_model() {
|
|||
potential_cfg_options: CfgOptions(
|
||||
[],
|
||||
),
|
||||
target_layout: None,
|
||||
target_layout: Err(
|
||||
"rust-project.json projects have no target layout set",
|
||||
),
|
||||
env: Env {
|
||||
entries: {},
|
||||
},
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
|
|||
use anyhow::{format_err, Context, Result};
|
||||
use base_db::{
|
||||
CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
|
||||
FileId, LangCrateOrigin, ProcMacroLoadResult,
|
||||
FileId, LangCrateOrigin, ProcMacroLoadResult, TargetLayoutLoadResult,
|
||||
};
|
||||
use cfg::{CfgDiff, CfgOptions};
|
||||
use paths::{AbsPath, AbsPathBuf};
|
||||
|
@ -63,7 +63,7 @@ pub struct PackageRoot {
|
|||
pub exclude: Vec<AbsPathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
#[derive(Clone)]
|
||||
pub enum ProjectWorkspace {
|
||||
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
|
||||
Cargo {
|
||||
|
@ -79,11 +79,10 @@ pub enum ProjectWorkspace {
|
|||
rustc_cfg: Vec<CfgFlag>,
|
||||
cfg_overrides: CfgOverrides,
|
||||
toolchain: Option<Version>,
|
||||
target_layout: Option<String>,
|
||||
target_layout: Result<String, String>,
|
||||
},
|
||||
/// Project workspace was manually specified using a `rust-project.json` file.
|
||||
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
|
||||
|
||||
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
|
||||
// That's not the end user experience we should strive for.
|
||||
// Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
|
||||
|
@ -163,7 +162,7 @@ impl ProjectWorkspace {
|
|||
project_json,
|
||||
config.target.as_deref(),
|
||||
&config.extra_env,
|
||||
)?
|
||||
)
|
||||
}
|
||||
ProjectManifest::CargoToml(cargo_toml) => {
|
||||
let cargo_version = utf8_stdout({
|
||||
|
@ -191,24 +190,52 @@ impl ProjectWorkspace {
|
|||
})?;
|
||||
let cargo = CargoWorkspace::new(meta);
|
||||
|
||||
let sysroot = match &config.sysroot {
|
||||
Some(RustcSource::Path(path)) => {
|
||||
Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
|
||||
format!("Failed to find sysroot at {}.", path.display())
|
||||
})?)
|
||||
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) => {
|
||||
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(RustcSource::Discover) => Some(
|
||||
Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
|
||||
|| {
|
||||
format!(
|
||||
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
|
||||
cargo_toml.display()
|
||||
)
|
||||
},
|
||||
)?,
|
||||
),
|
||||
None => None,
|
||||
(Some(RustcSource::Discover), None) => {
|
||||
match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
(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");
|
||||
}
|
||||
|
@ -225,18 +252,22 @@ impl ProjectWorkspace {
|
|||
}
|
||||
|
||||
let rustc = match rustc_dir {
|
||||
Some(rustc_dir) => Some({
|
||||
let meta = CargoWorkspace::fetch_metadata(
|
||||
&rustc_dir,
|
||||
cargo_toml.parent(),
|
||||
config,
|
||||
progress,
|
||||
)
|
||||
.with_context(|| {
|
||||
"Failed to read Cargo metadata for Rust sources".to_string()
|
||||
})?;
|
||||
CargoWorkspace::new(meta)
|
||||
}),
|
||||
Some(rustc_dir) => match CargoWorkspace::fetch_metadata(
|
||||
&rustc_dir,
|
||||
cargo_toml.parent(),
|
||||
config,
|
||||
progress,
|
||||
) {
|
||||
Ok(meta) => Some(CargoWorkspace::new(meta)),
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
%e,
|
||||
"Failed to read Cargo metadata from rustc source at {}",
|
||||
rustc_dir.display()
|
||||
);
|
||||
None
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
};
|
||||
|
||||
|
@ -249,6 +280,9 @@ impl ProjectWorkspace {
|
|||
config.target.as_deref(),
|
||||
&config.extra_env,
|
||||
);
|
||||
if let Err(e) = &data_layout {
|
||||
tracing::error!(%e, "failed fetching data layout for {cargo_toml:?} workspace");
|
||||
}
|
||||
ProjectWorkspace::Cargo {
|
||||
cargo,
|
||||
build_scripts: WorkspaceBuildScripts::default(),
|
||||
|
@ -257,7 +291,7 @@ impl ProjectWorkspace {
|
|||
rustc_cfg,
|
||||
cfg_overrides,
|
||||
toolchain,
|
||||
target_layout: data_layout,
|
||||
target_layout: data_layout.map_err(|it| it.to_string()),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -269,15 +303,14 @@ impl ProjectWorkspace {
|
|||
project_json: ProjectJson,
|
||||
target: Option<&str>,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
) -> Result<ProjectWorkspace> {
|
||||
) -> ProjectWorkspace {
|
||||
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
|
||||
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
|
||||
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)),
|
||||
(Some(sysroot), None) => {
|
||||
// assume sysroot is structured like rustup's and guess `sysroot_src`
|
||||
let sysroot_src =
|
||||
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
|
||||
|
||||
Some(Sysroot::load(sysroot, sysroot_src)?)
|
||||
Some(Sysroot::load(sysroot, sysroot_src))
|
||||
}
|
||||
(None, Some(sysroot_src)) => {
|
||||
// assume sysroot is structured like rustup's and guess `sysroot`
|
||||
|
@ -285,7 +318,7 @@ impl ProjectWorkspace {
|
|||
for _ in 0..5 {
|
||||
sysroot.pop();
|
||||
}
|
||||
Some(Sysroot::load(sysroot, sysroot_src)?)
|
||||
Some(Sysroot::load(sysroot, sysroot_src))
|
||||
}
|
||||
(None, None) => None,
|
||||
};
|
||||
|
@ -294,7 +327,7 @@ impl ProjectWorkspace {
|
|||
}
|
||||
|
||||
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
|
||||
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
|
||||
ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }
|
||||
}
|
||||
|
||||
pub fn load_detached_files(
|
||||
|
@ -302,18 +335,29 @@ impl ProjectWorkspace {
|
|||
config: &CargoConfig,
|
||||
) -> Result<ProjectWorkspace> {
|
||||
let sysroot = match &config.sysroot {
|
||||
Some(RustcSource::Path(path)) => Some(
|
||||
Sysroot::with_sysroot_dir(path.clone())
|
||||
.with_context(|| format!("Failed to find sysroot at {}.", path.display()))?,
|
||||
),
|
||||
Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) {
|
||||
Ok(it) => Some(it),
|
||||
Err(e) => {
|
||||
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
|
||||
None
|
||||
}
|
||||
},
|
||||
Some(RustcSource::Discover) => {
|
||||
let dir = &detached_files
|
||||
.first()
|
||||
.and_then(|it| it.parent())
|
||||
.ok_or_else(|| format_err!("No detached files to load"))?;
|
||||
Some(Sysroot::discover(dir, &config.extra_env).with_context(|| {
|
||||
format!("Failed to find sysroot in {}. Is rust-src installed?", dir.display())
|
||||
})?)
|
||||
match Sysroot::discover(dir, &config.extra_env) {
|
||||
Ok(it) => Some(it),
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
%e,
|
||||
"Failed to find sysroot for {}. Is rust-src installed?",
|
||||
dir.display()
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
@ -366,7 +410,7 @@ impl ProjectWorkspace {
|
|||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let ref mut outputs = match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
|
||||
let outputs = &mut match WorkspaceBuildScripts::run_once(config, &cargo_ws, progress) {
|
||||
Ok(it) => Ok(it.into_iter()),
|
||||
// io::Error is not Clone?
|
||||
Err(e) => Err(Arc::new(e)),
|
||||
|
@ -417,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(),
|
||||
})
|
||||
|
@ -434,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,
|
||||
|
@ -484,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,
|
||||
|
@ -501,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(),
|
||||
}
|
||||
}
|
||||
|
@ -538,9 +584,9 @@ impl ProjectWorkspace {
|
|||
load_proc_macro,
|
||||
load,
|
||||
project,
|
||||
sysroot,
|
||||
sysroot.as_ref(),
|
||||
extra_env,
|
||||
None,
|
||||
Err("rust-project.json projects have no target layout set".into()),
|
||||
),
|
||||
ProjectWorkspace::Cargo {
|
||||
cargo,
|
||||
|
@ -560,10 +606,19 @@ impl ProjectWorkspace {
|
|||
rustc_cfg.clone(),
|
||||
cfg_overrides,
|
||||
build_scripts,
|
||||
target_layout.as_deref().map(Arc::from),
|
||||
match target_layout.as_ref() {
|
||||
Ok(it) => Ok(Arc::from(it.as_str())),
|
||||
Err(it) => Err(Arc::from(it.as_str())),
|
||||
},
|
||||
),
|
||||
ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
|
||||
detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot, None)
|
||||
detached_files_to_crate_graph(
|
||||
rustc_cfg.clone(),
|
||||
load,
|
||||
files,
|
||||
sysroot,
|
||||
Err("detached file projects have no target layout set".into()),
|
||||
)
|
||||
}
|
||||
};
|
||||
if crate_graph.patch_cfg_if() {
|
||||
|
@ -573,6 +628,49 @@ impl ProjectWorkspace {
|
|||
}
|
||||
crate_graph
|
||||
}
|
||||
|
||||
pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(
|
||||
Self::Cargo {
|
||||
cargo,
|
||||
sysroot,
|
||||
rustc,
|
||||
rustc_cfg,
|
||||
cfg_overrides,
|
||||
toolchain,
|
||||
build_scripts: _,
|
||||
target_layout: _,
|
||||
},
|
||||
Self::Cargo {
|
||||
cargo: o_cargo,
|
||||
sysroot: o_sysroot,
|
||||
rustc: o_rustc,
|
||||
rustc_cfg: o_rustc_cfg,
|
||||
cfg_overrides: o_cfg_overrides,
|
||||
toolchain: o_toolchain,
|
||||
build_scripts: _,
|
||||
target_layout: _,
|
||||
},
|
||||
) => {
|
||||
cargo == o_cargo
|
||||
&& rustc == o_rustc
|
||||
&& rustc_cfg == o_rustc_cfg
|
||||
&& cfg_overrides == o_cfg_overrides
|
||||
&& toolchain == o_toolchain
|
||||
&& sysroot == o_sysroot
|
||||
}
|
||||
(
|
||||
Self::Json { project, sysroot, rustc_cfg },
|
||||
Self::Json { project: o_project, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
|
||||
) => project == o_project && rustc_cfg == o_rustc_cfg && sysroot == o_sysroot,
|
||||
(
|
||||
Self::DetachedFiles { files, sysroot, rustc_cfg },
|
||||
Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
|
||||
) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn project_json_to_crate_graph(
|
||||
|
@ -580,9 +678,9 @@ fn project_json_to_crate_graph(
|
|||
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
project: &ProjectJson,
|
||||
sysroot: &Option<Sysroot>,
|
||||
sysroot: Option<&Sysroot>,
|
||||
extra_env: &FxHashMap<String, String>,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
) -> CrateGraph {
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
let sysroot_deps = sysroot.as_ref().map(|sysroot| {
|
||||
|
@ -686,7 +784,7 @@ fn cargo_to_crate_graph(
|
|||
rustc_cfg: Vec<CfgFlag>,
|
||||
override_cfg: &CfgOverrides,
|
||||
build_scripts: &WorkspaceBuildScripts,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
) -> CrateGraph {
|
||||
let _p = profile::span("cargo_to_crate_graph");
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
|
@ -852,7 +950,7 @@ fn detached_files_to_crate_graph(
|
|||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
detached_files: &[AbsPathBuf],
|
||||
sysroot: &Option<Sysroot>,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
) -> CrateGraph {
|
||||
let _p = profile::span("detached_files_to_crate_graph");
|
||||
let mut crate_graph = CrateGraph::default();
|
||||
|
@ -917,7 +1015,7 @@ fn handle_rustc_crates(
|
|||
cfg_options: &CfgOptions,
|
||||
override_cfg: &CfgOverrides,
|
||||
build_scripts: &WorkspaceBuildScripts,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
) {
|
||||
let mut rustc_pkg_crates = FxHashMap::default();
|
||||
// The root package of the rustc-dev component is rustc_driver, so we match that
|
||||
|
@ -1039,7 +1137,7 @@ fn add_target_crate_root(
|
|||
file_id: FileId,
|
||||
cargo_name: &str,
|
||||
is_proc_macro: bool,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
) -> CrateId {
|
||||
let edition = pkg.edition;
|
||||
let mut potential_cfg_options = cfg_options.clone();
|
||||
|
@ -1108,7 +1206,7 @@ fn sysroot_to_crate_graph(
|
|||
crate_graph: &mut CrateGraph,
|
||||
sysroot: &Sysroot,
|
||||
rustc_cfg: Vec<CfgFlag>,
|
||||
target_layout: Option<Arc<str>>,
|
||||
target_layout: TargetLayoutLoadResult,
|
||||
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
|
||||
) -> (SysrootPublicDeps, Option<CrateId>) {
|
||||
let _p = profile::span("sysroot_to_crate_graph");
|
||||
|
@ -1150,9 +1248,7 @@ fn sysroot_to_crate_graph(
|
|||
let public_deps = SysrootPublicDeps {
|
||||
deps: sysroot
|
||||
.public_deps()
|
||||
.map(|(name, idx, prelude)| {
|
||||
(CrateName::new(name).unwrap(), sysroot_crates[&idx], prelude)
|
||||
})
|
||||
.map(|(name, idx, prelude)| (name, sysroot_crates[&idx], prelude))
|
||||
.collect::<Vec<_>>(),
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue