From 31db1fc75fe24c81e58ba7ee4612e4be3f323f95 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 31 Mar 2023 09:10:18 +0200 Subject: [PATCH] internal: Refine CrateOrigin variants --- crates/base-db/src/fixture.rs | 17 +- crates/base-db/src/input.rs | 70 +++- crates/base-db/src/lib.rs | 4 +- crates/ide/src/doc_links.rs | 31 +- crates/ide/src/lib.rs | 3 +- crates/ide/src/moniker.rs | 8 +- crates/ide/src/shuffle_crate_graph.rs | 1 + .../test_data/highlight_extern_crate.html | 2 +- crates/project-model/src/tests.rs | 298 ++++++++---------- crates/project-model/src/workspace.rs | 121 +++++-- crates/rust-analyzer/src/reload.rs | 21 +- crates/vfs/src/lib.rs | 2 +- 12 files changed, 343 insertions(+), 235 deletions(-) diff --git a/crates/base-db/src/fixture.rs b/crates/base-db/src/fixture.rs index 7269180a5d6..0ce8ec864be 100644 --- a/crates/base-db/src/fixture.rs +++ b/crates/base-db/src/fixture.rs @@ -166,6 +166,7 @@ pub fn parse_with_proc_macros( .as_deref() .map(Arc::from) .ok_or_else(|| "target_data_layout unset".into()), + None, ); let prev = crates.insert(crate_name.clone(), crate_id); assert!(prev.is_none()); @@ -200,10 +201,11 @@ pub fn parse_with_proc_macros( default_cfg, Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, default_target_data_layout .map(|x| x.into()) .ok_or_else(|| "target_data_layout unset".into()), + None, ); } else { for (from, to, prelude) in crate_deps { @@ -245,6 +247,7 @@ pub fn parse_with_proc_macros( false, CrateOrigin::Lang(LangCrateOrigin::Core), target_layout.clone(), + None, ); for krate in all_crates { @@ -281,8 +284,9 @@ pub fn parse_with_proc_macros( CfgOptions::default(), Env::default(), true, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, target_layout, + None, ); proc_macros.insert(proc_macros_crate, Ok(proc_macro)); @@ -427,7 +431,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { let (version, origin) = match b.split_once(':') { Some(("CratesIo", data)) => match data.split_once(',') { Some((version, url)) => { - (version, CrateOrigin::CratesIo { repo: Some(url.to_owned()), name: None }) + (version, CrateOrigin::Local { repo: Some(url.to_owned()), name: None }) } _ => panic!("Bad crates.io parameter: {data}"), }, @@ -435,10 +439,9 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option) { }; (a.to_owned(), origin, Some(version.to_string())) } else { - let crate_origin = match &*crate_str { - "std" => CrateOrigin::Lang(LangCrateOrigin::Std), - "core" => CrateOrigin::Lang(LangCrateOrigin::Core), - _ => CrateOrigin::CratesIo { repo: None, name: None }, + let crate_origin = match LangCrateOrigin::from(&*crate_str) { + LangCrateOrigin::Other => CrateOrigin::Local { repo: None, name: None }, + origin => CrateOrigin::Lang(origin), }; (crate_str, crate_origin, None) } diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs index 3a8c0c385a4..e65568bb8ef 100644 --- a/crates/base-db/src/input.rs +++ b/crates/base-db/src/input.rs @@ -135,8 +135,12 @@ fn deref(&self) -> &str { /// Origin of the crates. It is used in emitting monikers. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum CrateOrigin { - /// Crates that are from crates.io official registry, - CratesIo { repo: Option, name: Option }, + /// Crates that are from the rustc workspace + Rustc { name: String }, + /// Crates that are workspace members, + Local { repo: Option, name: Option }, + /// Crates that are non member libraries. + Library { repo: Option, name: String }, /// Crates that are provided by the language, like std, core, proc-macro, ... Lang(LangCrateOrigin), } @@ -257,6 +261,32 @@ pub struct ProcMacro { pub expander: Arc, } +#[derive(Debug, Copy, Clone)] +pub enum ReleaseChannel { + Stable, + Beta, + Nightly, +} + +impl ReleaseChannel { + pub fn as_str(self) -> &'static str { + match self { + ReleaseChannel::Stable => "stable", + ReleaseChannel::Beta => "beta", + ReleaseChannel::Nightly => "nightly", + } + } + + pub fn from_str(str: &str) -> Option { + Some(match str { + "stable" => ReleaseChannel::Stable, + "beta" => ReleaseChannel::Beta, + "nightly" => ReleaseChannel::Nightly, + _ => return None, + }) + } +} + #[derive(Debug, Clone)] pub struct CrateData { pub root_file_id: FileId, @@ -271,11 +301,13 @@ pub struct CrateData { pub display_name: Option, pub cfg_options: CfgOptions, pub potential_cfg_options: CfgOptions, - pub target_layout: TargetLayoutLoadResult, pub env: Env, pub dependencies: Vec, pub origin: CrateOrigin, pub is_proc_macro: bool, + // FIXME: These things should not be per crate! These are more per workspace crate graph level things + pub target_layout: TargetLayoutLoadResult, + pub channel: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -329,6 +361,7 @@ pub fn add_crate_root( is_proc_macro: bool, origin: CrateOrigin, target_layout: Result, Arc>, + channel: Option, ) -> CrateId { let data = CrateData { root_file_id, @@ -342,6 +375,7 @@ pub fn add_crate_root( origin, target_layout, is_proc_macro, + channel, }; let crate_id = CrateId(self.arena.len() as u32); let prev = self.arena.insert(crate_id, data); @@ -653,8 +687,9 @@ fn detect_cyclic_dependency_indirect() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), @@ -665,8 +700,9 @@ fn detect_cyclic_dependency_indirect() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), @@ -677,8 +713,9 @@ fn detect_cyclic_dependency_indirect() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -703,8 +740,9 @@ fn detect_cyclic_dependency_direct() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), @@ -715,8 +753,9 @@ fn detect_cyclic_dependency_direct() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -738,8 +777,9 @@ fn it_works() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), @@ -750,8 +790,9 @@ fn it_works() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate3 = graph.add_crate_root( FileId(3u32), @@ -762,8 +803,9 @@ fn it_works() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2)) @@ -785,8 +827,9 @@ fn dashes_are_normalized() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); let crate2 = graph.add_crate_root( FileId(2u32), @@ -797,8 +840,9 @@ fn dashes_are_normalized() { CfgOptions::default(), Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("".into()), + None, ); assert!(graph .add_dep( diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs index f6975f2fbd7..2ffcd7a0899 100644 --- a/crates/base-db/src/lib.rs +++ b/crates/base-db/src/lib.rs @@ -16,8 +16,8 @@ input::{ CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, - ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, - SourceRootId, TargetLayoutLoadResult, + ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, + ReleaseChannel, SourceRoot, SourceRootId, TargetLayoutLoadResult, }, }; pub use salsa::{self, Cancelled}; diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs index fae25f31023..8d86c615d44 100644 --- a/crates/ide/src/doc_links.rs +++ b/crates/ide/src/doc_links.rs @@ -12,7 +12,7 @@ use hir::{db::HirDatabase, Adt, AsAssocItem, AssocItem, AssocItemContainer, HasAttrs}; use ide_db::{ - base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase}, + base_db::{CrateOrigin, LangCrateOrigin, ReleaseChannel, SourceDatabase}, defs::{Definition, NameClass, NameRefClass}, helpers::pick_best_token, RootDatabase, @@ -436,8 +436,9 @@ fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { let krate = def.krate(db)?; let display_name = krate.display_name(db)?; - - let base = match db.crate_graph()[krate.into()].origin { + let crate_data = &db.crate_graph()[krate.into()]; + let channel = crate_data.channel.map_or("nightly", ReleaseChannel::as_str); + let base = match &crate_data.origin { // std and co do not specify `html_root_url` any longer so we gotta handwrite this ourself. // FIXME: Use the toolchains channel instead of nightly CrateOrigin::Lang( @@ -447,9 +448,14 @@ fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { | LangCrateOrigin::Std | LangCrateOrigin::Test), ) => { - format!("https://doc.rust-lang.org/nightly/{origin}") + format!("https://doc.rust-lang.org/{channel}/{origin}") } - _ => { + CrateOrigin::Lang(_) => return None, + CrateOrigin::Rustc { name: _ } => { + format!("https://doc.rust-lang.org/{channel}/nightly-rustc/") + } + CrateOrigin::Local { repo: _, name: _ } => { + // FIXME: These should not attempt to link to docs.rs! krate.get_html_root_url(db).or_else(|| { let version = krate.version(db); // Fallback to docs.rs. This uses `display_name` and can never be @@ -464,6 +470,21 @@ fn get_doc_base_url(db: &RootDatabase, def: Definition) -> Option { )) })? } + CrateOrigin::Library { repo: _, name } => { + krate.get_html_root_url(db).or_else(|| { + let version = krate.version(db); + // Fallback to docs.rs. This uses `display_name` and can never be + // correct, but that's what fallbacks are about. + // + // FIXME: clicking on the link should just open the file in the editor, + // instead of falling back to external urls. + Some(format!( + "https://docs.rs/{krate}/{version}/", + krate = name, + version = version.as_deref().unwrap_or("*") + )) + })? + } }; Url::parse(&base).ok()?.join(&format!("{display_name}/")).ok() } diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index f70496451d2..22ddf91ab33 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs @@ -240,8 +240,9 @@ pub fn from_single_file(text: String) -> (Analysis, FileId) { cfg_options, Env::default(), false, - CrateOrigin::CratesIo { repo: None, name: None }, + CrateOrigin::Local { repo: None, name: None }, Err("Analysis::from_single_file has no target layout".into()), + None, ); change.change_file(file_id, Some(Arc::new(text))); change.set_crate_graph(crate_graph); diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs index 349e79ecfdd..7f36e1df547 100644 --- a/crates/ide/src/moniker.rs +++ b/crates/ide/src/moniker.rs @@ -245,11 +245,17 @@ pub(crate) fn def_to_moniker( kind: if krate == from_crate { MonikerKind::Export } else { MonikerKind::Import }, package_information: { let (name, repo, version) = match krate.origin(db) { - CrateOrigin::CratesIo { repo, name } => ( + CrateOrigin::Library { repo, name } => (name, repo, krate.version(db)), + CrateOrigin::Local { repo, name } => ( name.unwrap_or(krate.display_name(db)?.canonical_name().to_string()), repo, krate.version(db), ), + CrateOrigin::Rustc { name } => ( + name.clone(), + Some("https://github.com/rust-lang/rust/".to_string()), + Some(format!("https://github.com/rust-lang/rust/compiler/{name}",)), + ), CrateOrigin::Lang(lang) => ( krate.display_name(db)?.canonical_name().to_string(), Some("https://github.com/rust-lang/rust/".to_string()), diff --git a/crates/ide/src/shuffle_crate_graph.rs b/crates/ide/src/shuffle_crate_graph.rs index 471c36dfecf..d94b15f60c8 100644 --- a/crates/ide/src/shuffle_crate_graph.rs +++ b/crates/ide/src/shuffle_crate_graph.rs @@ -40,6 +40,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { data.is_proc_macro, data.origin.clone(), data.target_layout.clone(), + data.channel, ); new_proc_macros.insert(new_id, proc_macros[&old_id].clone()); map.insert(old_id, new_id); diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index af41796e216..87b9da46e2c 100644 --- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html @@ -43,5 +43,5 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
extern crate std;
-extern crate alloc as abc;
+extern crate alloc as abc;
 
\ No newline at end of file diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs index 26c4c89f764..ea238ad5985 100644 --- a/crates/project-model/src/tests.rs +++ b/crates/project-model/src/tests.rs @@ -41,7 +41,8 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { let data = get_test_json_file(file); let project = rooted_project_json(data); let sysroot = Ok(get_fake_sysroot()); - let project_workspace = ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new() }; + let project_workspace = + ProjectWorkspace::Json { project, sysroot, rustc_cfg: Vec::new(), toolchain: None }; to_crate_graph(project_workspace) } @@ -154,9 +155,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { "debug_assertions", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -187,13 +185,14 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 1, @@ -223,9 +222,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { "debug_assertions", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -265,13 +261,14 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 2, @@ -301,9 +298,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { "debug_assertions", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -343,13 +337,14 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 3, @@ -379,9 +374,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { "debug_assertions", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -421,13 +413,14 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 4, @@ -466,9 +459,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { "feature=use_std", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -489,15 +479,14 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() { }, }, dependencies: [], - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), + origin: Rustc { + name: "libc", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, }, }"#]], @@ -552,9 +541,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -585,13 +571,14 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 1, @@ -623,9 +610,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -665,13 +649,14 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 2, @@ -703,9 +688,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -745,13 +727,14 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 3, @@ -783,9 +766,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -825,13 +805,14 @@ fn cargo_hello_world_project_model_with_selective_overrides() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 4, @@ -870,9 +851,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() { "feature=use_std", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -893,15 +871,14 @@ fn cargo_hello_world_project_model_with_selective_overrides() { }, }, dependencies: [], - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), + origin: Rustc { + name: "libc", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, }, }"#]], @@ -946,9 +923,6 @@ fn cargo_hello_world_project_model() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -979,13 +953,14 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 1, @@ -1017,9 +992,6 @@ fn cargo_hello_world_project_model() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -1059,13 +1031,14 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 2, @@ -1097,9 +1070,6 @@ fn cargo_hello_world_project_model() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -1139,13 +1109,14 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 3, @@ -1177,9 +1148,6 @@ fn cargo_hello_world_project_model() { "test", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -1219,13 +1187,14 @@ fn cargo_hello_world_project_model() { prelude: true, }, ], - origin: CratesIo { - repo: None, - name: Some( - "hello-world", - ), + origin: Rustc { + name: "hello-world", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, CrateId( 4, @@ -1264,9 +1233,6 @@ fn cargo_hello_world_project_model() { "feature=use_std", ], ), - target_layout: Err( - "target_data_layout not loaded", - ), env: Env { entries: { "CARGO_PKG_LICENSE": "", @@ -1287,15 +1253,14 @@ fn cargo_hello_world_project_model() { }, }, dependencies: [], - origin: CratesIo { - repo: Some( - "https://github.com/rust-lang/libc", - ), - name: Some( - "libc", - ), + origin: Rustc { + name: "libc", }, is_proc_macro: false, + target_layout: Err( + "target_data_layout not loaded", + ), + channel: None, }, }, }"#]], @@ -1332,9 +1297,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1353,6 +1315,10 @@ fn rust_project_hello_world_project_model() { Alloc, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 1, @@ -1376,9 +1342,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1387,6 +1350,10 @@ fn rust_project_hello_world_project_model() { Core, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 2, @@ -1410,9 +1377,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1421,6 +1385,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 3, @@ -1444,9 +1412,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1455,6 +1420,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 4, @@ -1478,9 +1447,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1508,6 +1474,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 5, @@ -1531,9 +1501,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1542,6 +1509,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 6, @@ -1565,9 +1536,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1649,6 +1617,10 @@ fn rust_project_hello_world_project_model() { Std, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 7, @@ -1672,9 +1644,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1683,6 +1652,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 8, @@ -1706,9 +1679,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1717,6 +1687,10 @@ fn rust_project_hello_world_project_model() { Test, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 9, @@ -1740,9 +1714,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1751,6 +1722,10 @@ fn rust_project_hello_world_project_model() { Other, ), is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, CrateId( 10, @@ -1774,9 +1749,6 @@ fn rust_project_hello_world_project_model() { potential_cfg_options: CfgOptions( [], ), - target_layout: Err( - "rust-project.json projects have no target layout set", - ), env: Env { entries: {}, }, @@ -1818,13 +1790,17 @@ fn rust_project_hello_world_project_model() { prelude: false, }, ], - origin: CratesIo { + origin: Local { repo: None, name: Some( "hello_world", ), }, is_proc_macro: false, + target_layout: Err( + "rust-project.json projects have no target layout set", + ), + channel: None, }, }, }"#]], diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs index a6f1453582b..aac5f428b57 100644 --- a/crates/project-model/src/workspace.rs +++ b/crates/project-model/src/workspace.rs @@ -7,7 +7,7 @@ use anyhow::{format_err, Context, Result}; use base_db::{ CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, - FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult, + FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult, }; use cfg::{CfgDiff, CfgOptions}; use paths::{AbsPath, AbsPathBuf}; @@ -82,7 +82,14 @@ pub enum ProjectWorkspace { target_layout: Result, }, /// Project workspace was manually specified using a `rust-project.json` file. - Json { project: ProjectJson, sysroot: Result>, rustc_cfg: Vec }, + Json { + project: ProjectJson, + sysroot: Result>, + /// Holds cfg flags for the current target. We get those by running + /// `rustc --print cfg`. + rustc_cfg: Vec, + toolchain: Option, + }, // 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. @@ -96,6 +103,8 @@ pub enum ProjectWorkspace { DetachedFiles { files: Vec, sysroot: Result>, + /// Holds cfg flags for the current target. We get those by running + /// `rustc --print cfg`. rustc_cfg: Vec, }, } @@ -127,12 +136,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { .field("toolchain", &toolchain) .field("data_layout", &data_layout) .finish(), - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => { + ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => { let mut debug_struct = f.debug_struct("Json"); debug_struct.field("n_crates", &project.n_crates()); if let Ok(sysroot) = sysroot { debug_struct.field("n_sysroot_crates", &sysroot.crates().len()); } + debug_struct.field("toolchain", &toolchain); debug_struct.field("n_rustc_cfg", &rustc_cfg.len()); debug_struct.finish() } @@ -152,6 +162,19 @@ pub fn load( config: &CargoConfig, progress: &dyn Fn(String), ) -> Result { + let version = |current_dir, cmd_path, prefix: &str| { + let cargo_version = utf8_stdout({ + let mut cmd = Command::new(cmd_path); + cmd.envs(&config.extra_env); + cmd.arg("--version").current_dir(current_dir); + cmd + })?; + anyhow::Ok( + cargo_version + .get(prefix.len()..) + .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()), + ) + }; let res = match manifest { ProjectManifest::ProjectJson(project_json) => { let project_json = project_json.canonicalize()?; @@ -162,24 +185,17 @@ pub fn load( format!("Failed to deserialize json file {}", project_json.display()) })?; let project_location = project_json.parent().to_path_buf(); + let toolchain = version(&*project_location, toolchain::rustc(), "rustc ")?; let project_json = ProjectJson::new(&project_location, data); ProjectWorkspace::load_inline( project_json, config.target.as_deref(), &config.extra_env, + toolchain, ) } ProjectManifest::CargoToml(cargo_toml) => { - let cargo_version = utf8_stdout({ - let mut cmd = Command::new(toolchain::cargo()); - cmd.envs(&config.extra_env); - cmd.arg("--version"); - cmd - })?; - let toolchain = cargo_version - .get("cargo ".len()..) - .and_then(|it| Version::parse(it.split_whitespace().next()?).ok()); - + let toolchain = version(cargo_toml.parent(), toolchain::cargo(), "cargo ")?; let meta = CargoWorkspace::fetch_metadata( &cargo_toml, cargo_toml.parent(), @@ -304,6 +320,7 @@ pub fn load_inline( project_json: ProjectJson, target: Option<&str>, extra_env: &FxHashMap, + toolchain: Option, ) -> ProjectWorkspace { let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) { (Some(sysroot), Some(sysroot_src)) => Ok(Sysroot::load(sysroot, sysroot_src)), @@ -328,7 +345,7 @@ pub fn load_inline( } let rustc_cfg = rustc_cfg::get(None, target, extra_env); - ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg } + ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg, toolchain } } pub fn load_detached_files( @@ -470,7 +487,7 @@ pub fn to_roots(&self) -> Vec { }) }; match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg: _ } => project + ProjectWorkspace::Json { project, sysroot, rustc_cfg: _, toolchain: _ } => project .crates() .map(|(_, krate)| PackageRoot { is_local: krate.is_workspace_member, @@ -577,14 +594,17 @@ pub fn to_crate_graph( let _p = profile::span("ProjectWorkspace::to_crate_graph"); let (mut crate_graph, proc_macros) = match self { - ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( - rustc_cfg.clone(), - load, - project, - sysroot.as_ref().ok(), - extra_env, - Err("rust-project.json projects have no target layout set".into()), - ), + ProjectWorkspace::Json { project, sysroot, rustc_cfg, toolchain } => { + project_json_to_crate_graph( + rustc_cfg.clone(), + load, + project, + sysroot.as_ref().ok(), + extra_env, + Err("rust-project.json projects have no target layout set".into()), + toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())), + ) + } ProjectWorkspace::Cargo { cargo, sysroot, @@ -592,7 +612,7 @@ pub fn to_crate_graph( rustc_cfg, cfg_overrides, build_scripts, - toolchain: _, + toolchain, target_layout, } => cargo_to_crate_graph( load, @@ -606,6 +626,7 @@ pub fn to_crate_graph( Ok(it) => Ok(Arc::from(it.as_str())), Err(it) => Err(Arc::from(it.as_str())), }, + toolchain.as_ref().and_then(|it| ReleaseChannel::from_str(it.pre.as_str())), ), ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => { detached_files_to_crate_graph( @@ -657,9 +678,19 @@ pub fn eq_ignore_build_data(&self, other: &Self) -> bool { && 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::Json { project, sysroot, rustc_cfg, toolchain }, + Self::Json { + project: o_project, + sysroot: o_sysroot, + rustc_cfg: o_rustc_cfg, + toolchain: o_toolchain, + }, + ) => { + project == o_project + && rustc_cfg == o_rustc_cfg + && sysroot == o_sysroot + && toolchain == o_toolchain + } ( Self::DetachedFiles { files, sysroot, rustc_cfg }, Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg }, @@ -684,6 +715,7 @@ fn project_json_to_crate_graph( sysroot: Option<&Sysroot>, extra_env: &FxHashMap, target_layout: TargetLayoutLoadResult, + channel: Option, ) -> (CrateGraph, ProcMacroPaths) { let mut crate_graph = CrateGraph::default(); let mut proc_macros: ProcMacroPaths = FxHashMap::default(); @@ -694,6 +726,7 @@ fn project_json_to_crate_graph( rustc_cfg.clone(), target_layout.clone(), load, + channel, ) }); @@ -726,15 +759,16 @@ fn project_json_to_crate_graph( cfg_options, env, krate.is_proc_macro, - if krate.display_name.is_some() { - CrateOrigin::CratesIo { + if let Some(name) = krate.display_name.clone() { + CrateOrigin::Local { repo: krate.repository.clone(), - name: krate.display_name.clone().map(|n| n.canonical_name().to_string()), + name: Some(name.canonical_name().to_string()), } } else { - CrateOrigin::CratesIo { repo: None, name: None } + CrateOrigin::Local { repo: None, name: None } }, target_layout.clone(), + None, ); if krate.is_proc_macro { if let Some(path) = krate.proc_macro_dylib_path.clone() { @@ -784,6 +818,7 @@ fn cargo_to_crate_graph( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, + channel: Option, ) -> (CrateGraph, ProcMacroPaths) { let _p = profile::span("cargo_to_crate_graph"); let mut crate_graph = CrateGraph::default(); @@ -795,6 +830,7 @@ fn cargo_to_crate_graph( rustc_cfg.clone(), target_layout.clone(), load, + channel, ), None => (SysrootPublicDeps::default(), None), }; @@ -859,6 +895,8 @@ fn cargo_to_crate_graph( &cargo[tgt].name, cargo[tgt].is_proc_macro, target_layout.clone(), + true, + channel, ); if cargo[tgt].kind == TargetKind::Lib { lib_tgt = Some((crate_id, cargo[tgt].name.clone())); @@ -945,6 +983,7 @@ fn cargo_to_crate_graph( rustc_build_scripts }, target_layout, + channel, ); } } @@ -967,6 +1006,7 @@ fn detached_files_to_crate_graph( rustc_cfg.clone(), target_layout.clone(), load, + None, ), None => (SysrootPublicDeps::default(), None), }; @@ -995,11 +1035,12 @@ fn detached_files_to_crate_graph( cfg_options.clone(), Env::default(), false, - CrateOrigin::CratesIo { + CrateOrigin::Local { repo: None, name: display_name.map(|n| n.canonical_name().to_string()), }, target_layout.clone(), + None, ); public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); @@ -1021,6 +1062,7 @@ fn handle_rustc_crates( override_cfg: &CfgOverrides, build_scripts: &WorkspaceBuildScripts, target_layout: TargetLayoutLoadResult, + channel: Option, ) { let mut rustc_pkg_crates = FxHashMap::default(); // The root package of the rustc-dev component is rustc_driver, so we match that @@ -1078,6 +1120,8 @@ fn handle_rustc_crates( &rustc_workspace[tgt].name, rustc_workspace[tgt].is_proc_macro, target_layout.clone(), + true, + channel, ); pkg_to_lib_crate.insert(pkg, crate_id); // Add dependencies on core / std / alloc for this crate @@ -1143,6 +1187,8 @@ fn add_target_crate_root( cargo_name: &str, is_proc_macro: bool, target_layout: TargetLayoutLoadResult, + rustc_crate: bool, + channel: Option, ) -> CrateId { let edition = pkg.edition; let mut potential_cfg_options = cfg_options.clone(); @@ -1181,8 +1227,15 @@ fn add_target_crate_root( potential_cfg_options, env, is_proc_macro, - CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) }, + if rustc_crate { + CrateOrigin::Rustc { name: pkg.name.clone() } + } else if pkg.is_member { + CrateOrigin::Local { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) } + } else { + CrateOrigin::Library { repo: pkg.repository.clone(), name: pkg.name.clone() } + }, target_layout, + channel, ); if is_proc_macro { let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) { @@ -1217,6 +1270,7 @@ fn sysroot_to_crate_graph( rustc_cfg: Vec, target_layout: TargetLayoutLoadResult, load: &mut dyn FnMut(&AbsPath) -> Option, + channel: Option, ) -> (SysrootPublicDeps, Option) { let _p = profile::span("sysroot_to_crate_graph"); let mut cfg_options = CfgOptions::default(); @@ -1239,6 +1293,7 @@ fn sysroot_to_crate_graph( false, CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), target_layout.clone(), + channel, ); Some((krate, crate_id)) }) diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index ec90cb17f7c..899c31d2063 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -192,6 +192,7 @@ pub(crate) fn fetch_workspaces(&mut self, cause: Cause) { it.clone(), cargo_config.target.as_deref(), &cargo_config.extra_env, + None, )) } }) @@ -427,19 +428,19 @@ pub(crate) fn switch_workspaces(&mut self, cause: Cause) { let (crate_graph, proc_macro_paths) = { let vfs = &mut self.vfs.write().0; let loader = &mut self.loader; - let mem_docs = &self.mem_docs; - let mut load = move |path: &AbsPath| { + let mut load = |path: &AbsPath| { let _p = profile::span("switch_workspaces::load"); let vfs_path = vfs::VfsPath::from(path.to_path_buf()); - if !mem_docs.contains(&vfs_path) { - let contents = loader.handle.load_sync(path); - vfs.set_file_contents(vfs_path.clone(), contents); + match vfs.file_id(&vfs_path) { + Some(file_id) => Some(file_id), + None => { + if !self.mem_docs.contains(&vfs_path) { + let contents = loader.handle.load_sync(path); + vfs.set_file_contents(vfs_path.clone(), contents); + } + vfs.file_id(&vfs_path) + } } - let res = vfs.file_id(&vfs_path); - if res.is_none() { - tracing::warn!("failed to load {}", path.display()) - } - res }; let mut crate_graph = CrateGraph::default(); diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs index 14972d29074..8ffa3a808f1 100644 --- a/crates/vfs/src/lib.rs +++ b/crates/vfs/src/lib.rs @@ -160,7 +160,7 @@ pub fn iter(&self) -> impl Iterator + '_ { /// [`FileId`] for it. pub fn set_file_contents(&mut self, path: VfsPath, contents: Option>) -> bool { let file_id = self.alloc_file_id(path); - let change_kind = match (&self.get(file_id), &contents) { + let change_kind = match (self.get(file_id), &contents) { (None, None) => return false, (Some(old), Some(new)) if old == new => return false, (None, Some(_)) => ChangeKind::Create,