aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-01-10 21:37:10 +0000
committerAleksey Kladov <[email protected]>2019-01-10 21:51:34 +0000
commitcd00158b1db9dd8565d2db08b4b0ebab9d5c00b3 (patch)
tree2072596e298e76aa6d5a8896ef30f591d7c7051c /crates/ra_lsp_server
parente35374ec7c26be8de61ec7c6175c2385ee5c006f (diff)
wire sysroot into crate graph
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/src/project_model/sysroot.rs27
-rw-r--r--crates/ra_lsp_server/src/server_world.rs51
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs41
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs13
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)]
21struct SysrootCrateData { 21struct 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
79impl 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
75const SYSROOT_CRATES: &str = " 94const SYSROOT_CRATES: &str = "
76std 95std
77core 96core
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 @@
1mod support; 1mod support;
2 2
3use std::{
4 collections::HashMap,
5 time::Instant,
6};
7
3use languageserver_types::{ 8use 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]
16fn completes_items_from_standard_library() { 21fn 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"
22version = "0.0.0" 28version = "0.0.0"
23 29
24//- src/lib.rs 30//- src/lib.rs
25use std::collections::; 31use 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
164use std::collections::HashMap;
165#[test] 156#[test]
166fn test_format_document() { 157fn 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, &params); 117 let r = RawRequest::new::<R>(id, &params);
117 self.send_request_(r) 118 self.send_request_(r)
118 } 119 }
@@ -178,7 +179,7 @@ impl Server {
178 179
179impl Drop for Server { 180impl 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
190fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> { 191fn 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"),