Auto merge of #14405 - Veykril:proc-macro-loading, r=Veykril

feat: Load proc-macros asynchronously

Closes https://github.com/rust-lang/rust-analyzer/issues/8646
This commit is contained in:
bors 2023-03-25 17:22:45 +00:00
commit 90340b71ad
23 changed files with 289 additions and 228 deletions

View file

@ -6,7 +6,7 @@ use std::{fmt, sync::Arc};
use salsa::Durability; use salsa::Durability;
use vfs::FileId; use vfs::FileId;
use crate::{CrateGraph, SourceDatabaseExt, SourceRoot, SourceRootId}; use crate::{CrateGraph, ProcMacros, SourceDatabaseExt, SourceRoot, SourceRootId};
/// Encapsulate a bunch of raw `.set` calls on the database. /// Encapsulate a bunch of raw `.set` calls on the database.
#[derive(Default)] #[derive(Default)]
@ -14,6 +14,7 @@ pub struct Change {
pub roots: Option<Vec<SourceRoot>>, pub roots: Option<Vec<SourceRoot>>,
pub files_changed: Vec<(FileId, Option<Arc<String>>)>, pub files_changed: Vec<(FileId, Option<Arc<String>>)>,
pub crate_graph: Option<CrateGraph>, pub crate_graph: Option<CrateGraph>,
pub proc_macros: Option<ProcMacros>,
} }
impl fmt::Debug for Change { impl fmt::Debug for Change {
@ -49,6 +50,10 @@ impl Change {
self.crate_graph = Some(graph); self.crate_graph = Some(graph);
} }
pub fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
self.proc_macros = Some(proc_macros);
}
pub fn apply(self, db: &mut dyn SourceDatabaseExt) { pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
let _p = profile::span("RootDatabase::apply_change"); let _p = profile::span("RootDatabase::apply_change");
if let Some(roots) = self.roots { if let Some(roots) = self.roots {
@ -73,6 +78,9 @@ impl Change {
if let Some(crate_graph) = self.crate_graph { if let Some(crate_graph) = self.crate_graph {
db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH) db.set_crate_graph_with_durability(Arc::new(crate_graph), Durability::HIGH)
} }
if let Some(proc_macros) = self.proc_macros {
db.set_proc_macros_with_durability(Arc::new(proc_macros), Durability::HIGH)
}
} }
} }

View file

