diff options
author | Aleksey Kladov <[email protected]> | 2019-01-10 21:37:10 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-10 21:51:34 +0000 |
commit | cd00158b1db9dd8565d2db08b4b0ebab9d5c00b3 (patch) | |
tree | 2072596e298e76aa6d5a8896ef30f591d7c7051c | |
parent | e35374ec7c26be8de61ec7c6175c2385ee5c006f (diff) |
wire sysroot into crate graph
-rw-r--r-- | crates/ra_lsp_server/src/project_model/sysroot.rs | 27 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 51 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 41 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/support.rs | 13 |
4 files changed, 95 insertions, 37 deletions
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); | |||
20 | #[derive(Debug, Clone)] | 20 | #[derive(Debug, Clone)] |
21 | struct SysrootCrateData { | 21 | struct SysrootCrateData { |
22 | name: SmolStr, | 22 | name: SmolStr, |
23 | path: PathBuf, | 23 | root: PathBuf, |
24 | deps: Vec<SysrootCrate>, | 24 | deps: Vec<SysrootCrate>, |
25 | } | 25 | } |
26 | 26 | ||
@@ -29,6 +29,10 @@ impl Sysroot { | |||
29 | self.by_name("std") | 29 | self.by_name("std") |
30 | } | 30 | } |
31 | 31 | ||
32 | pub(crate) fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + 'a { | ||
33 | self.crates.iter().map(|(id, _data)| id) | ||
34 | } | ||
35 | |||
32 | pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> { | 36 | pub(super) fn discover(cargo_toml: &Path) -> Result<Sysroot> { |
33 | let rustc_output = Command::new("rustc") | 37 | let rustc_output = Command::new("rustc") |
34 | .current_dir(cargo_toml.parent().unwrap()) | 38 | .current_dir(cargo_toml.parent().unwrap()) |
@@ -45,11 +49,11 @@ impl Sysroot { | |||
45 | crates: Arena::default(), | 49 | crates: Arena::default(), |
46 | }; | 50 | }; |
47 | for name in SYSROOT_CRATES.trim().lines() { | 51 | for name in SYSROOT_CRATES.trim().lines() { |
48 | let path = src.join(format!("lib{}", name)).join("lib.rs"); | 52 | let root = src.join(format!("lib{}", name)).join("lib.rs"); |
49 | if path.exists() { | 53 | if root.exists() { |
50 | sysroot.crates.alloc(SysrootCrateData { | 54 | sysroot.crates.alloc(SysrootCrateData { |
51 | name: name.into(), | 55 | name: name.into(), |
52 | path, | 56 | root, |
53 | deps: Vec::new(), | 57 | deps: Vec::new(), |
54 | }); | 58 | }); |
55 | } | 59 | } |
@@ -72,6 +76,21 @@ impl Sysroot { | |||
72 | } | 76 | } |
73 | } | 77 | } |
74 | 78 | ||
79 | impl SysrootCrate { | ||
80 | pub(crate) fn name(self, sysroot: &Sysroot) -> &SmolStr { | ||
81 | &sysroot.crates[self].name | ||
82 | } | ||
83 | pub(crate) fn root(self, sysroot: &Sysroot) -> &Path { | ||
84 | sysroot.crates[self].root.as_path() | ||
85 | } | ||
86 | pub(crate) fn root_dir(self, sysroot: &Sysroot) -> &Path { | ||
87 | self.root(sysroot).parent().unwrap() | ||
88 | } | ||
89 | pub(crate) fn deps<'a>(self, sysroot: &'a Sysroot) -> impl Iterator<Item = SysrootCrate> + 'a { | ||
90 | sysroot.crates[self].deps.iter().map(|&it| it) | ||
91 | } | ||
92 | } | ||
93 | |||
75 | const SYSROOT_CRATES: &str = " | 94 | const SYSROOT_CRATES: &str = " |
76 | std | 95 | std |
77 | core | 96 | 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 { | |||
44 | for pkg in ws.cargo.packages() { | 44 | for pkg in ws.cargo.packages() { |
45 | roots.push(pkg.root(&ws.cargo).to_path_buf()); | 45 | roots.push(pkg.root(&ws.cargo).to_path_buf()); |
46 | } | 46 | } |
47 | for krate in ws.sysroot.crates() { | ||
48 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) | ||
49 | } | ||
47 | } | 50 | } |
51 | roots.sort(); | ||
52 | roots.dedup(); | ||
48 | let roots_to_scan = roots.len(); | 53 | let roots_to_scan = roots.len(); |
49 | let (mut vfs, roots) = Vfs::new(roots); | 54 | let (mut vfs, roots) = Vfs::new(roots); |
50 | for r in roots { | 55 | for r in roots { |
@@ -53,16 +58,43 @@ impl ServerWorldState { | |||
53 | } | 58 | } |
54 | 59 | ||
55 | let mut crate_graph = CrateGraph::default(); | 60 | let mut crate_graph = CrateGraph::default(); |
56 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
57 | let mut pkg_crates = FxHashMap::default(); | ||
58 | for ws in workspaces.iter() { | 61 | for ws in workspaces.iter() { |
62 | // First, load std | ||
63 | let mut sysroot_crates = FxHashMap::default(); | ||
64 | for krate in ws.sysroot.crates() { | ||
65 | if let Some(file_id) = vfs.load(krate.root(&ws.sysroot)) { | ||
66 | let file_id = FileId(file_id.0.into()); | ||
67 | sysroot_crates.insert(krate, crate_graph.add_crate_root(file_id)); | ||
68 | } | ||
69 | } | ||
70 | for from in ws.sysroot.crates() { | ||
71 | for to in from.deps(&ws.sysroot) { | ||
72 | let name = to.name(&ws.sysroot); | ||
73 | if let (Some(&from), Some(&to)) = | ||
74 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | ||
75 | { | ||
76 | crate_graph.add_dep(from, name.clone(), to); | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | |||
81 | let libstd = ws | ||
82 | .sysroot | ||
83 | .std() | ||
84 | .and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | ||
85 | |||
86 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
87 | let mut pkg_crates = FxHashMap::default(); | ||
88 | // Next, create crates for each package, target pair | ||
59 | for pkg in ws.cargo.packages() { | 89 | for pkg in ws.cargo.packages() { |
90 | let mut lib_tgt = None; | ||
60 | for tgt in pkg.targets(&ws.cargo) { | 91 | for tgt in pkg.targets(&ws.cargo) { |
61 | let root = tgt.root(&ws.cargo); | 92 | let root = tgt.root(&ws.cargo); |
62 | if let Some(file_id) = vfs.load(root) { | 93 | if let Some(file_id) = vfs.load(root) { |
63 | let file_id = FileId(file_id.0.into()); | 94 | let file_id = FileId(file_id.0.into()); |
64 | let crate_id = crate_graph.add_crate_root(file_id); | 95 | let crate_id = crate_graph.add_crate_root(file_id); |
65 | if tgt.kind(&ws.cargo) == TargetKind::Lib { | 96 | if tgt.kind(&ws.cargo) == TargetKind::Lib { |
97 | lib_tgt = Some(crate_id); | ||
66 | pkg_to_lib_crate.insert(pkg, crate_id); | 98 | pkg_to_lib_crate.insert(pkg, crate_id); |
67 | } | 99 | } |
68 | pkg_crates | 100 | pkg_crates |
@@ -71,7 +103,22 @@ impl ServerWorldState { | |||
71 | .push(crate_id); | 103 | .push(crate_id); |
72 | } | 104 | } |
73 | } | 105 | } |
106 | |||
107 | // Set deps to the std and to the lib target of the current package | ||
108 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
109 | if let Some(to) = lib_tgt { | ||
110 | if to != from { | ||
111 | crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to); | ||
112 | } | ||
113 | } | ||
114 | if let Some(std) = libstd { | ||
115 | crate_graph.add_dep(from, "std".into(), std); | ||
116 | } | ||
117 | } | ||
74 | } | 118 | } |
119 | |||
120 | // Now add a dep ednge from all targets of upstream to the lib | ||
121 | // target of downstream. | ||
75 | for pkg in ws.cargo.packages() { | 122 | for pkg in ws.cargo.packages() { |
76 | for dep in pkg.dependencies(&ws.cargo) { | 123 | for dep in pkg.dependencies(&ws.cargo) { |
77 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | 124 | 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 @@ | |||
1 | mod support; | 1 | mod support; |
2 | 2 | ||
3 | use std::{ | ||
4 | collections::HashMap, | ||
5 | time::Instant, | ||
6 | }; | ||
7 | |||
3 | use languageserver_types::{ | 8 | use languageserver_types::{ |
4 | CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, | 9 | CodeActionContext, DocumentFormattingParams, FormattingOptions, Position, Range, |
5 | }; | 10 | }; |
@@ -14,6 +19,7 @@ const LOG: &'static str = ""; | |||
14 | 19 | ||
15 | #[test] | 20 | #[test] |
16 | fn completes_items_from_standard_library() { | 21 | fn completes_items_from_standard_library() { |
22 | let project_start = Instant::now(); | ||
17 | let server = project( | 23 | let server = project( |
18 | r#" | 24 | r#" |
19 | //- Cargo.toml | 25 | //- Cargo.toml |
@@ -22,33 +28,19 @@ name = "foo" | |||
22 | version = "0.0.0" | 28 | version = "0.0.0" |
23 | 29 | ||
24 | //- src/lib.rs | 30 | //- src/lib.rs |
25 | use std::collections::; | 31 | use std::collections::Spam; |
26 | "#, | 32 | "#, |
27 | ); | 33 | ); |
28 | server.wait_for_feedback("workspace loaded"); | 34 | server.wait_for_feedback("workspace loaded"); |
29 | server.request::<Completion>( | 35 | eprintln!("loading took {:?}", project_start.elapsed()); |
30 | CompletionParams { | 36 | let completion_start = Instant::now(); |
31 | text_document: server.doc_id("src/lib.rs"), | 37 | let res = server.send_request::<Completion>(CompletionParams { |
32 | context: None, | 38 | text_document: server.doc_id("src/lib.rs"), |
33 | position: Position::new(0, 22), | 39 | context: None, |
34 | }, | 40 | position: Position::new(0, 23), |
35 | json!([ | 41 | }); |
36 | { | 42 | assert!(format!("{}", res).contains("HashMap")); |
37 | "filterText": "self", | 43 | eprintln!("completion took {:?}", completion_start.elapsed()); |
38 | "insertText": "self", | ||
39 | "insertTextFormat": 1, | ||
40 | "kind": 14, | ||
41 | "label": "self" | ||
42 | }, | ||
43 | { | ||
44 | "filterText": "super", | ||
45 | "insertText": "super", | ||
46 | "insertTextFormat": 1, | ||
47 | "kind": 14, | ||
48 | "label": "super" | ||
49 | } | ||
50 | ]), | ||
51 | ); | ||
52 | } | 44 | } |
53 | 45 | ||
54 | #[test] | 46 | #[test] |
@@ -161,7 +153,6 @@ fn test_eggs() {} | |||
161 | ); | 153 | ); |
162 | } | 154 | } |
163 | 155 | ||
164 | use std::collections::HashMap; | ||
165 | #[test] | 156 | #[test] |
166 | fn test_format_document() { | 157 | fn test_format_document() { |
167 | let server = project( | 158 | 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 { | |||
93 | R: Request, | 93 | R: Request, |
94 | R::Params: Serialize, | 94 | R::Params: Serialize, |
95 | { | 95 | { |
96 | let id = self.req_id.get(); | 96 | let actual = self.send_request::<R>(params); |
97 | self.req_id.set(id + 1); | ||
98 | let actual = self.send_request::<R>(id, params); | ||
99 | match find_mismatch(&expected_resp, &actual) { | 97 | match find_mismatch(&expected_resp, &actual) { |
100 | Some((expected_part, actual_part)) => panic!( | 98 | Some((expected_part, actual_part)) => panic!( |
101 | "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", | 99 | "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n", |
@@ -108,11 +106,14 @@ impl Server { | |||
108 | } | 106 | } |
109 | } | 107 | } |
110 | 108 | ||
111 | fn send_request<R>(&self, id: u64, params: R::Params) -> Value | 109 | pub fn send_request<R>(&self, params: R::Params) -> Value |
112 | where | 110 | where |
113 | R: Request, | 111 | R: Request, |
114 | R::Params: Serialize, | 112 | R::Params: Serialize, |
115 | { | 113 | { |
114 | let id = self.req_id.get(); | ||
115 | self.req_id.set(id + 1); | ||
116 | |||
116 | let r = RawRequest::new::<R>(id, ¶ms); | 117 | let r = RawRequest::new::<R>(id, ¶ms); |
117 | self.send_request_(r) | 118 | self.send_request_(r) |
118 | } | 119 | } |
@@ -178,7 +179,7 @@ impl Server { | |||
178 | 179 | ||
179 | impl Drop for Server { | 180 | impl Drop for Server { |
180 | fn drop(&mut self) { | 181 | fn drop(&mut self) { |
181 | self.send_request::<Shutdown>(666, ()); | 182 | self.send_request::<Shutdown>(()); |
182 | let receiver = self.worker.take().unwrap().shutdown(); | 183 | let receiver = self.worker.take().unwrap().shutdown(); |
183 | while let Some(msg) = recv_timeout(&receiver) { | 184 | while let Some(msg) = recv_timeout(&receiver) { |
184 | drop(msg); | 185 | drop(msg); |
@@ -188,7 +189,7 @@ impl Drop for Server { | |||
188 | } | 189 | } |
189 | 190 | ||
190 | fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> { | 191 | fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> { |
191 | let timeout = Duration::from_secs(5); | 192 | let timeout = Duration::from_secs(50); |
192 | select! { | 193 | select! { |
193 | recv(receiver) -> msg => msg.ok(), | 194 | recv(receiver) -> msg => msg.ok(), |
194 | recv(after(timeout)) -> _ => panic!("timed out"), | 195 | recv(after(timeout)) -> _ => panic!("timed out"), |