diff options
25 files changed, 346 insertions, 133 deletions
diff --git a/Cargo.lock b/Cargo.lock index e3ad50623..330bdd1cb 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -88,21 +88,6 @@ dependencies = [ | |||
88 | ] | 88 | ] |
89 | 89 | ||
90 | [[package]] | 90 | [[package]] |
91 | name = "byteorder" | ||
92 | version = "1.3.4" | ||
93 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
94 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" | ||
95 | |||
96 | [[package]] | ||
97 | name = "c2-chacha" | ||
98 | version = "0.2.3" | ||
99 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
100 | checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" | ||
101 | dependencies = [ | ||
102 | "ppv-lite86", | ||
103 | ] | ||
104 | |||
105 | [[package]] | ||
106 | name = "cargo_metadata" | 91 | name = "cargo_metadata" |
107 | version = "0.9.1" | 92 | version = "0.9.1" |
108 | source = "registry+https://github.com/rust-lang/crates.io-index" | 93 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -401,12 +386,9 @@ dependencies = [ | |||
401 | 386 | ||
402 | [[package]] | 387 | [[package]] |
403 | name = "fst" | 388 | name = "fst" |
404 | version = "0.3.5" | 389 | version = "0.4.0" |
405 | source = "registry+https://github.com/rust-lang/crates.io-index" | 390 | source = "registry+https://github.com/rust-lang/crates.io-index" |
406 | checksum = "927fb434ff9f0115b215dc0efd2e4fbdd7448522a92a1aa37c77d6a2f8f1ebd6" | 391 | checksum = "3f7c13470d799474d44e2b9c6a0925807def7af4d120cd4de761433be76f7579" |
407 | dependencies = [ | ||
408 | "byteorder", | ||
409 | ] | ||
410 | 392 | ||
411 | [[package]] | 393 | [[package]] |
412 | name = "fuchsia-zircon" | 394 | name = "fuchsia-zircon" |
@@ -1180,11 +1162,11 @@ dependencies = [ | |||
1180 | 1162 | ||
1181 | [[package]] | 1163 | [[package]] |
1182 | name = "rand_chacha" | 1164 | name = "rand_chacha" |
1183 | version = "0.2.1" | 1165 | version = "0.2.2" |
1184 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1185 | checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" | 1167 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" |
1186 | dependencies = [ | 1168 | dependencies = [ |
1187 | "c2-chacha", | 1169 | "ppv-lite86", |
1188 | "rand_core", | 1170 | "rand_core", |
1189 | ] | 1171 | ] |
1190 | 1172 | ||
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 947d6ad56..7f43c2971 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -5,7 +5,7 @@ use std::sync::Arc; | |||
5 | 5 | ||
6 | use ra_cfg::CfgOptions; | 6 | use ra_cfg::CfgOptions; |
7 | use rustc_hash::FxHashMap; | 7 | use rustc_hash::FxHashMap; |
8 | use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; | 8 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 11 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, |
@@ -45,23 +45,37 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { | |||
45 | 45 | ||
46 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} | 46 | impl<DB: SourceDatabaseExt + Default + 'static> WithFixture for DB {} |
47 | 47 | ||
48 | fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { | 48 | fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId { |
49 | let file_id = FileId(0); | 49 | let file_id = FileId(0); |
50 | let rel_path: RelativePathBuf = "/main.rs".into(); | 50 | let rel_path: RelativePathBuf = "/main.rs".into(); |
51 | 51 | ||
52 | let mut source_root = SourceRoot::new_local(); | 52 | let mut source_root = SourceRoot::new_local(); |
53 | source_root.insert_file(rel_path.clone(), file_id); | 53 | source_root.insert_file(rel_path.clone(), file_id); |
54 | 54 | ||
55 | let mut crate_graph = CrateGraph::default(); | 55 | let fixture = parse_single_fixture(ra_fixture); |
56 | crate_graph.add_crate_root( | 56 | |
57 | file_id, | 57 | let crate_graph = if let Some(entry) = fixture { |
58 | Edition::Edition2018, | 58 | let meta = match parse_meta(&entry.meta) { |
59 | None, | 59 | ParsedMeta::File(it) => it, |
60 | CfgOptions::default(), | 60 | _ => panic!("with_single_file only support file meta"), |
61 | Env::default(), | 61 | }; |
62 | ); | 62 | |
63 | 63 | let mut crate_graph = CrateGraph::default(); | |
64 | db.set_file_text(file_id, Arc::new(text.to_string())); | 64 | crate_graph.add_crate_root(file_id, meta.edition, meta.krate, meta.cfg, meta.env); |
65 | crate_graph | ||
66 | } else { | ||
67 | let mut crate_graph = CrateGraph::default(); | ||
68 | crate_graph.add_crate_root( | ||
69 | file_id, | ||
70 | Edition::Edition2018, | ||
71 | None, | ||
72 | CfgOptions::default(), | ||
73 | Env::default(), | ||
74 | ); | ||
75 | crate_graph | ||
76 | }; | ||
77 | |||
78 | db.set_file_text(file_id, Arc::new(ra_fixture.to_string())); | ||
65 | db.set_file_relative_path(file_id, rel_path); | 79 | db.set_file_relative_path(file_id, rel_path); |
66 | db.set_file_source_root(file_id, WORKSPACE); | 80 | db.set_file_source_root(file_id, WORKSPACE); |
67 | db.set_source_root(WORKSPACE, Arc::new(source_root)); | 81 | db.set_source_root(WORKSPACE, Arc::new(source_root)); |
@@ -104,7 +118,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
104 | meta.edition, | 118 | meta.edition, |
105 | Some(krate.clone()), | 119 | Some(krate.clone()), |
106 | meta.cfg, | 120 | meta.cfg, |
107 | Env::default(), | 121 | meta.env, |
108 | ); | 122 | ); |
109 | let prev = crates.insert(krate.clone(), crate_id); | 123 | let prev = crates.insert(krate.clone(), crate_id); |
110 | assert!(prev.is_none()); | 124 | assert!(prev.is_none()); |
@@ -167,9 +181,10 @@ struct FileMeta { | |||
167 | deps: Vec<String>, | 181 | deps: Vec<String>, |
168 | cfg: CfgOptions, | 182 | cfg: CfgOptions, |
169 | edition: Edition, | 183 | edition: Edition, |
184 | env: Env, | ||
170 | } | 185 | } |
171 | 186 | ||
172 | //- /lib.rs crate:foo deps:bar,baz | 187 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo) |
173 | fn parse_meta(meta: &str) -> ParsedMeta { | 188 | fn parse_meta(meta: &str) -> ParsedMeta { |
174 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 189 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); |
175 | 190 | ||
@@ -186,6 +201,7 @@ fn parse_meta(meta: &str) -> ParsedMeta { | |||
186 | let mut deps = Vec::new(); | 201 | let mut deps = Vec::new(); |
187 | let mut edition = Edition::Edition2018; | 202 | let mut edition = Edition::Edition2018; |
188 | let mut cfg = CfgOptions::default(); | 203 | let mut cfg = CfgOptions::default(); |
204 | let mut env = Env::default(); | ||
189 | for component in components[1..].iter() { | 205 | for component in components[1..].iter() { |
190 | let (key, value) = split1(component, ':').unwrap(); | 206 | let (key, value) = split1(component, ':').unwrap(); |
191 | match key { | 207 | match key { |
@@ -200,11 +216,18 @@ fn parse_meta(meta: &str) -> ParsedMeta { | |||
200 | } | 216 | } |
201 | } | 217 | } |
202 | } | 218 | } |
219 | "env" => { | ||
220 | for key in value.split(',') { | ||
221 | if let Some((k, v)) = split1(key, '=') { | ||
222 | env.set(k.into(), v.into()); | ||
223 | } | ||
224 | } | ||
225 | } | ||
203 | _ => panic!("bad component: {:?}", component), | 226 | _ => panic!("bad component: {:?}", component), |
204 | } | 227 | } |
205 | } | 228 | } |
206 | 229 | ||
207 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) | 230 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env }) |
208 | } | 231 | } |
209 | 232 | ||
210 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | 233 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index b77640b2b..1a1c64202 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -261,6 +261,16 @@ impl fmt::Display for Edition { | |||
261 | } | 261 | } |
262 | } | 262 | } |
263 | 263 | ||
264 | impl Env { | ||
265 | pub fn set(&mut self, env: &str, value: String) { | ||
266 | self.entries.insert(env.to_owned(), value); | ||
267 | } | ||
268 | |||
269 | pub fn get(&self, env: &str) -> Option<String> { | ||
270 | self.entries.get(env).cloned() | ||
271 | } | ||
272 | } | ||
273 | |||
264 | #[derive(Debug)] | 274 | #[derive(Debug)] |
265 | pub struct ParseEditionError { | 275 | pub struct ParseEditionError { |
266 | invalid_input: String, | 276 | invalid_input: String, |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index b7e8855fb..7f5e1469e 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -516,9 +516,31 @@ pub(crate) fn inherent_impl_substs( | |||
516 | let self_ty_with_vars = | 516 | let self_ty_with_vars = |
517 | Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; | 517 | Canonical { num_vars: vars.len() + self_ty.num_vars, value: self_ty_with_vars }; |
518 | let substs = super::infer::unify(&self_ty_with_vars, self_ty); | 518 | let substs = super::infer::unify(&self_ty_with_vars, self_ty); |
519 | // we only want the substs for the vars we added, not the ones from self_ty | 519 | // We only want the substs for the vars we added, not the ones from self_ty. |
520 | let result = substs.map(|s| s.suffix(vars.len())); | 520 | // Also, if any of the vars we added are still in there, we replace them by |
521 | result | 521 | // Unknown. I think this can only really happen if self_ty contained |
522 | // Unknown, and in that case we want the result to contain Unknown in those | ||
523 | // places again. | ||
524 | substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.num_vars)) | ||
525 | } | ||
526 | |||
527 | /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past | ||
528 | /// num_vars_to_keep) by `Ty::Unknown`. | ||
529 | fn fallback_bound_vars(s: Substs, num_vars_to_keep: usize) -> Substs { | ||
530 | s.fold_binders( | ||
531 | &mut |ty, binders| { | ||
532 | if let Ty::Bound(idx) = &ty { | ||
533 | if *idx >= binders as u32 { | ||
534 | Ty::Unknown | ||
535 | } else { | ||
536 | ty | ||
537 | } | ||
538 | } else { | ||
539 | ty | ||
540 | } | ||
541 | }, | ||
542 | num_vars_to_keep, | ||
543 | ) | ||
522 | } | 544 | } |
523 | 545 | ||
524 | fn transform_receiver_ty( | 546 | fn transform_receiver_ty( |
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index c378c2c62..a27e0fc15 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -33,6 +33,23 @@ pub use crate::completion::completion_item::{ | |||
33 | CompletionItem, CompletionItemKind, InsertTextFormat, | 33 | CompletionItem, CompletionItemKind, InsertTextFormat, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
37 | pub struct CompletionOptions { | ||
38 | pub enable_postfix_completions: bool, | ||
39 | pub add_call_parenthesis: bool, | ||
40 | pub add_call_argument_snippets: bool, | ||
41 | } | ||
42 | |||
43 | impl Default for CompletionOptions { | ||
44 | fn default() -> Self { | ||
45 | CompletionOptions { | ||
46 | enable_postfix_completions: true, | ||
47 | add_call_parenthesis: true, | ||
48 | add_call_argument_snippets: true, | ||
49 | } | ||
50 | } | ||
51 | } | ||
52 | |||
36 | /// Main entry point for completion. We run completion as a two-phase process. | 53 | /// Main entry point for completion. We run completion as a two-phase process. |
37 | /// | 54 | /// |
38 | /// First, we look at the position and collect a so-called `CompletionContext. | 55 | /// First, we look at the position and collect a so-called `CompletionContext. |
@@ -55,8 +72,12 @@ pub use crate::completion::completion_item::{ | |||
55 | /// `foo` *should* be present among the completion variants. Filtering by | 72 | /// `foo` *should* be present among the completion variants. Filtering by |
56 | /// identifier prefix/fuzzy match should be done higher in the stack, together | 73 | /// identifier prefix/fuzzy match should be done higher in the stack, together |
57 | /// with ordering of completions (currently this is done by the client). | 74 | /// with ordering of completions (currently this is done by the client). |
58 | pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option<Completions> { | 75 | pub(crate) fn completions( |
59 | let ctx = CompletionContext::new(db, position)?; | 76 | db: &RootDatabase, |
77 | position: FilePosition, | ||
78 | opts: &CompletionOptions, | ||
79 | ) -> Option<Completions> { | ||
80 | let ctx = CompletionContext::new(db, position, opts)?; | ||
60 | 81 | ||
61 | let mut acc = Completions::default(); | 82 | let mut acc = Completions::default(); |
62 | 83 | ||
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs index f275305e2..d8f6f0d9d 100644 --- a/crates/ra_ide/src/completion/complete_dot.rs +++ b/crates/ra_ide/src/completion/complete_dot.rs | |||
@@ -718,4 +718,35 @@ mod tests { | |||
718 | "### | 718 | "### |
719 | ); | 719 | ); |
720 | } | 720 | } |
721 | |||
722 | #[test] | ||
723 | fn test_method_completion_3547() { | ||
724 | assert_debug_snapshot!( | ||
725 | do_ref_completion( | ||
726 | r" | ||
727 | struct HashSet<T> {} | ||
728 | impl<T> HashSet<T> { | ||
729 | pub fn the_method(&self) {} | ||
730 | } | ||
731 | fn foo() { | ||
732 | let s: HashSet<_>; | ||
733 | s.<|> | ||
734 | } | ||
735 | ", | ||
736 | ), | ||
737 | @r###" | ||
738 | [ | ||
739 | CompletionItem { | ||
740 | label: "the_method()", | ||
741 | source_range: [201; 201), | ||
742 | delete: [201; 201), | ||
743 | insert: "the_method()$0", | ||
744 | kind: Method, | ||
745 | lookup: "the_method", | ||
746 | detail: "pub fn the_method(&self)", | ||
747 | }, | ||
748 | ] | ||
749 | "### | ||
750 | ); | ||
751 | } | ||
721 | } | 752 | } |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 65ecea125..6d000548d 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -12,7 +12,7 @@ use crate::{ | |||
12 | }; | 12 | }; |
13 | 13 | ||
14 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | 14 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
15 | if !ctx.db.feature_flags.get("completion.enable-postfix") { | 15 | if !ctx.options.enable_postfix_completions { |
16 | return; | 16 | return; |
17 | } | 17 | } |
18 | 18 | ||
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 18a1d2995..2bf654a57 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -34,7 +34,7 @@ | |||
34 | use hir::{self, Docs, HasSource}; | 34 | use hir::{self, Docs, HasSource}; |
35 | use ra_assists::utils::get_missing_impl_items; | 35 | use ra_assists::utils::get_missing_impl_items; |
36 | use ra_syntax::{ | 36 | use ra_syntax::{ |
37 | ast::{self, edit}, | 37 | ast::{self, edit, ImplDef}, |
38 | AstNode, SyntaxKind, SyntaxNode, TextRange, | 38 | AstNode, SyntaxKind, SyntaxNode, TextRange, |
39 | }; | 39 | }; |
40 | use ra_text_edit::TextEdit; | 40 | use ra_text_edit::TextEdit; |
@@ -47,22 +47,22 @@ use crate::{ | |||
47 | }; | 47 | }; |
48 | 48 | ||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
50 | let trigger = ctx.token.ancestors().find(|p| match p.kind() { | 50 | if let Some((trigger, impl_def)) = completion_match(ctx) { |
51 | SyntaxKind::FN_DEF | ||
52 | | SyntaxKind::TYPE_ALIAS_DEF | ||
53 | | SyntaxKind::CONST_DEF | ||
54 | | SyntaxKind::BLOCK_EXPR => true, | ||
55 | _ => false, | ||
56 | }); | ||
57 | |||
58 | let impl_def = trigger | ||
59 | .as_ref() | ||
60 | .and_then(|node| node.parent()) | ||
61 | .and_then(|node| node.parent()) | ||
62 | .and_then(ast::ImplDef::cast); | ||
63 | |||
64 | if let (Some(trigger), Some(impl_def)) = (trigger, impl_def) { | ||
65 | match trigger.kind() { | 51 | match trigger.kind() { |
52 | SyntaxKind::NAME_REF => { | ||
53 | get_missing_impl_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { | ||
54 | hir::AssocItem::Function(fn_item) => { | ||
55 | add_function_impl(&trigger, acc, ctx, &fn_item) | ||
56 | } | ||
57 | hir::AssocItem::TypeAlias(type_item) => { | ||
58 | add_type_alias_impl(&trigger, acc, ctx, &type_item) | ||
59 | } | ||
60 | hir::AssocItem::Const(const_item) => { | ||
61 | add_const_impl(&trigger, acc, ctx, &const_item) | ||
62 | } | ||
63 | }) | ||
64 | } | ||
65 | |||
66 | SyntaxKind::FN_DEF => { | 66 | SyntaxKind::FN_DEF => { |
67 | for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( | 67 | for missing_fn in get_missing_impl_items(&ctx.sema, &impl_def).iter().filter_map( |
68 | |item| match item { | 68 | |item| match item { |
@@ -101,6 +101,21 @@ pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext | |||
101 | } | 101 | } |
102 | } | 102 | } |
103 | 103 | ||
104 | fn completion_match(ctx: &CompletionContext) -> Option<(SyntaxNode, ImplDef)> { | ||
105 | let (trigger, impl_def_offset) = ctx.token.ancestors().find_map(|p| match p.kind() { | ||
106 | SyntaxKind::FN_DEF | ||
107 | | SyntaxKind::TYPE_ALIAS_DEF | ||
108 | | SyntaxKind::CONST_DEF | ||
109 | | SyntaxKind::BLOCK_EXPR => Some((p, 2)), | ||
110 | SyntaxKind::NAME_REF => Some((p, 5)), | ||
111 | _ => None, | ||
112 | })?; | ||
113 | let impl_def = (0..impl_def_offset - 1) | ||
114 | .try_fold(trigger.parent()?, |t, _| t.parent()) | ||
115 | .and_then(ast::ImplDef::cast)?; | ||
116 | Some((trigger, impl_def)) | ||
117 | } | ||
118 | |||
104 | fn add_function_impl( | 119 | fn add_function_impl( |
105 | fn_def_node: &SyntaxNode, | 120 | fn_def_node: &SyntaxNode, |
106 | acc: &mut Completions, | 121 | acc: &mut Completions, |
@@ -210,6 +225,103 @@ mod tests { | |||
210 | } | 225 | } |
211 | 226 | ||
212 | #[test] | 227 | #[test] |
228 | fn name_ref_function_type_const() { | ||
229 | let completions = complete( | ||
230 | r" | ||
231 | trait Test { | ||
232 | type TestType; | ||
233 | const TEST_CONST: u16; | ||
234 | fn test(); | ||
235 | } | ||
236 | |||
237 | struct T1; | ||
238 | |||
239 | impl Test for T1 { | ||
240 | t<|> | ||
241 | } | ||
242 | ", | ||
243 | ); | ||
244 | assert_debug_snapshot!(completions, @r###" | ||
245 | [ | ||
246 | CompletionItem { | ||
247 | label: "const TEST_CONST: u16 = ", | ||
248 | source_range: [209; 210), | ||
249 | delete: [209; 210), | ||
250 | insert: "const TEST_CONST: u16 = ", | ||
251 | kind: Const, | ||
252 | lookup: "TEST_CONST", | ||
253 | }, | ||
254 | CompletionItem { | ||
255 | label: "fn test()", | ||
256 | source_range: [209; 210), | ||
257 | delete: [209; 210), | ||
258 | insert: "fn test() {}", | ||
259 | kind: Function, | ||
260 | lookup: "test", | ||
261 | }, | ||
262 | CompletionItem { | ||
263 | label: "type TestType = ", | ||
264 | source_range: [209; 210), | ||
265 | delete: [209; 210), | ||
266 | insert: "type TestType = ", | ||
267 | kind: TypeAlias, | ||
268 | lookup: "TestType", | ||
269 | }, | ||
270 | ] | ||
271 | "###); | ||
272 | } | ||
273 | |||
274 | #[test] | ||
275 | fn no_nested_fn_completions() { | ||
276 | let completions = complete( | ||
277 | r" | ||
278 | trait Test { | ||
279 | fn test(); | ||
280 | fn test2(); | ||
281 | } | ||
282 | |||
283 | struct T1; | ||
284 | |||
285 | impl Test for T1 { | ||
286 | fn test() { | ||
287 | t<|> | ||
288 | } | ||
289 | } | ||
290 | ", | ||
291 | ); | ||
292 | assert_debug_snapshot!(completions, @r###"[]"###); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn name_ref_single_function() { | ||
297 | let completions = complete( | ||
298 | r" | ||
299 | trait Test { | ||
300 | fn test(); | ||
301 | } | ||
302 | |||
303 | struct T1; | ||
304 | |||
305 | impl Test for T1 { | ||
306 | t<|> | ||
307 | } | ||
308 | ", | ||
309 | ); | ||
310 | assert_debug_snapshot!(completions, @r###" | ||
311 | [ | ||
312 | CompletionItem { | ||
313 | label: "fn test()", | ||
314 | source_range: [139; 140), | ||
315 | delete: [139; 140), | ||
316 | insert: "fn test() {}", | ||
317 | kind: Function, | ||
318 | lookup: "test", | ||
319 | }, | ||
320 | ] | ||
321 | "###); | ||
322 | } | ||
323 | |||
324 | #[test] | ||
213 | fn single_function() { | 325 | fn single_function() { |
214 | let completions = complete( | 326 | let completions = complete( |
215 | r" | 327 | r" |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 40535c09e..3646fb8dc 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 | }; |
12 | use ra_text_edit::AtomTextEdit; | 12 | use ra_text_edit::AtomTextEdit; |
13 | 13 | ||
14 | use crate::FilePosition; | 14 | use crate::{completion::CompletionOptions, 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,6 +19,7 @@ use crate::FilePosition; | |||
19 | pub(crate) struct CompletionContext<'a> { | 19 | pub(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) offset: TextUnit, | 23 | pub(super) offset: TextUnit, |
23 | /// The token before the cursor, in the original file. | 24 | /// The token before the cursor, in the original file. |
24 | pub(super) original_token: SyntaxToken, | 25 | pub(super) original_token: SyntaxToken, |
@@ -57,6 +58,7 @@ impl<'a> CompletionContext<'a> { | |||
57 | pub(super) fn new( | 58 | pub(super) fn new( |
58 | db: &'a RootDatabase, | 59 | db: &'a RootDatabase, |
59 | position: FilePosition, | 60 | position: FilePosition, |
61 | options: &'a CompletionOptions, | ||
60 | ) -> Option<CompletionContext<'a>> { | 62 | ) -> Option<CompletionContext<'a>> { |
61 | let sema = Semantics::new(db); | 63 | let sema = Semantics::new(db); |
62 | 64 | ||
@@ -80,6 +82,7 @@ impl<'a> CompletionContext<'a> { | |||
80 | let mut ctx = CompletionContext { | 82 | let mut ctx = CompletionContext { |
81 | sema, | 83 | sema, |
82 | db, | 84 | db, |
85 | options, | ||
83 | original_token, | 86 | original_token, |
84 | token, | 87 | token, |
85 | offset: position.offset, | 88 | offset: position.offset, |
diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 19bbb2517..1d14e9636 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs | |||
@@ -321,14 +321,18 @@ impl Into<Vec<CompletionItem>> for Completions { | |||
321 | 321 | ||
322 | #[cfg(test)] | 322 | #[cfg(test)] |
323 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { | 323 | pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec<CompletionItem> { |
324 | use crate::completion::completions; | 324 | use crate::{ |
325 | use crate::mock_analysis::{analysis_and_position, single_file_with_position}; | 325 | completion::{completions, CompletionOptions}, |
326 | mock_analysis::{analysis_and_position, single_file_with_position}, | ||
327 | }; | ||
328 | |||
326 | let (analysis, position) = if code.contains("//-") { | 329 | let (analysis, position) = if code.contains("//-") { |
327 | analysis_and_position(code) | 330 | analysis_and_position(code) |
328 | } else { | 331 | } else { |
329 | single_file_with_position(code) | 332 | single_file_with_position(code) |
330 | }; | 333 | }; |
331 | let completions = completions(&analysis.db, position).unwrap(); | 334 | let options = CompletionOptions::default(); |
335 | let completions = completions(&analysis.db, position, &options).unwrap(); | ||
332 | let completion_items: Vec<CompletionItem> = completions.into(); | 336 | let completion_items: Vec<CompletionItem> = completions.into(); |
333 | let mut kind_completions: Vec<CompletionItem> = | 337 | let mut kind_completions: Vec<CompletionItem> = |
334 | completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); | 338 | completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); |
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index aada4d025..3dc56e4a3 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -104,10 +104,7 @@ impl Completions { | |||
104 | }; | 104 | }; |
105 | 105 | ||
106 | // Add `<>` for generic types | 106 | // Add `<>` for generic types |
107 | if ctx.is_path_type | 107 | if ctx.is_path_type && !ctx.has_type_args && ctx.options.add_call_parenthesis { |
108 | && !ctx.has_type_args | ||
109 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
110 | { | ||
111 | let has_non_default_type_params = match resolution { | 108 | let has_non_default_type_params = match resolution { |
112 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | 109 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), |
113 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | 110 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), |
@@ -212,21 +209,14 @@ impl Completions { | |||
212 | .detail(function_signature.to_string()); | 209 | .detail(function_signature.to_string()); |
213 | 210 | ||
214 | // If not an import, add parenthesis automatically. | 211 | // If not an import, add parenthesis automatically. |
215 | if ctx.use_item_syntax.is_none() | 212 | if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.options.add_call_parenthesis { |
216 | && !ctx.is_call | ||
217 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
218 | { | ||
219 | tested_by!(inserts_parens_for_function_calls); | 213 | tested_by!(inserts_parens_for_function_calls); |
220 | 214 | ||
221 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { | 215 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { |
222 | (format!("{}()$0", name), format!("{}()", name)) | 216 | (format!("{}()$0", name), format!("{}()", name)) |
223 | } else { | 217 | } else { |
224 | builder = builder.trigger_call_info(); | 218 | builder = builder.trigger_call_info(); |
225 | let snippet = if ctx | 219 | let snippet = if ctx.options.add_call_argument_snippets { |
226 | .db | ||
227 | .feature_flags | ||
228 | .get("completion.insertion.add-argument-snippets") | ||
229 | { | ||
230 | let to_skip = if has_self_param { 1 } else { 0 }; | 220 | let to_skip = if has_self_param { 1 } else { 0 }; |
231 | let function_params_snippet = join( | 221 | let function_params_snippet = join( |
232 | function_signature.parameter_names.iter().skip(to_skip).enumerate().map( | 222 | function_signature.parameter_names.iter().skip(to_skip).enumerate().map( |
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index c60e86aea..9f45003d3 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -62,7 +62,7 @@ use crate::display::ToNav; | |||
62 | pub use crate::{ | 62 | pub use crate::{ |
63 | assists::{Assist, AssistId}, | 63 | assists::{Assist, AssistId}, |
64 | call_hierarchy::CallItem, | 64 | call_hierarchy::CallItem, |
65 | completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, | 65 | completion::{CompletionItem, CompletionItemKind, CompletionOptions, 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, |
@@ -84,7 +84,6 @@ pub use ra_db::{ | |||
84 | }; | 84 | }; |
85 | pub use ra_ide_db::{ | 85 | pub use ra_ide_db::{ |
86 | change::{AnalysisChange, LibraryData}, | 86 | change::{AnalysisChange, LibraryData}, |
87 | feature_flags::FeatureFlags, | ||
88 | line_index::{LineCol, LineIndex}, | 87 | line_index::{LineCol, LineIndex}, |
89 | line_index_utils::translate_offset_with_edit, | 88 | line_index_utils::translate_offset_with_edit, |
90 | search::SearchScope, | 89 | search::SearchScope, |
@@ -131,13 +130,13 @@ pub struct AnalysisHost { | |||
131 | 130 | ||
132 | impl Default for AnalysisHost { | 131 | impl Default for AnalysisHost { |
133 | fn default() -> AnalysisHost { | 132 | fn default() -> AnalysisHost { |
134 | AnalysisHost::new(None, FeatureFlags::default()) | 133 | AnalysisHost::new(None) |
135 | } | 134 | } |
136 | } | 135 | } |
137 | 136 | ||
138 | impl AnalysisHost { | 137 | impl AnalysisHost { |
139 | pub fn new(lru_capcity: Option<usize>, feature_flags: FeatureFlags) -> AnalysisHost { | 138 | pub fn new(lru_capacity: Option<usize>) -> AnalysisHost { |
140 | AnalysisHost { db: RootDatabase::new(lru_capcity, feature_flags) } | 139 | AnalysisHost { db: RootDatabase::new(lru_capacity) } |
141 | } | 140 | } |
142 | /// Returns a snapshot of the current state, which you can query for | 141 | /// Returns a snapshot of the current state, which you can query for |
143 | /// semantic information. | 142 | /// semantic information. |
@@ -145,10 +144,6 @@ impl AnalysisHost { | |||
145 | Analysis { db: self.db.snapshot() } | 144 | Analysis { db: self.db.snapshot() } |
146 | } | 145 | } |
147 | 146 | ||
148 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
149 | &self.db.feature_flags | ||
150 | } | ||
151 | |||
152 | /// Applies changes to the current state of the world. If there are | 147 | /// Applies changes to the current state of the world. If there are |
153 | /// outstanding snapshots, they will be canceled. | 148 | /// outstanding snapshots, they will be canceled. |
154 | pub fn apply_change(&mut self, change: AnalysisChange) { | 149 | pub fn apply_change(&mut self, change: AnalysisChange) { |
@@ -224,11 +219,6 @@ impl Analysis { | |||
224 | (host.analysis(), file_id) | 219 | (host.analysis(), file_id) |
225 | } | 220 | } |
226 | 221 | ||
227 | /// Features for Analysis. | ||
228 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
229 | &self.db.feature_flags | ||
230 | } | ||
231 | |||
232 | /// Debug info about the current state of the analysis. | 222 | /// Debug info about the current state of the analysis. |
233 | pub fn status(&self) -> Cancelable<String> { | 223 | pub fn status(&self) -> Cancelable<String> { |
234 | self.with_db(|db| status::status(&*db)) | 224 | self.with_db(|db| status::status(&*db)) |
@@ -450,8 +440,12 @@ impl Analysis { | |||
450 | } | 440 | } |
451 | 441 | ||
452 | /// Computes completions at the given position. | 442 | /// Computes completions at the given position. |
453 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 443 | pub fn completions( |
454 | self.with_db(|db| completion::completions(db, position).map(Into::into)) | 444 | &self, |
445 | position: FilePosition, | ||
446 | options: &CompletionOptions, | ||
447 | ) -> Cancelable<Option<Vec<CompletionItem>>> { | ||
448 | self.with_db(|db| completion::completions(db, position, options).map(Into::into)) | ||
455 | } | 449 | } |
456 | 450 | ||
457 | /// Computes assists (aka code actions aka intentions) for the given | 451 | /// Computes assists (aka code actions aka intentions) for the given |
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index 52f0f23df..de4f5bce0 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml | |||
@@ -13,7 +13,7 @@ wasm = [] | |||
13 | [dependencies] | 13 | [dependencies] |
14 | log = "0.4.8" | 14 | log = "0.4.8" |
15 | rayon = "1.3.0" | 15 | rayon = "1.3.0" |
16 | fst = { version = "0.3.5", default-features = false } | 16 | fst = { version = "0.4", default-features = false } |
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | superslice = "1.0.0" | 18 | superslice = "1.0.0" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index a105c7556..6bcccc848 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs | |||
@@ -5,7 +5,6 @@ | |||
5 | pub mod marks; | 5 | pub mod marks; |
6 | pub mod line_index; | 6 | pub mod line_index; |
7 | pub mod line_index_utils; | 7 | pub mod line_index_utils; |
8 | pub mod feature_flags; | ||
9 | pub mod symbol_index; | 8 | pub mod symbol_index; |
10 | pub mod change; | 9 | pub mod change; |
11 | pub mod defs; | 10 | pub mod defs; |
@@ -22,7 +21,7 @@ use ra_db::{ | |||
22 | }; | 21 | }; |
23 | use rustc_hash::FxHashMap; | 22 | use rustc_hash::FxHashMap; |
24 | 23 | ||
25 | use crate::{feature_flags::FeatureFlags, line_index::LineIndex, symbol_index::SymbolsDatabase}; | 24 | use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; |
26 | 25 | ||
27 | #[salsa::database( | 26 | #[salsa::database( |
28 | ra_db::SourceDatabaseStorage, | 27 | ra_db::SourceDatabaseStorage, |
@@ -37,7 +36,6 @@ use crate::{feature_flags::FeatureFlags, line_index::LineIndex, symbol_index::Sy | |||
37 | #[derive(Debug)] | 36 | #[derive(Debug)] |
38 | pub struct RootDatabase { | 37 | pub struct RootDatabase { |
39 | runtime: salsa::Runtime<RootDatabase>, | 38 | runtime: salsa::Runtime<RootDatabase>, |
40 | pub feature_flags: Arc<FeatureFlags>, | ||
41 | pub(crate) debug_data: Arc<DebugData>, | 39 | pub(crate) debug_data: Arc<DebugData>, |
42 | pub last_gc: crate::wasm_shims::Instant, | 40 | pub last_gc: crate::wasm_shims::Instant, |
43 | pub last_gc_check: crate::wasm_shims::Instant, | 41 | pub last_gc_check: crate::wasm_shims::Instant, |
@@ -82,17 +80,16 @@ impl salsa::Database for RootDatabase { | |||
82 | 80 | ||
83 | impl Default for RootDatabase { | 81 | impl Default for RootDatabase { |
84 | fn default() -> RootDatabase { | 82 | fn default() -> RootDatabase { |
85 | RootDatabase::new(None, FeatureFlags::default()) | 83 | RootDatabase::new(None) |
86 | } | 84 | } |
87 | } | 85 | } |
88 | 86 | ||
89 | impl RootDatabase { | 87 | impl RootDatabase { |
90 | pub fn new(lru_capacity: Option<usize>, feature_flags: FeatureFlags) -> RootDatabase { | 88 | pub fn new(lru_capacity: Option<usize>) -> RootDatabase { |
91 | let mut db = RootDatabase { | 89 | let mut db = RootDatabase { |
92 | runtime: salsa::Runtime::default(), | 90 | runtime: salsa::Runtime::default(), |
93 | last_gc: crate::wasm_shims::Instant::now(), | 91 | last_gc: crate::wasm_shims::Instant::now(), |
94 | last_gc_check: crate::wasm_shims::Instant::now(), | 92 | last_gc_check: crate::wasm_shims::Instant::now(), |
95 | feature_flags: Arc::new(feature_flags), | ||
96 | debug_data: Default::default(), | 93 | debug_data: Default::default(), |
97 | }; | 94 | }; |
98 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); | 95 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); |
@@ -112,7 +109,6 @@ impl salsa::ParallelDatabase for RootDatabase { | |||
112 | runtime: self.runtime.snapshot(self), | 109 | runtime: self.runtime.snapshot(self), |
113 | last_gc: self.last_gc, | 110 | last_gc: self.last_gc, |
114 | last_gc_check: self.last_gc_check, | 111 | last_gc_check: self.last_gc_check, |
115 | feature_flags: Arc::clone(&self.feature_flags), | ||
116 | debug_data: Arc::clone(&self.debug_data), | 112 | debug_data: Arc::clone(&self.debug_data), |
117 | }) | 113 | }) |
118 | } | 114 | } |
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs index e6b3126b6..884359ee3 100644 --- a/crates/ra_ide_db/src/symbol_index.rs +++ b/crates/ra_ide_db/src/symbol_index.rs | |||
@@ -163,7 +163,7 @@ pub fn index_resolve(db: &RootDatabase, name_ref: &ast::NameRef) -> Vec<FileSymb | |||
163 | #[derive(Default)] | 163 | #[derive(Default)] |
164 | pub struct SymbolIndex { | 164 | pub struct SymbolIndex { |
165 | symbols: Vec<FileSymbol>, | 165 | symbols: Vec<FileSymbol>, |
166 | map: fst::Map, | 166 | map: fst::Map<Vec<u8>>, |
167 | } | 167 | } |
168 | 168 | ||
169 | impl fmt::Debug for SymbolIndex { | 169 | impl fmt::Debug for SymbolIndex { |
@@ -221,7 +221,7 @@ impl SymbolIndex { | |||
221 | builder.insert(key, value).unwrap(); | 221 | builder.insert(key, value).unwrap(); |
222 | } | 222 | } |
223 | 223 | ||
224 | let map = fst::Map::from_bytes(builder.into_inner().unwrap()).unwrap(); | 224 | let map = fst::Map::new(builder.into_inner().unwrap()).unwrap(); |
225 | SymbolIndex { symbols, map } | 225 | SymbolIndex { symbols, map } |
226 | } | 226 | } |
227 | 227 | ||
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 91855e592..28a23934f 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 | }; |
15 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; | 15 | use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionOptions, FilePosition, LineCol}; |
16 | 16 | ||
17 | use crate::cli::{load_cargo::load_cargo, Verbosity}; | 17 | use crate::cli::{load_cargo::load_cargo, Verbosity}; |
18 | 18 | ||
@@ -94,17 +94,19 @@ pub fn analysis_bench(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Res | |||
94 | .analysis() | 94 | .analysis() |
95 | .file_line_index(file_id)? | 95 | .file_line_index(file_id)? |
96 | .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); | 96 | .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); |
97 | let file_postion = FilePosition { file_id, offset }; | 97 | let file_position = FilePosition { file_id, offset }; |
98 | 98 | ||
99 | if is_completion { | 99 | if is_completion { |
100 | let res = | 100 | let options = CompletionOptions::default(); |
101 | do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); | 101 | let res = do_work(&mut host, file_id, |analysis| { |
102 | analysis.completions(file_position, &options) | ||
103 | }); | ||
102 | if verbosity.is_verbose() { | 104 | if verbosity.is_verbose() { |
103 | println!("\n{:#?}", res); | 105 | println!("\n{:#?}", res); |
104 | } | 106 | } |
105 | } else { | 107 | } else { |
106 | let res = | 108 | let res = |
107 | do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion)); | 109 | do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_position)); |
108 | if verbosity.is_verbose() { | 110 | if verbosity.is_verbose() { |
109 | println!("\n{:#?}", res); | 111 | println!("\n{:#?}", res); |
110 | } | 112 | } |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 4be987860..5df29a383 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -6,7 +6,7 @@ use std::path::Path; | |||
6 | use anyhow::Result; | 6 | use anyhow::Result; |
7 | use crossbeam_channel::{unbounded, Receiver}; | 7 | use crossbeam_channel::{unbounded, Receiver}; |
8 | use ra_db::{CrateGraph, FileId, SourceRootId}; | 8 | use ra_db::{CrateGraph, FileId, SourceRootId}; |
9 | use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags}; | 9 | use ra_ide::{AnalysisChange, AnalysisHost}; |
10 | use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; | 10 | use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; |
11 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 11 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
12 | use rustc_hash::{FxHashMap, FxHashSet}; | 12 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -82,7 +82,7 @@ pub(crate) fn load( | |||
82 | receiver: Receiver<VfsTask>, | 82 | receiver: Receiver<VfsTask>, |
83 | ) -> AnalysisHost { | 83 | ) -> AnalysisHost { |
84 | let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); | 84 | let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); |
85 | let mut host = AnalysisHost::new(lru_cap, FeatureFlags::default()); | 85 | let mut host = AnalysisHost::new(lru_cap); |
86 | let mut analysis_change = AnalysisChange::new(); | 86 | let mut analysis_change = AnalysisChange::new(); |
87 | analysis_change.set_crate_graph(crate_graph); | 87 | analysis_change.set_crate_graph(crate_graph); |
88 | 88 | ||
diff --git a/crates/ra_ide_db/src/feature_flags.rs b/crates/rust-analyzer/src/feature_flags.rs index 968415072..dbb3f50a0 100644 --- a/crates/ra_ide_db/src/feature_flags.rs +++ b/crates/rust-analyzer/src/feature_flags.rs | |||
@@ -2,6 +2,10 @@ | |||
2 | 2 | ||
3 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
4 | 4 | ||
5 | // FIXME: looks like a much better design is to pass options to each call, | ||
6 | // rather than to have a global ambient feature flags -- that way, the clients | ||
7 | // can issue two successive calls with different options. | ||
8 | |||
5 | /// Feature flags hold fine-grained toggles for all *user-visible* features of | 9 | /// Feature flags hold fine-grained toggles for all *user-visible* features of |
6 | /// rust-analyzer. | 10 | /// rust-analyzer. |
7 | /// | 11 | /// |
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index a0f968823..e50e47b19 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -37,6 +37,7 @@ mod config; | |||
37 | mod world; | 37 | mod world; |
38 | mod diagnostics; | 38 | mod diagnostics; |
39 | mod semantic_tokens; | 39 | mod semantic_tokens; |
40 | mod feature_flags; | ||
40 | 41 | ||
41 | use serde::de::DeserializeOwned; | 42 | use serde::de::DeserializeOwned; |
42 | 43 | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 221f464b6..f9de712a0 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -18,7 +18,7 @@ use crossbeam_channel::{select, unbounded, RecvError, Sender}; | |||
18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
19 | use lsp_types::{ClientCapabilities, NumberOrString}; | 19 | use lsp_types::{ClientCapabilities, NumberOrString}; |
20 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; | 20 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; |
21 | use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; | 21 | use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; |
22 | use ra_prof::profile; | 22 | use ra_prof::profile; |
23 | use ra_vfs::{VfsFile, VfsTask, Watch}; | 23 | use ra_vfs::{VfsFile, VfsTask, Watch}; |
24 | use relative_path::RelativePathBuf; | 24 | use relative_path::RelativePathBuf; |
@@ -28,6 +28,7 @@ use threadpool::ThreadPool; | |||
28 | 28 | ||
29 | use crate::{ | 29 | use crate::{ |
30 | diagnostics::DiagnosticTask, | 30 | diagnostics::DiagnosticTask, |
31 | feature_flags::FeatureFlags, | ||
31 | main_loop::{ | 32 | main_loop::{ |
32 | pending_requests::{PendingRequest, PendingRequests}, | 33 | pending_requests::{PendingRequest, PendingRequests}, |
33 | subscriptions::Subscriptions, | 34 | subscriptions::Subscriptions, |
@@ -423,7 +424,7 @@ fn loop_turn( | |||
423 | { | 424 | { |
424 | loop_state.workspace_loaded = true; | 425 | loop_state.workspace_loaded = true; |
425 | let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum(); | 426 | let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum(); |
426 | if world_state.feature_flags().get("notifications.workspace-loaded") { | 427 | if world_state.feature_flags.get("notifications.workspace-loaded") { |
427 | let msg = format!("workspace loaded, {} rust packages", n_packages); | 428 | let msg = format!("workspace loaded, {} rust packages", n_packages); |
428 | show_message(req::MessageType::Info, msg, &connection.sender); | 429 | show_message(req::MessageType::Info, msg, &connection.sender); |
429 | } | 430 | } |
@@ -839,7 +840,7 @@ fn update_file_notifications_on_threadpool( | |||
839 | subscriptions: Vec<FileId>, | 840 | subscriptions: Vec<FileId>, |
840 | ) { | 841 | ) { |
841 | log::trace!("updating notifications for {:?}", subscriptions); | 842 | log::trace!("updating notifications for {:?}", subscriptions); |
842 | let publish_diagnostics = world.feature_flags().get("lsp.diagnostics"); | 843 | let publish_diagnostics = world.feature_flags.get("lsp.diagnostics"); |
843 | pool.execute(move || { | 844 | pool.execute(move || { |
844 | for file_id in subscriptions { | 845 | for file_id in subscriptions { |
845 | if publish_diagnostics { | 846 | if publish_diagnostics { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 8dc6e8dc0..fcb40432d 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -20,8 +20,8 @@ use lsp_types::{ | |||
20 | TextEdit, WorkspaceEdit, | 20 | TextEdit, WorkspaceEdit, |
21 | }; | 21 | }; |
22 | use ra_ide::{ | 22 | use ra_ide::{ |
23 | Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, | 23 | Assist, AssistId, CompletionOptions, FileId, FilePosition, FileRange, Query, RangeInfo, |
24 | SearchScope, | 24 | Runnable, RunnableKind, SearchScope, |
25 | }; | 25 | }; |
26 | use ra_prof::profile; | 26 | use ra_prof::profile; |
27 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; | 27 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; |
@@ -424,7 +424,15 @@ pub fn handle_completion( | |||
424 | return Ok(None); | 424 | return Ok(None); |
425 | } | 425 | } |
426 | 426 | ||
427 | let items = match world.analysis().completions(position)? { | 427 | let options = CompletionOptions { |
428 | enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"), | ||
429 | add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"), | ||
430 | add_call_argument_snippets: world | ||
431 | .feature_flags | ||
432 | .get("completion.insertion.add-argument-snippets"), | ||
433 | }; | ||
434 | |||
435 | let items = match world.analysis().completions(position, &options)? { | ||
428 | None => return Ok(None), | 436 | None => return Ok(None), |
429 | Some(items) => items, | 437 | Some(items) => items, |
430 | }; | 438 | }; |
@@ -461,7 +469,7 @@ pub fn handle_signature_help( | |||
461 | let _p = profile("handle_signature_help"); | 469 | let _p = profile("handle_signature_help"); |
462 | let position = params.try_conv_with(&world)?; | 470 | let position = params.try_conv_with(&world)?; |
463 | if let Some(call_info) = world.analysis().call_info(position)? { | 471 | if let Some(call_info) = world.analysis().call_info(position)? { |
464 | let concise = !world.analysis().feature_flags().get("call-info.full"); | 472 | let concise = !world.feature_flags.get("call-info.full"); |
465 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); | 473 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); |
466 | if concise && call_info.signature.has_self_param { | 474 | if concise && call_info.signature.has_self_param { |
467 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); | 475 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); |
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 6f394055a..1ddc3c1a5 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -13,8 +13,7 @@ use lsp_types::Url; | |||
13 | use parking_lot::RwLock; | 13 | use parking_lot::RwLock; |
14 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher}; | 14 | use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher}; |
15 | use ra_ide::{ | 15 | use ra_ide::{ |
16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, | 16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, |
17 | SourceRootId, | ||
18 | }; | 17 | }; |
19 | use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; | 18 | use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; |
20 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; | 19 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; |
@@ -22,6 +21,7 @@ use relative_path::RelativePathBuf; | |||
22 | 21 | ||
23 | use crate::{ | 22 | use crate::{ |
24 | diagnostics::{CheckFixes, DiagnosticCollection}, | 23 | diagnostics::{CheckFixes, DiagnosticCollection}, |
24 | feature_flags::FeatureFlags, | ||
25 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | 25 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, |
26 | vfs_glob::{Glob, RustPackageFilterBuilder}, | 26 | vfs_glob::{Glob, RustPackageFilterBuilder}, |
27 | LspError, Result, | 27 | LspError, Result, |
@@ -45,6 +45,7 @@ pub struct Options { | |||
45 | #[derive(Debug)] | 45 | #[derive(Debug)] |
46 | pub struct WorldState { | 46 | pub struct WorldState { |
47 | pub options: Options, | 47 | pub options: Options, |
48 | pub feature_flags: Arc<FeatureFlags>, | ||
48 | //FIXME: this belongs to `LoopState` rather than to `WorldState` | 49 | //FIXME: this belongs to `LoopState` rather than to `WorldState` |
49 | pub roots_to_scan: usize, | 50 | pub roots_to_scan: usize, |
50 | pub roots: Vec<PathBuf>, | 51 | pub roots: Vec<PathBuf>, |
@@ -60,6 +61,7 @@ pub struct WorldState { | |||
60 | /// An immutable snapshot of the world's state at a point in time. | 61 | /// An immutable snapshot of the world's state at a point in time. |
61 | pub struct WorldSnapshot { | 62 | pub struct WorldSnapshot { |
62 | pub options: Options, | 63 | pub options: Options, |
64 | pub feature_flags: Arc<FeatureFlags>, | ||
63 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 65 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
64 | pub analysis: Analysis, | 66 | pub analysis: Analysis, |
65 | pub latest_requests: Arc<RwLock<LatestRequests>>, | 67 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
@@ -146,10 +148,11 @@ impl WorldState { | |||
146 | CheckWatcher::dummy() | 148 | CheckWatcher::dummy() |
147 | }); | 149 | }); |
148 | 150 | ||
149 | let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); | 151 | let mut analysis_host = AnalysisHost::new(lru_capacity); |
150 | analysis_host.apply_change(change); | 152 | analysis_host.apply_change(change); |
151 | WorldState { | 153 | WorldState { |
152 | options, | 154 | options, |
155 | feature_flags: Arc::new(feature_flags), | ||
153 | roots_to_scan, | 156 | roots_to_scan, |
154 | roots: folder_roots, | 157 | roots: folder_roots, |
155 | workspaces: Arc::new(workspaces), | 158 | workspaces: Arc::new(workspaces), |
@@ -216,6 +219,7 @@ impl WorldState { | |||
216 | pub fn snapshot(&self) -> WorldSnapshot { | 219 | pub fn snapshot(&self) -> WorldSnapshot { |
217 | WorldSnapshot { | 220 | WorldSnapshot { |
218 | options: self.options.clone(), | 221 | options: self.options.clone(), |
222 | feature_flags: Arc::clone(&self.feature_flags), | ||
219 | workspaces: Arc::clone(&self.workspaces), | 223 | workspaces: Arc::clone(&self.workspaces), |
220 | analysis: self.analysis_host.analysis(), | 224 | analysis: self.analysis_host.analysis(), |
221 | vfs: Arc::clone(&self.vfs), | 225 | vfs: Arc::clone(&self.vfs), |
@@ -235,10 +239,6 @@ impl WorldState { | |||
235 | pub fn complete_request(&mut self, request: CompletedRequest) { | 239 | pub fn complete_request(&mut self, request: CompletedRequest) { |
236 | self.latest_requests.write().record(request) | 240 | self.latest_requests.write().record(request) |
237 | } | 241 | } |
238 | |||
239 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
240 | self.analysis_host.feature_flags() | ||
241 | } | ||
242 | } | 242 | } |
243 | 243 | ||
244 | impl WorldSnapshot { | 244 | impl WorldSnapshot { |
@@ -306,8 +306,4 @@ impl WorldSnapshot { | |||
306 | let path = self.vfs.read().file2path(VfsFile(file_id.0)); | 306 | let path = self.vfs.read().file2path(VfsFile(file_id.0)); |
307 | self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) | 307 | self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) |
308 | } | 308 | } |
309 | |||
310 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
311 | self.analysis.feature_flags() | ||
312 | } | ||
313 | } | 309 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index 69deddcb5..a0d8f4d37 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -202,6 +202,19 @@ pub fn parse_fixture(fixture: &str) -> Vec<FixtureEntry> { | |||
202 | res | 202 | res |
203 | } | 203 | } |
204 | 204 | ||
205 | /// Same as `parse_fixture`, except it allow empty fixture | ||
206 | pub fn parse_single_fixture(fixture: &str) -> Option<FixtureEntry> { | ||
207 | if !fixture.lines().any(|it| it.trim_start().starts_with("//-")) { | ||
208 | return None; | ||
209 | } | ||
210 | |||
211 | let fixtures = parse_fixture(fixture); | ||
212 | if fixtures.len() > 1 { | ||
213 | panic!("too many fixtures"); | ||
214 | } | ||
215 | fixtures.into_iter().nth(0) | ||
216 | } | ||
217 | |||
205 | // Comparison functionality borrowed from cargo: | 218 | // Comparison functionality borrowed from cargo: |
206 | 219 | ||
207 | /// Compare a line with an expected pattern. | 220 | /// Compare a line with an expected pattern. |
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json index 77ee5a0cf..b07964546 100644 --- a/editors/code/package-lock.json +++ b/editors/code/package-lock.json | |||
@@ -114,9 +114,9 @@ | |||
114 | } | 114 | } |
115 | }, | 115 | }, |
116 | "@types/vscode": { | 116 | "@types/vscode": { |
117 | "version": "1.42.0", | 117 | "version": "1.43.0", |
118 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.42.0.tgz", | 118 | "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.43.0.tgz", |
119 | "integrity": "sha512-ds6TceMsh77Fs0Mq0Vap6Y72JbGWB8Bay4DrnJlf5d9ui2RSe1wis13oQm+XhguOeH1HUfLGzaDAoupTUtgabw==", | 119 | "integrity": "sha512-kIaR9qzd80rJOxePKpCB/mdy00mz8Apt2QA5Y6rdrKFn13QNFNeP3Hzmsf37Bwh/3cS7QjtAeGSK7wSqAU0sYQ==", |
120 | "dev": true | 120 | "dev": true |
121 | }, | 121 | }, |
122 | "@typescript-eslint/eslint-plugin": { | 122 | "@typescript-eslint/eslint-plugin": { |
diff --git a/editors/code/package.json b/editors/code/package.json index 7a4a93e30..512885454 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -21,7 +21,7 @@ | |||
21 | "Programming Languages" | 21 | "Programming Languages" |
22 | ], | 22 | ], |
23 | "engines": { | 23 | "engines": { |
24 | "vscode": "^1.42.0" | 24 | "vscode": "^1.43.0" |
25 | }, | 25 | }, |
26 | "enableProposedApi": true, | 26 | "enableProposedApi": true, |
27 | "scripts": { | 27 | "scripts": { |
@@ -41,7 +41,7 @@ | |||
41 | "@rollup/plugin-node-resolve": "^7.1.1", | 41 | "@rollup/plugin-node-resolve": "^7.1.1", |
42 | "@types/node": "^12.12.29", | 42 | "@types/node": "^12.12.29", |
43 | "@types/node-fetch": "^2.5.5", | 43 | "@types/node-fetch": "^2.5.5", |
44 | "@types/vscode": "^1.42.0", | 44 | "@types/vscode": "^1.43.0", |
45 | "@typescript-eslint/eslint-plugin": "^2.22.0", | 45 | "@typescript-eslint/eslint-plugin": "^2.22.0", |
46 | "@typescript-eslint/parser": "^2.22.0", | 46 | "@typescript-eslint/parser": "^2.22.0", |
47 | "eslint": "^6.8.0", | 47 | "eslint": "^6.8.0", |