aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Aleksanov <[email protected]>2020-10-17 09:03:07 +0100
committerIgor Aleksanov <[email protected]>2020-10-17 09:03:07 +0100
commit6f573bd84f4564f11b08db720401ae16a0f42f2f (patch)
tree774202cfd275bd30380bc7618885da5e012b5690
parent8f303daf458ae798b678d7e908ce5b2f27504111 (diff)
Allow hints after 'fn' keyword if it's an impl trait block
-rw-r--r--crates/ide/src/completion/completion_context.rs11
-rw-r--r--crates/ide/src/completion/patterns.rs18
-rw-r--r--crates/ide/src/completion/test_utils.rs12
3 files changed, 37 insertions, 4 deletions
diff --git a/crates/ide/src/completion/completion_context.rs b/crates/ide/src/completion/completion_context.rs
index c9473cca6..cff0afae9 100644
--- a/crates/ide/src/completion/completion_context.rs
+++ b/crates/ide/src/completion/completion_context.rs
@@ -18,8 +18,9 @@ use crate::{
18 patterns::{ 18 patterns::{
19 fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent, 19 fn_is_prev, for_is_prev2, has_bind_pat_parent, has_block_expr_parent,
20 has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent, 20 has_field_list_parent, has_impl_as_prev_sibling, has_impl_parent,
21 has_item_list_or_source_file_parent, has_ref_parent, has_trait_as_prev_sibling, 21 has_impl_trait_parent, has_item_list_or_source_file_parent, has_ref_parent,
22 has_trait_parent, if_is_prev, is_in_loop_body, is_match_arm, unsafe_is_prev, 22 has_trait_as_prev_sibling, has_trait_parent, if_is_prev, is_in_loop_body, is_match_arm,
23 unsafe_is_prev,
23 }, 24 },
24 CompletionConfig, 25 CompletionConfig,
25 }, 26 },
@@ -86,6 +87,7 @@ pub(crate) struct CompletionContext<'a> {
86 pub(super) in_loop_body: bool, 87 pub(super) in_loop_body: bool,
87 pub(super) has_trait_parent: bool, 88 pub(super) has_trait_parent: bool,
88 pub(super) has_impl_parent: bool, 89 pub(super) has_impl_parent: bool,
90 pub(super) has_impl_trait_parent: bool,
89 pub(super) has_field_list_parent: bool, 91 pub(super) has_field_list_parent: bool,
90 pub(super) trait_as_prev_sibling: bool, 92 pub(super) trait_as_prev_sibling: bool,
91 pub(super) impl_as_prev_sibling: bool, 93 pub(super) impl_as_prev_sibling: bool,
@@ -170,6 +172,7 @@ impl<'a> CompletionContext<'a> {
170 block_expr_parent: false, 172 block_expr_parent: false,
171 has_trait_parent: false, 173 has_trait_parent: false,
172 has_impl_parent: false, 174 has_impl_parent: false,
175 has_impl_trait_parent: false,
173 has_field_list_parent: false, 176 has_field_list_parent: false,
174 trait_as_prev_sibling: false, 177 trait_as_prev_sibling: false,
175 impl_as_prev_sibling: false, 178 impl_as_prev_sibling: false,
@@ -228,9 +231,10 @@ impl<'a> CompletionContext<'a> {
228 /// Checks whether completions in that particular case don't make much sense. 231 /// Checks whether completions in that particular case don't make much sense.
229 /// Examples: 232 /// Examples:
230 /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful. 233 /// - `fn <|>` -- we expect function name, it's unlikely that "hint" will be helpful.
234 /// Exception for this case is `impl Trait for Foo`, where we would like to hint trait method names.
231 /// - `for _ i<|>` -- obviously, it'll be "in" keyword. 235 /// - `for _ i<|>` -- obviously, it'll be "in" keyword.
232 pub(crate) fn no_completion_required(&self) -> bool { 236 pub(crate) fn no_completion_required(&self) -> bool {
233 self.fn_is_prev || self.for_is_prev2 237 (self.fn_is_prev && !self.has_impl_trait_parent) || self.for_is_prev2
234 } 238 }
235 239
236 /// The range of the identifier that is being completed. 240 /// The range of the identifier that is being completed.
@@ -256,6 +260,7 @@ impl<'a> CompletionContext<'a> {
256 self.in_loop_body = is_in_loop_body(syntax_element.clone()); 260 self.in_loop_body = is_in_loop_body(syntax_element.clone());
257 self.has_trait_parent = has_trait_parent(syntax_element.clone()); 261 self.has_trait_parent = has_trait_parent(syntax_element.clone());
258 self.has_impl_parent = has_impl_parent(syntax_element.clone()); 262 self.has_impl_parent = has_impl_parent(syntax_element.clone());
263 self.has_impl_trait_parent = has_impl_trait_parent(syntax_element.clone());
259 self.has_field_list_parent = has_field_list_parent(syntax_element.clone()); 264 self.has_field_list_parent = has_field_list_parent(syntax_element.clone());
260 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); 265 self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone());
261 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); 266 self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone());
diff --git a/crates/ide/src/completion/patterns.rs b/crates/ide/src/completion/patterns.rs
index f00ddeed7..bdce7a6e7 100644
--- a/crates/ide/src/completion/patterns.rs
+++ b/crates/ide/src/completion/patterns.rs
@@ -9,7 +9,7 @@ use syntax::{
9}; 9};
10 10
11#[cfg(test)] 11#[cfg(test)]
12use crate::completion::test_utils::check_pattern_is_applicable; 12use crate::completion::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable};
13 13
14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { 14pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
15 not_same_range_ancestor(element) 15 not_same_range_ancestor(element)
@@ -34,6 +34,22 @@ pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
34fn test_has_impl_parent() { 34fn test_has_impl_parent() {
35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent); 35 check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
36} 36}
37
38pub(crate) fn has_impl_trait_parent(element: SyntaxElement) -> bool {
39 not_same_range_ancestor(element)
40 .filter(|it| it.kind() == ASSOC_ITEM_LIST)
41 .and_then(|it| it.parent())
42 .filter(|it| it.kind() == IMPL)
43 .map(|it| ast::Impl::cast(it).unwrap())
44 .map(|it| it.trait_().is_some())
45 .unwrap_or(false)
46}
47#[test]
48fn test_has_impl_trait_parent() {
49 check_pattern_is_applicable(r"impl Foo for Bar { f<|> }", has_impl_trait_parent);
50 check_pattern_is_not_applicable(r"impl A { f<|> }", has_impl_trait_parent);
51}
52
37pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { 53pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
38 not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some() 54 not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some()
39} 55}
diff --git a/crates/ide/src/completion/test_utils.rs b/crates/ide/src/completion/test_utils.rs
index feb8cd2a6..dabbef888 100644
--- a/crates/ide/src/completion/test_utils.rs
+++ b/crates/ide/src/completion/test_utils.rs
@@ -104,6 +104,18 @@ pub(crate) fn check_pattern_is_applicable(code: &str, check: fn(SyntaxElement) -
104 .unwrap(); 104 .unwrap();
105} 105}
106 106
107pub(crate) fn check_pattern_is_not_applicable(code: &str, check: fn(SyntaxElement) -> bool) {
108 let (analysis, pos) = fixture::position(code);
109 analysis
110 .with_db(|db| {
111 let sema = Semantics::new(db);
112 let original_file = sema.parse(pos.file_id);
113 let token = original_file.syntax().token_at_offset(pos.offset).left_biased().unwrap();
114 assert!(!check(NodeOrToken::Token(token)));
115 })
116 .unwrap();
117}
118
107pub(crate) fn get_all_completion_items( 119pub(crate) fn get_all_completion_items(
108 config: CompletionConfig, 120 config: CompletionConfig,
109 code: &str, 121 code: &str,