1 //! Loads a Cargo project into a static instance of analysis, without support
2 //! for incorporating changes.
3 use std::{path::Path, sync::Arc};
6 use crossbeam_channel::{unbounded, Receiver};
7 use ide::{AnalysisHost, Change};
8 use ide_db::base_db::CrateGraph;
10 BuildDataCollector, CargoConfig, ProcMacroClient, ProjectManifest, ProjectWorkspace,
12 use vfs::{loader::Handle, AbsPath, AbsPathBuf};
14 use crate::reload::{ProjectFolders, SourceRootConfig};
18 load_out_dirs_from_check: bool,
19 with_proc_macro: bool,
20 ) -> Result<(AnalysisHost, vfs::Vfs)> {
21 let root = AbsPathBuf::assert(std::env::current_dir()?.join(root));
22 let root = ProjectManifest::discover_single(&root)?;
23 let ws = ProjectWorkspace::load(root, &CargoConfig::default(), &|_| {})?;
25 let (sender, receiver) = unbounded();
26 let mut vfs = vfs::Vfs::default();
29 vfs_notify::NotifyHandle::spawn(Box::new(move |msg| sender.send(msg).unwrap()));
33 let proc_macro_client = if with_proc_macro {
34 let path = std::env::current_exe()?;
35 Some(ProcMacroClient::extern_process(path, &["proc-macro"]).unwrap())
40 let build_data = if load_out_dirs_from_check {
41 let mut collector = BuildDataCollector::default();
42 ws.collect_build_data_configs(&mut collector);
43 Some(collector.collect(&|_| {})?)
48 let crate_graph = ws.to_crate_graph(
50 proc_macro_client.as_ref(),
51 &mut |path: &AbsPath| {
52 let contents = loader.load_sync(path);
53 let path = vfs::VfsPath::from(path.to_path_buf());
54 vfs.set_file_contents(path.clone(), contents);
59 let project_folders = ProjectFolders::new(&[ws], &[], build_data.as_ref());
60 loader.set_config(vfs::loader::Config { load: project_folders.load, watch: vec![] });
62 log::debug!("crate graph: {:?}", crate_graph);
63 let host = load(crate_graph, project_folders.source_root_config, &mut vfs, &receiver);
68 crate_graph: CrateGraph,
69 source_root_config: SourceRootConfig,
71 receiver: &Receiver<vfs::loader::Message>,
73 let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
74 let mut host = AnalysisHost::new(lru_cap);
75 let mut analysis_change = Change::new();
77 // wait until Vfs has loaded all roots
78 for task in receiver {
80 vfs::loader::Message::Progress { n_done, n_total } => {
81 if n_done == n_total {
85 vfs::loader::Message::Loaded { files } => {
86 for (path, contents) in files {
87 vfs.set_file_contents(path.into(), contents);
92 let changes = vfs.take_changes();
95 let contents = vfs.file_contents(file.file_id).to_vec();
96 if let Ok(text) = String::from_utf8(contents) {
97 analysis_change.change_file(file.file_id, Some(Arc::new(text)))
101 let source_roots = source_root_config.partition(&vfs);
102 analysis_change.set_roots(source_roots);
104 analysis_change.set_crate_graph(crate_graph);
106 host.apply_change(analysis_change);
117 fn test_loading_rust_analyzer() {
118 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
119 let (host, _vfs) = load_cargo(path, false, false).unwrap();
120 let n_crates = Crate::all(host.raw_database()).len();
121 // RA has quite a few crates, but the exact count doesn't matter
122 assert!(n_crates > 20);