diff options
3 files changed, 67 insertions, 30 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 610fec65a..13d5b90c9 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -3,8 +3,6 @@ | |||
3 | //! This module uses a bit of static metadata to provide completions | 3 | //! This module uses a bit of static metadata to provide completions |
4 | //! for built-in attributes. | 4 | //! for built-in attributes. |
5 | 5 | ||
6 | use std::mem; | ||
7 | |||
8 | use once_cell::sync::Lazy; | 6 | use once_cell::sync::Lazy; |
9 | use rustc_hash::{FxHashMap, FxHashSet}; | 7 | use rustc_hash::{FxHashMap, FxHashSet}; |
10 | use syntax::{ast, AstNode, NodeOrToken, SyntaxKind, T}; | 8 | use syntax::{ast, AstNode, NodeOrToken, SyntaxKind, T}; |
@@ -272,27 +270,27 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
272 | fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Option<FxHashSet<String>> { | 270 | fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Option<FxHashSet<String>> { |
273 | let (l_paren, r_paren) = derive_input.l_paren_token().zip(derive_input.r_paren_token())?; | 271 | let (l_paren, r_paren) = derive_input.l_paren_token().zip(derive_input.r_paren_token())?; |
274 | let mut input_derives = FxHashSet::default(); | 272 | let mut input_derives = FxHashSet::default(); |
275 | let mut current_derive = String::new(); | 273 | let mut tokens = derive_input |
276 | for token in derive_input | ||
277 | .syntax() | 274 | .syntax() |
278 | .children_with_tokens() | 275 | .children_with_tokens() |
279 | .filter_map(NodeOrToken::into_token) | 276 | .filter_map(NodeOrToken::into_token) |
280 | .skip_while(|token| token != &l_paren) | 277 | .skip_while(|token| token != &l_paren) |
281 | .skip(1) | 278 | .skip(1) |
282 | .take_while(|token| token != &r_paren) | 279 | .take_while(|token| token != &r_paren) |
283 | { | 280 | .peekable(); |
284 | if token.kind() == T![,] { | 281 | let mut input = String::new(); |
285 | if !current_derive.is_empty() { | 282 | while tokens.peek().is_some() { |
286 | input_derives.insert(mem::take(&mut current_derive)); | 283 | for token in tokens.by_ref().take_while(|t| t.kind() != T![,]) { |
287 | } | 284 | input.push_str(token.text()); |
288 | } else { | ||
289 | current_derive.push_str(token.text().trim()); | ||
290 | } | 285 | } |
291 | } | ||
292 | 286 | ||
293 | if !current_derive.is_empty() { | 287 | if !input.is_empty() { |
294 | input_derives.insert(current_derive); | 288 | input_derives.insert(input.trim().to_owned()); |
289 | } | ||
290 | |||
291 | input.clear(); | ||
295 | } | 292 | } |
293 | |||
296 | Some(input_derives) | 294 | Some(input_derives) |
297 | } | 295 | } |
298 | 296 | ||
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index 7b0a778a2..634c0cb00 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -45,6 +45,7 @@ pub(super) fn complete_derive( | |||
45 | } | 45 | } |
46 | } | 46 | } |
47 | } | 47 | } |
48 | |||
48 | fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { | 49 | fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { |
49 | let mut result = FxHashSet::default(); | 50 | let mut result = FxHashSet::default(); |
50 | ctx.scope.process_all_names(&mut |name, scope_def| { | 51 | ctx.scope.process_all_names(&mut |name, scope_def| { |
@@ -89,12 +90,14 @@ mod tests { | |||
89 | } | 90 | } |
90 | 91 | ||
91 | #[test] | 92 | #[test] |
92 | fn empty_derive_completion() { | 93 | fn no_completion_for_incorrect_derive() { |
94 | check(r#"#[derive{$0)] struct Test;"#, expect![[]]) | ||
95 | } | ||
96 | |||
97 | #[test] | ||
98 | fn empty_derive() { | ||
93 | check( | 99 | check( |
94 | r#" | 100 | r#"#[derive($0)] struct Test;"#, |
95 | #[derive($0)] | ||
96 | struct Test {} | ||
97 | "#, | ||
98 | expect![[r#" | 101 | expect![[r#" |
99 | at Clone | 102 | at Clone |
100 | at Clone, Copy | 103 | at Clone, Copy |
@@ -110,23 +113,26 @@ struct Test {} | |||
110 | } | 113 | } |
111 | 114 | ||
112 | #[test] | 115 | #[test] |
113 | fn no_completion_for_incorrect_derive() { | 116 | fn derive_with_input() { |
114 | check( | 117 | check( |
115 | r#" | 118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, |
116 | #[derive{$0)] | 119 | expect![[r#" |
117 | struct Test {} | 120 | at Clone |
118 | "#, | 121 | at Clone, Copy |
119 | expect![[r#""#]], | 122 | at Debug |
123 | at Default | ||
124 | at Hash | ||
125 | at Eq | ||
126 | at PartialOrd | ||
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | ||
120 | ) | 129 | ) |
121 | } | 130 | } |
122 | 131 | ||
123 | #[test] | 132 | #[test] |
124 | fn derive_with_input_completion() { | 133 | fn derive_with_input2() { |
125 | check( | 134 | check( |
126 | r#" | 135 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, |
127 | #[derive(serde::Serialize, PartialEq, $0)] | ||
128 | struct Test {} | ||
129 | "#, | ||
130 | expect![[r#" | 136 | expect![[r#" |
131 | at Clone | 137 | at Clone |
132 | at Clone, Copy | 138 | at Clone, Copy |
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs index 115c6cfe0..403630dce 100644 --- a/crates/ide_completion/src/completions/attribute/lint.rs +++ b/crates/ide_completion/src/completions/attribute/lint.rs | |||
@@ -152,3 +152,36 @@ pub(super) const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[ | |||
152 | LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# }, | 152 | LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# }, |
153 | LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# }, | 153 | LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# }, |
154 | ]; | 154 | ]; |
155 | |||
156 | #[cfg(test)] | ||
157 | mod tests { | ||
158 | |||
159 | use crate::test_utils::check_edit; | ||
160 | |||
161 | #[test] | ||
162 | fn check_empty() { | ||
163 | check_edit( | ||
164 | "deprecated", | ||
165 | r#"#[allow($0)] struct Test;"#, | ||
166 | r#"#[allow(deprecated)] struct Test;"#, | ||
167 | ) | ||
168 | } | ||
169 | |||
170 | #[test] | ||
171 | fn check_with_existing() { | ||
172 | check_edit( | ||
173 | "deprecated", | ||
174 | r#"#[allow(keyword_idents, $0)] struct Test;"#, | ||
175 | r#"#[allow(keyword_idents, deprecated)] struct Test;"#, | ||
176 | ) | ||
177 | } | ||
178 | |||
179 | #[test] | ||
180 | fn check_qualified() { | ||
181 | check_edit( | ||
182 | "deprecated", | ||
183 | r#"#[allow(keyword_idents, $0)] struct Test;"#, | ||
184 | r#"#[allow(keyword_idents, deprecated)] struct Test;"#, | ||
185 | ) | ||
186 | } | ||
187 | } | ||