diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-10-17 11:31:37 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-17 11:31:37 +0100 |
commit | b1315be010f0d9f67ee4794cb57f7d1baa88a30d (patch) | |
tree | b4259ce1810c3cd6c2bea62bae499415b764728d /crates/ide/src/completion/patterns.rs | |
parent | 59483c217662fc5d89ef9da1cb93760e14a48418 (diff) | |
parent | 99c435939c941fe5216c39bc136769098abbbfea (diff) |
Merge #6262
6262: Do not spawn redundant hints r=SomeoneToIgnore a=popzxc
Closes #5206
This is a second part of the fix (first was #5997).
This PR adds a new method to the `CompletionContext`: `no_completion_required`. If this method returns `true`, it essentially means that user is unlikely to expect any hints from the IDE at this cursor position.
Currently, checks for the following cases were added:
- Previous item is `fn`: user creates a new function, names of existing functions won't be helpful. Exception for this case is `impl Foo for Bar` -- we must suggest trait function names.
- User entered `for _ i<|>`: it's obviously going to be `in` keyword, any hints here will be confusing.
More checks may be added there later, but currently I've only figured two cases.
![no_redundant_hints](https://user-images.githubusercontent.com/12111581/96332088-da4d2a00-106a-11eb-89a1-1159ece18f9d.png)
Co-authored-by: Igor Aleksanov <[email protected]>
Diffstat (limited to 'crates/ide/src/completion/patterns.rs')
-rw-r--r-- | crates/ide/src/completion/patterns.rs | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/crates/ide/src/completion/patterns.rs b/crates/ide/src/completion/patterns.rs index b17ddf133..cf6d5947d 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,25 @@ 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 inside_impl_trait_block(element: SyntaxElement) -> bool { | ||
39 | // Here we search `impl` keyword up through the all ancestors, unlike in `has_impl_parent`, | ||
40 | // where we only check the first parent with different text range. | ||
41 | element | ||
42 | .ancestors() | ||
43 | .find(|it| it.kind() == IMPL) | ||
44 | .map(|it| ast::Impl::cast(it).unwrap()) | ||
45 | .map(|it| it.trait_().is_some()) | ||
46 | .unwrap_or(false) | ||
47 | } | ||
48 | #[test] | ||
49 | fn test_inside_impl_trait_block() { | ||
50 | check_pattern_is_applicable(r"impl Foo for Bar { f<|> }", inside_impl_trait_block); | ||
51 | check_pattern_is_applicable(r"impl Foo for Bar { fn f<|> }", inside_impl_trait_block); | ||
52 | check_pattern_is_not_applicable(r"impl A { f<|> }", inside_impl_trait_block); | ||
53 | check_pattern_is_not_applicable(r"impl A { fn f<|> }", inside_impl_trait_block); | ||
54 | } | ||
55 | |||
37 | pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool { | 56 | 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() | 57 | not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some() |
39 | } | 58 | } |
@@ -116,6 +135,33 @@ pub(crate) fn if_is_prev(element: SyntaxElement) -> bool { | |||
116 | .is_some() | 135 | .is_some() |
117 | } | 136 | } |
118 | 137 | ||
138 | pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool { | ||
139 | element | ||
140 | .into_token() | ||
141 | .and_then(|it| previous_non_trivia_token(it)) | ||
142 | .filter(|it| it.kind() == FN_KW) | ||
143 | .is_some() | ||
144 | } | ||
145 | #[test] | ||
146 | fn test_fn_is_prev() { | ||
147 | check_pattern_is_applicable(r"fn l<|>", fn_is_prev); | ||
148 | } | ||
149 | |||
150 | /// Check if the token previous to the previous one is `for`. | ||
151 | /// For example, `for _ i<|>` => true. | ||
152 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { | ||
153 | element | ||
154 | .into_token() | ||
155 | .and_then(|it| previous_non_trivia_token(it)) | ||
156 | .and_then(|it| previous_non_trivia_token(it)) | ||
157 | .filter(|it| it.kind() == FOR_KW) | ||
158 | .is_some() | ||
159 | } | ||
160 | #[test] | ||
161 | fn test_for_is_prev2() { | ||
162 | check_pattern_is_applicable(r"for i i<|>", for_is_prev2); | ||
163 | } | ||
164 | |||
119 | #[test] | 165 | #[test] |
120 | fn test_if_is_prev() { | 166 | fn test_if_is_prev() { |
121 | check_pattern_is_applicable(r"if l<|>", if_is_prev); | 167 | check_pattern_is_applicable(r"if l<|>", if_is_prev); |