2020-02-18 11:11:32 +00:00
|
|
|
//! Loads a Cargo project into a static instance of analysis, without support
|
|
|
|
//! for incorporating changes.
|
2020-06-24 13:52:07 +00:00
|
|
|
use std::{path::Path, sync::Arc};
|
2019-02-05 21:54:17 +00:00
|
|
|
|
2020-02-18 11:11:32 +00:00
|
|
|
use anyhow::Result;
|
2019-08-25 10:04:56 +00:00
|
|
|
use crossbeam_channel::{unbounded, Receiver};
|
Enable attribute macro expansion in `analysis-stats`
Before:
```
> $ rust-analyzer -q analysis-stats --with-proc-macro --load-output-dirs .
Database loaded: 19.08s, 277minstr
crates: 34, mods: 688, decls: 13202, fns: 10412
Item Collection: 16.21s, 76ginstr
exprs: 290580, ??ty: 2508 (0%), ?ty: 1814 (0%), !ty: 947
Inference: 27.46s, 108ginstr
Total: 43.67s, 184ginstr
```
After:
```
> $ ./target/release/rust-analyzer -q analysis-stats --with-proc-macro --load-output-dirs .
Database loaded: 1.09s, 277minstr
crates: 34, mods: 688, decls: 14790, fns: 11006
Item Collection: 18.20s, 78ginstr
exprs: 297826, ??ty: 493 (0%), ?ty: 558 (0%), !ty: 342
Inference: 28.34s, 111ginstr
Total: 46.54s, 190ginstr
```
2021-06-05 09:29:24 +00:00
|
|
|
use hir::db::DefDatabase;
|
2020-10-02 13:45:09 +00:00
|
|
|
use ide::{AnalysisHost, Change};
|
2020-10-24 08:39:57 +00:00
|
|
|
use ide_db::base_db::CrateGraph;
|
2021-01-28 15:33:02 +00:00
|
|
|
use project_model::{
|
|
|
|
BuildDataCollector, CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace,
|
|
|
|
};
|
2020-07-08 16:22:57 +00:00
|
|
|
use vfs::{loader::Handle, AbsPath, AbsPathBuf};
|
2020-02-17 18:07:30 +00:00
|
|
|
|
2020-06-25 21:44:58 +00:00
|
|
|
use crate::reload::{ProjectFolders, SourceRootConfig};
|
2019-02-09 12:06:12 +00:00
|
|
|
|
2021-06-10 22:48:15 +00:00
|
|
|
pub(crate) struct LoadCargoConfig {
|
|
|
|
pub(crate) load_out_dirs_from_check: bool,
|
|
|
|
pub(crate) wrap_rustc: bool,
|
|
|
|
pub(crate) with_proc_macro: bool,
|
2021-06-11 06:27:25 +00:00
|
|
|
pub(crate) prefill_caches: bool,
|
2021-02-08 10:30:16 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 22:48:15 +00:00
|
|
|
pub(crate) fn load_workspace_at(
|
2021-02-15 23:26:47 +00:00
|
|
|
root: &Path,
|
|
|
|
cargo_config: &CargoConfig,
|
|
|
|
load_config: &LoadCargoConfig,
|
|
|
|
progress: &dyn Fn(String),
|
2021-03-02 05:14:05 +00:00
|
|
|
) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroClient>)> {
|
2020-06-24 11:34:24 +00:00
|
|
|
let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
|
2020-06-03 10:05:50 +00:00
|
|
|
let root = ProjectManifest::discover_single(&root)?;
|
2021-02-15 23:26:47 +00:00
|
|
|
let workspace = ProjectWorkspace::load(root, cargo_config, progress)?;
|
2020-03-16 13:51:44 +00:00
|
|
|
|
2021-02-15 23:26:47 +00:00
|
|
|
load_workspace(workspace, load_config, progress)
|
|
|
|
}
|
|
|
|
|
2021-06-10 22:35:14 +00:00
|
|
|
fn load_workspace(
|
2021-02-15 23:26:47 +00:00
|
|
|
ws: ProjectWorkspace,
|
|
|
|
config: &LoadCargoConfig,
|
|
|
|
progress: &dyn Fn(String),
|
2021-03-02 05:14:05 +00:00
|
|
|
) -> Result<(AnalysisHost, vfs::Vfs, Option<ProcMacroClient>)> {
|
2019-08-25 10:04:56 +00:00
|
|
|
let (sender, receiver) = unbounded();
|
2020-06-11 09:04:09 +00:00
|
|
|
let mut vfs = vfs::Vfs::default();
|
|
|
|
let mut loader = {
|
|
|
|
let loader =
|
2020-06-25 06:59:55 +00:00
|
|
|
vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
|
2020-06-11 09:04:09 +00:00
|
|
|
Box::new(loader)
|
|
|
|
};
|
2020-03-18 12:56:46 +00:00
|
|
|
|
2021-02-08 10:30:16 +00:00
|
|
|
let proc_macro_client = if config.with_proc_macro {
|
2020-04-16 20:42:05 +00:00
|
|
|
let path = std::env::current_exe()?;
|
2020-12-07 16:16:50 +00:00
|
|
|
Some(ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap())
|
2020-06-11 09:04:09 +00:00
|
|
|
} else {
|
2020-12-07 16:16:50 +00:00
|
|
|
None
|
2020-04-12 10:25:31 +00:00
|
|
|
};
|
2020-06-11 09:04:09 +00:00
|
|
|
|
2021-02-08 10:30:16 +00:00
|
|
|
let build_data = if config.load_out_dirs_from_check {
|
2021-04-12 08:04:36 +00:00
|
|
|
let mut collector = BuildDataCollector::new(config.wrap_rustc);
|
2021-01-28 15:33:02 +00:00
|
|
|
ws.collect_build_data_configs(&mut collector);
|
2021-02-15 23:26:47 +00:00
|
|
|
Some(collector.collect(progress)?)
|
2021-01-28 15:33:02 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let crate_graph = ws.to_crate_graph(
|
|
|
|
build_data.as_ref(),
|
|
|
|
proc_macro_client.as_ref(),
|
|
|
|
&mut |path: &AbsPath| {
|
|
|
|
let contents = loader.load_sync(path);
|
|
|
|
let path = vfs::VfsPath::from(path.to_path_buf());
|
|
|
|
vfs.set_file_contents(path.clone(), contents);
|
|
|
|
vfs.file_id(&path)
|
|
|
|
},
|
|
|
|
);
|
2020-06-11 09:04:09 +00:00
|
|
|
|
2021-01-28 15:33:02 +00:00
|
|
|
let project_folders = ProjectFolders::new(&[ws], &[], build_data.as_ref());
|
2021-02-12 14:58:29 +00:00
|
|
|
loader.set_config(vfs::loader::Config {
|
|
|
|
load: project_folders.load,
|
|
|
|
watch: vec![],
|
|
|
|
version: 0,
|
|
|
|
});
|
2020-06-11 09:04:09 +00:00
|
|
|
|
|
|
|
log::debug!("crate graph: {:?}", crate_graph);
|
2021-02-15 23:26:47 +00:00
|
|
|
let host =
|
|
|
|
load_crate_graph(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
|
2021-06-10 22:35:14 +00:00
|
|
|
|
2021-06-11 06:27:25 +00:00
|
|
|
if config.prefill_caches {
|
|
|
|
host.analysis().prime_caches(|_| {})?;
|
|
|
|
}
|
2021-03-02 05:14:05 +00:00
|
|
|
Ok((host, vfs, proc_macro_client))
|
2019-06-15 13:29:23 +00:00
|
|
|
}
|
2019-02-09 12:06:12 +00:00
|
|
|
|
2021-02-15 23:26:47 +00:00
|
|
|
fn load_crate_graph(
|
2020-06-11 09:04:09 +00:00
|
|
|
crate_graph: CrateGraph,
|
|
|
|
source_root_config: SourceRootConfig,
|
|
|
|
vfs: &mut vfs::Vfs,
|
|
|
|
receiver: &Receiver<vfs::loader::Message>,
|
2019-06-16 16:19:38 +00:00
|
|
|
) -> AnalysisHost {
|
2019-06-15 13:29:23 +00:00
|
|
|
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
|
2020-03-10 17:56:15 +00:00
|
|
|
let mut host = AnalysisHost::new(lru_cap);
|
2020-10-02 13:45:09 +00:00
|
|
|
let mut analysis_change = Change::new();
|
2019-06-15 13:29:23 +00:00
|
|
|
|
Enable attribute macro expansion in `analysis-stats`
Before:
```
> $ rust-analyzer -q analysis-stats --with-proc-macro --load-output-dirs .
Database loaded: 19.08s, 277minstr
crates: 34, mods: 688, decls: 13202, fns: 10412
Item Collection: 16.21s, 76ginstr
exprs: 290580, ??ty: 2508 (0%), ?ty: 1814 (0%), !ty: 947
Inference: 27.46s, 108ginstr
Total: 43.67s, 184ginstr
```
After:
```
> $ ./target/release/rust-analyzer -q analysis-stats --with-proc-macro --load-output-dirs .
Database loaded: 1.09s, 277minstr
crates: 34, mods: 688, decls: 14790, fns: 11006
Item Collection: 18.20s, 78ginstr
exprs: 297826, ??ty: 493 (0%), ?ty: 558 (0%), !ty: 342
Inference: 28.34s, 111ginstr
Total: 46.54s, 190ginstr
```
2021-06-05 09:29:24 +00:00
|
|
|
host.raw_database_mut().set_enable_proc_attr_macros(true);
|
|
|
|
|
2019-06-15 13:29:23 +00:00
|
|
|
// wait until Vfs has loaded all roots
|
|
|
|
for task in receiver {
|
2020-06-11 09:04:09 +00:00
|
|
|
match task {
|
2021-02-12 14:58:29 +00:00
|
|
|
vfs::loader::Message::Progress { n_done, n_total, config_version: _ } => {
|
2020-06-24 14:58:49 +00:00
|
|
|
if n_done == n_total {
|
2020-06-11 09:04:09 +00:00
|
|
|
break;
|
2019-11-24 09:06:00 +00:00
|
|
|
}
|
2020-06-11 09:04:09 +00:00
|
|
|
}
|
|
|
|
vfs::loader::Message::Loaded { files } => {
|
|
|
|
for (path, contents) in files {
|
2020-12-09 16:29:34 +00:00
|
|
|
vfs.set_file_contents(path.into(), contents);
|
2019-06-15 13:29:23 +00:00
|
|
|
}
|
2019-02-09 12:06:12 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-11 09:04:09 +00:00
|
|
|
}
|
|
|
|
let changes = vfs.take_changes();
|
|
|
|
for file in changes {
|
|
|
|
if file.exists() {
|
|
|
|
let contents = vfs.file_contents(file.file_id).to_vec();
|
|
|
|
if let Ok(text) = String::from_utf8(contents) {
|
|
|
|
analysis_change.change_file(file.file_id, Some(Arc::new(text)))
|
|
|
|
}
|
2019-06-15 13:29:23 +00:00
|
|
|
}
|
2019-02-09 12:06:12 +00:00
|
|
|
}
|
2021-06-13 03:54:16 +00:00
|
|
|
let source_roots = source_root_config.partition(vfs);
|
2020-06-11 09:04:09 +00:00
|
|
|
analysis_change.set_roots(source_roots);
|
2019-02-09 12:06:12 +00:00
|
|
|
|
2020-03-16 13:51:44 +00:00
|
|
|
analysis_change.set_crate_graph(crate_graph);
|
|
|
|
|
2019-06-15 13:29:23 +00:00
|
|
|
host.apply_change(analysis_change);
|
|
|
|
host
|
2019-02-09 12:06:12 +00:00
|
|
|
}
|
2019-02-10 10:44:53 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-02-17 16:31:09 +00:00
|
|
|
|
|
|
|
use hir::Crate;
|
2019-02-10 10:44:53 +00:00
|
|
|
|
|
|
|
#[test]
|
2021-02-15 23:26:47 +00:00
|
|
|
fn test_loading_rust_analyzer() -> Result<()> {
|
2019-04-04 09:57:10 +00:00
|
|
|
let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
|
2021-02-15 23:26:47 +00:00
|
|
|
let cargo_config = Default::default();
|
2021-04-12 08:04:36 +00:00
|
|
|
let load_cargo_config = LoadCargoConfig {
|
|
|
|
load_out_dirs_from_check: false,
|
|
|
|
wrap_rustc: false,
|
|
|
|
with_proc_macro: false,
|
2021-06-11 06:27:25 +00:00
|
|
|
prefill_caches: false,
|
2021-04-12 08:04:36 +00:00
|
|
|
};
|
2021-03-02 05:14:05 +00:00
|
|
|
let (host, _vfs, _proc_macro) =
|
|
|
|
load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?;
|
2021-02-08 10:30:16 +00:00
|
|
|
|
2019-10-14 12:15:47 +00:00
|
|
|
let n_crates = Crate::all(host.raw_database()).len();
|
2019-02-10 10:44:53 +00:00
|
|
|
// RA has quite a few crates, but the exact count doesn't matter
|
2019-02-17 18:05:33 +00:00
|
|
|
assert!(n_crates > 20);
|
2021-02-15 23:26:47 +00:00
|
|
|
|
|
|
|
Ok(())
|
2019-02-10 10:44:53 +00:00
|
|
|
}
|
|
|
|
}
|