From cd00158b1db9dd8565d2db08b4b0ebab9d5c00b3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 11 Jan 2019 00:37:10 +0300 Subject: wire sysroot into crate graph --- crates/ra_lsp_server/src/project_model/sysroot.rs | 27 ++++++++++-- crates/ra_lsp_server/src/server_world.rs | 51 ++++++++++++++++++++++- crates/ra_lsp_server/tests/heavy_tests/main.rs | 41 +++++++----------- crates/ra_lsp_server/tests/heavy_tests/support.rs | 13 +++--- 4 files changed, 95 insertions(+), 37 deletions(-) (limited to 'crates') diff --git a/crates/ra_lsp_server/src/project_model/sysroot.rs b/crates/ra_lsp_server/src/project_model/sysroot.rs index c4028a1fe..1dbab57f8 100644 --- a/crates/ra_lsp_server/src/project_model/sysroot.rs +++ b/crates/ra_lsp_server/src/project_model/sysroot.rs @@ -20,7 +20,7 @@ impl_arena_id!(SysrootCrate); #[derive(Debug, Clone)] struct SysrootCrateData { name: SmolStr, - path: PathBuf, + root: PathBuf, deps: Vec, } @@ -29,6 +29,10 @@ impl Sysroot { self.by_name("std") } + pub(crate) fn crates<'a>(&'a self) -> impl Iterator + 'a { + self.crates.iter().map(|(id, _data)| id) + } + pub(super) fn discover(cargo_toml: &Path) -> Result { let rustc_output = Command::new("rustc") .current_dir(cargo_toml.parent().unwrap()) @@ -45,11 +49,11 @@ impl Sysroot { crates: Arena::default(), }; for name in SYSROOT_CRATES.trim().lines() { - let path = src.join(format!("lib{}", name)).join("lib.rs"); - if path.exists() { + let root = src.join(format!("lib{}", name)).join("lib.rs"); + if root.exists() { sysroot.crates.alloc(SysrootCrateData { name: name.into(), - path, + root, deps: Vec::new(), }); } @@ -72,6 +76,21 @@ impl Sysroot { } } +impl SysrootCrate { + pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { + &sysroot.crates[self].name + } + pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { + sysroot.crates[self].root.as_path() + } + pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { + self.root(sysroot).parent().unwrap() + } + pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator + 'a { + sysroot.crates[self].deps.iter().map(|&it| it) + } +} + const SYSROOT_CRATES: &str = " std core diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 2debbe557..4f3c231d3 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -44,7 +44,12 @@ impl ServerWorldState { for pkg in ws.cargo.packages() { roots.push(pkg.root(&ws.cargo).to_path_buf()); } + for krate in ws.sysroot.crates() { + roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) + } } + roots.sort(); + roots.dedup(); let roots_to_scan = roots.len(); let (mut vfs, roots) = Vfs::new(roots); for r in roots { @@ -53,16 +58,43 @@ impl ServerWorldState { } let mut crate_graph = CrateGraph::default(); - let mut pkg_to_lib_crate = FxHashMap::default(); - let mut pkg_crates = FxHashMap::default(); for ws in workspaces.iter() { + // First, load std + let mut sysroot_crates = FxHashMap::default(); + for krate in ws.sysroot.crates() { + if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) { + let file_id = FileId(file_id.0.into()); + sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); + } + } + for from in ws.sysroot.crates() { + for to in from.deps(&ws.sysroot) { + let name = to.name(&ws.sysroot); + if let (Some(&from), Some(&to)) = + (sysroot_crates.get(&from), sysroot_crates.get(&to)) + { + crate_graph.add_dep(from, name.clone(), to); + } + } + } + + let libstd = ws + .sysroot + .std() + .and_then(|it| sysroot_crates.get(&it).map(|&it| it)); + + let mut pkg_to_lib_crate = FxHashMap::default(); + let mut pkg_crates = FxHashMap::default(); + // Next, create crates for each package, target pair for pkg in ws.cargo.packages() { + let mut lib_tgt = None; for tgt in pkg.targets(&ws.cargo) { let root = tgt.root(&ws.cargo); if let Some(file_id) = vfs.load(root) { let file_id = FileId(file_id.0.into()); let crate_id = crate_graph.add_crate_root(file_id); if tgt.kind(&ws.cargo) == TargetKind::Lib { + lib_tgt = Some(crate_id); pkg_to_lib_crate.insert(pkg, crate_id); } pkg_crates @@ -71,7 +103,22 @@ impl ServerWorldState { .push(crate_id); } } + + // Set deps to the std and to the lib target of the current package + for &from in pkg_crates.get(&pkg).into_iter().flatten() { + if let Some(to) = lib_tgt { + if to != from { + crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to); + } + } + if let Some(std) = libstd { + crate_graph.add_dep(from, "std".into(), std); + } + } } + + // Now add a dep ednge from all targets of upstream to the lib + // target of downstream. for pkg in ws.cargo.packages() { for dep in pkg.dependencies(&ws.cargo) { if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 927664ffb..02d62a259 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs @@ -1,5 +1,10 @@ mod support; +use std::{ + collections::HashMap, + time::Instant, +}; + use languageserver_types::{ CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, }; @@ -14,6 +19,7 @@ const LOG: &'static str = ""; #[test] fn completes_items_from_standard_library() { + let project_start = Instant::now(); let server = project( r#" //- Cargo.toml @@ -22,33 +28,19 @@ name = "foo" version = "0.0.0" //- src/lib.rs -use std::collections::; +use std::collections::Spam; "#, ); server.wait_for_feedback("workspace loaded"); - server.request::( - CompletionParams { - text_document: server.doc_id("src/lib.rs"), - context: None, - position: Position::new(0, 22), - }, - json!([ - { - "filterText": "self", - "insertText": "self", - "insertTextFormat": 1, - "kind": 14, - "label": "self" - }, - { - "filterText": "super", - "insertText": "super", - "insertTextFormat": 1, - "kind": 14, - "label": "super" - } - ]), - ); + eprintln!("loading took {:?}", project_start.elapsed()); + let completion_start = Instant::now(); + let res = server.send_request::(CompletionParams { + text_document: server.doc_id("src/lib.rs"), + context: None, + position: Position::new(0, 23), + }); + assert!(format!("{}", res).contains("HashMap")); + eprintln!("completion took {:?}", completion_start.elapsed()); } #[test] @@ -161,7 +153,6 @@ fn test_eggs() {} ); } -use std::collections::HashMap; #[test] fn test_format_document() { let server = project( diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index 7db168b0f..46107b6b6 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs @@ -93,9 +93,7 @@ impl Server { R: Request, R::Params: Serialize, { - let id = self.req_id.get(); - self.req_id.set(id + 1); - let actual = self.send_request::(id, params); + let actual = self.send_request::(params); match find_mismatch(&expected_resp, &actual) { Some((expected_part, actual_part)) => panic!( "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", @@ -108,11 +106,14 @@ impl Server { } } - fn send_request(&self, id: u64, params: R::Params) -> Value + pub fn send_request(&self, params: R::Params) -> Value where R: Request, R::Params: Serialize, { + let id = self.req_id.get(); + self.req_id.set(id + 1); + let r = RawRequest::new::(id, ¶ms); self.send_request_(r) } @@ -178,7 +179,7 @@ impl Server { impl Drop for Server { fn drop(&mut self) { - self.send_request::(666, ()); + self.send_request::(()); let receiver = self.worker.take().unwrap().shutdown(); while let Some(msg) = recv_timeout(&receiver) { drop(msg); @@ -188,7 +189,7 @@ impl Drop for Server { } fn recv_timeout(receiver: &Receiver) -> Option { - let timeout = Duration::from_secs(5); + let timeout = Duration::from_secs(50); select! { recv(receiver) -> msg => msg.ok(), recv(after(timeout)) -> _ => panic!("timed out"), -- cgit v1.2.3