@ -12,8 +12,8 @@ use vfs::{file_set::FileSet, VfsPath};
use crate::{ use crate::{
input::{CrateName, CrateOrigin, LangCrateOrigin}, input::{CrateName, CrateOrigin, LangCrateOrigin},
Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition, Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition,
FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros,
SourceRoot, SourceRootId, SourceDatabaseExt, SourceRoot, SourceRootId,
}; };
pub const WORKSPACE: SourceRootId = SourceRootId(0); pub const WORKSPACE: SourceRootId = SourceRootId(0);
@ -100,7 +100,7 @@ impl ChangeFixture {
pub fn parse_with_proc_macros( pub fn parse_with_proc_macros(
ra_fixture: &str, ra_fixture: &str,
mut proc_macros: Vec<(String, ProcMacro)>, mut proc_macro_defs: Vec<(String, ProcMacro)>,
) -> ChangeFixture { ) -> ChangeFixture {
let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture); let (mini_core, proc_macro_names, fixture) = Fixture::parse(ra_fixture);
let mut change = Change::new(); let mut change = Change::new();
@ -160,7 +160,6 @@ impl ChangeFixture {
meta.cfg.clone(), meta.cfg.clone(),
meta.cfg, meta.cfg,
meta.env, meta.env,
Ok(Vec::new()),
false, false,
origin, origin,
meta.target_data_layout meta.target_data_layout
@ -200,7 +199,6 @@ impl ChangeFixture {
default_cfg.clone(), default_cfg.clone(),
default_cfg, default_cfg,
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
default_target_data_layout default_target_data_layout
@ -244,7 +242,6 @@ impl ChangeFixture {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::Lang(LangCrateOrigin::Core), CrateOrigin::Lang(LangCrateOrigin::Core),
target_layout.clone(), target_layout.clone(),
@ -257,12 +254,13 @@ impl ChangeFixture {
} }
} }
let mut proc_macros = ProcMacros::default();
if !proc_macro_names.is_empty() { if !proc_macro_names.is_empty() {
let proc_lib_file = file_id; let proc_lib_file = file_id;
file_id.0 += 1; file_id.0 += 1;
proc_macros.extend(default_test_proc_macros()); proc_macro_defs.extend(default_test_proc_macros());
let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macros); let (proc_macro, source) = filter_test_proc_macros(&proc_macro_names, proc_macro_defs);
let mut fs = FileSet::default(); let mut fs = FileSet::default();
fs.insert( fs.insert(
proc_lib_file, proc_lib_file,
@ -282,11 +280,11 @@ impl ChangeFixture {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(proc_macro),
true, true,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
target_layout, target_layout,
); );
proc_macros.insert(proc_macros_crate, Ok(proc_macro));
for krate in all_crates { for krate in all_crates {
crate_graph crate_graph
@ -305,6 +303,7 @@ impl ChangeFixture {
roots.push(root); roots.push(root);
change.set_roots(roots); change.set_roots(roots);
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
change.set_proc_macros(proc_macros);
ChangeFixture { file_position, files, change } ChangeFixture { file_position, files, change }
} }

View file

@ -6,14 +6,17 @@
//! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how //! actual IO. See `vfs` and `project_model` in the `rust-analyzer` crate for how
//! actual IO is done and lowered to input. //! actual IO is done and lowered to input.
use std::{fmt, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc}; use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc};
use cfg::CfgOptions; use cfg::CfgOptions;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use stdx::hash::{NoHashHashMap, NoHashHashSet}; use stdx::hash::{NoHashHashMap, NoHashHashSet};
use syntax::SmolStr; use syntax::SmolStr;
use tt::token_id::Subtree; use tt::token_id::Subtree;
use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath}; use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>;
pub type ProcMacros = FxHashMap<CrateId, ProcMacroLoadResult>;
/// Files are grouped into source roots. A source root is a directory on the /// Files are grouped into source roots. A source root is a directory on the
/// file systems which is watched for changes. Typically it corresponds to a /// file systems which is watched for changes. Typically it corresponds to a
@ -269,7 +272,6 @@ pub struct CrateData {
pub target_layout: TargetLayoutLoadResult, pub target_layout: TargetLayoutLoadResult,
pub env: Env, pub env: Env,
pub dependencies: Vec<Dependency>, pub dependencies: Vec<Dependency>,
pub proc_macro: ProcMacroLoadResult,
pub origin: CrateOrigin, pub origin: CrateOrigin,
pub is_proc_macro: bool, pub is_proc_macro: bool,
} }
@ -322,7 +324,6 @@ impl CrateGraph {
cfg_options: CfgOptions, cfg_options: CfgOptions,
potential_cfg_options: CfgOptions, potential_cfg_options: CfgOptions,
env: Env, env: Env,
proc_macro: ProcMacroLoadResult,
is_proc_macro: bool, is_proc_macro: bool,
origin: CrateOrigin, origin: CrateOrigin,
target_layout: Result<Arc<str>, Arc<str>>, target_layout: Result<Arc<str>, Arc<str>>,
@ -335,7 +336,6 @@ impl CrateGraph {
cfg_options, cfg_options,
potential_cfg_options, potential_cfg_options,
env, env,
proc_macro,
dependencies: Vec::new(), dependencies: Vec::new(),
origin, origin,
target_layout, target_layout,
@ -456,11 +456,11 @@ impl CrateGraph {
} }
/// Extends this crate graph by adding a complete disjoint second crate /// Extends this crate graph by adding a complete disjoint second crate
/// graph. /// graph and adjust the ids in the [`ProcMacroPaths`] accordingly.
/// ///
/// The ids of the crates in the `other` graph are shifted by the return /// The ids of the crates in the `other` graph are shifted by the return
/// amount. /// amount.
pub fn extend(&mut self, other: CrateGraph) -> u32 { pub fn extend(&mut self, other: CrateGraph, proc_macros: &mut ProcMacroPaths) -> u32 {
let start = self.arena.len() as u32; let start = self.arena.len() as u32;
self.arena.extend(other.arena.into_iter().map(|(id, mut data)| { self.arena.extend(other.arena.into_iter().map(|(id, mut data)| {
let new_id = id.shift(start); let new_id = id.shift(start);
@ -469,6 +469,11 @@ impl CrateGraph {
} }
(new_id, data) (new_id, data)
})); }));
*proc_macros = mem::take(proc_macros)
.into_iter()
.map(|(id, macros)| (id.shift(start), macros))
.collect();
start start
} }
@ -645,7 +650,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -658,7 +662,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -671,7 +674,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -698,7 +700,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -711,7 +712,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -735,7 +735,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -748,7 +747,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -761,7 +759,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -785,7 +782,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),
@ -798,7 +794,6 @@ mod tests {
CfgOptions::default(), CfgOptions::default(),
CfgOptions::default(), CfgOptions::default(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("".into()), Err("".into()),

View file

@ -16,8 +16,8 @@ pub use crate::{
input::{ input::{
CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
ProcMacroId, ProcMacroKind, ProcMacroLoadResult, SourceRoot, SourceRootId, ProcMacroId, ProcMacroKind, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot,
TargetLayoutLoadResult, SourceRootId, TargetLayoutLoadResult,
}, },
}; };
pub use salsa::{self, Cancelled}; pub use salsa::{self, Cancelled};
@ -73,6 +73,10 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
/// The crate graph. /// The crate graph.
#[salsa::input] #[salsa::input]
fn crate_graph(&self) -> Arc<CrateGraph>; fn crate_graph(&self) -> Arc<CrateGraph>;
/// The crate graph.
#[salsa::input]
fn proc_macros(&self) -> Arc<ProcMacros>;
} }
fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { fn parse_query(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {

View file

@ -78,25 +78,35 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
} }
let cfg_options = &krate.cfg_options; let cfg_options = &krate.cfg_options;
let proc_macros = match &krate.proc_macro {
Ok(proc_macros) => {
proc_macros
.iter()
.enumerate()
.map(|(idx, it)| {
// FIXME: a hacky way to create a Name from string.
let name =
tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
(name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
})
.collect()
}
Err(e) => {
def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str());
Vec::new()
}
};
let is_proc_macro = krate.is_proc_macro; let is_proc_macro = krate.is_proc_macro;
let proc_macros = if is_proc_macro {
match db.proc_macros().get(&def_map.krate) {
Some(Ok(proc_macros)) => {
proc_macros
.iter()
.enumerate()
.map(|(idx, it)| {
// FIXME: a hacky way to create a Name from string.
let name =
tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
(name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
})
.collect()
}
Some(Err(e)) => {
def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str());
Vec::new()
}
None => {
def_map.proc_macro_loading_error =
Some("No proc-macros present for crate".to_owned().into_boxed_str());
Vec::new()
}
}
} else {
vec![]
};
let mut collector = DefCollector { let mut collector = DefCollector {
db, db,

View file

@ -33,10 +33,10 @@ impl ProcMacroExpander {
) -> ExpandResult<tt::Subtree> { ) -> ExpandResult<tt::Subtree> {
match self.proc_macro_id { match self.proc_macro_id {
Some(id) => { Some(id) => {
let krate_graph = db.crate_graph(); let proc_macros = db.proc_macros();
let proc_macros = match &krate_graph[def_crate].proc_macro { let proc_macros = match proc_macros.get(&def_crate) {
Ok(proc_macros) => proc_macros, Some(Ok(proc_macros)) => proc_macros,
Err(_) => { Some(Err(_)) | None => {
never!("Non-dummy expander even though there are no proc macros"); never!("Non-dummy expander even though there are no proc macros");
return ExpandResult::with_err( return ExpandResult::with_err(
tt::Subtree::empty(), tt::Subtree::empty(),
@ -59,6 +59,7 @@ impl ProcMacroExpander {
} }
}; };
let krate_graph = db.crate_graph();
// Proc macros have access to the environment variables of the invoking crate. // Proc macros have access to the environment variables of the invoking crate.
let env = &krate_graph[calling_crate].env; let env = &krate_graph[calling_crate].env;
match proc_macro.expander.expand(tt, attr_arg, env) { match proc_macro.expander.expand(tt, attr_arg, env) {

View file

@ -64,6 +64,7 @@ impl RootDatabase {
// SourceDatabase // SourceDatabase
base_db::ParseQuery base_db::ParseQuery
base_db::CrateGraphQuery base_db::CrateGraphQuery
base_db::ProcMacrosQuery
// SourceDatabaseExt // SourceDatabaseExt
base_db::FileTextQuery base_db::FileTextQuery

View file

@ -137,6 +137,7 @@ impl RootDatabase {
pub fn new(lru_capacity: Option<usize>) -> RootDatabase { pub fn new(lru_capacity: Option<usize>) -> RootDatabase {
let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) }; let mut db = RootDatabase { storage: ManuallyDrop::new(salsa::Storage::default()) };
db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); db.set_crate_graph_with_durability(Default::default(), Durability::HIGH);
db.set_proc_macros_with_durability(Default::default(), Durability::HIGH);
db.set_local_roots_with_durability(Default::default(), Durability::HIGH); db.set_local_roots_with_durability(Default::default(), Durability::HIGH);
db.set_library_roots_with_durability(Default::default(), Durability::HIGH); db.set_library_roots_with_durability(Default::default(), Durability::HIGH);
db.set_enable_proc_attr_macros(false); db.set_enable_proc_attr_macros(false);

View file

@ -235,7 +235,6 @@ impl Analysis {
cfg_options.clone(), cfg_options.clone(),
cfg_options, cfg_options,
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { repo: None, name: None }, CrateOrigin::CratesIo { repo: None, name: None },
Err("Analysis::from_single_file has no target layout".into()), Err("Analysis::from_single_file has no target layout".into()),

View file

@ -1,7 +1,7 @@
use std::sync::Arc; use std::sync::Arc;
use ide_db::{ use ide_db::{
base_db::{salsa::Durability, CrateGraph, SourceDatabase}, base_db::{salsa::Durability, CrateGraph, ProcMacros, SourceDatabase},
FxHashMap, RootDatabase, FxHashMap, RootDatabase,
}; };
@ -16,6 +16,7 @@ use ide_db::{
// |=== // |===
pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) { pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
let crate_graph = db.crate_graph(); let crate_graph = db.crate_graph();
let proc_macros = db.proc_macros();
let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>(); let mut shuffled_ids = crate_graph.iter().collect::<Vec<_>>();
@ -23,6 +24,7 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
stdx::rand::shuffle(&mut shuffled_ids, |i| rng.rand_range(0..i as u32) as usize); stdx::rand::shuffle(&mut shuffled_ids, |i| rng.rand_range(0..i as u32) as usize);
let mut new_graph = CrateGraph::default(); let mut new_graph = CrateGraph::default();
let mut new_proc_macros = ProcMacros::default();
let mut map = FxHashMap::default(); let mut map = FxHashMap::default();
for old_id in shuffled_ids.iter().copied() { for old_id in shuffled_ids.iter().copied() {
@ -35,11 +37,11 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
data.cfg_options.clone(), data.cfg_options.clone(),
data.potential_cfg_options.clone(), data.potential_cfg_options.clone(),
data.env.clone(), data.env.clone(),
data.proc_macro.clone(),
data.is_proc_macro, data.is_proc_macro,
data.origin.clone(), data.origin.clone(),
data.target_layout.clone(), data.target_layout.clone(),
); );
new_proc_macros.insert(new_id, proc_macros[&old_id].clone());
map.insert(old_id, new_id); map.insert(old_id, new_id);
} }
@ -53,4 +55,5 @@ pub(crate) fn shuffle_crate_graph(db: &mut RootDatabase) {
} }
db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH); db.set_crate_graph_with_durability(Arc::new(new_graph), Durability::HIGH);
db.set_proc_macros_with_durability(Arc::new(new_proc_macros), Durability::HIGH);
} }

View file

@ -3,7 +3,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use base_db::{CrateGraph, FileId}; use base_db::{CrateGraph, FileId, ProcMacroPaths};
use cfg::{CfgAtom, CfgDiff}; use cfg::{CfgAtom, CfgDiff};
use expect_test::{expect, Expect}; use expect_test::{expect, Expect};
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
@ -14,11 +14,14 @@ use crate::{
WorkspaceBuildScripts, WorkspaceBuildScripts,
}; };
fn load_cargo(file: &str) -> CrateGraph { fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) {
load_cargo_with_overrides(file, CfgOverrides::default()) load_cargo_with_overrides(file, CfgOverrides::default())
} }
fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGraph { fn load_cargo_with_overrides(
file: &str,
cfg_overrides: CfgOverrides,
) -> (CrateGraph, ProcMacroPaths) {
let meta = get_test_json_file(file); let meta = get_test_json_file(file);
let cargo_workspace = CargoWorkspace::new(meta); let cargo_workspace = CargoWorkspace::new(meta);
let project_workspace = ProjectWorkspace::Cargo { let project_workspace = ProjectWorkspace::Cargo {
@ -34,7 +37,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
to_crate_graph(project_workspace) to_crate_graph(project_workspace)
} }
fn load_rust_project(file: &str) -> CrateGraph { fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) {
let data = get_test_json_file(file); let data = get_test_json_file(file);
let project = rooted_project_json(data); let project = rooted_project_json(data);
let sysroot = Ok(get_fake_sysroot()); let sysroot = Ok(get_fake_sysroot());
@ -92,9 +95,8 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
ProjectJson::new(base, data) ProjectJson::new(base, data)
} }
fn to_crate_graph(project_workspace: ProjectWorkspace) -> CrateGraph { fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) {
project_workspace.to_crate_graph( project_workspace.to_crate_graph(
&mut |_, _| Ok(Vec::new()),
&mut { &mut {
let mut counter = 0; let mut counter = 0;
move |_path| { move |_path| {
@ -117,7 +119,8 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
let cfg_overrides = CfgOverrides::Wildcard( let cfg_overrides = CfgOverrides::Wildcard(
CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(), CfgDiff::new(Vec::new(), vec![CfgAtom::Flag("test".into())]).unwrap(),
); );
let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
check_crate_graph( check_crate_graph(
crate_graph, crate_graph,
expect![[r#" expect![[r#"
@ -184,9 +187,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -265,9 +265,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -346,9 +343,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -427,9 +421,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -498,9 +489,6 @@ fn cargo_hello_world_project_model_with_wildcard_overrides() {
}, },
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: Some( repo: Some(
"https://github.com/rust-lang/libc", "https://github.com/rust-lang/libc",
@ -527,7 +515,8 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
.collect(), .collect(),
) )
}; };
let crate_graph = load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides); let (crate_graph, _proc_macros) =
load_cargo_with_overrides("hello-world-metadata.json", cfg_overrides);
check_crate_graph( check_crate_graph(
crate_graph, crate_graph,
expect![[r#" expect![[r#"
@ -596,9 +585,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -679,9 +665,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -762,9 +745,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -845,9 +825,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -916,9 +893,6 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
}, },
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: Some( repo: Some(
"https://github.com/rust-lang/libc", "https://github.com/rust-lang/libc",
@ -936,7 +910,7 @@ fn cargo_hello_world_project_model_with_selective_overrides() {
#[test] #[test]
fn cargo_hello_world_project_model() { fn cargo_hello_world_project_model() {
let crate_graph = load_cargo("hello-world-metadata.json"); let (crate_graph, _proc_macros) = load_cargo("hello-world-metadata.json");
check_crate_graph( check_crate_graph(
crate_graph, crate_graph,
expect![[r#" expect![[r#"
@ -1005,9 +979,6 @@ fn cargo_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -1088,9 +1059,6 @@ fn cargo_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -1171,9 +1139,6 @@ fn cargo_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -1254,9 +1219,6 @@ fn cargo_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -1325,9 +1287,6 @@ fn cargo_hello_world_project_model() {
}, },
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"crate has not (yet) been built",
),
origin: CratesIo { origin: CratesIo {
repo: Some( repo: Some(
"https://github.com/rust-lang/libc", "https://github.com/rust-lang/libc",
@ -1345,7 +1304,7 @@ fn cargo_hello_world_project_model() {
#[test] #[test]
fn rust_project_hello_world_project_model() { fn rust_project_hello_world_project_model() {
let crate_graph = load_rust_project("hello-world-project.json"); let (crate_graph, _proc_macros) = load_rust_project("hello-world-project.json");
check_crate_graph( check_crate_graph(
crate_graph, crate_graph,
expect![[r#" expect![[r#"
@ -1390,9 +1349,6 @@ fn rust_project_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Alloc, Alloc,
), ),
@ -1427,9 +1383,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Core, Core,
), ),
@ -1464,9 +1417,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1501,9 +1451,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1557,9 +1504,6 @@ fn rust_project_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1594,9 +1538,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1704,9 +1645,6 @@ fn rust_project_hello_world_project_model() {
prelude: true, prelude: true,
}, },
], ],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Std, Std,
), ),
@ -1741,9 +1679,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1778,9 +1713,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Test, Test,
), ),
@ -1815,9 +1747,6 @@ fn rust_project_hello_world_project_model() {
entries: {}, entries: {},
}, },
dependencies: [], dependencies: [],
proc_macro: Err(
"no proc macro loaded for sysroot crate",
),
origin: Lang( origin: Lang(
Other, Other,
), ),
@ -1889,9 +1818,6 @@ fn rust_project_hello_world_project_model() {
prelude: false, prelude: false,
}, },
], ],
proc_macro: Err(
"no proc macro dylib present",
),
origin: CratesIo { origin: CratesIo {
repo: None, repo: None,
name: Some( name: Some(
@ -1907,7 +1833,7 @@ fn rust_project_hello_world_project_model() {
#[test] #[test]
fn rust_project_is_proc_macro_has_proc_macro_dep() { fn rust_project_is_proc_macro_has_proc_macro_dep() {
let crate_graph = load_rust_project("is-proc-macro-project.json"); let (crate_graph, _proc_macros) = load_rust_project("is-proc-macro-project.json");
// Since the project only defines one crate (outside the sysroot crates), // Since the project only defines one crate (outside the sysroot crates),
// it should be the one with the biggest Id. // it should be the one with the biggest Id.
let crate_id = crate_graph.iter().max().unwrap(); let crate_id = crate_graph.iter().max().unwrap();

View file

@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
use anyhow::{bail, format_err, Context, Result}; use anyhow::{bail, format_err, Context, Result};
use base_db::{ use base_db::{
CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
FileId, LangCrateOrigin, ProcMacroLoadResult, TargetLayoutLoadResult, FileId, LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
}; };
use cfg::{CfgDiff, CfgOptions}; use cfg::{CfgDiff, CfgOptions};
use paths::{AbsPath, AbsPathBuf}; use paths::{AbsPath, AbsPathBuf};
@ -576,16 +576,14 @@ impl ProjectWorkspace {
pub fn to_crate_graph( pub fn to_crate_graph(
&self, &self,
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
) -> CrateGraph { ) -> (CrateGraph, ProcMacroPaths) {
let _p = profile::span("ProjectWorkspace::to_crate_graph"); let _p = profile::span("ProjectWorkspace::to_crate_graph");
let mut crate_graph = match self { let (mut crate_graph, proc_macros) = match self {
ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph( ProjectWorkspace::Json { project, sysroot, rustc_cfg } => project_json_to_crate_graph(
rustc_cfg.clone(), rustc_cfg.clone(),
load_proc_macro,
load, load,
project, project,
sysroot.as_ref().ok(), sysroot.as_ref().ok(),
@ -602,7 +600,6 @@ impl ProjectWorkspace {
toolchain: _, toolchain: _,
target_layout, target_layout,
} => cargo_to_crate_graph( } => cargo_to_crate_graph(
load_proc_macro,
load, load,
rustc.as_ref().ok(), rustc.as_ref().ok(),
cargo, cargo,
@ -630,7 +627,7 @@ impl ProjectWorkspace {
} else { } else {
tracing::debug!("Did not patch std to depend on cfg-if") tracing::debug!("Did not patch std to depend on cfg-if")
} }
crate_graph (crate_graph, proc_macros)
} }
pub fn eq_ignore_build_data(&self, other: &Self) -> bool { pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
@ -679,14 +676,14 @@ impl ProjectWorkspace {
fn project_json_to_crate_graph( fn project_json_to_crate_graph(
rustc_cfg: Vec<CfgFlag>, rustc_cfg: Vec<CfgFlag>,
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
project: &ProjectJson, project: &ProjectJson,
sysroot: Option<&Sysroot>, sysroot: Option<&Sysroot>,
extra_env: &FxHashMap<String, String>, extra_env: &FxHashMap<String, String>,
target_layout: TargetLayoutLoadResult, target_layout: TargetLayoutLoadResult,
) -> CrateGraph { ) -> (CrateGraph, ProcMacroPaths) {
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let mut proc_macros = FxHashMap::default();
let sysroot_deps = sysroot.as_ref().map(|sysroot| { let sysroot_deps = sysroot.as_ref().map(|sysroot| {
sysroot_to_crate_graph( sysroot_to_crate_graph(
&mut crate_graph, &mut crate_graph,
@ -707,14 +704,15 @@ fn project_json_to_crate_graph(
}) })
.map(|(crate_id, krate, file_id)| { .map(|(crate_id, krate, file_id)| {
let env = krate.env.clone().into_iter().collect(); let env = krate.env.clone().into_iter().collect();
let proc_macro = match krate.proc_macro_dylib_path.clone() { if let Some(path) = krate.proc_macro_dylib_path.clone() {
Some(it) => load_proc_macro( proc_macros.insert(
krate.display_name.as_ref().map(|it| it.canonical_name()).unwrap_or(""), crate_id,
&it, Ok((
), krate.display_name.as_ref().map(|it| it.canonical_name().to_owned()),
None => Err("no proc macro dylib present".into()), path,
}; )),
);
}
let target_cfgs = match krate.target.as_deref() { let target_cfgs = match krate.target.as_deref() {
Some(target) => cfg_cache Some(target) => cfg_cache
.entry(target) .entry(target)
@ -734,7 +732,6 @@ fn project_json_to_crate_graph(
cfg_options.clone(), cfg_options.clone(),
cfg_options, cfg_options,
env, env,
proc_macro,
krate.is_proc_macro, krate.is_proc_macro,
if krate.display_name.is_some() { if krate.display_name.is_some() {
CrateOrigin::CratesIo { CrateOrigin::CratesIo {
@ -776,11 +773,10 @@ fn project_json_to_crate_graph(
} }
} }
} }
crate_graph (crate_graph, proc_macros)
} }
fn cargo_to_crate_graph( fn cargo_to_crate_graph(
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>, rustc: Option<&(CargoWorkspace, WorkspaceBuildScripts)>,
cargo: &CargoWorkspace, cargo: &CargoWorkspace,
@ -789,9 +785,10 @@ fn cargo_to_crate_graph(
override_cfg: &CfgOverrides, override_cfg: &CfgOverrides,
build_scripts: &WorkspaceBuildScripts, build_scripts: &WorkspaceBuildScripts,
target_layout: TargetLayoutLoadResult, target_layout: TargetLayoutLoadResult,
) -> CrateGraph { ) -> (CrateGraph, ProcMacroPaths) {
let _p = profile::span("cargo_to_crate_graph"); let _p = profile::span("cargo_to_crate_graph");
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let mut proc_macros = FxHashMap::default();
let (public_deps, libproc_macro) = match sysroot { let (public_deps, libproc_macro) = match sysroot {
Some(sysroot) => sysroot_to_crate_graph( Some(sysroot) => sysroot_to_crate_graph(
&mut crate_graph, &mut crate_graph,
@ -855,10 +852,10 @@ fn cargo_to_crate_graph(
if let Some(file_id) = load(&cargo[tgt].root) { if let Some(file_id) = load(&cargo[tgt].root) {
let crate_id = add_target_crate_root( let crate_id = add_target_crate_root(
&mut crate_graph, &mut crate_graph,
&mut proc_macros,
&cargo[pkg], &cargo[pkg],
build_scripts.get_output(pkg), build_scripts.get_output(pkg),
cfg_options.clone(), cfg_options.clone(),
&mut |path| load_proc_macro(&cargo[tgt].name, path),
file_id, file_id,
&cargo[tgt].name, &cargo[tgt].name,
cargo[tgt].is_proc_macro, cargo[tgt].is_proc_macro,
@ -931,9 +928,9 @@ fn cargo_to_crate_graph(
if let Some((rustc_workspace, rustc_build_scripts)) = rustc { if let Some((rustc_workspace, rustc_build_scripts)) = rustc {
handle_rustc_crates( handle_rustc_crates(
&mut crate_graph, &mut crate_graph,
&mut proc_macros,
&mut pkg_to_lib_crate, &mut pkg_to_lib_crate,
load, load,
load_proc_macro,
rustc_workspace, rustc_workspace,
cargo, cargo,
&public_deps, &public_deps,
@ -952,7 +949,7 @@ fn cargo_to_crate_graph(
); );
} }
} }
crate_graph (crate_graph, proc_macros)
} }
fn detached_files_to_crate_graph( fn detached_files_to_crate_graph(
@ -961,7 +958,7 @@ fn detached_files_to_crate_graph(
detached_files: &[AbsPathBuf], detached_files: &[AbsPathBuf],
sysroot: Option<&Sysroot>, sysroot: Option<&Sysroot>,
target_layout: TargetLayoutLoadResult, target_layout: TargetLayoutLoadResult,
) -> CrateGraph { ) -> (CrateGraph, ProcMacroPaths) {
let _p = profile::span("detached_files_to_crate_graph"); let _p = profile::span("detached_files_to_crate_graph");
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
let (public_deps, _libproc_macro) = match sysroot { let (public_deps, _libproc_macro) = match sysroot {
@ -998,7 +995,6 @@ fn detached_files_to_crate_graph(
cfg_options.clone(), cfg_options.clone(),
cfg_options.clone(), cfg_options.clone(),
Env::default(), Env::default(),
Ok(Vec::new()),
false, false,
CrateOrigin::CratesIo { CrateOrigin::CratesIo {
repo: None, repo: None,
@ -1009,14 +1005,14 @@ fn detached_files_to_crate_graph(
public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate); public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
} }
crate_graph (crate_graph, FxHashMap::default())
} }
fn handle_rustc_crates( fn handle_rustc_crates(
crate_graph: &mut CrateGraph, crate_graph: &mut CrateGraph,
proc_macros: &mut ProcMacroPaths,
pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>, pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
rustc_workspace: &CargoWorkspace, rustc_workspace: &CargoWorkspace,
cargo: &CargoWorkspace, cargo: &CargoWorkspace,
public_deps: &SysrootPublicDeps, public_deps: &SysrootPublicDeps,
@ -1075,10 +1071,10 @@ fn handle_rustc_crates(
if let Some(file_id) = load(&rustc_workspace[tgt].root) { if let Some(file_id) = load(&rustc_workspace[tgt].root) {
let crate_id = add_target_crate_root( let crate_id = add_target_crate_root(
crate_graph, crate_graph,
proc_macros,
&rustc_workspace[pkg], &rustc_workspace[pkg],
build_scripts.get_output(pkg), build_scripts.get_output(pkg),
cfg_options.clone(), cfg_options.clone(),
&mut |path| load_proc_macro(&rustc_workspace[tgt].name, path),
file_id, file_id,
&rustc_workspace[tgt].name, &rustc_workspace[tgt].name,
rustc_workspace[tgt].is_proc_macro, rustc_workspace[tgt].is_proc_macro,
@ -1140,10 +1136,10 @@ fn handle_rustc_crates(
fn add_target_crate_root( fn add_target_crate_root(
crate_graph: &mut CrateGraph, crate_graph: &mut CrateGraph,
proc_macros: &mut ProcMacroPaths,
pkg: &PackageData, pkg: &PackageData,
build_data: Option<&BuildScriptOutput>, build_data: Option<&BuildScriptOutput>,
cfg_options: CfgOptions, cfg_options: CfgOptions,
load_proc_macro: &mut dyn FnMut(&AbsPath) -> ProcMacroLoadResult,
file_id: FileId, file_id: FileId,
cargo_name: &str, cargo_name: &str,
is_proc_macro: bool, is_proc_macro: bool,
@ -1176,14 +1172,8 @@ fn add_target_crate_root(
} }
} }
let proc_macro = match build_data.as_ref().map(|it| it.proc_macro_dylib_path.as_ref()) {
Some(Some(it)) => load_proc_macro(it),
Some(None) => Err("no proc macro dylib present".into()),
None => Err("crate has not (yet) been built".into()),
};
let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string()); let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
crate_graph.add_crate_root( let crate_id = crate_graph.add_crate_root(
file_id, file_id,
edition, edition,
Some(display_name), Some(display_name),
@ -1191,11 +1181,19 @@ fn add_target_crate_root(
cfg_options, cfg_options,
potential_cfg_options, potential_cfg_options,
env, env,
proc_macro,
is_proc_macro, is_proc_macro,
CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) }, CrateOrigin::CratesIo { repo: pkg.repository.clone(), name: Some(pkg.name.clone()) },
target_layout, target_layout,
) );
let proc_macro = match build_data.as_ref().map(|it| &it.proc_macro_dylib_path) {
Some(it) => it.clone().map(Ok),
None => Some(Err("crate has not (yet) been built".into())),
};
if let Some(proc_macro) = proc_macro {
proc_macros.insert(crate_id, proc_macro.map(|path| (Some(cargo_name.to_owned()), path)));
}
crate_id
} }
#[derive(Default)] #[derive(Default)]
@ -1237,7 +1235,6 @@ fn sysroot_to_crate_graph(
cfg_options.clone(), cfg_options.clone(),
cfg_options.clone(), cfg_options.clone(),
env, env,
Err("no proc macro loaded for sysroot crate".into()),
false, false,
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)), CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
target_layout.clone(), target_layout.clone(),

View file

@ -6,7 +6,10 @@ use anyhow::Result;
use crossbeam_channel::{unbounded, Receiver}; use crossbeam_channel::{unbounded, Receiver};
use hir::db::DefDatabase; use hir::db::DefDatabase;
use ide::{AnalysisHost, Change}; use ide::{AnalysisHost, Change};
use ide_db::{base_db::CrateGraph, FxHashMap}; use ide_db::{
base_db::{CrateGraph, ProcMacros},
FxHashMap,
};
use proc_macro_api::ProcMacroServer; use proc_macro_api::ProcMacroServer;
use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace}; use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace};
use vfs::{loader::Handle, AbsPath, AbsPathBuf}; use vfs::{loader::Handle, AbsPath, AbsPathBuf};
@ -66,7 +69,7 @@ pub fn load_workspace(
Box::new(loader) Box::new(loader)
}; };
let proc_macro_client = match &load_config.with_proc_macro_server { let proc_macro_server = match &load_config.with_proc_macro_server {
ProcMacroServerChoice::Sysroot => ws ProcMacroServerChoice::Sysroot => ws
.find_sysroot_proc_macro_srv() .find_sysroot_proc_macro_srv()
.ok_or_else(|| "failed to find sysroot proc-macro server".to_owned()) .ok_or_else(|| "failed to find sysroot proc-macro server".to_owned())
@ -79,10 +82,7 @@ pub fn load_workspace(
ProcMacroServerChoice::None => Err("proc macro server disabled".to_owned()), ProcMacroServerChoice::None => Err("proc macro server disabled".to_owned()),
}; };
let crate_graph = ws.to_crate_graph( let (crate_graph, proc_macros) = ws.to_crate_graph(
&mut |_, path: &AbsPath| {
load_proc_macro(proc_macro_client.as_ref().map_err(|e| &**e), path, &[])
},
&mut |path: &AbsPath| { &mut |path: &AbsPath| {
let contents = loader.load_sync(path); let contents = loader.load_sync(path);
let path = vfs::VfsPath::from(path.to_path_buf()); let path = vfs::VfsPath::from(path.to_path_buf());
@ -91,6 +91,21 @@ pub fn load_workspace(
}, },
extra_env, extra_env,
); );
let proc_macros = {
let proc_macro_server = match &proc_macro_server {
Ok(it) => Ok(it),
Err(e) => Err(e.as_str()),
};
proc_macros
.into_iter()
.map(|(crate_id, path)| {
(
crate_id,
path.and_then(|(_, path)| load_proc_macro(proc_macro_server, &path, &[])),
)
})
.collect()
};
let project_folders = ProjectFolders::new(&[ws], &[]); let project_folders = ProjectFolders::new(&[ws], &[]);
loader.set_config(vfs::loader::Config { loader.set_config(vfs::loader::Config {
@ -100,17 +115,23 @@ pub fn load_workspace(
}); });
tracing::debug!("crate graph: {:?}", crate_graph); tracing::debug!("crate graph: {:?}", crate_graph);
let host = let host = load_crate_graph(
load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver); crate_graph,
proc_macros,
project_folders.source_root_config,
&mut vfs,
&receiver,
);
if load_config.prefill_caches { if load_config.prefill_caches {
host.analysis().parallel_prime_caches(1, |_| {})?; host.analysis().parallel_prime_caches(1, |_| {})?;
} }
Ok((host, vfs, proc_macro_client.ok())) Ok((host, vfs, proc_macro_server.ok()))
} }
fn load_crate_graph( fn load_crate_graph(
crate_graph: CrateGraph, crate_graph: CrateGraph,
proc_macros: ProcMacros,
source_root_config: SourceRootConfig, source_root_config: SourceRootConfig,
vfs: &mut vfs::Vfs, vfs: &mut vfs::Vfs,
receiver: &Receiver<vfs::loader::Message>, receiver: &Receiver<vfs::loader::Message>,
@ -149,6 +170,7 @@ fn load_crate_graph(
analysis_change.set_roots(source_roots); analysis_change.set_roots(source_roots);
analysis_change.set_crate_graph(crate_graph); analysis_change.set_crate_graph(crate_graph);
analysis_change.set_proc_macros(proc_macros);
host.apply_change(analysis_change); host.apply_change(analysis_change);
host host

View file

@ -59,10 +59,11 @@ pub(crate) struct GlobalState {
pub(crate) mem_docs: MemDocs, pub(crate) mem_docs: MemDocs,
pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
pub(crate) shutdown_requested: bool, pub(crate) shutdown_requested: bool,
pub(crate) proc_macro_changed: bool,
pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>, pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
pub(crate) source_root_config: SourceRootConfig, pub(crate) source_root_config: SourceRootConfig,
pub(crate) proc_macro_clients: Vec<Result<ProcMacroServer, String>>,
pub(crate) proc_macro_changed: bool,
pub(crate) proc_macro_clients: Arc<[Result<ProcMacroServer, String>]>,
pub(crate) flycheck: Arc<[FlycheckHandle]>, pub(crate) flycheck: Arc<[FlycheckHandle]>,
pub(crate) flycheck_sender: Sender<flycheck::Message>, pub(crate) flycheck_sender: Sender<flycheck::Message>,
@ -151,10 +152,11 @@ impl GlobalState {
mem_docs: MemDocs::default(), mem_docs: MemDocs::default(),
semantic_tokens_cache: Arc::new(Default::default()), semantic_tokens_cache: Arc::new(Default::default()),
shutdown_requested: false, shutdown_requested: false,
proc_macro_changed: false,
last_reported_status: None, last_reported_status: None,
source_root_config: SourceRootConfig::default(), source_root_config: SourceRootConfig::default(),
proc_macro_clients: vec![],
proc_macro_changed: false,
proc_macro_clients: Arc::new([]),
flycheck: Arc::new([]), flycheck: Arc::new([]),
flycheck_sender, flycheck_sender,

View file

@ -5,6 +5,7 @@
use std::{ use std::{
io::Write as _, io::Write as _,
process::{self, Stdio}, process::{self, Stdio},
sync::Arc,
}; };
use anyhow::Context; use anyhow::Context;
@ -44,7 +45,7 @@ use crate::{
}; };
pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> { pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<()> {
state.proc_macro_clients.clear(); state.proc_macro_clients = Arc::new([]);
state.proc_macro_changed = false; state.proc_macro_changed = false;
state.fetch_workspaces_queue.request_op("reload workspace request".to_string()); state.fetch_workspaces_queue.request_op("reload workspace request".to_string());
@ -52,6 +53,14 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> Result<
Ok(()) Ok(())
} }
pub(crate) fn handle_proc_macros_reload(state: &mut GlobalState, _: ()) -> Result<()> {
state.proc_macro_clients = Arc::new([]);
state.proc_macro_changed = false;
state.fetch_build_data_queue.request_op("reload proc macros request".to_string());
Ok(())
}
pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> { pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> Result<()> {
let _p = profile::span("handle_stop_flycheck"); let _p = profile::span("handle_stop_flycheck");
state.flycheck.iter().for_each(|flycheck| flycheck.cancel()); state.flycheck.iter().for_each(|flycheck| flycheck.cancel());

View file

@ -51,6 +51,14 @@ impl Request for ReloadWorkspace {
const METHOD: &'static str = "rust-analyzer/reloadWorkspace"; const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
} }
pub enum ReloadProcMacros {}
impl Request for ReloadProcMacros {
type Params = ();
type Result = ();
const METHOD: &'static str = "rust-analyzer/reloadProcMacros";
}
pub enum SyntaxTree {} pub enum SyntaxTree {}
impl Request for SyntaxTree { impl Request for SyntaxTree {

View file

@ -24,7 +24,7 @@ use crate::{
handlers, lsp_ext, handlers, lsp_ext,
lsp_utils::{apply_document_changes, notification_is, Progress}, lsp_utils::{apply_document_changes, notification_is, Progress},
mem_docs::DocumentData, mem_docs::DocumentData,
reload::{self, BuildDataProgress, ProjectWorkspaceProgress}, reload::{self, BuildDataProgress, ProcMacroProgress, ProjectWorkspaceProgress},
Result, Result,
}; };
@ -68,6 +68,7 @@ pub(crate) enum Task {
PrimeCaches(PrimeCachesProgress), PrimeCaches(PrimeCachesProgress),
FetchWorkspace(ProjectWorkspaceProgress), FetchWorkspace(ProjectWorkspaceProgress),
FetchBuildData(BuildDataProgress), FetchBuildData(BuildDataProgress),
LoadProcMacros(ProcMacroProgress),
} }
#[derive(Debug)] #[derive(Debug)]
@ -487,6 +488,21 @@ impl GlobalState {
} }
}; };
if let Some(state) = state {
self.report_progress("Building", state, msg, None, None);
}
}
Task::LoadProcMacros(progress) => {
let (state, msg) = match progress {
ProcMacroProgress::Begin => (Some(Progress::Begin), None),
ProcMacroProgress::Report(msg) => (Some(Progress::Report), Some(msg)),
ProcMacroProgress::End(proc_macro_load_result) => {
self.set_proc_macros(proc_macro_load_result);
(Some(Progress::End), None)
}
};
if let Some(state) = state { if let Some(state) = state {
self.report_progress("Loading", state, msg, None, None); self.report_progress("Loading", state, msg, None, None);
} }
@ -633,6 +649,7 @@ impl GlobalState {
dispatcher dispatcher
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload) .on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
.on_sync_mut::<lsp_ext::ReloadProcMacros>(handlers::handle_proc_macros_reload)
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage) .on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph) .on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines) .on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)

View file

@ -12,7 +12,7 @@
//! correct. Instead, we try to provide a best-effort service. Even if the //! correct. Instead, we try to provide a best-effort service. Even if the
//! project is currently loading and we don't have a full project model, we //! project is currently loading and we don't have a full project model, we
//! still want to respond to various requests. //! still want to respond to various requests.
use std::{collections::hash_map::Entry, mem, sync::Arc}; use std::{collections::hash_map::Entry, iter, mem, sync::Arc};
use flycheck::{FlycheckConfig, FlycheckHandle}; use flycheck::{FlycheckConfig, FlycheckHandle};
use hir::db::DefDatabase; use hir::db::DefDatabase;
@ -20,7 +20,7 @@ use ide::Change;
use ide_db::{ use ide_db::{
base_db::{ base_db::{
CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind, CrateGraph, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind,
ProcMacroLoadResult, SourceRoot, VfsPath, ProcMacroLoadResult, ProcMacroPaths, ProcMacros, SourceRoot, VfsPath,
}, },
FxHashMap, FxHashMap,
}; };
@ -54,6 +54,13 @@ pub(crate) enum BuildDataProgress {
End((Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)), End((Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)),
} }
#[derive(Debug)]
pub(crate) enum ProcMacroProgress {
Begin,
Report(String),
End(ProcMacros),
}
impl GlobalState { impl GlobalState {
pub(crate) fn is_quiescent(&self) -> bool { pub(crate) fn is_quiescent(&self) -> bool {
!(self.last_reported_status.is_none() !(self.last_reported_status.is_none()
@ -216,6 +223,59 @@ impl GlobalState {
}); });
} }
pub(crate) fn load_proc_macros(&mut self, paths: Vec<ProcMacroPaths>) {
tracing::info!("will load proc macros");
let dummy_replacements = self.config.dummy_replacements().clone();
let proc_macro_clients = self.proc_macro_clients.clone();
self.task_pool.handle.spawn_with_sender(move |sender| {
sender.send(Task::LoadProcMacros(ProcMacroProgress::Begin)).unwrap();
let dummy_replacements = &dummy_replacements;
let progress = {
let sender = sender.clone();
&move |msg| {
sender.send(Task::LoadProcMacros(ProcMacroProgress::Report(msg))).unwrap()
}
};
let mut res = FxHashMap::default();
for (client, paths) in proc_macro_clients
.iter()
.map(|res| res.as_ref().map_err(|e| &**e))
.chain(iter::repeat_with(|| Err("Proc macros are disabled")))
.zip(paths)
{
res.extend(paths.into_iter().map(move |(crate_id, res)| {
(
crate_id,
res.and_then(|(crate_name, path)| {
progress(path.display().to_string());
load_proc_macro(
client,
&path,
crate_name
.as_deref()
.and_then(|crate_name| {
dummy_replacements.get(crate_name).map(|v| &**v)
})
.unwrap_or_default(),
)
}),
)
}));
}
sender.send(Task::LoadProcMacros(ProcMacroProgress::End(res))).unwrap();
});
}
pub(crate) fn set_proc_macros(&mut self, proc_macros: ProcMacros) {
let mut change = Change::new();
change.set_proc_macros(proc_macros);
self.analysis_host.apply_change(change);
}
pub(crate) fn switch_workspaces(&mut self, cause: Cause) { pub(crate) fn switch_workspaces(&mut self, cause: Cause) {
let _p = profile::span("GlobalState::switch_workspaces"); let _p = profile::span("GlobalState::switch_workspaces");
tracing::info!(%cause, "will switch workspaces"); tracing::info!(%cause, "will switch workspaces");
@ -303,8 +363,6 @@ impl GlobalState {
); );
} }
let mut change = Change::new();
let files_config = self.config.files(); let files_config = self.config.files();
let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
@ -353,11 +411,10 @@ impl GlobalState {
watch, watch,
version: self.vfs_config_version, version: self.vfs_config_version,
}); });
self.source_root_config = project_folders.source_root_config;
// Create crate graph from all the workspaces // Create crate graph from all the workspaces
let crate_graph = { let (crate_graph, proc_macro_paths) = {
let dummy_replacements = self.config.dummy_replacements();
let vfs = &mut self.vfs.write().0; let vfs = &mut self.vfs.write().0;
let loader = &mut self.loader; let loader = &mut self.loader;
let mem_docs = &self.mem_docs; let mem_docs = &self.mem_docs;
@ -376,33 +433,26 @@ impl GlobalState {
}; };
let mut crate_graph = CrateGraph::default(); let mut crate_graph = CrateGraph::default();
for (idx, ws) in self.workspaces.iter().enumerate() { let mut proc_macros = Vec::default();
let proc_macro_client = match self.proc_macro_clients.get(idx) { for ws in &**self.workspaces {
Some(res) => res.as_ref().map_err(|e| &**e), let (other, mut crate_proc_macros) =
None => Err("Proc macros are disabled"), ws.to_crate_graph(&mut load, &self.config.cargo().extra_env);
}; crate_graph.extend(other, &mut crate_proc_macros);
let mut load_proc_macro = move |crate_name: &str, path: &AbsPath| { proc_macros.push(crate_proc_macros);
load_proc_macro(
proc_macro_client,
path,
dummy_replacements.get(crate_name).map(|v| &**v).unwrap_or_default(),
)
};
crate_graph.extend(ws.to_crate_graph(
&mut load_proc_macro,
&mut load,
&self.config.cargo().extra_env,
));
} }
crate_graph (crate_graph, proc_macros)
}; };
let mut change = Change::new();
change.set_crate_graph(crate_graph); change.set_crate_graph(crate_graph);
self.source_root_config = project_folders.source_root_config;
self.analysis_host.apply_change(change); self.analysis_host.apply_change(change);
self.process_changes(); self.process_changes();
if same_workspaces && !self.fetch_workspaces_queue.op_requested() {
self.load_proc_macros(proc_macro_paths);
}
self.reload_flycheck(); self.reload_flycheck();
tracing::info!("did switch workspaces"); tracing::info!("did switch workspaces");
} }

View file

@ -1,5 +1,5 @@
<!--- <!---
lsp_ext.rs hash: 37f31ae648632897 lsp_ext.rs hash: 92fe1037312754df
If you need to change the above hash to make the test pass, please check if you If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: need to adjust this doc as well and ping this issue:

View file

@ -749,6 +749,10 @@ export function reloadWorkspace(ctx: CtxInit): Cmd {
return async () => ctx.client.sendRequest(ra.reloadWorkspace); return async () => ctx.client.sendRequest(ra.reloadWorkspace);
} }
export function reloadProcMacros(ctx: CtxInit): Cmd {
return async () => ctx.client.sendRequest(ra.reloadProcMacros);
}
export function addProject(ctx: CtxInit): Cmd { export function addProject(ctx: CtxInit): Cmd {
return async () => { return async () => {
const discoverProjectCommand = ctx.config.discoverProjectCommand; const discoverProjectCommand = ctx.config.discoverProjectCommand;

View file

@ -378,10 +378,13 @@ export class Ctx {
if (statusBar.tooltip.value) { if (statusBar.tooltip.value) {
statusBar.tooltip.appendText("\n\n"); statusBar.tooltip.appendText("\n\n");
} }
statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)");
statusBar.tooltip.appendMarkdown( statusBar.tooltip.appendMarkdown(
"\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)" "\n\n[Reload Workspace](command:rust-analyzer.reloadWorkspace)"
); );
statusBar.tooltip.appendMarkdown("\n\n[Open logs](command:rust-analyzer.openLogs)"); statusBar.tooltip.appendMarkdown(
"\n\n[Rebuild Proc Macros](command:rust-analyzer.reloadProcMacros)"
);
statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)"); statusBar.tooltip.appendMarkdown("\n\n[Restart server](command:rust-analyzer.startServer)");
statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)"); statusBar.tooltip.appendMarkdown("\n\n[Stop server](command:rust-analyzer.stopServer)");
if (!status.quiescent) icon = "$(sync~spin) "; if (!status.quiescent) icon = "$(sync~spin) ";

View file

@ -43,6 +43,7 @@ export const relatedTests = new lc.RequestType<lc.TextDocumentPositionParams, Te
"rust-analyzer/relatedTests" "rust-analyzer/relatedTests"
); );
export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace"); export const reloadWorkspace = new lc.RequestType0<null, void>("rust-analyzer/reloadWorkspace");
export const reloadProcMacros = new lc.RequestType0<null, void>("rust-analyzer/reloadProcMacros");
export const runFlycheck = new lc.NotificationType<{ export const runFlycheck = new lc.NotificationType<{
textDocument: lc.TextDocumentIdentifier | null; textDocument: lc.TextDocumentIdentifier | null;

View file

@ -153,6 +153,7 @@ function createCommands(): Record<string, CommandFactory> {
memoryUsage: { enabled: commands.memoryUsage }, memoryUsage: { enabled: commands.memoryUsage },
shuffleCrateGraph: { enabled: commands.shuffleCrateGraph }, shuffleCrateGraph: { enabled: commands.shuffleCrateGraph },
reloadWorkspace: { enabled: commands.reloadWorkspace }, reloadWorkspace: { enabled: commands.reloadWorkspace },
reloadProcMacros: { enabled: commands.reloadProcMacros },
addProject: { enabled: commands.addProject }, addProject: { enabled: commands.addProject },
matchingBrace: { enabled: commands.matchingBrace }, matchingBrace: { enabled: commands.matchingBrace },
joinLines: { enabled: commands.joinLines }, joinLines: { enabled: commands.joinLines },