diff options
Diffstat (limited to 'crates/ide')
-rw-r--r-- | crates/ide/src/completion/completion_context.rs | 11 | ||||
-rw-r--r-- | crates/ide/src/completion/patterns.rs | 18 | ||||
-rw-r--r-- | crates/ide/src/completion/test_utils.rs | 12 |
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)] |
12 | use crate::completion::test_utils::check_pattern_is_applicable; | 12 | use crate::completion::test_utils::{check_pattern_is_applicable, check_pattern_is_not_applicable}; |
13 | 13 | ||
14 | pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool { | 14 | pub(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 { | |||
34 | fn test_has_impl_parent() { | 34 | fn 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 | |||
38 | pub(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] | ||
48 | fn 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 | |||
37 | pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { | 53 | pub(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 | ||
107 | pub(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 | |||
107 | pub(crate) fn get_all_completion_items( | 119 | pub(crate) fn get_all_completion_items( |
108 | config: CompletionConfig, | 120 | config: CompletionConfig, |
109 | code: &str, | 121 | code: &str, |