aboutsummaryrefslogtreecommitdiff
path: root/crates/project_model/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/project_model/src')
-rw-r--r--crates/project_model/src/lib.rs245
-rw-r--r--crates/project_model/src/project_json.rs19
-rw-r--r--crates/project_model/src/sysroot.rs20
3 files changed, 143 insertions, 141 deletions
diff --git a/crates/project_model/src/lib.rs b/crates/project_model/src/lib.rs
index 2d65fc076..2d91939ce 100644
--- a/crates/project_model/src/lib.rs
+++ b/crates/project_model/src/lib.rs
@@ -39,11 +39,18 @@ pub enum ProjectWorkspace {
39impl fmt::Debug for ProjectWorkspace { 39impl fmt::Debug for ProjectWorkspace {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 match self { 41 match self {
42 ProjectWorkspace::Cargo { cargo, .. } => { 42 ProjectWorkspace::Cargo { cargo, sysroot } => f
43 f.debug_struct("Cargo").field("n_packages", &cargo.packages().len()).finish() 43 .debug_struct("Cargo")
44 } 44 .field("n_packages", &cargo.packages().len())
45 .field("n_sysroot_crates", &sysroot.crates().len())
46 .finish(),
45 ProjectWorkspace::Json { project } => { 47 ProjectWorkspace::Json { project } => {
46 f.debug_struct("Json").field("n_crates", &project.crates.len()).finish() 48 let mut debug_struct = f.debug_struct("Json");
49 debug_struct.field("n_crates", &project.n_crates());
50 if let Some(sysroot) = &project.sysroot {
51 debug_struct.field("n_sysroot_crates", &sysroot.crates().len());
52 }
53 debug_struct.finish()
47 } 54 }
48 } 55 }
49 } 56 }
@@ -202,15 +209,21 @@ impl ProjectWorkspace {
202 pub fn to_roots(&self) -> Vec<PackageRoot> { 209 pub fn to_roots(&self) -> Vec<PackageRoot> {
203 match self { 210 match self {
204 ProjectWorkspace::Json { project } => project 211 ProjectWorkspace::Json { project } => project
205 .crates 212 .crates()
206 .iter() 213 .map(|(_, krate)| PackageRoot {
207 .map(|krate| PackageRoot {
208 is_member: krate.is_workspace_member, 214 is_member: krate.is_workspace_member,
209 include: krate.include.clone(), 215 include: krate.include.clone(),
210 exclude: krate.exclude.clone(), 216 exclude: krate.exclude.clone(),
211 }) 217 })
212 .collect::<FxHashSet<_>>() 218 .collect::<FxHashSet<_>>()
213 .into_iter() 219 .into_iter()
220 .chain(project.sysroot.as_ref().into_iter().flat_map(|sysroot| {
221 sysroot.crates().map(move |krate| PackageRoot {
222 is_member: false,
223 include: vec![sysroot[krate].root_dir().to_path_buf()],
224 exclude: Vec::new(),
225 })
226 }))
214 .collect::<Vec<_>>(), 227 .collect::<Vec<_>>(),
215 ProjectWorkspace::Cargo { cargo, sysroot } => cargo 228 ProjectWorkspace::Cargo { cargo, sysroot } => cargo
216 .packages() 229 .packages()
@@ -243,9 +256,8 @@ impl ProjectWorkspace {
243 pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { 256 pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> {
244 match self { 257 match self {
245 ProjectWorkspace::Json { project } => project 258 ProjectWorkspace::Json { project } => project
246 .crates 259 .crates()
247 .iter() 260 .filter_map(|(_, krate)| krate.proc_macro_dylib_path.as_ref())
248 .filter_map(|krate| krate.proc_macro_dylib_path.as_ref())
249 .cloned() 261 .cloned()
250 .collect(), 262 .collect(),
251 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo 263 ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo
@@ -258,7 +270,7 @@ impl ProjectWorkspace {
258 270
259 pub fn n_packages(&self) -> usize { 271 pub fn n_packages(&self) -> usize {
260 match self { 272 match self {
261 ProjectWorkspace::Json { project, .. } => project.crates.len(), 273 ProjectWorkspace::Json { project, .. } => project.n_crates(),
262 ProjectWorkspace::Cargo { cargo, sysroot } => { 274 ProjectWorkspace::Cargo { cargo, sysroot } => {
263 cargo.packages().len() + sysroot.crates().len() 275 cargo.packages().len() + sysroot.crates().len()
264 } 276 }
@@ -274,12 +286,15 @@ impl ProjectWorkspace {
274 let mut crate_graph = CrateGraph::default(); 286 let mut crate_graph = CrateGraph::default();
275 match self { 287 match self {
276 ProjectWorkspace::Json { project } => { 288 ProjectWorkspace::Json { project } => {
289 let sysroot_dps = project
290 .sysroot
291 .as_ref()
292 .map(|sysroot| sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load));
293
277 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default(); 294 let mut cfg_cache: FxHashMap<Option<&str>, Vec<CfgFlag>> = FxHashMap::default();
278 let crates: FxHashMap<_, _> = project 295 let crates: FxHashMap<_, _> = project
279 .crates 296 .crates()
280 .iter() 297 .filter_map(|(crate_id, krate)| {
281 .enumerate()
282 .filter_map(|(seq_index, krate)| {
283 let file_path = &krate.root_module; 298 let file_path = &krate.root_module;
284 let file_id = load(&file_path)?; 299 let file_id = load(&file_path)?;
285 300
@@ -297,9 +312,8 @@ impl ProjectWorkspace {
297 let mut cfg_options = CfgOptions::default(); 312 let mut cfg_options = CfgOptions::default();
298 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned()); 313 cfg_options.extend(target_cfgs.iter().chain(krate.cfg.iter()).cloned());
299 314
300 // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env
301 Some(( 315 Some((
302 CrateId(seq_index as u32), 316 crate_id,
303 crate_graph.add_crate_root( 317 crate_graph.add_crate_root(
304 file_id, 318 file_id,
305 krate.edition, 319 krate.edition,
@@ -313,67 +327,33 @@ impl ProjectWorkspace {
313 }) 327 })
314 .collect(); 328 .collect();
315 329
316 for (id, krate) in project.crates.iter().enumerate() { 330 for (from, krate) in project.crates() {
317 for dep in &krate.deps { 331 if let Some(&from) = crates.get(&from) {
318 let from_crate_id = CrateId(id as u32); 332 if let Some((public_deps, _proc_macro)) = &sysroot_dps {
319 let to_crate_id = dep.crate_id; 333 for (name, to) in public_deps.iter() {
320 if let (Some(&from), Some(&to)) = 334 if let Err(_) = crate_graph.add_dep(from, name.clone(), *to) {
321 (crates.get(&from_crate_id), crates.get(&to_crate_id)) 335 log::error!("cyclic dependency on {} for {:?}", name, from)
322 { 336 }
323 if crate_graph.add_dep(from, dep.name.clone(), to).is_err() {
324 log::error!(
325 "cyclic dependency {:?} -> {:?}",
326 from_crate_id,
327 to_crate_id
328 );
329 } 337 }
330 } 338 }
331 }
332 }
333 }
334 ProjectWorkspace::Cargo { cargo, sysroot } => {
335 let mut cfg_options = CfgOptions::default();
336 cfg_options.extend(get_rustc_cfg_options(target));
337
338 let sysroot_crates: FxHashMap<_, _> = sysroot
339 .crates()
340 .filter_map(|krate| {
341 let file_id = load(&sysroot[krate].root)?;
342
343 let env = Env::default();
344 let proc_macro = vec![];
345 let name = sysroot[krate].name.clone();
346 let crate_id = crate_graph.add_crate_root(
347 file_id,
348 Edition::Edition2018,
349 Some(name),
350 cfg_options.clone(),
351 env,
352 proc_macro,
353 );
354 Some((krate, crate_id))
355 })
356 .collect();
357 339
358 for from in sysroot.crates() { 340 for dep in &krate.deps {
359 for &to in sysroot[from].deps.iter() { 341 let to_crate_id = dep.crate_id;
360 let name = &sysroot[to].name; 342 if let Some(&to) = crates.get(&to_crate_id) {
361 if let (Some(&from), Some(&to)) = 343 if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
362 (sysroot_crates.get(&from), sysroot_crates.get(&to)) 344 log::error!("cyclic dependency {:?} -> {:?}", from, to);
363 { 345 }
364 if crate_graph.add_dep(from, CrateName::new(name).unwrap(), to).is_err()
365 {
366 log::error!("cyclic dependency between sysroot crates")
367 } 346 }
368 } 347 }
369 } 348 }
370 } 349 }
350 }
351 ProjectWorkspace::Cargo { cargo, sysroot } => {
352 let (public_deps, libproc_macro) =
353 sysroot_to_crate_graph(&mut crate_graph, sysroot, target, load);
371 354
372 let libcore = sysroot.core().and_then(|it| sysroot_crates.get(&it).copied()); 355 let mut cfg_options = CfgOptions::default();
373 let liballoc = sysroot.alloc().and_then(|it| sysroot_crates.get(&it).copied()); 356 cfg_options.extend(get_rustc_cfg_options(target));
374 let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).copied());
375 let libproc_macro =
376 sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
377 357
378 let mut pkg_to_lib_crate = FxHashMap::default(); 358 let mut pkg_to_lib_crate = FxHashMap::default();
379 let mut pkg_crates = FxHashMap::default(); 359 let mut pkg_crates = FxHashMap::default();
@@ -424,14 +404,11 @@ impl ProjectWorkspace {
424 } 404 }
425 if cargo[tgt].is_proc_macro { 405 if cargo[tgt].is_proc_macro {
426 if let Some(proc_macro) = libproc_macro { 406 if let Some(proc_macro) = libproc_macro {
427 if crate_graph 407 if let Err(_) = crate_graph.add_dep(
428 .add_dep( 408 crate_id,
429 crate_id, 409 CrateName::new("proc_macro").unwrap(),
430 CrateName::new("proc_macro").unwrap(), 410 proc_macro,
431 proc_macro, 411 ) {
432 )
433 .is_err()
434 {
435 log::error!( 412 log::error!(
436 "cyclic dependency on proc_macro for {}", 413 "cyclic dependency on proc_macro for {}",
437 &cargo[pkg].name 414 &cargo[pkg].name
@@ -447,50 +424,24 @@ impl ProjectWorkspace {
447 // Set deps to the core, std and to the lib target of the current package 424 // Set deps to the core, std and to the lib target of the current package
448 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 425 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
449 if let Some((to, name)) = lib_tgt.clone() { 426 if let Some((to, name)) = lib_tgt.clone() {
450 if to != from 427 // For root projects with dashes in their name,
451 && crate_graph 428 // cargo metadata does not do any normalization,
452 .add_dep( 429 // so we do it ourselves currently
453 from, 430 let name = CrateName::normalize_dashes(&name);
454 // For root projects with dashes in their name, 431 if to != from && crate_graph.add_dep(from, name, to).is_err() {
455 // cargo metadata does not do any normalization, 432 log::error!(
456 // so we do it ourselves currently 433 "cyclic dependency between targets of {}",
457 CrateName::normalize_dashes(&name), 434 &cargo[pkg].name
458 to, 435 )
459 )
460 .is_err()
461 {
462 {
463 log::error!(
464 "cyclic dependency between targets of {}",
465 &cargo[pkg].name
466 )
467 }
468 }
469 }
470 // core is added as a dependency before std in order to
471 // mimic rustcs dependency order
472 if let Some(core) = libcore {
473 if crate_graph
474 .add_dep(from, CrateName::new("core").unwrap(), core)
475 .is_err()
476 {
477 log::error!("cyclic dependency on core for {}", &cargo[pkg].name)
478 }
479 }
480 if let Some(alloc) = liballoc {
481 if crate_graph
482 .add_dep(from, CrateName::new("alloc").unwrap(), alloc)
483 .is_err()
484 {
485 log::error!("cyclic dependency on alloc for {}", &cargo[pkg].name)
486 } 436 }
487 } 437 }
488 if let Some(std) = libstd { 438 for (name, krate) in public_deps.iter() {
489 if crate_graph 439 if let Err(_) = crate_graph.add_dep(from, name.clone(), *krate) {
490 .add_dep(from, CrateName::new("std").unwrap(), std) 440 log::error!(
491 .is_err() 441 "cyclic dependency on {} for {}",
492 { 442 name,
493 log::error!("cyclic dependency on std for {}", &cargo[pkg].name) 443 &cargo[pkg].name
444 )
494 } 445 }
495 } 446 }
496 } 447 }
@@ -500,12 +451,10 @@ impl ProjectWorkspace {
500 // target of downstream. 451 // target of downstream.
501 for pkg in cargo.packages() { 452 for pkg in cargo.packages() {
502 for dep in cargo[pkg].dependencies.iter() { 453 for dep in cargo[pkg].dependencies.iter() {
454 let name = CrateName::new(&dep.name).unwrap();
503 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 455 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
504 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 456 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
505 if crate_graph 457 if let Err(_) = crate_graph.add_dep(from, name.clone(), to) {
506 .add_dep(from, CrateName::new(&dep.name).unwrap(), to)
507 .is_err()
508 {
509 log::error!( 458 log::error!(
510 "cyclic dependency {} -> {}", 459 "cyclic dependency {} -> {}",
511 &cargo[pkg].name, 460 &cargo[pkg].name,
@@ -563,3 +512,51 @@ fn utf8_stdout(mut cmd: Command) -> Result<String> {
563 let stdout = String::from_utf8(output.stdout)?; 512 let stdout = String::from_utf8(output.stdout)?;
564 Ok(stdout.trim().to_string()) 513 Ok(stdout.trim().to_string())
565} 514}
515
516fn sysroot_to_crate_graph(
517 crate_graph: &mut CrateGraph,
518 sysroot: &Sysroot,
519 target: Option<&str>,
520 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
521) -> (Vec<(CrateName, CrateId)>, Option<CrateId>) {
522 let mut cfg_options = CfgOptions::default();
523 cfg_options.extend(get_rustc_cfg_options(target));
524 let sysroot_crates: FxHashMap<_, _> = sysroot
525 .crates()
526 .filter_map(|krate| {
527 let file_id = load(&sysroot[krate].root)?;
528
529 let env = Env::default();
530 let proc_macro = vec![];
531 let name = sysroot[krate].name.clone();
532 let crate_id = crate_graph.add_crate_root(
533 file_id,
534 Edition::Edition2018,
535 Some(name),
536 cfg_options.clone(),
537 env,
538 proc_macro,
539 );
540 Some((krate, crate_id))
541 })
542 .collect();
543
544 for from in sysroot.crates() {
545 for &to in sysroot[from].deps.iter() {
546 let name = CrateName::new(&sysroot[to].name).unwrap();
547 if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
548 if let Err(_) = crate_graph.add_dep(from, name, to) {
549 log::error!("cyclic dependency between sysroot crates")
550 }
551 }
552 }
553 }
554
555 let public_deps = sysroot
556 .public_deps()
557 .map(|(name, idx)| (CrateName::new(name).unwrap(), sysroot_crates[&idx]))
558 .collect::<Vec<_>>();
559
560 let libproc_macro = sysroot.proc_macro().and_then(|it| sysroot_crates.get(&it).copied());
561 (public_deps, libproc_macro)
562}
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs
index 060ea5b7d..5a0fe749a 100644
--- a/crates/project_model/src/project_json.rs
+++ b/crates/project_model/src/project_json.rs
@@ -7,12 +7,13 @@ use paths::{AbsPath, AbsPathBuf};
7use rustc_hash::FxHashMap; 7use rustc_hash::FxHashMap;
8use serde::{de, Deserialize}; 8use serde::{de, Deserialize};
9 9
10use crate::cfg_flag::CfgFlag; 10use crate::{cfg_flag::CfgFlag, Sysroot};
11 11
12/// Roots and crates that compose this Rust project. 12/// Roots and crates that compose this Rust project.
13#[derive(Clone, Debug, Eq, PartialEq)] 13#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct ProjectJson { 14pub struct ProjectJson {
15 pub(crate) crates: Vec<Crate>, 15 pub(crate) sysroot: Option<Sysroot>,
16 crates: Vec<Crate>,
16} 17}
17 18
18/// A crate points to the root module of a crate and lists the dependencies of the crate. This is 19/// A crate points to the root module of a crate and lists the dependencies of the crate. This is
@@ -34,6 +35,7 @@ pub struct Crate {
34impl ProjectJson { 35impl ProjectJson {
35 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { 36 pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
36 ProjectJson { 37 ProjectJson {
38 sysroot: data.sysroot_src.map(|it| base.join(it)).map(|it| Sysroot::load(&it)),
37 crates: data 39 crates: data
38 .crates 40 .crates
39 .into_iter() 41 .into_iter()
@@ -43,11 +45,13 @@ impl ProjectJson {
43 && !crate_data.root_module.starts_with("..") 45 && !crate_data.root_module.starts_with("..")
44 || crate_data.root_module.starts_with(base) 46 || crate_data.root_module.starts_with(base)
45 }); 47 });
46 let root_module = base.join(crate_data.root_module); 48 let root_module = base.join(crate_data.root_module).normalize();
47 let (include, exclude) = match crate_data.source { 49 let (include, exclude) = match crate_data.source {
48 Some(src) => { 50 Some(src) => {
49 let absolutize = |dirs: Vec<PathBuf>| { 51 let absolutize = |dirs: Vec<PathBuf>| {
50 dirs.into_iter().map(|it| base.join(it)).collect::<Vec<_>>() 52 dirs.into_iter()
53 .map(|it| base.join(it).normalize())
54 .collect::<Vec<_>>()
51 }; 55 };
52 (absolutize(src.include_dirs), absolutize(src.exclude_dirs)) 56 (absolutize(src.include_dirs), absolutize(src.exclude_dirs))
53 } 57 }
@@ -79,10 +83,17 @@ impl ProjectJson {
79 .collect::<Vec<_>>(), 83 .collect::<Vec<_>>(),
80 } 84 }
81 } 85 }
86 pub fn n_crates(&self) -> usize {
87 self.crates.len()
88 }
89 pub fn crates(&self) -> impl Iterator<Item = (CrateId, &Crate)> + '_ {
90 self.crates.iter().enumerate().map(|(idx, krate)| (CrateId(idx as u32), krate))
91 }
82} 92}
83 93
84#[derive(Deserialize)] 94#[derive(Deserialize)]
85pub struct ProjectJsonData { 95pub struct ProjectJsonData {
96 sysroot_src: Option<PathBuf>,
86 crates: Vec<CrateData>, 97 crates: Vec<CrateData>,
87} 98}
88 99
diff --git a/crates/project_model/src/sysroot.rs b/crates/project_model/src/sysroot.rs
index 687e15337..74c0eda9a 100644
--- a/crates/project_model/src/sysroot.rs
+++ b/crates/project_model/src/sysroot.rs
@@ -34,16 +34,10 @@ impl ops::Index<SysrootCrate> for Sysroot {
34} 34}
35 35
36impl Sysroot { 36impl Sysroot {
37 pub fn core(&self) -> Option<SysrootCrate> { 37 pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
38 self.by_name("core") 38 // core is added as a dependency before std in order to
39 } 39 // mimic rustcs dependency order
40 40 vec!["core", "alloc", "std"].into_iter().filter_map(move |it| Some((it, self.by_name(it)?)))
41 pub fn alloc(&self) -> Option<SysrootCrate> {
42 self.by_name("alloc")
43 }
44
45 pub fn std(&self) -> Option<SysrootCrate> {
46 self.by_name("std")
47 } 41 }
48 42
49 pub fn proc_macro(&self) -> Option<SysrootCrate> { 43 pub fn proc_macro(&self) -> Option<SysrootCrate> {
@@ -81,7 +75,7 @@ impl Sysroot {
81 } 75 }
82 } 76 }
83 77
84 if let Some(std) = sysroot.std() { 78 if let Some(std) = sysroot.by_name("std") {
85 for dep in STD_DEPS.trim().lines() { 79 for dep in STD_DEPS.trim().lines() {
86 if let Some(dep) = sysroot.by_name(dep) { 80 if let Some(dep) = sysroot.by_name(dep) {
87 sysroot.crates[std].deps.push(dep) 81 sysroot.crates[std].deps.push(dep)
@@ -89,8 +83,8 @@ impl Sysroot {
89 } 83 }
90 } 84 }
91 85
92 if let Some(alloc) = sysroot.alloc() { 86 if let Some(alloc) = sysroot.by_name("alloc") {
93 if let Some(core) = sysroot.core() { 87 if let Some(core) = sysroot.by_name("core") {
94 sysroot.crates[alloc].deps.push(core); 88 sysroot.crates[alloc].deps.push(core);
95 } 89 }
96 } 90 }