Skip to content

Commit e50bc18

Browse files
authored
Merge pull request #19096 from darichey/rust-project-sysroot
Allow rust-project.json to specify sysroot workspace
2 parents d69e2e7 + 18a678e commit e50bc18

File tree

8 files changed

+146
-1228
lines changed

8 files changed

+146
-1228
lines changed

crates/project-model/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ fn parse_cfg(s: &str) -> Result<cfg::CfgAtom, String> {
262262
#[derive(Clone, Debug, PartialEq, Eq)]
263263
pub enum RustSourceWorkspaceConfig {
264264
CargoMetadata(CargoMetadataConfig),
265-
Stitched,
265+
Json(ProjectJson),
266266
}
267267

268268
impl Default for RustSourceWorkspaceConfig {

crates/project-model/src/project_json.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub struct ProjectJson {
6565
pub(crate) sysroot: Option<AbsPathBuf>,
6666
/// e.g. `path/to/sysroot/lib/rustlib/src/rust/library`
6767
pub(crate) sysroot_src: Option<AbsPathBuf>,
68+
/// A nested project describing the layout of the sysroot
69+
pub(crate) sysroot_project: Option<Box<ProjectJson>>,
6870
project_root: AbsPathBuf,
6971
/// The path to the rust-project.json file. May be None if this
7072
/// data was generated by the discoverConfig command.
@@ -91,9 +93,16 @@ impl ProjectJson {
9193
data: ProjectJsonData,
9294
) -> ProjectJson {
9395
let absolutize_on_base = |p| base.absolutize(p);
96+
let sysroot_src = data.sysroot_src.map(absolutize_on_base);
97+
let sysroot_project =
98+
data.sysroot_project.zip(sysroot_src.clone()).map(|(sysroot_data, sysroot_src)| {
99+
Box::new(ProjectJson::new(None, &sysroot_src, *sysroot_data))
100+
});
101+
94102
ProjectJson {
95103
sysroot: data.sysroot.map(absolutize_on_base),
96-
sysroot_src: data.sysroot_src.map(absolutize_on_base),
104+
sysroot_src,
105+
sysroot_project,
97106
project_root: base.to_path_buf(),
98107
manifest,
99108
runnables: data.runnables.into_iter().map(Runnable::from).collect(),
@@ -330,6 +339,7 @@ pub enum RunnableKind {
330339
pub struct ProjectJsonData {
331340
sysroot: Option<Utf8PathBuf>,
332341
sysroot_src: Option<Utf8PathBuf>,
342+
sysroot_project: Option<Box<ProjectJsonData>>,
333343
#[serde(default)]
334344
cfg_groups: FxHashMap<String, CfgList>,
335345
crates: Vec<CrateData>,

crates/project-model/src/sysroot.rs

Lines changed: 12 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,17 @@
44
//! but we can't process `.rlib` and need source code instead. The source code
55
//! is typically installed with `rustup component add rust-src` command.
66
7-
use std::{
8-
env, fs,
9-
ops::{self, Not},
10-
path::Path,
11-
process::Command,
12-
};
7+
use std::{env, fs, ops::Not, path::Path, process::Command};
138

149
use anyhow::{format_err, Result};
15-
use base_db::CrateName;
1610
use itertools::Itertools;
17-
use la_arena::{Arena, Idx};
1811
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
1912
use rustc_hash::FxHashMap;
2013
use stdx::format_to;
2114
use toolchain::{probe_for_binary, Tool};
2215

2316
use crate::{
24-
cargo_workspace::CargoMetadataConfig, utf8_stdout, CargoWorkspace, ManifestPath,
17+
cargo_workspace::CargoMetadataConfig, utf8_stdout, CargoWorkspace, ManifestPath, ProjectJson,
2518
RustSourceWorkspaceConfig,
2619
};
2720

@@ -36,58 +29,10 @@ pub struct Sysroot {
3629
#[derive(Debug, Clone, Eq, PartialEq)]
3730
pub enum RustLibSrcWorkspace {
3831
Workspace(CargoWorkspace),
39-
Stitched(Stitched),
32+
Json(ProjectJson),
4033
Empty,
4134
}
4235

43-
#[derive(Debug, Clone, Eq, PartialEq)]
44-
pub struct Stitched {
45-
crates: Arena<RustLibSrcCrateData>,
46-
}
47-
48-
impl ops::Index<RustLibSrcCrate> for Stitched {
49-
type Output = RustLibSrcCrateData;
50-
fn index(&self, index: RustLibSrcCrate) -> &RustLibSrcCrateData {
51-
&self.crates[index]
52-
}
53-
}
54-
55-
impl Stitched {
56-
pub(crate) fn public_deps(
57-
&self,
58-
) -> impl Iterator<Item = (CrateName, RustLibSrcCrate, bool)> + '_ {
59-
// core is added as a dependency before std in order to
60-
// mimic rustcs dependency order
61-
[("core", true), ("alloc", false), ("std", true), ("test", false)].into_iter().filter_map(
62-
move |(name, prelude)| {
63-
Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
64-
},
65-
)
66-
}
67-
68-
pub(crate) fn proc_macro(&self) -> Option<RustLibSrcCrate> {
69-
self.by_name("proc_macro")
70-
}
71-
72-
pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = RustLibSrcCrate> + '_ {
73-
self.crates.iter().map(|(id, _data)| id)
74-
}
75-
76-
fn by_name(&self, name: &str) -> Option<RustLibSrcCrate> {
77-
let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
78-
Some(id)
79-
}
80-
}
81-
82-
pub(crate) type RustLibSrcCrate = Idx<RustLibSrcCrateData>;
83-
84-
#[derive(Debug, Clone, Eq, PartialEq)]
85-
pub(crate) struct RustLibSrcCrateData {
86-
pub(crate) name: String,
87-
pub(crate) root: ManifestPath,
88-
pub(crate) deps: Vec<RustLibSrcCrate>,
89-
}
90-
9136
impl Sysroot {
9237
pub const fn empty() -> Sysroot {
9338
Sysroot {
@@ -114,7 +59,7 @@ impl Sysroot {
11459
pub fn is_rust_lib_src_empty(&self) -> bool {
11560
match &self.workspace {
11661
RustLibSrcWorkspace::Workspace(ws) => ws.packages().next().is_none(),
117-
RustLibSrcWorkspace::Stitched(stitched) => stitched.crates.is_empty(),
62+
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates() == 0,
11863
RustLibSrcWorkspace::Empty => true,
11964
}
12065
}
@@ -126,7 +71,7 @@ impl Sysroot {
12671
pub fn num_packages(&self) -> usize {
12772
match &self.workspace {
12873
RustLibSrcWorkspace::Workspace(ws) => ws.packages().count(),
129-
RustLibSrcWorkspace::Stitched(c) => c.crates().count(),
74+
RustLibSrcWorkspace::Json(project_json) => project_json.n_crates(),
13075
RustLibSrcWorkspace::Empty => 0,
13176
}
13277
}
@@ -252,52 +197,11 @@ impl Sysroot {
252197
return Some(loaded);
253198
}
254199
}
255-
}
256-
tracing::debug!("Stitching sysroot library: {src_root}");
257-
258-
let mut stitched = Stitched { crates: Arena::default() };
259-
260-
for path in SYSROOT_CRATES.trim().lines() {
261-
let name = path.split('/').last().unwrap();
262-
let root = [format!("{path}/src/lib.rs"), format!("lib{path}/lib.rs")]
263-
.into_iter()
264-
.map(|it| src_root.join(it))
265-
.filter_map(|it| ManifestPath::try_from(it).ok())
266-
.find(|it| fs::metadata(it).is_ok());
267-
268-
if let Some(root) = root {
269-
stitched.crates.alloc(RustLibSrcCrateData {
270-
name: name.into(),
271-
root,
272-
deps: Vec::new(),
273-
});
274-
}
275-
}
276-
277-
if let Some(std) = stitched.by_name("std") {
278-
for dep in STD_DEPS.trim().lines() {
279-
if let Some(dep) = stitched.by_name(dep) {
280-
stitched.crates[std].deps.push(dep)
281-
}
282-
}
283-
}
284-
285-
if let Some(alloc) = stitched.by_name("alloc") {
286-
for dep in ALLOC_DEPS.trim().lines() {
287-
if let Some(dep) = stitched.by_name(dep) {
288-
stitched.crates[alloc].deps.push(dep)
289-
}
290-
}
200+
} else if let RustSourceWorkspaceConfig::Json(project_json) = sysroot_source_config {
201+
return Some(RustLibSrcWorkspace::Json(project_json.clone()));
291202
}
292203

293-
if let Some(proc_macro) = stitched.by_name("proc_macro") {
294-
for dep in PROC_MACRO_DEPS.trim().lines() {
295-
if let Some(dep) = stitched.by_name(dep) {
296-
stitched.crates[proc_macro].deps.push(dep)
297-
}
298-
}
299-
}
300-
Some(RustLibSrcWorkspace::Stitched(stitched))
204+
None
301205
}
302206

303207
pub fn set_workspace(&mut self, workspace: RustLibSrcWorkspace) {
@@ -308,7 +212,10 @@ impl Sysroot {
308212
RustLibSrcWorkspace::Workspace(ws) => {
309213
ws.packages().any(|p| ws[p].name == "core")
310214
}
311-
RustLibSrcWorkspace::Stitched(stitched) => stitched.by_name("core").is_some(),
215+
RustLibSrcWorkspace::Json(project_json) => project_json
216+
.crates()
217+
.filter_map(|(_, krate)| krate.display_name.clone())
218+
.any(|name| name.canonical_name().as_str() == "core"),
312219
RustLibSrcWorkspace::Empty => true,
313220
};
314221
if !has_core {
@@ -484,33 +391,3 @@ fn get_rust_lib_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
484391
None
485392
}
486393
}
487-
488-
const SYSROOT_CRATES: &str = "
489-
alloc
490-
backtrace
491-
core
492-
panic_abort
493-
panic_unwind
494-
proc_macro
495-
profiler_builtins
496-
std
497-
stdarch/crates/std_detect
498-
test
499-
unwind";
500-
501-
const ALLOC_DEPS: &str = "core";
502-
503-
const STD_DEPS: &str = "
504-
alloc
505-
panic_unwind
506-
panic_abort
507-
core
508-
profiler_builtins
509-
unwind
510-
std_detect
511-
test";
512-
513-
// core is required for our builtin derives to work in the proc_macro lib currently
514-
const PROC_MACRO_DEPS: &str = "
515-
std
516-
core";

crates/project-model/src/tests.rs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::ops::Deref;
2-
31
use base_db::{CrateGraph, ProcMacroPaths};
42
use cargo_metadata::Metadata;
53
use cfg::{CfgAtom, CfgDiff};
@@ -225,18 +223,6 @@ fn rust_project_cfg_groups() {
225223
check_crate_graph(crate_graph, expect_file!["../test_data/output/rust_project_cfg_groups.txt"]);
226224
}
227225

228-
#[test]
229-
fn rust_project_is_proc_macro_has_proc_macro_dep() {
230-
let (crate_graph, _proc_macros) = load_rust_project("is-proc-macro-project.json");
231-
// Since the project only defines one crate (outside the sysroot crates),
232-
// it should be the one with the biggest Id.
233-
let crate_id = crate_graph.iter().max().unwrap();
234-
let crate_data = &crate_graph[crate_id];
235-
// Assert that the project crate with `is_proc_macro` has a dependency
236-
// on the proc_macro sysroot crate.
237-
crate_data.dependencies.iter().find(|&dep| *dep.name.deref() == sym::proc_macro).unwrap();
238-
}
239-
240226
#[test]
241227
fn crate_graph_dedup_identical() {
242228
let (mut crate_graph, proc_macros) = load_cargo("regex-metadata.json");

0 commit comments

Comments
 (0)