aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_arena/src/map.rs10
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs30
-rw-r--r--crates/ra_flycheck/Cargo.toml (renamed from crates/ra_cargo_watch/Cargo.toml)2
-rw-r--r--crates/ra_flycheck/src/conv.rs (renamed from crates/ra_cargo_watch/src/conv.rs)0
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_clippy_pass_by_ref.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_handles_macro_location.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_macro_compiler_error.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_multi_line_fix.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_incompatible_type_for_trait.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_mismatched_type.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_unused_variable.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_wrong_number_of_parameters.snap (renamed from crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap)2
-rw-r--r--crates/ra_flycheck/src/conv/test.rs (renamed from crates/ra_cargo_watch/src/conv/test.rs)0
-rw-r--r--crates/ra_flycheck/src/lib.rs (renamed from crates/ra_cargo_watch/src/lib.rs)16
-rw-r--r--crates/ra_hir_expand/src/proc_macro.rs27
-rw-r--r--crates/ra_hir_ty/src/display.rs29
-rw-r--r--crates/ra_ide/src/completion.rs10
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs8
-rw-r--r--crates/ra_ide/src/completion/presentation.rs12
-rw-r--r--crates/ra_ide/src/completion/test_utils.rs6
-rw-r--r--crates/ra_ide/src/inlay_hints.rs68
-rw-r--r--crates/ra_ide/src/lib.rs12
-rw-r--r--crates/ra_proc_macro/Cargo.toml5
-rw-r--r--crates/ra_proc_macro/src/lib.rs85
-rw-r--r--crates/ra_proc_macro/src/msg.rs93
-rw-r--r--crates/ra_proc_macro/src/process.rs196
-rw-r--r--crates/ra_proc_macro/src/rpc.rs266
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs91
-rw-r--r--crates/ra_syntax/src/ast/edit.rs29
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs13
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0065_comment_newline.txt17
-rw-r--r--crates/ra_tt/src/lib.rs7
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/cargo_target_spec.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs4
-rw-r--r--crates/rust-analyzer/src/conv.rs2
-rw-r--r--crates/rust-analyzer/src/main_loop.rs37
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs14
-rw-r--r--crates/rust-analyzer/src/world.rs52
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs46
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/support.rs22
44 files changed, 1014 insertions, 221 deletions
diff --git a/crates/ra_arena/src/map.rs b/crates/ra_arena/src/map.rs
index 5e764113d..0f33907c0 100644
--- a/crates/ra_arena/src/map.rs
+++ b/crates/ra_arena/src/map.rs
@@ -14,14 +14,8 @@ pub struct ArenaMap<ID, V> {
14impl<T, V> ArenaMap<Idx<T>, V> { 14impl<T, V> ArenaMap<Idx<T>, V> {
15 pub fn insert(&mut self, id: Idx<T>, t: V) { 15 pub fn insert(&mut self, id: Idx<T>, t: V) {
16 let idx = Self::to_idx(id); 16 let idx = Self::to_idx(id);
17 if self.v.capacity() <= idx { 17
18 self.v.reserve(idx + 1 - self.v.capacity()); 18 self.v.resize_with((idx + 1).max(self.v.len()), || None);
19 }
20 if self.v.len() <= idx {
21 while self.v.len() <= idx {
22 self.v.push(None);
23 }
24 }
25 self.v[idx] = Some(t); 19 self.v[idx] = Some(t);
26 } 20 }
27 21
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 41bb97928..8d1af9933 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -1,15 +1,11 @@
1//! FIXME: write short doc here
2
3use std::iter; 1use std::iter;
4 2
5use hir::{Adt, HasSource, ModuleDef, Semantics}; 3use hir::{Adt, HasSource, ModuleDef, Semantics};
6use itertools::Itertools; 4use itertools::Itertools;
7use ra_ide_db::RootDatabase; 5use ra_ide_db::RootDatabase;
6use ra_syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
8 7
9use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
10use ra_syntax::ast::{self, make, AstNode, NameOwner};
11
12use ast::{MatchArm, Pat};
13 9
14// Assist: fill_match_arms 10// Assist: fill_match_arms
15// 11//
@@ -717,4 +713,28 @@ mod tests {
717 "#, 713 "#,
718 ); 714 );
719 } 715 }
716
717 #[test]
718 fn fill_match_arms_placeholder() {
719 check_assist(
720 fill_match_arms,
721 r#"
722 enum A { One, Two, }
723 fn foo(a: A) {
724 match a<|> {
725 _ => (),
726 }
727 }
728 "#,
729 r#"
730 enum A { One, Two, }
731 fn foo(a: A) {
732 match <|>a {
733 A::One => {}
734 A::Two => {}
735 }
736 }
737 "#,
738 );
739 }
720} 740}
diff --git a/crates/ra_cargo_watch/Cargo.toml b/crates/ra_flycheck/Cargo.toml
index 300033a18..c9a9ddc12 100644
--- a/crates/ra_cargo_watch/Cargo.toml
+++ b/crates/ra_flycheck/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2edition = "2018" 2edition = "2018"
3name = "ra_cargo_watch" 3name = "ra_flycheck"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
diff --git a/crates/ra_cargo_watch/src/conv.rs b/crates/ra_flycheck/src/conv.rs
index 817543deb..817543deb 100644
--- a/crates/ra_cargo_watch/src/conv.rs
+++ b/crates/ra_flycheck/src/conv.rs
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_clippy_pass_by_ref.snap
index a59fa84fa..4c9db0385 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_clippy_pass_by_ref.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_clippy_pass_by_ref.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_handles_macro_location.snap
index 61ae0c9ae..7cde4d867 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_handles_macro_location.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_handles_macro_location.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_macro_compiler_error.snap
index 641da1a58..1cc37e087 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_macro_compiler_error.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_macro_compiler_error.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_multi_line_fix.snap
index 0557a2e79..615ed8378 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_multi_line_fix.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_multi_line_fix.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_incompatible_type_for_trait.snap
index 754bc33a4..0df0fce18 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_incompatible_type_for_trait.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_incompatible_type_for_trait.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_mismatched_type.snap
index 78b7f7cc8..28ebcb3b3 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_mismatched_type.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_mismatched_type.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_unused_variable.snap
index 5989ed202..5e0873281 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_unused_variable.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_unused_variable.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_wrong_number_of_parameters.snap
index e34b546dc..e500d3cd6 100644
--- a/crates/ra_cargo_watch/src/conv/snapshots/ra_cargo_watch__conv__test__snap_rustc_wrong_number_of_parameters.snap
+++ b/crates/ra_flycheck/src/conv/snapshots/ra_flycheck__conv__test__snap_rustc_wrong_number_of_parameters.snap
@@ -1,5 +1,5 @@
1--- 1---
2source: crates/ra_cargo_watch/src/conv/test.rs 2source: crates/ra_flycheck/src/conv/test.rs
3expression: diag 3expression: diag
4--- 4---
5[ 5[
diff --git a/crates/ra_cargo_watch/src/conv/test.rs b/crates/ra_flycheck/src/conv/test.rs
index 4e81455ca..4e81455ca 100644
--- a/crates/ra_cargo_watch/src/conv/test.rs
+++ b/crates/ra_flycheck/src/conv/test.rs
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_flycheck/src/lib.rs
index 2692c1bf5..38940a77b 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_flycheck/src/lib.rs
@@ -22,7 +22,7 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic};
22pub use crate::conv::url_from_path_with_drive_lowercasing; 22pub use crate::conv::url_from_path_with_drive_lowercasing;
23 23
24#[derive(Clone, Debug)] 24#[derive(Clone, Debug)]
25pub struct CheckOptions { 25pub struct CheckConfig {
26 pub enable: bool, 26 pub enable: bool,
27 pub args: Vec<String>, 27 pub args: Vec<String>,
28 pub command: String, 28 pub command: String,
@@ -42,13 +42,11 @@ pub struct CheckWatcher {
42} 42}
43 43
44impl CheckWatcher { 44impl CheckWatcher {
45 pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher { 45 pub fn new(config: CheckConfig, workspace_root: PathBuf) -> CheckWatcher {
46 let options = options.clone();
47
48 let (task_send, task_recv) = unbounded::<CheckTask>(); 46 let (task_send, task_recv) = unbounded::<CheckTask>();
49 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 47 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
50 let handle = jod_thread::spawn(move || { 48 let handle = jod_thread::spawn(move || {
51 let mut check = CheckWatcherThread::new(options, workspace_root); 49 let mut check = CheckWatcherThread::new(config, workspace_root);
52 check.run(&task_send, &cmd_recv); 50 check.run(&task_send, &cmd_recv);
53 }); 51 });
54 CheckWatcher { task_recv, cmd_send, handle: Some(handle) } 52 CheckWatcher { task_recv, cmd_send, handle: Some(handle) }
@@ -78,14 +76,14 @@ pub enum CheckCommand {
78} 76}
79 77
80struct CheckWatcherThread { 78struct CheckWatcherThread {
81 options: CheckOptions, 79 options: CheckConfig,
82 workspace_root: PathBuf, 80 workspace_root: PathBuf,
83 watcher: WatchThread, 81 watcher: WatchThread,
84 last_update_req: Option<Instant>, 82 last_update_req: Option<Instant>,
85} 83}
86 84
87impl CheckWatcherThread { 85impl CheckWatcherThread {
88 fn new(options: CheckOptions, workspace_root: PathBuf) -> CheckWatcherThread { 86 fn new(options: CheckConfig, workspace_root: PathBuf) -> CheckWatcherThread {
89 CheckWatcherThread { 87 CheckWatcherThread {
90 options, 88 options,
91 workspace_root, 89 workspace_root,
@@ -245,7 +243,7 @@ impl fmt::Display for CargoError {
245} 243}
246impl error::Error for CargoError {} 244impl error::Error for CargoError {}
247 245
248pub fn run_cargo( 246fn run_cargo(
249 args: &[String], 247 args: &[String],
250 current_dir: Option<&Path>, 248 current_dir: Option<&Path>,
251 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool, 249 on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
@@ -324,7 +322,7 @@ impl WatchThread {
324 WatchThread { message_recv: never(), _handle: None } 322 WatchThread { message_recv: never(), _handle: None }
325 } 323 }
326 324
327 fn new(options: &CheckOptions, workspace_root: &Path) -> WatchThread { 325 fn new(options: &CheckConfig, workspace_root: &Path) -> WatchThread {
328 let mut args: Vec<String> = vec![ 326 let mut args: Vec<String> = vec![
329 options.command.clone(), 327 options.command.clone(),
330 "--workspace".to_string(), 328 "--workspace".to_string(),
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs
index 4d270e0de..97d1208ec 100644
--- a/crates/ra_hir_expand/src/proc_macro.rs
+++ b/crates/ra_hir_expand/src/proc_macro.rs
@@ -9,6 +9,15 @@ pub struct ProcMacroExpander {
9 proc_macro_id: ProcMacroId, 9 proc_macro_id: ProcMacroId,
10} 10}
11 11
12macro_rules! err {
13 ($fmt:literal, $($tt:tt),*) => {
14 mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown(format!($fmt, $($tt),*)))
15 };
16 ($fmt:literal) => {
17 mbe::ExpandError::ProcMacroError(tt::ExpansionError::Unknown($fmt.to_string()))
18 }
19}
20
12impl ProcMacroExpander { 21impl ProcMacroExpander {
13 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander { 22 pub fn new(krate: CrateId, proc_macro_id: ProcMacroId) -> ProcMacroExpander {
14 ProcMacroExpander { krate, proc_macro_id } 23 ProcMacroExpander { krate, proc_macro_id }
@@ -25,8 +34,24 @@ impl ProcMacroExpander {
25 .proc_macro 34 .proc_macro
26 .get(self.proc_macro_id.0 as usize) 35 .get(self.proc_macro_id.0 as usize)
27 .clone() 36 .clone()
28 .ok_or_else(|| mbe::ExpandError::ConversionError)?; 37 .ok_or_else(|| err!("No derive macro found."))?;
38
39 let tt = remove_derive_atr(tt, &proc_macro.name)
40 .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
29 41
30 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from) 42 proc_macro.expander.expand(&tt, None).map_err(mbe::ExpandError::from)
31 } 43 }
32} 44}
45
46fn remove_derive_atr(tt: &tt::Subtree, _name: &str) -> Option<tt::Subtree> {
47 // FIXME: proper handle the remove derive
48 // We assume the first 2 tokens are #[derive(name)]
49 if tt.token_trees.len() > 2 {
50 let mut tt = tt.clone();
51 tt.token_trees.remove(0);
52 tt.token_trees.remove(0);
53 return Some(tt);
54 }
55
56 None
57}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index c3d92a268..13ecd537a 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -190,8 +190,6 @@ impl HirDisplay for ApplicationTy {
190 }; 190 };
191 write!(f, "{}", name)?; 191 write!(f, "{}", name)?;
192 if self.parameters.len() > 0 { 192 if self.parameters.len() > 0 {
193 write!(f, "<")?;
194
195 let mut non_default_parameters = Vec::with_capacity(self.parameters.len()); 193 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
196 let parameters_to_write = if f.omit_verbose_types() { 194 let parameters_to_write = if f.omit_verbose_types() {
197 match self 195 match self
@@ -200,8 +198,8 @@ impl HirDisplay for ApplicationTy {
200 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 198 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
201 .filter(|defaults| !defaults.is_empty()) 199 .filter(|defaults| !defaults.is_empty())
202 { 200 {
203 Option::None => self.parameters.0.as_ref(), 201 None => self.parameters.0.as_ref(),
204 Option::Some(default_parameters) => { 202 Some(default_parameters) => {
205 for (i, parameter) in self.parameters.iter().enumerate() { 203 for (i, parameter) in self.parameters.iter().enumerate() {
206 match (parameter, default_parameters.get(i)) { 204 match (parameter, default_parameters.get(i)) {
207 (&Ty::Unknown, _) | (_, None) => { 205 (&Ty::Unknown, _) | (_, None) => {
@@ -221,7 +219,7 @@ impl HirDisplay for ApplicationTy {
221 } else { 219 } else {
222 self.parameters.0.as_ref() 220 self.parameters.0.as_ref()
223 }; 221 };
224 222 write!(f, "<")?;
225 f.write_joined(parameters_to_write, ", ")?; 223 f.write_joined(parameters_to_write, ", ")?;
226 write!(f, ">")?; 224 write!(f, ">")?;
227 } 225 }
@@ -231,9 +229,9 @@ impl HirDisplay for ApplicationTy {
231 AssocContainerId::TraitId(it) => it, 229 AssocContainerId::TraitId(it) => it,
232 _ => panic!("not an associated type"), 230 _ => panic!("not an associated type"),
233 }; 231 };
234 let trait_name = f.db.trait_data(trait_).name.clone(); 232 let trait_ = f.db.trait_data(trait_);
235 let name = f.db.type_alias_data(type_alias).name.clone(); 233 let type_alias = f.db.type_alias_data(type_alias);
236 write!(f, "{}::{}", trait_name, name)?; 234 write!(f, "{}::{}", trait_.name, type_alias.name)?;
237 if self.parameters.len() > 0 { 235 if self.parameters.len() > 0 {
238 write!(f, "<")?; 236 write!(f, "<")?;
239 f.write_joined(&*self.parameters.0, ", ")?; 237 f.write_joined(&*self.parameters.0, ", ")?;
@@ -266,8 +264,8 @@ impl HirDisplay for ProjectionTy {
266 return write!(f, "{}", TYPE_HINT_TRUNCATION); 264 return write!(f, "{}", TYPE_HINT_TRUNCATION);
267 } 265 }
268 266
269 let trait_name = f.db.trait_data(self.trait_(f.db)).name.clone(); 267 let trait_ = f.db.trait_data(self.trait_(f.db));
270 write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; 268 write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_.name)?;
271 if self.parameters.len() > 1 { 269 if self.parameters.len() > 1 {
272 write!(f, "<")?; 270 write!(f, "<")?;
273 f.write_joined(&self.parameters[1..], ", ")?; 271 f.write_joined(&self.parameters[1..], ", ")?;
@@ -312,7 +310,7 @@ impl HirDisplay for Ty {
312 Ty::Opaque(_) => write!(f, "impl ")?, 310 Ty::Opaque(_) => write!(f, "impl ")?,
313 _ => unreachable!(), 311 _ => unreachable!(),
314 }; 312 };
315 write_bounds_like_dyn_trait(&predicates, f)?; 313 write_bounds_like_dyn_trait(predicates, f)?;
316 } 314 }
317 Ty::Unknown => write!(f, "{{unknown}}")?, 315 Ty::Unknown => write!(f, "{{unknown}}")?,
318 Ty::Infer(..) => write!(f, "_")?, 316 Ty::Infer(..) => write!(f, "_")?,
@@ -345,7 +343,7 @@ fn write_bounds_like_dyn_trait(
345 // We assume that the self type is $0 (i.e. the 343 // We assume that the self type is $0 (i.e. the
346 // existential) here, which is the only thing that's 344 // existential) here, which is the only thing that's
347 // possible in actual Rust, and hence don't print it 345 // possible in actual Rust, and hence don't print it
348 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?; 346 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name)?;
349 if trait_ref.substs.len() > 1 { 347 if trait_ref.substs.len() > 1 {
350 write!(f, "<")?; 348 write!(f, "<")?;
351 f.write_joined(&trait_ref.substs[1..], ", ")?; 349 f.write_joined(&trait_ref.substs[1..], ", ")?;
@@ -362,9 +360,8 @@ fn write_bounds_like_dyn_trait(
362 write!(f, "<")?; 360 write!(f, "<")?;
363 angle_open = true; 361 angle_open = true;
364 } 362 }
365 let name = 363 let type_alias = f.db.type_alias_data(projection_pred.projection_ty.associated_ty);
366 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone(); 364 write!(f, "{} = ", type_alias.name)?;
367 write!(f, "{} = ", name)?;
368 projection_pred.ty.hir_fmt(f)?; 365 projection_pred.ty.hir_fmt(f)?;
369 } 366 }
370 GenericPredicate::Error => { 367 GenericPredicate::Error => {
@@ -398,7 +395,7 @@ impl TraitRef {
398 } else { 395 } else {
399 write!(f, ": ")?; 396 write!(f, ": ")?;
400 } 397 }
401 write!(f, "{}", f.db.trait_data(self.trait_).name.clone())?; 398 write!(f, "{}", f.db.trait_data(self.trait_).name)?;
402 if self.substs.len() > 1 { 399 if self.substs.len() > 1 {
403 write!(f, "<")?; 400 write!(f, "<")?;
404 f.write_joined(&self.substs[1..], ", ")?; 401 f.write_joined(&self.substs[1..], ", ")?;
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs
index cd0757be5..b683572fb 100644
--- a/crates/ra_ide/src/completion.rs
+++ b/crates/ra_ide/src/completion.rs
@@ -34,15 +34,15 @@ pub use crate::completion::completion_item::{
34}; 34};
35 35
36#[derive(Clone, Debug, PartialEq, Eq)] 36#[derive(Clone, Debug, PartialEq, Eq)]
37pub struct CompletionOptions { 37pub struct CompletionConfig {
38 pub enable_postfix_completions: bool, 38 pub enable_postfix_completions: bool,
39 pub add_call_parenthesis: bool, 39 pub add_call_parenthesis: bool,
40 pub add_call_argument_snippets: bool, 40 pub add_call_argument_snippets: bool,
41} 41}
42 42
43impl Default for CompletionOptions { 43impl Default for CompletionConfig {
44 fn default() -> Self { 44 fn default() -> Self {
45 CompletionOptions { 45 CompletionConfig {
46 enable_postfix_completions: true, 46 enable_postfix_completions: true,
47 add_call_parenthesis: true, 47 add_call_parenthesis: true,
48 add_call_argument_snippets: true, 48 add_call_argument_snippets: true,
@@ -75,9 +75,9 @@ impl Default for CompletionOptions {
75pub(crate) fn completions( 75pub(crate) fn completions(
76 db: &RootDatabase, 76 db: &RootDatabase,
77 position: FilePosition, 77 position: FilePosition,
78 options: &CompletionOptions, 78 config: &CompletionConfig,
79) -> Option<Completions> { 79) -> Option<Completions> {
80 let ctx = CompletionContext::new(db, position, options)?; 80 let ctx = CompletionContext::new(db, position, config)?;
81 81
82 let mut acc = Completions::default(); 82 let mut acc = Completions::default();
83 83
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 0a00054b2..29c2881c6 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -15,7 +15,7 @@ use crate::{
15}; 15};
16 16
17pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 17pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
18 if !ctx.options.enable_postfix_completions { 18 if !ctx.config.enable_postfix_completions {
19 return; 19 return;
20 } 20 }
21 21
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index 319e33b61..fdc0da2c5 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -11,7 +11,7 @@ use ra_syntax::{
11}; 11};
12use ra_text_edit::AtomTextEdit; 12use ra_text_edit::AtomTextEdit;
13 13
14use crate::{completion::CompletionOptions, FilePosition}; 14use crate::{completion::CompletionConfig, FilePosition};
15 15
16/// `CompletionContext` is created early during completion to figure out, where 16/// `CompletionContext` is created early during completion to figure out, where
17/// exactly is the cursor, syntax-wise. 17/// exactly is the cursor, syntax-wise.
@@ -19,7 +19,7 @@ use crate::{completion::CompletionOptions, FilePosition};
19pub(crate) struct CompletionContext<'a> { 19pub(crate) struct CompletionContext<'a> {
20 pub(super) sema: Semantics<'a, RootDatabase>, 20 pub(super) sema: Semantics<'a, RootDatabase>,
21 pub(super) db: &'a RootDatabase, 21 pub(super) db: &'a RootDatabase,
22 pub(super) options: &'a CompletionOptions, 22 pub(super) config: &'a CompletionConfig,
23 pub(super) offset: TextUnit, 23 pub(super) offset: TextUnit,
24 /// The token before the cursor, in the original file. 24 /// The token before the cursor, in the original file.
25 pub(super) original_token: SyntaxToken, 25 pub(super) original_token: SyntaxToken,
@@ -61,7 +61,7 @@ impl<'a> CompletionContext<'a> {
61 pub(super) fn new( 61 pub(super) fn new(
62 db: &'a RootDatabase, 62 db: &'a RootDatabase,
63 position: FilePosition, 63 position: FilePosition,
64 options: &'a CompletionOptions, 64 config: &'a CompletionConfig,
65 ) -> Option<CompletionContext<'a>> { 65 ) -> Option<CompletionContext<'a>> {
66 let sema = Semantics::new(db); 66 let sema = Semantics::new(db);
67 67
@@ -85,7 +85,7 @@ impl<'a> CompletionContext<'a> {
85 let mut ctx = CompletionContext { 85 let mut ctx = CompletionContext {
86 sema, 86 sema,
87 db, 87 db,
88 options, 88 config,
89 original_token, 89 original_token,
90 token, 90 token,
91 offset: position.offset, 91 offset: position.offset,
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 60f1b83f3..1c7c0924d 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -106,7 +106,7 @@ impl Completions {
106 }; 106 };
107 107
108 // Add `<>` for generic types 108 // Add `<>` for generic types
109 if ctx.is_path_type && !ctx.has_type_args && ctx.options.add_call_parenthesis { 109 if ctx.is_path_type && !ctx.has_type_args && ctx.config.add_call_parenthesis {
110 let has_non_default_type_params = match resolution { 110 let has_non_default_type_params = match resolution {
111 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), 111 ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db),
112 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), 112 ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db),
@@ -211,14 +211,14 @@ impl Completions {
211 .detail(function_signature.to_string()); 211 .detail(function_signature.to_string());
212 212
213 // If not an import, add parenthesis automatically. 213 // If not an import, add parenthesis automatically.
214 if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.options.add_call_parenthesis { 214 if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.config.add_call_parenthesis {
215 tested_by!(inserts_parens_for_function_calls); 215 tested_by!(inserts_parens_for_function_calls);
216 216
217 let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { 217 let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 {
218 (format!("{}()$0", name), format!("{}()", name)) 218 (format!("{}()$0", name), format!("{}()", name))
219 } else { 219 } else {
220 builder = builder.trigger_call_info(); 220 builder = builder.trigger_call_info();
221 let snippet = if ctx.options.add_call_argument_snippets { 221 let snippet = if ctx.config.add_call_argument_snippets {
222 let to_skip = if has_self_param { 1 } else { 0 }; 222 let to_skip = if has_self_param { 1 } else { 0 };
223 let function_params_snippet = function_signature 223 let function_params_snippet = function_signature
224 .parameter_names 224 .parameter_names
@@ -311,7 +311,7 @@ mod tests {
311 311
312 use crate::completion::{ 312 use crate::completion::{
313 test_utils::{do_completion, do_completion_with_options}, 313 test_utils::{do_completion, do_completion_with_options},
314 CompletionItem, CompletionKind, CompletionOptions, 314 CompletionConfig, CompletionItem, CompletionKind,
315 }; 315 };
316 316
317 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> { 317 fn do_reference_completion(ra_fixture: &str) -> Vec<CompletionItem> {
@@ -320,7 +320,7 @@ mod tests {
320 320
321 fn do_reference_completion_with_options( 321 fn do_reference_completion_with_options(
322 ra_fixture: &str, 322 ra_fixture: &str,
323 options: CompletionOptions, 323 options: CompletionConfig,
324 ) -> Vec<CompletionItem> { 324 ) -> Vec<CompletionItem> {
325 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options) 325 do_completion_with_options(ra_fixture, CompletionKind::Reference, &options)
326 } 326 }
@@ -589,7 +589,7 @@ mod tests {
589 s.f<|> 589 s.f<|>
590 } 590 }
591 ", 591 ",
592 CompletionOptions { 592 CompletionConfig {
593 add_call_argument_snippets: false, 593 add_call_argument_snippets: false,
594 .. Default::default() 594 .. Default::default()
595 } 595 }
diff --git a/crates/ra_ide/src/completion/test_utils.rs b/crates/ra_ide/src/completion/test_utils.rs
index 136857315..eb90b5279 100644
--- a/crates/ra_ide/src/completion/test_utils.rs
+++ b/crates/ra_ide/src/completion/test_utils.rs
@@ -1,19 +1,19 @@
1//! Runs completion for testing purposes. 1//! Runs completion for testing purposes.
2 2
3use crate::{ 3use crate::{
4 completion::{completion_item::CompletionKind, CompletionOptions}, 4 completion::{completion_item::CompletionKind, CompletionConfig},
5 mock_analysis::{analysis_and_position, single_file_with_position}, 5 mock_analysis::{analysis_and_position, single_file_with_position},
6 CompletionItem, 6 CompletionItem,
7}; 7};
8 8
9pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { 9pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> {
10 do_completion_with_options(code, kind, &CompletionOptions::default()) 10 do_completion_with_options(code, kind, &CompletionConfig::default())
11} 11}
12 12
13pub(crate) fn do_completion_with_options( 13pub(crate) fn do_completion_with_options(
14 code: &str, 14 code: &str,
15 kind: CompletionKind, 15 kind: CompletionKind,
16 options: &CompletionOptions, 16 options: &CompletionConfig,
17) -> Vec<CompletionItem> { 17) -> Vec<CompletionItem> {
18 let (analysis, position) = if code.contains("//-") { 18 let (analysis, position) = if code.contains("//-") {
19 analysis_and_position(code) 19 analysis_and_position(code)
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index f4f0751c0..d06fc03d3 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -11,14 +11,14 @@ use ra_syntax::{
11use crate::{FileId, FunctionSignature}; 11use crate::{FileId, FunctionSignature};
12 12
13#[derive(Clone, Debug, PartialEq, Eq)] 13#[derive(Clone, Debug, PartialEq, Eq)]
14pub struct InlayHintsOptions { 14pub struct InlayHintsConfig {
15 pub type_hints: bool, 15 pub type_hints: bool,
16 pub parameter_hints: bool, 16 pub parameter_hints: bool,
17 pub chaining_hints: bool, 17 pub chaining_hints: bool,
18 pub max_length: Option<usize>, 18 pub max_length: Option<usize>,
19} 19}
20 20
21impl Default for InlayHintsOptions { 21impl Default for InlayHintsConfig {
22 fn default() -> Self { 22 fn default() -> Self {
23 Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } 23 Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None }
24 } 24 }
@@ -41,7 +41,7 @@ pub struct InlayHint {
41pub(crate) fn inlay_hints( 41pub(crate) fn inlay_hints(
42 db: &RootDatabase, 42 db: &RootDatabase,
43 file_id: FileId, 43 file_id: FileId,
44 options: &InlayHintsOptions, 44 config: &InlayHintsConfig,
45) -> Vec<InlayHint> { 45) -> Vec<InlayHint> {
46 let _p = profile("inlay_hints"); 46 let _p = profile("inlay_hints");
47 let sema = Semantics::new(db); 47 let sema = Semantics::new(db);
@@ -50,14 +50,14 @@ pub(crate) fn inlay_hints(
50 let mut res = Vec::new(); 50 let mut res = Vec::new();
51 for node in file.syntax().descendants() { 51 for node in file.syntax().descendants() {
52 if let Some(expr) = ast::Expr::cast(node.clone()) { 52 if let Some(expr) = ast::Expr::cast(node.clone()) {
53 get_chaining_hints(&mut res, &sema, options, expr); 53 get_chaining_hints(&mut res, &sema, config, expr);
54 } 54 }
55 55
56 match_ast! { 56 match_ast! {
57 match node { 57 match node {
58 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, 58 ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
59 ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, options, ast::Expr::from(it)); }, 59 ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, config, ast::Expr::from(it)); },
60 ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, options, it); }, 60 ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, config, it); },
61 _ => (), 61 _ => (),
62 } 62 }
63 } 63 }
@@ -68,10 +68,10 @@ pub(crate) fn inlay_hints(
68fn get_chaining_hints( 68fn get_chaining_hints(
69 acc: &mut Vec<InlayHint>, 69 acc: &mut Vec<InlayHint>,
70 sema: &Semantics<RootDatabase>, 70 sema: &Semantics<RootDatabase>,
71 options: &InlayHintsOptions, 71 config: &InlayHintsConfig,
72 expr: ast::Expr, 72 expr: ast::Expr,
73) -> Option<()> { 73) -> Option<()> {
74 if !options.chaining_hints { 74 if !config.chaining_hints {
75 return None; 75 return None;
76 } 76 }
77 77
@@ -95,7 +95,7 @@ fn get_chaining_hints(
95 let next = tokens.next()?.kind(); 95 let next = tokens.next()?.kind();
96 let next_next = tokens.next()?.kind(); 96 let next_next = tokens.next()?.kind();
97 if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT { 97 if next == SyntaxKind::WHITESPACE && next_next == SyntaxKind::DOT {
98 let label = ty.display_truncated(sema.db, options.max_length).to_string(); 98 let label = ty.display_truncated(sema.db, config.max_length).to_string();
99 acc.push(InlayHint { 99 acc.push(InlayHint {
100 range: expr.syntax().text_range(), 100 range: expr.syntax().text_range(),
101 kind: InlayKind::ChainingHint, 101 kind: InlayKind::ChainingHint,
@@ -108,10 +108,10 @@ fn get_chaining_hints(
108fn get_param_name_hints( 108fn get_param_name_hints(
109 acc: &mut Vec<InlayHint>, 109 acc: &mut Vec<InlayHint>,
110 sema: &Semantics<RootDatabase>, 110 sema: &Semantics<RootDatabase>,
111 options: &InlayHintsOptions, 111 config: &InlayHintsConfig,
112 expr: ast::Expr, 112 expr: ast::Expr,
113) -> Option<()> { 113) -> Option<()> {
114 if !options.parameter_hints { 114 if !config.parameter_hints {
115 return None; 115 return None;
116 } 116 }
117 117
@@ -148,10 +148,10 @@ fn get_param_name_hints(
148fn get_bind_pat_hints( 148fn get_bind_pat_hints(
149 acc: &mut Vec<InlayHint>, 149 acc: &mut Vec<InlayHint>,
150 sema: &Semantics<RootDatabase>, 150 sema: &Semantics<RootDatabase>,
151 options: &InlayHintsOptions, 151 config: &InlayHintsConfig,
152 pat: ast::BindPat, 152 pat: ast::BindPat,
153) -> Option<()> { 153) -> Option<()> {
154 if !options.type_hints { 154 if !config.type_hints {
155 return None; 155 return None;
156 } 156 }
157 157
@@ -164,7 +164,7 @@ fn get_bind_pat_hints(
164 acc.push(InlayHint { 164 acc.push(InlayHint {
165 range: pat.syntax().text_range(), 165 range: pat.syntax().text_range(),
166 kind: InlayKind::TypeHint, 166 kind: InlayKind::TypeHint,
167 label: ty.display_truncated(sema.db, options.max_length).to_string().into(), 167 label: ty.display_truncated(sema.db, config.max_length).to_string().into(),
168 }); 168 });
169 Some(()) 169 Some(())
170} 170}
@@ -270,7 +270,7 @@ fn get_fn_signature(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<
270 270
271#[cfg(test)] 271#[cfg(test)]
272mod tests { 272mod tests {
273 use crate::inlay_hints::InlayHintsOptions; 273 use crate::inlay_hints::InlayHintsConfig;
274 use insta::assert_debug_snapshot; 274 use insta::assert_debug_snapshot;
275 275
276 use crate::mock_analysis::single_file; 276 use crate::mock_analysis::single_file;
@@ -284,7 +284,7 @@ mod tests {
284 let _x = foo(4, 4); 284 let _x = foo(4, 4);
285 }"#, 285 }"#,
286 ); 286 );
287 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" 287 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: true, type_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
288 [ 288 [
289 InlayHint { 289 InlayHint {
290 range: [106; 107), 290 range: [106; 107),
@@ -308,7 +308,7 @@ mod tests {
308 let _x = foo(4, 4); 308 let _x = foo(4, 4);
309 }"#, 309 }"#,
310 ); 310 );
311 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###); 311 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: false, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"[]"###);
312 } 312 }
313 313
314 #[test] 314 #[test]
@@ -320,7 +320,7 @@ mod tests {
320 let _x = foo(4, 4); 320 let _x = foo(4, 4);
321 }"#, 321 }"#,
322 ); 322 );
323 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###" 323 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ type_hints: true, parameter_hints: false, chaining_hints: false, max_length: None}).unwrap(), @r###"
324 [ 324 [
325 InlayHint { 325 InlayHint {
326 range: [97; 99), 326 range: [97; 99),
@@ -344,7 +344,7 @@ fn main() {
344}"#, 344}"#,
345 ); 345 );
346 346
347 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 347 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
348 [ 348 [
349 InlayHint { 349 InlayHint {
350 range: [69; 71), 350 range: [69; 71),
@@ -401,7 +401,7 @@ fn main() {
401}"#, 401}"#,
402 ); 402 );
403 403
404 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 404 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
405 [ 405 [
406 InlayHint { 406 InlayHint {
407 range: [193; 197), 407 range: [193; 197),
@@ -481,7 +481,7 @@ fn main() {
481}"#, 481}"#,
482 ); 482 );
483 483
484 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 484 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
485 [ 485 [
486 InlayHint { 486 InlayHint {
487 range: [21; 30), 487 range: [21; 30),
@@ -545,7 +545,7 @@ fn main() {
545}"#, 545}"#,
546 ); 546 );
547 547
548 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 548 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
549 [ 549 [
550 InlayHint { 550 InlayHint {
551 range: [21; 30), 551 range: [21; 30),
@@ -595,7 +595,7 @@ fn main() {
595}"#, 595}"#,
596 ); 596 );
597 597
598 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 598 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
599 [ 599 [
600 InlayHint { 600 InlayHint {
601 range: [188; 192), 601 range: [188; 192),
@@ -690,7 +690,7 @@ fn main() {
690}"#, 690}"#,
691 ); 691 );
692 692
693 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 693 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
694 [ 694 [
695 InlayHint { 695 InlayHint {
696 range: [188; 192), 696 range: [188; 192),
@@ -785,7 +785,7 @@ fn main() {
785}"#, 785}"#,
786 ); 786 );
787 787
788 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 788 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
789 [ 789 [
790 InlayHint { 790 InlayHint {
791 range: [252; 256), 791 range: [252; 256),
@@ -857,7 +857,7 @@ fn main() {
857}"#, 857}"#,
858 ); 858 );
859 859
860 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" 860 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
861 [ 861 [
862 InlayHint { 862 InlayHint {
863 range: [74; 75), 863 range: [74; 75),
@@ -945,7 +945,7 @@ fn main() {
945}"#, 945}"#,
946 ); 946 );
947 947
948 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions::default()).unwrap(), @r###" 948 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig::default()).unwrap(), @r###"
949 [ 949 [
950 InlayHint { 950 InlayHint {
951 range: [798; 809), 951 range: [798; 809),
@@ -1067,7 +1067,7 @@ fn main() {
1067}"#, 1067}"#,
1068 ); 1068 );
1069 1069
1070 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" 1070 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1071 [] 1071 []
1072 "### 1072 "###
1073 ); 1073 );
@@ -1093,7 +1093,7 @@ fn main() {
1093}"#, 1093}"#,
1094 ); 1094 );
1095 1095
1096 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions { max_length: Some(8), ..Default::default() }).unwrap(), @r###" 1096 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig { max_length: Some(8), ..Default::default() }).unwrap(), @r###"
1097 [] 1097 []
1098 "### 1098 "###
1099 ); 1099 );
@@ -1115,7 +1115,7 @@ fn main() {
1115 .into_c(); 1115 .into_c();
1116 }"#, 1116 }"#,
1117 ); 1117 );
1118 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" 1118 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1119 [ 1119 [
1120 InlayHint { 1120 InlayHint {
1121 range: [232; 269), 1121 range: [232; 269),
@@ -1144,7 +1144,7 @@ fn main() {
1144 let c = A(B(C)).into_b().into_c(); 1144 let c = A(B(C)).into_b().into_c();
1145 }"#, 1145 }"#,
1146 ); 1146 );
1147 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###); 1147 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"[]"###);
1148 } 1148 }
1149 1149
1150 #[test] 1150 #[test]
@@ -1162,7 +1162,7 @@ fn main() {
1162 .0; 1162 .0;
1163 }"#, 1163 }"#,
1164 ); 1164 );
1165 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" 1165 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1166 [ 1166 [
1167 InlayHint { 1167 InlayHint {
1168 range: [150; 221), 1168 range: [150; 221),
@@ -1204,7 +1204,7 @@ fn main() {
1204 .into_c(); 1204 .into_c();
1205 }"#, 1205 }"#,
1206 ); 1206 );
1207 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsOptions{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###" 1207 assert_debug_snapshot!(analysis.inlay_hints(file_id, &InlayHintsConfig{ parameter_hints: false, type_hints: false, chaining_hints: true, max_length: None}).unwrap(), @r###"
1208 [ 1208 [
1209 InlayHint { 1209 InlayHint {
1210 range: [403; 452), 1210 range: [403; 452),
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index 937c9caa5..285381086 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -62,13 +62,13 @@ use crate::display::ToNav;
62pub use crate::{ 62pub use crate::{
63 assists::{Assist, AssistId}, 63 assists::{Assist, AssistId},
64 call_hierarchy::CallItem, 64 call_hierarchy::CallItem,
65 completion::{CompletionItem, CompletionItemKind, CompletionOptions, InsertTextFormat}, 65 completion::{CompletionConfig, CompletionItem, CompletionItemKind, InsertTextFormat},
66 diagnostics::Severity, 66 diagnostics::Severity,
67 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 67 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
68 expand_macro::ExpandedMacro, 68 expand_macro::ExpandedMacro,
69 folding_ranges::{Fold, FoldKind}, 69 folding_ranges::{Fold, FoldKind},
70 hover::HoverResult, 70 hover::HoverResult,
71 inlay_hints::{InlayHint, InlayHintsOptions, InlayKind}, 71 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
72 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult}, 72 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
73 runnables::{Runnable, RunnableKind, TestId}, 73 runnables::{Runnable, RunnableKind, TestId},
74 source_change::{FileSystemEdit, SourceChange, SourceFileEdit}, 74 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
@@ -325,9 +325,9 @@ impl Analysis {
325 pub fn inlay_hints( 325 pub fn inlay_hints(
326 &self, 326 &self,
327 file_id: FileId, 327 file_id: FileId,
328 inlay_hint_opts: &InlayHintsOptions, 328 config: &InlayHintsConfig,
329 ) -> Cancelable<Vec<InlayHint>> { 329 ) -> Cancelable<Vec<InlayHint>> {
330 self.with_db(|db| inlay_hints::inlay_hints(db, file_id, inlay_hint_opts)) 330 self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config))
331 } 331 }
332 332
333 /// Returns the set of folding ranges. 333 /// Returns the set of folding ranges.
@@ -450,9 +450,9 @@ impl Analysis {
450 pub fn completions( 450 pub fn completions(
451 &self, 451 &self,
452 position: FilePosition, 452 position: FilePosition,
453 options: &CompletionOptions, 453 config: &CompletionConfig,
454 ) -> Cancelable<Option<Vec<CompletionItem>>> { 454 ) -> Cancelable<Option<Vec<CompletionItem>>> {
455 self.with_db(|db| completion::completions(db, position, options).map(Into::into)) 455 self.with_db(|db| completion::completions(db, position, config).map(Into::into))
456 } 456 }
457 457
458 /// Computes assists (aka code actions aka intentions) for the given 458 /// Computes assists (aka code actions aka intentions) for the given
diff --git a/crates/ra_proc_macro/Cargo.toml b/crates/ra_proc_macro/Cargo.toml
index bc2c37296..d009ceb82 100644
--- a/crates/ra_proc_macro/Cargo.toml
+++ b/crates/ra_proc_macro/Cargo.toml
@@ -10,3 +10,8 @@ doctest = false
10 10
11[dependencies] 11[dependencies]
12ra_tt = { path = "../ra_tt" } 12ra_tt = { path = "../ra_tt" }
13serde = { version = "1.0", features = ["derive"] }
14serde_json = "1.0"
15log = "0.4.8"
16crossbeam-channel = "0.4.0"
17jod-thread = "0.1.1"
diff --git a/crates/ra_proc_macro/src/lib.rs b/crates/ra_proc_macro/src/lib.rs
index 5e21dd487..51fbb046a 100644
--- a/crates/ra_proc_macro/src/lib.rs
+++ b/crates/ra_proc_macro/src/lib.rs
@@ -5,55 +5,104 @@
5//! is used to provide basic infrastructure for communication between two 5//! is used to provide basic infrastructure for communication between two
6//! processes: Client (RA itself), Server (the external program) 6//! processes: Client (RA itself), Server (the external program)
7 7
8mod rpc;
9mod process;
10pub mod msg;
11
12use process::{ProcMacroProcessSrv, ProcMacroProcessThread};
8use ra_tt::{SmolStr, Subtree}; 13use ra_tt::{SmolStr, Subtree};
14use rpc::ProcMacroKind;
9use std::{ 15use std::{
10 path::{Path, PathBuf}, 16 path::{Path, PathBuf},
11 sync::Arc, 17 sync::Arc,
12}; 18};
13 19
14#[derive(Debug, Clone, PartialEq, Eq)] 20pub use rpc::{ExpansionResult, ExpansionTask};
21
22#[derive(Debug, Clone)]
15pub struct ProcMacroProcessExpander { 23pub struct ProcMacroProcessExpander {
16 process: Arc<ProcMacroProcessSrv>, 24 process: Arc<ProcMacroProcessSrv>,
25 dylib_path: PathBuf,
17 name: SmolStr, 26 name: SmolStr,
18} 27}
19 28
29impl Eq for ProcMacroProcessExpander {}
30impl PartialEq for ProcMacroProcessExpander {
31 fn eq(&self, other: &Self) -> bool {
32 self.name == other.name
33 && self.dylib_path == other.dylib_path
34 && Arc::ptr_eq(&self.process, &other.process)
35 }
36}
37
20impl ra_tt::TokenExpander for ProcMacroProcessExpander { 38impl ra_tt::TokenExpander for ProcMacroProcessExpander {
21 fn expand( 39 fn expand(
22 &self, 40 &self,
23 _subtree: &Subtree, 41 subtree: &Subtree,
24 _attr: Option<&Subtree>, 42 _attr: Option<&Subtree>,
25 ) -> Result<Subtree, ra_tt::ExpansionError> { 43 ) -> Result<Subtree, ra_tt::ExpansionError> {
26 // FIXME: do nothing for now 44 self.process.custom_derive(&self.dylib_path, subtree, &self.name)
27 Ok(Subtree::default())
28 } 45 }
29} 46}
30 47
31#[derive(Debug, Clone, PartialEq, Eq)] 48#[derive(Debug)]
32pub struct ProcMacroProcessSrv { 49enum ProcMacroClientKind {
33 path: PathBuf, 50 Process { process: Arc<ProcMacroProcessSrv>, thread: ProcMacroProcessThread },
51 Dummy,
34} 52}
35 53
36#[derive(Debug, Clone, PartialEq, Eq)] 54#[derive(Debug)]
37pub enum ProcMacroClient { 55pub struct ProcMacroClient {
38 Process { process: Arc<ProcMacroProcessSrv> }, 56 kind: ProcMacroClientKind,
39 Dummy,
40} 57}
41 58
42impl ProcMacroClient { 59impl ProcMacroClient {
43 pub fn extern_process(process_path: &Path) -> ProcMacroClient { 60 pub fn extern_process(process_path: &Path) -> Result<ProcMacroClient, std::io::Error> {
44 let process = ProcMacroProcessSrv { path: process_path.into() }; 61 let (thread, process) = ProcMacroProcessSrv::run(process_path)?;
45 ProcMacroClient::Process { process: Arc::new(process) } 62 Ok(ProcMacroClient {
63 kind: ProcMacroClientKind::Process { process: Arc::new(process), thread },
64 })
46 } 65 }
47 66
48 pub fn dummy() -> ProcMacroClient { 67 pub fn dummy() -> ProcMacroClient {
49 ProcMacroClient::Dummy 68 ProcMacroClient { kind: ProcMacroClientKind::Dummy }
50 } 69 }
51 70
52 pub fn by_dylib_path( 71 pub fn by_dylib_path(
53 &self, 72 &self,
54 _dylib_path: &Path, 73 dylib_path: &Path,
55 ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> { 74 ) -> Vec<(SmolStr, Arc<dyn ra_tt::TokenExpander>)> {
56 // FIXME: return empty for now 75 match &self.kind {
57 vec![] 76 ProcMacroClientKind::Dummy => vec![],
77 ProcMacroClientKind::Process { process, .. } => {
78 let macros = match process.find_proc_macros(dylib_path) {
79 Err(err) => {
80 eprintln!("Fail to find proc macro. Error: {:#?}", err);
81 return vec![];
82 }
83 Ok(macros) => macros,
84 };
85
86 macros
87 .into_iter()
88 .filter_map(|(name, kind)| {
89 // FIXME: Support custom derive only for now.
90 match kind {
91 ProcMacroKind::CustomDerive => {
92 let name = SmolStr::new(&name);
93 let expander: Arc<dyn ra_tt::TokenExpander> =
94 Arc::new(ProcMacroProcessExpander {
95 process: process.clone(),
96 name: name.clone(),
97 dylib_path: dylib_path.into(),
98 });
99 Some((name, expander))
100 }
101 _ => None,
102 }
103 })
104 .collect()
105 }
106 }
58 } 107 }
59} 108}
diff --git a/crates/ra_proc_macro/src/msg.rs b/crates/ra_proc_macro/src/msg.rs
new file mode 100644
index 000000000..aa95bcc8f
--- /dev/null
+++ b/crates/ra_proc_macro/src/msg.rs
@@ -0,0 +1,93 @@
1//! Defines messages for cross-process message based on `ndjson` wire protocol
2
3use std::{
4 convert::TryFrom,
5 io::{self, BufRead, Write},
6};
7
8use crate::{
9 rpc::{ListMacrosResult, ListMacrosTask},
10 ExpansionResult, ExpansionTask,
11};
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13
14#[derive(Debug, Serialize, Deserialize, Clone)]
15pub enum Request {
16 ListMacro(ListMacrosTask),
17 ExpansionMacro(ExpansionTask),
18}
19
20#[derive(Debug, Serialize, Deserialize, Clone)]
21pub enum Response {
22 Error(ResponseError),
23 ListMacro(ListMacrosResult),
24 ExpansionMacro(ExpansionResult),
25}
26
27macro_rules! impl_try_from_response {
28 ($ty:ty, $tag:ident) => {
29 impl TryFrom<Response> for $ty {
30 type Error = &'static str;
31 fn try_from(value: Response) -> Result<Self, Self::Error> {
32 match value {
33 Response::$tag(res) => Ok(res),
34 _ => Err("Fail to convert from response"),
35 }
36 }
37 }
38 };
39}
40
41impl_try_from_response!(ListMacrosResult, ListMacro);
42impl_try_from_response!(ExpansionResult, ExpansionMacro);
43
44#[derive(Debug, Serialize, Deserialize, Clone)]
45pub struct ResponseError {
46 pub code: ErrorCode,
47 pub message: String,
48}
49
50#[derive(Debug, Serialize, Deserialize, Clone)]
51pub enum ErrorCode {
52 ServerErrorEnd,
53 ExpansionError,
54}
55
56pub trait Message: Sized + Serialize + DeserializeOwned {
57 fn read(r: &mut impl BufRead) -> io::Result<Option<Self>> {
58 let text = match read_json(r)? {
59 None => return Ok(None),
60 Some(text) => text,
61 };
62 let msg = serde_json::from_str(&text)?;
63 Ok(Some(msg))
64 }
65 fn write(self, w: &mut impl Write) -> io::Result<()> {
66 let text = serde_json::to_string(&self)?;
67 write_json(w, &text)
68 }
69}
70
71impl Message for Request {}
72impl Message for Response {}
73
74fn read_json(inp: &mut impl BufRead) -> io::Result<Option<String>> {
75 let mut buf = String::new();
76 if inp.read_line(&mut buf)? == 0 {
77 return Ok(None);
78 }
79 // Remove ending '\n'
80 let buf = &buf[..buf.len() - 1];
81 if buf.is_empty() {
82 return Ok(None);
83 }
84 Ok(Some(buf.to_string()))
85}
86
87fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
88 log::debug!("> {}", msg);
89 out.write_all(msg.as_bytes())?;
90 out.write_all(b"\n")?;
91 out.flush()?;
92 Ok(())
93}
diff --git a/crates/ra_proc_macro/src/process.rs b/crates/ra_proc_macro/src/process.rs
new file mode 100644
index 000000000..e8c85be38
--- /dev/null
+++ b/crates/ra_proc_macro/src/process.rs
@@ -0,0 +1,196 @@
1//! Handle process life-time and message passing for proc-macro client
2
3use crossbeam_channel::{bounded, Receiver, Sender};
4use ra_tt::Subtree;
5
6use crate::msg::{ErrorCode, Message, Request, Response, ResponseError};
7use crate::rpc::{ExpansionResult, ExpansionTask, ListMacrosResult, ListMacrosTask, ProcMacroKind};
8
9use io::{BufRead, BufReader};
10use std::{
11 convert::{TryFrom, TryInto},
12 io::{self, Write},
13 path::{Path, PathBuf},
14 process::{Child, Command, Stdio},
15 sync::{Arc, Weak},
16};
17
18#[derive(Debug, Default)]
19pub(crate) struct ProcMacroProcessSrv {
20 inner: Option<Weak<Sender<Task>>>,
21}
22
23#[derive(Debug)]
24pub(crate) struct ProcMacroProcessThread {
25 // XXX: drop order is significant
26 sender: Arc<Sender<Task>>,
27 handle: jod_thread::JoinHandle<()>,
28}
29
30struct Task {
31 req: Request,
32 result_tx: Sender<Option<Response>>,
33}
34
35struct Process {
36 path: PathBuf,
37 child: Child,
38}
39
40impl Drop for Process {
41 fn drop(&mut self) {
42 let _ = self.child.kill();
43 }
44}
45
46impl Process {
47 fn run(process_path: &Path) -> Result<Process, io::Error> {
48 let child = Command::new(process_path.clone())
49 .stdin(Stdio::piped())
50 .stdout(Stdio::piped())
51 .stderr(Stdio::null())
52 .spawn()?;
53
54 Ok(Process { path: process_path.into(), child })
55 }
56
57 fn restart(&mut self) -> Result<(), io::Error> {
58 let _ = self.child.kill();
59 self.child = Command::new(self.path.clone())
60 .stdin(Stdio::piped())
61 .stdout(Stdio::piped())
62 .stderr(Stdio::null())
63 .spawn()?;
64 Ok(())
65 }
66
67 fn stdio(&mut self) -> Option<(impl Write, impl BufRead)> {
68 let stdin = self.child.stdin.take()?;
69 let stdout = self.child.stdout.take()?;
70 let read = BufReader::new(stdout);
71
72 Some((stdin, read))
73 }
74}
75
76impl ProcMacroProcessSrv {
77 pub fn run(
78 process_path: &Path,
79 ) -> Result<(ProcMacroProcessThread, ProcMacroProcessSrv), io::Error> {
80 let process = Process::run(process_path)?;
81
82 let (task_tx, task_rx) = bounded(0);
83 let handle = jod_thread::spawn(move || {
84 client_loop(task_rx, process);
85 });
86
87 let task_tx = Arc::new(task_tx);
88 let srv = ProcMacroProcessSrv { inner: Some(Arc::downgrade(&task_tx)) };
89 let thread = ProcMacroProcessThread { handle, sender: task_tx };
90
91 Ok((thread, srv))
92 }
93
94 pub fn find_proc_macros(
95 &self,
96 dylib_path: &Path,
97 ) -> Result<Vec<(String, ProcMacroKind)>, ra_tt::ExpansionError> {
98 let task = ListMacrosTask { lib: dylib_path.to_path_buf() };
99
100 let result: ListMacrosResult = self.send_task(Request::ListMacro(task))?;
101 Ok(result.macros)
102 }
103
104 pub fn custom_derive(
105 &self,
106 dylib_path: &Path,
107 subtree: &Subtree,
108 derive_name: &str,
109 ) -> Result<Subtree, ra_tt::ExpansionError> {
110 let task = ExpansionTask {
111 macro_body: subtree.clone(),
112 macro_name: derive_name.to_string(),
113 attributes: None,
114 lib: dylib_path.to_path_buf(),
115 };
116
117 let result: ExpansionResult = self.send_task(Request::ExpansionMacro(task))?;
118 Ok(result.expansion)
119 }
120
121 pub fn send_task<R>(&self, req: Request) -> Result<R, ra_tt::ExpansionError>
122 where
123 R: TryFrom<Response, Error = &'static str>,
124 {
125 let sender = match &self.inner {
126 None => return Err(ra_tt::ExpansionError::Unknown("No sender is found.".to_string())),
127 Some(it) => it,
128 };
129
130 let (result_tx, result_rx) = bounded(0);
131 let sender = match sender.upgrade() {
132 None => {
133 return Err(ra_tt::ExpansionError::Unknown("Proc macro process is closed.".into()))
134 }
135 Some(it) => it,
136 };
137 sender.send(Task { req: req.into(), result_tx }).unwrap();
138 let res = result_rx
139 .recv()
140 .map_err(|_| ra_tt::ExpansionError::Unknown("Proc macro thread is closed.".into()))?;
141
142 match res {
143 Some(Response::Error(err)) => {
144 return Err(ra_tt::ExpansionError::ExpansionError(err.message));
145 }
146 Some(res) => Ok(res.try_into().map_err(|err| {
147 ra_tt::ExpansionError::Unknown(format!(
148 "Fail to get response, reason : {:#?} ",
149 err
150 ))
151 })?),
152 None => Err(ra_tt::ExpansionError::Unknown("Empty result".into())),
153 }
154 }
155}
156
157fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
158 let (mut stdin, mut stdout) = match process.stdio() {
159 None => return,
160 Some(it) => it,
161 };
162
163 for task in task_rx {
164 let Task { req, result_tx } = task;
165
166 match send_request(&mut stdin, &mut stdout, req) {
167 Ok(res) => result_tx.send(res).unwrap(),
168 Err(_err) => {
169 let res = Response::Error(ResponseError {
170 code: ErrorCode::ServerErrorEnd,
171 message: "Server closed".into(),
172 });
173 result_tx.send(res.into()).unwrap();
174 // Restart the process
175 if process.restart().is_err() {
176 break;
177 }
178 let stdio = match process.stdio() {
179 None => break,
180 Some(it) => it,
181 };
182 stdin = stdio.0;
183 stdout = stdio.1;
184 }
185 }
186 }
187}
188
189fn send_request(
190 mut writer: &mut impl Write,
191 mut reader: &mut impl BufRead,
192 req: Request,
193) -> Result<Option<Response>, io::Error> {
194 req.write(&mut writer)?;
195 Ok(Response::read(&mut reader)?)
196}
diff --git a/crates/ra_proc_macro/src/rpc.rs b/crates/ra_proc_macro/src/rpc.rs
new file mode 100644
index 000000000..66b3f55db
--- /dev/null
+++ b/crates/ra_proc_macro/src/rpc.rs
@@ -0,0 +1,266 @@
1//! Data struture serialization related stuffs for RPC
2//!
3//! Define all necessary rpc serialization data structure,
4//! which include ra_tt related data and some task messages.
5//! Although adding Serialize and Deserialize trait to ra_tt directly seem to be much easier,
6//! we deliberately duplicate the ra_tt struct with #[serde(with = "XXDef")]
7//! for separation of code responsibility.
8
9use ra_tt::{
10 Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, SmolStr, Spacing, Subtree, TokenId,
11 TokenTree,
12};
13use serde::{Deserialize, Serialize};
14use std::path::PathBuf;
15
16#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
17pub struct ListMacrosTask {
18 pub lib: PathBuf,
19}
20
21#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
22pub enum ProcMacroKind {
23 CustomDerive,
24 FuncLike,
25 Attr,
26}
27
28#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
29pub struct ListMacrosResult {
30 pub macros: Vec<(String, ProcMacroKind)>,
31}
32
33#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)]
34pub struct ExpansionTask {
35 /// Argument of macro call.
36 ///
37 /// In custom derive that would be a struct or enum; in attribute-like macro - underlying
38 /// item; in function-like macro - the macro body.
39 #[serde(with = "SubtreeDef")]
40 pub macro_body: Subtree,
41
42 /// Names of macros to expand.
43 ///
44 /// In custom derive those are names of derived traits (`Serialize`, `Getters`, etc.). In
45 /// attribute-like and functiona-like macros - single name of macro itself (`show_streams`).
46 pub macro_name: String,
47
48 /// Possible attributes for the attribute-like macros.
49 #[serde(with = "opt_subtree_def")]
50 pub attributes: Option<Subtree>,
51
52 pub lib: PathBuf,
53}
54
55#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
56pub struct ExpansionResult {
57 #[serde(with = "SubtreeDef")]
58 pub expansion: Subtree,
59}
60
61#[derive(Serialize, Deserialize)]
62#[serde(remote = "DelimiterKind")]
63enum DelimiterKindDef {
64 Parenthesis,
65 Brace,
66 Bracket,
67}
68
69#[derive(Serialize, Deserialize)]
70#[serde(remote = "TokenId")]
71struct TokenIdDef(u32);
72
73#[derive(Serialize, Deserialize)]
74#[serde(remote = "Delimiter")]
75struct DelimiterDef {
76 #[serde(with = "TokenIdDef")]
77 pub id: TokenId,
78 #[serde(with = "DelimiterKindDef")]
79 pub kind: DelimiterKind,
80}
81
82#[derive(Serialize, Deserialize)]
83#[serde(remote = "Subtree")]
84struct SubtreeDef {
85 #[serde(default, with = "opt_delimiter_def")]
86 pub delimiter: Option<Delimiter>,
87 #[serde(with = "vec_token_tree")]
88 pub token_trees: Vec<TokenTree>,
89}
90
91#[derive(Serialize, Deserialize)]
92#[serde(remote = "TokenTree")]
93enum TokenTreeDef {
94 #[serde(with = "LeafDef")]
95 Leaf(Leaf),
96 #[serde(with = "SubtreeDef")]
97 Subtree(Subtree),
98}
99
100#[derive(Serialize, Deserialize)]
101#[serde(remote = "Leaf")]
102enum LeafDef {
103 #[serde(with = "LiteralDef")]
104 Literal(Literal),
105 #[serde(with = "PunctDef")]
106 Punct(Punct),
107 #[serde(with = "IdentDef")]
108 Ident(Ident),
109}
110
111#[derive(Serialize, Deserialize)]
112#[serde(remote = "Literal")]
113struct LiteralDef {
114 pub text: SmolStr,
115 #[serde(with = "TokenIdDef")]
116 pub id: TokenId,
117}
118
119#[derive(Serialize, Deserialize)]
120#[serde(remote = "Punct")]
121struct PunctDef {
122 pub char: char,
123 #[serde(with = "SpacingDef")]
124 pub spacing: Spacing,
125 #[serde(with = "TokenIdDef")]
126 pub id: TokenId,
127}
128
129#[derive(Serialize, Deserialize)]
130#[serde(remote = "Spacing")]
131enum SpacingDef {
132 Alone,
133 Joint,
134}
135
136#[derive(Serialize, Deserialize)]
137#[serde(remote = "Ident")]
138struct IdentDef {
139 pub text: SmolStr,
140 #[serde(with = "TokenIdDef")]
141 pub id: TokenId,
142}
143
144mod opt_delimiter_def {
145 use super::{Delimiter, DelimiterDef};
146 use serde::{Deserialize, Deserializer, Serialize, Serializer};
147
148 pub fn serialize<S>(value: &Option<Delimiter>, serializer: S) -> Result<S::Ok, S::Error>
149 where
150 S: Serializer,
151 {
152 #[derive(Serialize)]
153 struct Helper<'a>(#[serde(with = "DelimiterDef")] &'a Delimiter);
154 value.as_ref().map(Helper).serialize(serializer)
155 }
156
157 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Delimiter>, D::Error>
158 where
159 D: Deserializer<'de>,
160 {
161 #[derive(Deserialize)]
162 struct Helper(#[serde(with = "DelimiterDef")] Delimiter);
163 let helper = Option::deserialize(deserializer)?;
164 Ok(helper.map(|Helper(external)| external))
165 }
166}
167
168mod opt_subtree_def {
169 use super::{Subtree, SubtreeDef};
170 use serde::{Deserialize, Deserializer, Serialize, Serializer};
171
172 pub fn serialize<S>(value: &Option<Subtree>, serializer: S) -> Result<S::Ok, S::Error>
173 where
174 S: Serializer,
175 {
176 #[derive(Serialize)]
177 struct Helper<'a>(#[serde(with = "SubtreeDef")] &'a Subtree);
178 value.as_ref().map(Helper).serialize(serializer)
179 }
180
181 pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Subtree>, D::Error>
182 where
183 D: Deserializer<'de>,
184 {
185 #[derive(Deserialize)]
186 struct Helper(#[serde(with = "SubtreeDef")] Subtree);
187 let helper = Option::deserialize(deserializer)?;
188 Ok(helper.map(|Helper(external)| external))
189 }
190}
191
192mod vec_token_tree {
193 use super::{TokenTree, TokenTreeDef};
194 use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
195
196 pub fn serialize<S>(value: &Vec<TokenTree>, serializer: S) -> Result<S::Ok, S::Error>
197 where
198 S: Serializer,
199 {
200 #[derive(Serialize)]
201 struct Helper<'a>(#[serde(with = "TokenTreeDef")] &'a TokenTree);
202
203 let items: Vec<_> = value.iter().map(Helper).collect();
204 let mut seq = serializer.serialize_seq(Some(items.len()))?;
205 for element in items {
206 seq.serialize_element(&element)?;
207 }
208 seq.end()
209 }
210
211 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<TokenTree>, D::Error>
212 where
213 D: Deserializer<'de>,
214 {
215 #[derive(Deserialize)]
216 struct Helper(#[serde(with = "TokenTreeDef")] TokenTree);
217
218 let helper = Vec::deserialize(deserializer)?;
219 Ok(helper.into_iter().map(|Helper(external)| external).collect())
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 fn fixture_token_tree() -> Subtree {
228 let mut subtree = Subtree::default();
229 subtree
230 .token_trees
231 .push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
232 subtree
233 .token_trees
234 .push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
235 subtree.token_trees.push(TokenTree::Subtree(
236 Subtree {
237 delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
238 token_trees: vec![],
239 }
240 .into(),
241 ));
242 subtree
243 }
244
245 #[test]
246 fn test_proc_macro_rpc_works() {
247 let tt = fixture_token_tree();
248 let task = ExpansionTask {
249 macro_body: tt.clone(),
250 macro_name: Default::default(),
251 attributes: None,
252 lib: Default::default(),
253 };
254
255 let json = serde_json::to_string(&task).unwrap();
256 let back: ExpansionTask = serde_json::from_str(&json).unwrap();
257
258 assert_eq!(task.macro_body, back.macro_body);
259
260 let result = ExpansionResult { expansion: tt.clone() };
261 let json = serde_json::to_string(&result).unwrap();
262 let back: ExpansionResult = serde_json::from_str(&json).unwrap();
263
264 assert_eq!(result, back);
265 }
266}
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index cdcdd63c9..b10644b4b 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -16,7 +16,6 @@ cargo_metadata = "0.9.1"
16ra_arena = { path = "../ra_arena" } 16ra_arena = { path = "../ra_arena" }
17ra_db = { path = "../ra_db" } 17ra_db = { path = "../ra_db" }
18ra_cfg = { path = "../ra_cfg" } 18ra_cfg = { path = "../ra_cfg" }
19ra_cargo_watch = { path = "../ra_cargo_watch" }
20ra_proc_macro = { path = "../ra_proc_macro" } 19ra_proc_macro = { path = "../ra_proc_macro" }
21 20
22serde = { version = "1.0.104", features = ["derive"] } 21serde = { version = "1.0.104", features = ["derive"] }
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 291594e2a..f4fd6ad28 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -1,14 +1,16 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{ 3use std::{
4 env,
5 ffi::OsStr,
4 ops, 6 ops,
5 path::{Path, PathBuf}, 7 path::{Path, PathBuf},
8 process::Command,
6}; 9};
7 10
8use anyhow::{Context, Result}; 11use anyhow::{Context, Result};
9use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 12use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
10use ra_arena::{Arena, Idx}; 13use ra_arena::{Arena, Idx};
11use ra_cargo_watch::run_cargo;
12use ra_db::Edition; 14use ra_db::Edition;
13use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
14use serde::Deserialize; 16use serde::Deserialize;
@@ -75,6 +77,7 @@ pub type Target = Idx<TargetData>;
75 77
76#[derive(Debug, Clone)] 78#[derive(Debug, Clone)]
77pub struct PackageData { 79pub struct PackageData {
80 pub id: String,
78 pub name: String, 81 pub name: String,
79 pub manifest: PathBuf, 82 pub manifest: PathBuf,
80 pub targets: Vec<Target>, 83 pub targets: Vec<Target>,
@@ -161,7 +164,7 @@ impl CargoWorkspace {
161 let mut out_dir_by_id = FxHashMap::default(); 164 let mut out_dir_by_id = FxHashMap::default();
162 let mut proc_macro_dylib_paths = FxHashMap::default(); 165 let mut proc_macro_dylib_paths = FxHashMap::default();
163 if cargo_features.load_out_dirs_from_check { 166 if cargo_features.load_out_dirs_from_check {
164 let resources = load_extern_resources(cargo_toml, cargo_features); 167 let resources = load_extern_resources(cargo_toml, cargo_features)?;
165 out_dir_by_id = resources.out_dirs; 168 out_dir_by_id = resources.out_dirs;
166 proc_macro_dylib_paths = resources.proc_dylib_paths; 169 proc_macro_dylib_paths = resources.proc_dylib_paths;
167 } 170 }
@@ -180,6 +183,7 @@ impl CargoWorkspace {
180 .with_context(|| format!("Failed to parse edition {}", edition))?; 183 .with_context(|| format!("Failed to parse edition {}", edition))?;
181 let pkg = packages.alloc(PackageData { 184 let pkg = packages.alloc(PackageData {
182 name, 185 name,
186 id: id.to_string(),
183 manifest: manifest_path, 187 manifest: manifest_path,
184 targets: Vec::new(), 188 targets: Vec::new(),
185 is_member, 189 is_member,
@@ -249,6 +253,18 @@ impl CargoWorkspace {
249 pub fn workspace_root(&self) -> &Path { 253 pub fn workspace_root(&self) -> &Path {
250 &self.workspace_root 254 &self.workspace_root
251 } 255 }
256
257 pub fn package_flag(&self, package: &PackageData) -> String {
258 if self.is_unique(&*package.name) {
259 package.name.clone()
260 } else {
261 package.id.clone()
262 }
263 }
264
265 fn is_unique(&self, name: &str) -> bool {
266 self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
267 }
252} 268}
253 269
254#[derive(Debug, Clone, Default)] 270#[derive(Debug, Clone, Default)]
@@ -257,48 +273,61 @@ pub struct ExternResources {
257 proc_dylib_paths: FxHashMap<PackageId, PathBuf>, 273 proc_dylib_paths: FxHashMap<PackageId, PathBuf>,
258} 274}
259 275
260pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) -> ExternResources { 276pub fn load_extern_resources(
261 let mut args: Vec<String> = vec![ 277 cargo_toml: &Path,
262 "check".to_string(), 278 cargo_features: &CargoFeatures,
263 "--message-format=json".to_string(), 279) -> Result<ExternResources> {
264 "--manifest-path".to_string(), 280 let mut cmd = Command::new(cargo_binary());
265 cargo_toml.display().to_string(), 281 cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
266 ];
267
268 if cargo_features.all_features { 282 if cargo_features.all_features {
269 args.push("--all-features".to_string()); 283 cmd.arg("--all-features");
270 } else if cargo_features.no_default_features { 284 } else if cargo_features.no_default_features {
271 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 285 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
272 // https://github.com/oli-obk/cargo_metadata/issues/79 286 // https://github.com/oli-obk/cargo_metadata/issues/79
273 args.push("--no-default-features".to_string()); 287 cmd.arg("--no-default-features");
274 } else { 288 } else {
275 args.extend(cargo_features.features.iter().cloned()); 289 cmd.args(&cargo_features.features);
276 } 290 }
277 291
278 let mut acc = ExternResources::default(); 292 let output = cmd.output()?;
279 let res = run_cargo(&args, cargo_toml.parent(), &mut |message| {
280 match message {
281 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
282 acc.out_dirs.insert(package_id, out_dir);
283 }
284 293
285 Message::CompilerArtifact(message) => { 294 let mut res = ExternResources::default();
286 if message.target.kind.contains(&"proc-macro".to_string()) { 295
287 let package_id = message.package_id; 296 let stdout = String::from_utf8(output.stdout)?;
288 if let Some(filename) = message.filenames.get(0) { 297 for line in stdout.lines() {
289 acc.proc_dylib_paths.insert(package_id, filename.clone()); 298 if let Ok(message) = serde_json::from_str::<cargo_metadata::Message>(&line) {
299 match message {
300 Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => {
301 res.out_dirs.insert(package_id, out_dir);
302 }
303
304 Message::CompilerArtifact(message) => {
305 if message.target.kind.contains(&"proc-macro".to_string()) {
306 let package_id = message.package_id;
307 // Skip rmeta file
308 if let Some(filename) =
309 message.filenames.iter().filter(|name| is_dylib(name)).next()
310 {
311 res.proc_dylib_paths.insert(package_id, filename.clone());
312 }
290 } 313 }
291 } 314 }
315 Message::CompilerMessage(_) => (),
316 Message::Unknown => (),
292 } 317 }
293 Message::CompilerMessage(_) => (),
294 Message::Unknown => (),
295 } 318 }
296 true 319 }
297 }); 320 Ok(res)
321}
298 322
299 if let Err(err) = res { 323// FIXME: File a better way to know if it is a dylib
300 log::error!("Failed to load outdirs: {:?}", err); 324fn is_dylib(path: &Path) -> bool {
325 match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
326 None => false,
327 Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
301 } 328 }
329}
302 330
303 acc 331fn cargo_binary() -> String {
332 env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
304} 333}
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 3d023f189..b69cae234 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -369,22 +369,33 @@ impl ast::MatchArmList {
369 369
370 #[must_use] 370 #[must_use]
371 pub fn remove_placeholder(&self) -> ast::MatchArmList { 371 pub fn remove_placeholder(&self) -> ast::MatchArmList {
372 let placeholder = self.arms().find(|arm| { 372 let placeholder =
373 if let Some(ast::Pat::PlaceholderPat(_)) = arm.pat() { 373 self.arms().find(|arm| matches!(arm.pat(), Some(ast::Pat::PlaceholderPat(_))));
374 return true;
375 }
376 false
377 });
378 if let Some(placeholder) = placeholder { 374 if let Some(placeholder) = placeholder {
379 let s: SyntaxElement = placeholder.syntax().clone().into(); 375 self.remove_arm(&placeholder)
380 let e = s.clone();
381 self.replace_children(s..=e, &mut iter::empty())
382 } else { 376 } else {
383 self.clone() 377 self.clone()
384 } 378 }
385 } 379 }
386 380
387 #[must_use] 381 #[must_use]
382 fn remove_arm(&self, arm: &ast::MatchArm) -> ast::MatchArmList {
383 let start = arm.syntax().clone();
384 let end = if let Some(comma) = start
385 .siblings_with_tokens(Direction::Next)
386 .skip(1)
387 .skip_while(|it| it.kind().is_trivia())
388 .next()
389 .filter(|it| it.kind() == T![,])
390 {
391 comma
392 } else {
393 start.clone().into()
394 };
395 self.replace_children(start.into()..=end, None)
396 }
397
398 #[must_use]
388 pub fn append_arm(&self, item: ast::MatchArm) -> ast::MatchArmList { 399 pub fn append_arm(&self, item: ast::MatchArm) -> ast::MatchArmList {
389 let r_curly = match self.syntax().children_with_tokens().find(|it| it.kind() == T!['}']) { 400 let r_curly = match self.syntax().children_with_tokens().find(|it| it.kind() == T!['}']) {
390 Some(t) => t, 401 Some(t) => t,
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index dd202601d..87bb21cd9 100644
--- a/crates/ra_syntax/src/parsing/text_tree_sink.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -149,10 +149,21 @@ fn n_attached_trivias<'a>(
149 MACRO_CALL | CONST_DEF | TYPE_ALIAS_DEF | STRUCT_DEF | ENUM_DEF | ENUM_VARIANT | FN_DEF 149 MACRO_CALL | CONST_DEF | TYPE_ALIAS_DEF | STRUCT_DEF | ENUM_DEF | ENUM_VARIANT | FN_DEF
150 | TRAIT_DEF | MODULE | RECORD_FIELD_DEF | STATIC_DEF => { 150 | TRAIT_DEF | MODULE | RECORD_FIELD_DEF | STATIC_DEF => {
151 let mut res = 0; 151 let mut res = 0;
152 for (i, (kind, text)) in trivias.enumerate() { 152 let mut trivias = trivias.enumerate().peekable();
153
154 while let Some((i, (kind, text))) = trivias.next() {
153 match kind { 155 match kind {
154 WHITESPACE => { 156 WHITESPACE => {
155 if text.contains("\n\n") { 157 if text.contains("\n\n") {
158 // we check whether the next token is a doc-comment
159 // and skip the whitespace in this case
160 if let Some((peek_kind, peek_text)) =
161 trivias.peek().map(|(_, pair)| pair)
162 {
163 if *peek_kind == COMMENT && peek_text.starts_with("///") {
164 continue;
165 }
166 }
156 break; 167 break;
157 } 168 }
158 } 169 }
diff --git a/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rs b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rs
new file mode 100644
index 000000000..1fafe216b
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.rs
@@ -0,0 +1,3 @@
1/// Example
2
3fn test() {}
diff --git a/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.txt b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.txt
new file mode 100644
index 000000000..91d0c3736
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0065_comment_newline.txt
@@ -0,0 +1,17 @@
1SOURCE_FILE@[0; 26)
2 FN_DEF@[0; 25)
3 COMMENT@[0; 11) "/// Example"
4 WHITESPACE@[11; 13) "\n\n"
5 FN_KW@[13; 15) "fn"
6 WHITESPACE@[15; 16) " "
7 NAME@[16; 20)
8 IDENT@[16; 20) "test"
9 PARAM_LIST@[20; 22)
10 L_PAREN@[20; 21) "("
11 R_PAREN@[21; 22) ")"
12 WHITESPACE@[22; 23) " "
13 BLOCK_EXPR@[23; 25)
14 BLOCK@[23; 25)
15 L_CURLY@[23; 24) "{"
16 R_CURLY@[24; 25) "}"
17 WHITESPACE@[25; 26) "\n"
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 1015ce0a6..bd484aa30 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -189,7 +189,12 @@ impl Subtree {
189pub mod buffer; 189pub mod buffer;
190 190
191#[derive(Debug, PartialEq, Eq)] 191#[derive(Debug, PartialEq, Eq)]
192pub enum ExpansionError {} 192pub enum ExpansionError {
193 IOError(String),
194 JsonError(String),
195 Unknown(String),
196 ExpansionError(String),
197}
193 198
194pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe { 199pub trait TokenExpander: Debug + Send + Sync + RefUnwindSafe {
195 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>) 200 fn expand(&self, subtree: &Subtree, attrs: Option<&Subtree>)
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 8fe6799d2..f5f773432 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -33,7 +33,7 @@ threadpool = "1.7.1"
33stdx = { path = "../stdx" } 33stdx = { path = "../stdx" }
34 34
35lsp-server = "0.3.1" 35lsp-server = "0.3.1"
36ra_cargo_watch = { path = "../ra_cargo_watch" } 36ra_flycheck = { path = "../ra_flycheck" }
37ra_ide = { path = "../ra_ide" } 37ra_ide = { path = "../ra_ide" }
38ra_prof = { path = "../ra_prof" } 38ra_prof = { path = "../ra_prof" }
39ra_project_model = { path = "../ra_project_model" } 39ra_project_model = { path = "../ra_project_model" }
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index f87bdcec5..942c30328 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -77,7 +77,7 @@ impl CargoTargetSpec {
77 ProjectWorkspace::Cargo { cargo, .. } => { 77 ProjectWorkspace::Cargo { cargo, .. } => {
78 let tgt = cargo.target_by_root(&path)?; 78 let tgt = cargo.target_by_root(&path)?;
79 Some(CargoTargetSpec { 79 Some(CargoTargetSpec {
80 package: cargo[cargo[tgt].package].name.clone(), 80 package: cargo.package_flag(&cargo[cargo[tgt].package]),
81 target: cargo[tgt].name.clone(), 81 target: cargo[tgt].name.clone(),
82 target_kind: cargo[tgt].kind, 82 target_kind: cargo[tgt].kind,
83 }) 83 })
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 7164b0ade..7667873d5 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -12,7 +12,7 @@ use ra_db::{
12 salsa::{Database, Durability}, 12 salsa::{Database, Durability},
13 FileId, SourceDatabaseExt, 13 FileId, SourceDatabaseExt,
14}; 14};
15use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionOptions, FilePosition, LineCol}; 15use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionConfig, FilePosition, LineCol};
16 16
17use crate::cli::{load_cargo::load_cargo, Verbosity}; 17use crate::cli::{load_cargo::load_cargo, Verbosity};
18 18
@@ -102,7 +102,7 @@ pub fn analysis_bench(
102 let file_position = FilePosition { file_id, offset }; 102 let file_position = FilePosition { file_id, offset };
103 103
104 if is_completion { 104 if is_completion {
105 let options = CompletionOptions::default(); 105 let options = CompletionConfig::default();
106 let res = do_work(&mut host, file_id, |analysis| { 106 let res = do_work(&mut host, file_id, |analysis| {
107 analysis.completions(file_position, &options) 107 analysis.completions(file_position, &options)
108 }); 108 });
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs
index 6edc03fe0..e8dc953c3 100644
--- a/crates/rust-analyzer/src/conv.rs
+++ b/crates/rust-analyzer/src/conv.rs
@@ -579,7 +579,7 @@ impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo<Vec<NavigationTarget>>)
579 .into_iter() 579 .into_iter()
580 .map(|nav| (file_id, RangeInfo::new(range, nav))) 580 .map(|nav| (file_id, RangeInfo::new(range, nav)))
581 .try_conv_with_to_vec(world)?; 581 .try_conv_with_to_vec(world)?;
582 if world.options.supports_location_link { 582 if world.config.supports_location_link {
583 Ok(links.into()) 583 Ok(links.into())
584 } else { 584 } else {
585 let locations: Vec<Location> = links 585 let locations: Vec<Location> = links
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 79ea90cc9..bb33fb27d 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -21,8 +21,8 @@ use lsp_types::{
21 WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, 21 WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd,
22 WorkDoneProgressReport, 22 WorkDoneProgressReport,
23}; 23};
24use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; 24use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckConfig, CheckTask};
25use ra_ide::{Canceled, FileId, InlayHintsOptions, LibraryData, SourceRootId}; 25use ra_ide::{Canceled, FileId, InlayHintsConfig, LibraryData, SourceRootId};
26use ra_prof::profile; 26use ra_prof::profile;
27use ra_vfs::{VfsFile, VfsTask, Watch}; 27use ra_vfs::{VfsFile, VfsTask, Watch};
28use relative_path::RelativePathBuf; 28use relative_path::RelativePathBuf;
@@ -38,7 +38,7 @@ use crate::{
38 subscriptions::Subscriptions, 38 subscriptions::Subscriptions,
39 }, 39 },
40 req, 40 req,
41 world::{Options, WorldSnapshot, WorldState}, 41 world::{Config, WorldSnapshot, WorldState},
42 Result, ServerConfig, 42 Result, ServerConfig,
43}; 43};
44use req::ConfigurationParams; 44use req::ConfigurationParams;
@@ -81,11 +81,11 @@ fn get_feature_flags(config: &ServerConfig, connection: &Connection) -> FeatureF
81 ff 81 ff
82} 82}
83 83
84fn get_options( 84fn get_config(
85 config: &ServerConfig, 85 config: &ServerConfig,
86 text_document_caps: Option<&TextDocumentClientCapabilities>, 86 text_document_caps: Option<&TextDocumentClientCapabilities>,
87) -> Options { 87) -> Config {
88 Options { 88 Config {
89 publish_decorations: config.publish_decorations, 89 publish_decorations: config.publish_decorations,
90 supports_location_link: text_document_caps 90 supports_location_link: text_document_caps
91 .and_then(|it| it.definition) 91 .and_then(|it| it.definition)
@@ -95,13 +95,13 @@ fn get_options(
95 .and_then(|it| it.folding_range.as_ref()) 95 .and_then(|it| it.folding_range.as_ref())
96 .and_then(|it| it.line_folding_only) 96 .and_then(|it| it.line_folding_only)
97 .unwrap_or(false), 97 .unwrap_or(false),
98 inlay_hints: InlayHintsOptions { 98 inlay_hints: InlayHintsConfig {
99 type_hints: config.inlay_hints_type, 99 type_hints: config.inlay_hints_type,
100 parameter_hints: config.inlay_hints_parameter, 100 parameter_hints: config.inlay_hints_parameter,
101 chaining_hints: config.inlay_hints_chaining, 101 chaining_hints: config.inlay_hints_chaining,
102 max_length: config.inlay_hints_max_length, 102 max_length: config.inlay_hints_max_length,
103 }, 103 },
104 cargo_watch: CheckOptions { 104 check: CheckConfig {
105 enable: config.cargo_watch_enable, 105 enable: config.cargo_watch_enable,
106 args: config.cargo_watch_args.clone(), 106 args: config.cargo_watch_args.clone(),
107 command: config.cargo_watch_command.clone(), 107 command: config.cargo_watch_command.clone(),
@@ -109,6 +109,7 @@ fn get_options(
109 }, 109 },
110 rustfmt_args: config.rustfmt_args.clone(), 110 rustfmt_args: config.rustfmt_args.clone(),
111 vscode_lldb: config.vscode_lldb, 111 vscode_lldb: config.vscode_lldb,
112 proc_macro_srv: None, // FIXME: get this from config
112 } 113 }
113} 114}
114 115
@@ -210,7 +211,7 @@ pub fn main_loop(
210 config.lru_capacity, 211 config.lru_capacity,
211 &globs, 212 &globs,
212 Watch(!config.use_client_watching), 213 Watch(!config.use_client_watching),
213 get_options(&config, text_document_caps), 214 get_config(&config, text_document_caps),
214 feature_flags, 215 feature_flags,
215 ) 216 )
216 }; 217 };
@@ -435,7 +436,7 @@ fn loop_turn(
435 .to_owned(); 436 .to_owned();
436 world_state.update_configuration( 437 world_state.update_configuration(
437 new_config.lru_capacity, 438 new_config.lru_capacity,
438 get_options(&new_config, text_document_caps), 439 get_config(&new_config, text_document_caps),
439 get_feature_flags(&new_config, connection), 440 get_feature_flags(&new_config, connection),
440 ); 441 );
441 } 442 }
@@ -498,7 +499,7 @@ fn loop_turn(
498 update_file_notifications_on_threadpool( 499 update_file_notifications_on_threadpool(
499 pool, 500 pool,
500 world_state.snapshot(), 501 world_state.snapshot(),
501 world_state.options.publish_decorations, 502 world_state.config.publish_decorations,
502 task_sender.clone(), 503 task_sender.clone(),
503 loop_state.subscriptions.subscriptions(), 504 loop_state.subscriptions.subscriptions(),
504 ) 505 )
@@ -808,14 +809,14 @@ fn send_startup_progress(sender: &Sender<Message>, loop_state: &mut LoopState) {
808 ), 809 ),
809 _ => {} 810 _ => {}
810 } 811 }
811}
812 812
813fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) { 813 fn send_startup_progress_notif(sender: &Sender<Message>, work_done_progress: WorkDoneProgress) {
814 let notif = notification_new::<req::Progress>(req::ProgressParams { 814 let notif = notification_new::<req::Progress>(req::ProgressParams {
815 token: req::ProgressToken::String("rustAnalyzer/startup".into()), 815 token: req::ProgressToken::String("rustAnalyzer/startup".into()),
816 value: req::ProgressParamsValue::WorkDone(work_done_progress), 816 value: req::ProgressParamsValue::WorkDone(work_done_progress),
817 }); 817 });
818 sender.send(notif.into()).unwrap(); 818 sender.send(notif.into()).unwrap();
819 }
819} 820}
820 821
821struct PoolDispatcher<'a> { 822struct PoolDispatcher<'a> {
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index f60a3f0a0..d5cb5d137 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -19,7 +19,7 @@ use lsp_types::{
19 TextEdit, WorkspaceEdit, 19 TextEdit, WorkspaceEdit,
20}; 20};
21use ra_ide::{ 21use ra_ide::{
22 Assist, AssistId, CompletionOptions, FileId, FilePosition, FileRange, Query, RangeInfo, 22 Assist, AssistId, CompletionConfig, FileId, FilePosition, FileRange, Query, RangeInfo,
23 Runnable, RunnableKind, SearchScope, 23 Runnable, RunnableKind, SearchScope,
24}; 24};
25use ra_prof::profile; 25use ra_prof::profile;
@@ -425,7 +425,7 @@ pub fn handle_completion(
425 return Ok(None); 425 return Ok(None);
426 } 426 }
427 427
428 let options = CompletionOptions { 428 let config = CompletionConfig {
429 enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"), 429 enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"),
430 add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"), 430 add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"),
431 add_call_argument_snippets: world 431 add_call_argument_snippets: world
@@ -433,7 +433,7 @@ pub fn handle_completion(
433 .get("completion.insertion.add-argument-snippets"), 433 .get("completion.insertion.add-argument-snippets"),
434 }; 434 };
435 435
436 let items = match world.analysis().completions(position, &options)? { 436 let items = match world.analysis().completions(position, &config)? {
437 None => return Ok(None), 437 None => return Ok(None),
438 Some(items) => items, 438 Some(items) => items,
439 }; 439 };
@@ -457,7 +457,7 @@ pub fn handle_folding_range(
457 let ctx = FoldConvCtx { 457 let ctx = FoldConvCtx {
458 text: &text, 458 text: &text,
459 line_index: &line_index, 459 line_index: &line_index,
460 line_folding_only: world.options.line_folding_only, 460 line_folding_only: world.config.line_folding_only,
461 }; 461 };
462 let res = Some(folds.into_iter().map_conv_with(&ctx).collect()); 462 let res = Some(folds.into_iter().map_conv_with(&ctx).collect());
463 Ok(res) 463 Ok(res)
@@ -611,7 +611,7 @@ pub fn handle_formatting(
611 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); 611 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
612 612
613 let mut rustfmt = process::Command::new("rustfmt"); 613 let mut rustfmt = process::Command::new("rustfmt");
614 rustfmt.args(&world.options.rustfmt_args); 614 rustfmt.args(&world.config.rustfmt_args);
615 if let Some(&crate_id) = crate_ids.first() { 615 if let Some(&crate_id) = crate_ids.first() {
616 // Assume all crates are in the same edition 616 // Assume all crates are in the same edition
617 let edition = world.analysis().crate_edition(crate_id)?; 617 let edition = world.analysis().crate_edition(crate_id)?;
@@ -815,7 +815,7 @@ pub fn handle_code_lens(
815 }; 815 };
816 lenses.push(lens); 816 lenses.push(lens);
817 817
818 if world.options.vscode_lldb { 818 if world.config.vscode_lldb {
819 if r.args[0] == "run" { 819 if r.args[0] == "run" {
820 r.args[0] = "build".into(); 820 r.args[0] = "build".into();
821 } else { 821 } else {
@@ -1028,7 +1028,7 @@ pub fn handle_inlay_hints(
1028 let analysis = world.analysis(); 1028 let analysis = world.analysis();
1029 let line_index = analysis.file_line_index(file_id)?; 1029 let line_index = analysis.file_line_index(file_id)?;
1030 Ok(analysis 1030 Ok(analysis
1031 .inlay_hints(file_id, &world.options.inlay_hints)? 1031 .inlay_hints(file_id, &world.config.inlay_hints)?
1032 .into_iter() 1032 .into_iter()
1033 .map_conv_with(&line_index) 1033 .map_conv_with(&line_index)
1034 .collect()) 1034 .collect())
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs
index ad096a1d8..acb729bae 100644
--- a/crates/rust-analyzer/src/world.rs
+++ b/crates/rust-analyzer/src/world.rs
@@ -11,9 +11,9 @@ use std::{
11use crossbeam_channel::{unbounded, Receiver}; 11use crossbeam_channel::{unbounded, Receiver};
12use lsp_types::Url; 12use lsp_types::Url;
13use parking_lot::RwLock; 13use parking_lot::RwLock;
14use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher}; 14use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckConfig, CheckWatcher};
15use ra_ide::{ 15use ra_ide::{
16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, InlayHintsOptions, LibraryData, 16 Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, InlayHintsConfig, LibraryData,
17 SourceRootId, 17 SourceRootId,
18}; 18};
19use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace}; 19use ra_project_model::{get_rustc_cfg_options, ProcMacroClient, ProjectWorkspace};
@@ -31,7 +31,7 @@ use crate::{
31use ra_db::ExternSourceId; 31use ra_db::ExternSourceId;
32use rustc_hash::{FxHashMap, FxHashSet}; 32use rustc_hash::{FxHashMap, FxHashSet};
33 33
34fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> Option<CheckWatcher> { 34fn create_watcher(workspaces: &[ProjectWorkspace], config: &Config) -> Option<CheckWatcher> {
35 // FIXME: Figure out the multi-workspace situation 35 // FIXME: Figure out the multi-workspace situation
36 workspaces 36 workspaces
37 .iter() 37 .iter()
@@ -41,7 +41,7 @@ fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> Option<
41 }) 41 })
42 .map(|cargo| { 42 .map(|cargo| {
43 let cargo_project_root = cargo.workspace_root().to_path_buf(); 43 let cargo_project_root = cargo.workspace_root().to_path_buf();
44 Some(CheckWatcher::new(&options.cargo_watch, cargo_project_root)) 44 Some(CheckWatcher::new(config.check.clone(), cargo_project_root))
45 }) 45 })
46 .unwrap_or_else(|| { 46 .unwrap_or_else(|| {
47 log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); 47 log::warn!("Cargo check watching only supported for cargo workspaces, disabling");
@@ -50,14 +50,15 @@ fn create_watcher(workspaces: &[ProjectWorkspace], options: &Options) -> Option<
50} 50}
51 51
52#[derive(Debug, Clone)] 52#[derive(Debug, Clone)]
53pub struct Options { 53pub struct Config {
54 pub publish_decorations: bool, 54 pub publish_decorations: bool,
55 pub supports_location_link: bool, 55 pub supports_location_link: bool,
56 pub line_folding_only: bool, 56 pub line_folding_only: bool,
57 pub inlay_hints: InlayHintsOptions, 57 pub inlay_hints: InlayHintsConfig,
58 pub rustfmt_args: Vec<String>, 58 pub rustfmt_args: Vec<String>,
59 pub cargo_watch: CheckOptions, 59 pub check: CheckConfig,
60 pub vscode_lldb: bool, 60 pub vscode_lldb: bool,
61 pub proc_macro_srv: Option<String>,
61} 62}
62 63
63/// `WorldState` is the primary mutable state of the language server 64/// `WorldState` is the primary mutable state of the language server
@@ -67,7 +68,7 @@ pub struct Options {
67/// incremental salsa database. 68/// incremental salsa database.
68#[derive(Debug)] 69#[derive(Debug)]
69pub struct WorldState { 70pub struct WorldState {
70 pub options: Options, 71 pub config: Config,
71 pub feature_flags: Arc<FeatureFlags>, 72 pub feature_flags: Arc<FeatureFlags>,
72 pub roots: Vec<PathBuf>, 73 pub roots: Vec<PathBuf>,
73 pub workspaces: Arc<Vec<ProjectWorkspace>>, 74 pub workspaces: Arc<Vec<ProjectWorkspace>>,
@@ -81,7 +82,7 @@ pub struct WorldState {
81 82
82/// An immutable snapshot of the world's state at a point in time. 83/// An immutable snapshot of the world's state at a point in time.
83pub struct WorldSnapshot { 84pub struct WorldSnapshot {
84 pub options: Options, 85 pub config: Config,
85 pub feature_flags: Arc<FeatureFlags>, 86 pub feature_flags: Arc<FeatureFlags>,
86 pub workspaces: Arc<Vec<ProjectWorkspace>>, 87 pub workspaces: Arc<Vec<ProjectWorkspace>>,
87 pub analysis: Analysis, 88 pub analysis: Analysis,
@@ -97,7 +98,7 @@ impl WorldState {
97 lru_capacity: Option<usize>, 98 lru_capacity: Option<usize>,
98 exclude_globs: &[Glob], 99 exclude_globs: &[Glob],
99 watch: Watch, 100 watch: Watch,
100 options: Options, 101 config: Config,
101 feature_flags: FeatureFlags, 102 feature_flags: FeatureFlags,
102 ) -> WorldState { 103 ) -> WorldState {
103 let mut change = AnalysisChange::new(); 104 let mut change = AnalysisChange::new();
@@ -167,8 +168,23 @@ impl WorldState {
167 vfs_file.map(|f| FileId(f.0)) 168 vfs_file.map(|f| FileId(f.0))
168 }; 169 };
169 170
170 let proc_macro_client = 171 let proc_macro_client = match &config.proc_macro_srv {
171 ProcMacroClient::extern_process(std::path::Path::new("ra_proc_macro_srv")); 172 None => ProcMacroClient::dummy(),
173 Some(srv) => {
174 let path = Path::new(&srv);
175 match ProcMacroClient::extern_process(path) {
176 Ok(it) => it,
177 Err(err) => {
178 log::error!(
179 "Fail to run ra_proc_macro_srv from path {}, error : {}",
180 path.to_string_lossy(),
181 err
182 );
183 ProcMacroClient::dummy()
184 }
185 }
186 }
187 };
172 188
173 workspaces 189 workspaces
174 .iter() 190 .iter()
@@ -185,12 +201,12 @@ impl WorldState {
185 }); 201 });
186 change.set_crate_graph(crate_graph); 202 change.set_crate_graph(crate_graph);
187 203
188 let check_watcher = create_watcher(&workspaces, &options); 204 let check_watcher = create_watcher(&workspaces, &config);
189 205
190 let mut analysis_host = AnalysisHost::new(lru_capacity); 206 let mut analysis_host = AnalysisHost::new(lru_capacity);
191 analysis_host.apply_change(change); 207 analysis_host.apply_change(change);
192 WorldState { 208 WorldState {
193 options, 209 config: config,
194 feature_flags: Arc::new(feature_flags), 210 feature_flags: Arc::new(feature_flags),
195 roots: folder_roots, 211 roots: folder_roots,
196 workspaces: Arc::new(workspaces), 212 workspaces: Arc::new(workspaces),
@@ -206,13 +222,13 @@ impl WorldState {
206 pub fn update_configuration( 222 pub fn update_configuration(
207 &mut self, 223 &mut self,
208 lru_capacity: Option<usize>, 224 lru_capacity: Option<usize>,
209 options: Options, 225 config: Config,
210 feature_flags: FeatureFlags, 226 feature_flags: FeatureFlags,
211 ) { 227 ) {
212 self.feature_flags = Arc::new(feature_flags); 228 self.feature_flags = Arc::new(feature_flags);
213 self.analysis_host.update_lru_capacity(lru_capacity); 229 self.analysis_host.update_lru_capacity(lru_capacity);
214 self.check_watcher = create_watcher(&self.workspaces, &options); 230 self.check_watcher = create_watcher(&self.workspaces, &config);
215 self.options = options; 231 self.config = config;
216 } 232 }
217 233
218 /// Returns a vec of libraries 234 /// Returns a vec of libraries
@@ -268,7 +284,7 @@ impl WorldState {
268 284
269 pub fn snapshot(&self) -> WorldSnapshot { 285 pub fn snapshot(&self) -> WorldSnapshot {
270 WorldSnapshot { 286 WorldSnapshot {
271 options: self.options.clone(), 287 config: self.config.clone(),
272 feature_flags: Arc::clone(&self.feature_flags), 288 feature_flags: Arc::clone(&self.feature_flags),
273 workspaces: Arc::clone(&self.workspaces), 289 workspaces: Arc::clone(&self.workspaces),
274 analysis: self.analysis_host.analysis(), 290 analysis: self.analysis_host.analysis(),
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index 145429571..5af5eaad2 100644
--- a/crates/rust-analyzer/tests/heavy_tests/main.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/main.rs
@@ -9,7 +9,7 @@ use lsp_types::{
9}; 9};
10use rust_analyzer::req::{ 10use rust_analyzer::req::{
11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, 11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
12 Formatting, OnEnter, Runnables, RunnablesParams, 12 Formatting, GotoDefinition, OnEnter, Runnables, RunnablesParams,
13}; 13};
14use serde_json::json; 14use serde_json::json;
15use tempfile::TempDir; 15use tempfile::TempDir;
@@ -581,3 +581,47 @@ version = \"0.0.0\"
581 }), 581 }),
582 ); 582 );
583} 583}
584
585#[test]
586fn resolve_include_concat_env() {
587 if skip_slow_tests() {
588 return;
589 }
590
591 let server = Project::with_fixture(
592 r###"
593//- Cargo.toml
594[package]
595name = "foo"
596version = "0.0.0"
597
598//- build.rs
599use std::{env, fs, path::Path};
600
601fn main() {
602 let out_dir = env::var_os("OUT_DIR").unwrap();
603 let dest_path = Path::new(&out_dir).join("hello.rs");
604 fs::write(
605 &dest_path,
606 r#"pub fn message() -> &'static str { "Hello, World!" }"#,
607 )
608 .unwrap();
609 println!("cargo:rerun-if-changed=build.rs");
610}
611//- src/main.rs
612include!(concat!(env!("OUT_DIR"), "/hello.rs"));
613
614fn main() { message(); }
615"###,
616 )
617 .with_config(|config| {
618 config.cargo_features.load_out_dirs_from_check = true;
619 })
620 .server();
621 server.wait_until_workspace_is_loaded();
622 let res = server.send_request::<GotoDefinition>(TextDocumentPositionParams::new(
623 server.doc_id("src/main.rs"),
624 Position::new(2, 15),
625 ));
626 assert!(format!("{}", res).contains("hello.rs"));
627}
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs
index 67f3c9332..d8bed6d7f 100644
--- a/crates/rust-analyzer/tests/heavy_tests/support.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/support.rs
@@ -27,11 +27,12 @@ pub struct Project<'a> {
27 with_sysroot: bool, 27 with_sysroot: bool,
28 tmp_dir: Option<TempDir>, 28 tmp_dir: Option<TempDir>,
29 roots: Vec<PathBuf>, 29 roots: Vec<PathBuf>,
30 config: Option<Box<dyn Fn(&mut ServerConfig)>>,
30} 31}
31 32
32impl<'a> Project<'a> { 33impl<'a> Project<'a> {
33 pub fn with_fixture(fixture: &str) -> Project { 34 pub fn with_fixture(fixture: &str) -> Project {
34 Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false } 35 Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None }
35 } 36 }
36 37
37 pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> { 38 pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
@@ -49,6 +50,11 @@ impl<'a> Project<'a> {
49 self 50 self
50 } 51 }
51 52
53 pub fn with_config(mut self, config: impl Fn(&mut ServerConfig) + 'static) -> Project<'a> {
54 self.config = Some(Box::new(config));
55 self
56 }
57
52 pub fn server(self) -> Server { 58 pub fn server(self) -> Server {
53 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap()); 59 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
54 static INIT: Once = Once::new(); 60 static INIT: Once = Once::new();
@@ -72,7 +78,14 @@ impl<'a> Project<'a> {
72 78
73 let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); 79 let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();
74 80
75 Server::new(tmp_dir, self.with_sysroot, roots, paths) 81 let mut config =
82 ServerConfig { with_sysroot: self.with_sysroot, ..ServerConfig::default() };
83
84 if let Some(f) = &self.config {
85 f(&mut config)
86 }
87
88 Server::new(tmp_dir, config, roots, paths)
76 } 89 }
77} 90}
78 91
@@ -92,7 +105,7 @@ pub struct Server {
92impl Server { 105impl Server {
93 fn new( 106 fn new(
94 dir: TempDir, 107 dir: TempDir,
95 with_sysroot: bool, 108 config: ServerConfig,
96 roots: Vec<PathBuf>, 109 roots: Vec<PathBuf>,
97 files: Vec<(PathBuf, String)>, 110 files: Vec<(PathBuf, String)>,
98 ) -> Server { 111 ) -> Server {
@@ -118,7 +131,7 @@ impl Server {
118 window: None, 131 window: None,
119 experimental: None, 132 experimental: None,
120 }, 133 },
121 ServerConfig { with_sysroot, ..ServerConfig::default() }, 134 config,
122 connection, 135 connection,
123 ) 136 )
124 .unwrap() 137 .unwrap()
@@ -188,6 +201,7 @@ impl Server {
188 self.client.sender.send(r.into()).unwrap(); 201 self.client.sender.send(r.into()).unwrap();
189 while let Some(msg) = self.recv() { 202 while let Some(msg) = self.recv() {
190 match msg { 203 match msg {
204 Message::Request(req) if req.method == "window/workDoneProgress/create" => (),
191 Message::Request(req) => panic!("unexpected request: {:?}", req), 205 Message::Request(req) => panic!("unexpected request: {:?}", req),
192 Message::Notification(_) => (), 206 Message::Notification(_) => (),
193 Message::Response(res) => { 207 Message::Response(res) => {