diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/hir_expand/src/builtin_macro.rs | 37 | ||||
-rw-r--r-- | crates/hir_expand/src/eager.rs | 3 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/macros.rs | 18 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 26 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute/derive.rs | 38 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute/lint.rs | 33 |
6 files changed, 102 insertions, 53 deletions
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs index 94d7aecb6..0b310ba2f 100644 --- a/crates/hir_expand/src/builtin_macro.rs +++ b/crates/hir_expand/src/builtin_macro.rs | |||
@@ -8,7 +8,6 @@ use base_db::{AnchoredPath, Edition, FileId}; | |||
8 | use cfg::CfgExpr; | 8 | use cfg::CfgExpr; |
9 | use either::Either; | 9 | use either::Either; |
10 | use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; | 10 | use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; |
11 | use parser::FragmentKind; | ||
12 | use syntax::ast::{self, AstToken}; | 11 | use syntax::ast::{self, AstToken}; |
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
@@ -47,7 +46,7 @@ macro_rules! register_builtin { | |||
47 | let expander = match *self { | 46 | let expander = match *self { |
48 | $( EagerExpander::$e_kind => $e_expand, )* | 47 | $( EagerExpander::$e_kind => $e_expand, )* |
49 | }; | 48 | }; |
50 | expander(db,arg_id,tt) | 49 | expander(db, arg_id, tt) |
51 | } | 50 | } |
52 | } | 51 | } |
53 | 52 | ||
@@ -64,14 +63,13 @@ macro_rules! register_builtin { | |||
64 | #[derive(Debug)] | 63 | #[derive(Debug)] |
65 | pub struct ExpandedEager { | 64 | pub struct ExpandedEager { |
66 | pub(crate) subtree: tt::Subtree, | 65 | pub(crate) subtree: tt::Subtree, |
67 | pub(crate) fragment: FragmentKind, | ||
68 | /// The included file ID of the include macro. | 66 | /// The included file ID of the include macro. |
69 | pub(crate) included_file: Option<FileId>, | 67 | pub(crate) included_file: Option<FileId>, |
70 | } | 68 | } |
71 | 69 | ||
72 | impl ExpandedEager { | 70 | impl ExpandedEager { |
73 | fn new(subtree: tt::Subtree, fragment: FragmentKind) -> Self { | 71 | fn new(subtree: tt::Subtree) -> Self { |
74 | ExpandedEager { subtree, fragment, included_file: None } | 72 | ExpandedEager { subtree, included_file: None } |
75 | } | 73 | } |
76 | } | 74 | } |
77 | 75 | ||
@@ -340,7 +338,7 @@ fn compile_error_expand( | |||
340 | _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()), | 338 | _ => mbe::ExpandError::BindingError("`compile_error!` argument must be a string".into()), |
341 | }; | 339 | }; |
342 | 340 | ||
343 | ExpandResult { value: Some(ExpandedEager::new(quote! {}, FragmentKind::Items)), err: Some(err) } | 341 | ExpandResult { value: Some(ExpandedEager::new(quote! {})), err: Some(err) } |
344 | } | 342 | } |
345 | 343 | ||
346 | fn concat_expand( | 344 | fn concat_expand( |
@@ -371,7 +369,7 @@ fn concat_expand( | |||
371 | } | 369 | } |
372 | } | 370 | } |
373 | } | 371 | } |
374 | ExpandResult { value: Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr)), err } | 372 | ExpandResult { value: Some(ExpandedEager::new(quote!(#text))), err } |
375 | } | 373 | } |
376 | 374 | ||
377 | fn concat_idents_expand( | 375 | fn concat_idents_expand( |
@@ -393,7 +391,7 @@ fn concat_idents_expand( | |||
393 | } | 391 | } |
394 | } | 392 | } |
395 | let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() }; | 393 | let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() }; |
396 | ExpandResult { value: Some(ExpandedEager::new(quote!(#ident), FragmentKind::Expr)), err } | 394 | ExpandResult { value: Some(ExpandedEager::new(quote!(#ident))), err } |
397 | } | 395 | } |
398 | 396 | ||
399 | fn relative_file( | 397 | fn relative_file( |
@@ -442,14 +440,7 @@ fn include_expand( | |||
442 | 440 | ||
443 | match res { | 441 | match res { |
444 | Ok((subtree, file_id)) => { | 442 | Ok((subtree, file_id)) => { |
445 | // FIXME: | 443 | ExpandResult::ok(Some(ExpandedEager { subtree, included_file: Some(file_id) })) |
446 | // Handle include as expression | ||
447 | |||
448 | ExpandResult::ok(Some(ExpandedEager { | ||
449 | subtree, | ||
450 | fragment: FragmentKind::Items, | ||
451 | included_file: Some(file_id), | ||
452 | })) | ||
453 | } | 444 | } |
454 | Err(e) => ExpandResult::only_err(e), | 445 | Err(e) => ExpandResult::only_err(e), |
455 | } | 446 | } |
@@ -472,7 +463,7 @@ fn include_bytes_expand( | |||
472 | id: tt::TokenId::unspecified(), | 463 | id: tt::TokenId::unspecified(), |
473 | }))], | 464 | }))], |
474 | }; | 465 | }; |
475 | ExpandResult::ok(Some(ExpandedEager::new(res, FragmentKind::Expr))) | 466 | ExpandResult::ok(Some(ExpandedEager::new(res))) |
476 | } | 467 | } |
477 | 468 | ||
478 | fn include_str_expand( | 469 | fn include_str_expand( |
@@ -492,14 +483,14 @@ fn include_str_expand( | |||
492 | let file_id = match relative_file(db, arg_id.into(), &path, true) { | 483 | let file_id = match relative_file(db, arg_id.into(), &path, true) { |
493 | Ok(file_id) => file_id, | 484 | Ok(file_id) => file_id, |
494 | Err(_) => { | 485 | Err(_) => { |
495 | return ExpandResult::ok(Some(ExpandedEager::new(quote!(""), FragmentKind::Expr))); | 486 | return ExpandResult::ok(Some(ExpandedEager::new(quote!("")))); |
496 | } | 487 | } |
497 | }; | 488 | }; |
498 | 489 | ||
499 | let text = db.file_text(file_id); | 490 | let text = db.file_text(file_id); |
500 | let text = &*text; | 491 | let text = &*text; |
501 | 492 | ||
502 | ExpandResult::ok(Some(ExpandedEager::new(quote!(#text), FragmentKind::Expr))) | 493 | ExpandResult::ok(Some(ExpandedEager::new(quote!(#text)))) |
503 | } | 494 | } |
504 | 495 | ||
505 | fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { | 496 | fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { |
@@ -535,7 +526,7 @@ fn env_expand( | |||
535 | }); | 526 | }); |
536 | let expanded = quote! { #s }; | 527 | let expanded = quote! { #s }; |
537 | 528 | ||
538 | ExpandResult { value: Some(ExpandedEager::new(expanded, FragmentKind::Expr)), err } | 529 | ExpandResult { value: Some(ExpandedEager::new(expanded)), err } |
539 | } | 530 | } |
540 | 531 | ||
541 | fn option_env_expand( | 532 | fn option_env_expand( |
@@ -553,7 +544,7 @@ fn option_env_expand( | |||
553 | Some(s) => quote! { std::option::Some(#s) }, | 544 | Some(s) => quote! { std::option::Some(#s) }, |
554 | }; | 545 | }; |
555 | 546 | ||
556 | ExpandResult::ok(Some(ExpandedEager::new(expanded, FragmentKind::Expr))) | 547 | ExpandResult::ok(Some(ExpandedEager::new(expanded))) |
557 | } | 548 | } |
558 | 549 | ||
559 | #[cfg(test)] | 550 | #[cfg(test)] |
@@ -565,6 +556,7 @@ mod tests { | |||
565 | }; | 556 | }; |
566 | use base_db::{fixture::WithFixture, SourceDatabase}; | 557 | use base_db::{fixture::WithFixture, SourceDatabase}; |
567 | use expect_test::{expect, Expect}; | 558 | use expect_test::{expect, Expect}; |
559 | use parser::FragmentKind; | ||
568 | use std::sync::Arc; | 560 | use std::sync::Arc; |
569 | use syntax::ast::NameOwner; | 561 | use syntax::ast::NameOwner; |
570 | 562 | ||
@@ -617,6 +609,7 @@ mod tests { | |||
617 | local_inner: false, | 609 | local_inner: false, |
618 | }; | 610 | }; |
619 | 611 | ||
612 | let fragment = crate::to_fragment_kind(¯o_call); | ||
620 | let args = macro_call.token_tree().unwrap(); | 613 | let args = macro_call.token_tree().unwrap(); |
621 | let parsed_args = mbe::ast_to_token_tree(&args).0; | 614 | let parsed_args = mbe::ast_to_token_tree(&args).0; |
622 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)); | 615 | let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(¯o_call)); |
@@ -639,7 +632,7 @@ mod tests { | |||
639 | arg_or_expansion: Arc::new(expanded.subtree), | 632 | arg_or_expansion: Arc::new(expanded.subtree), |
640 | included_file: expanded.included_file, | 633 | included_file: expanded.included_file, |
641 | }), | 634 | }), |
642 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment: expanded.fragment }, | 635 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment }, |
643 | }; | 636 | }; |
644 | 637 | ||
645 | let id: MacroCallId = db.intern_macro(loc).into(); | 638 | let id: MacroCallId = db.intern_macro(loc).into(); |
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs index 1464320ba..14af628a1 100644 --- a/crates/hir_expand/src/eager.rs +++ b/crates/hir_expand/src/eager.rs | |||
@@ -113,6 +113,7 @@ pub fn expand_eager_macro( | |||
113 | 113 | ||
114 | let ast_map = db.ast_id_map(macro_call.file_id); | 114 | let ast_map = db.ast_id_map(macro_call.file_id); |
115 | let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); | 115 | let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value)); |
116 | let fragment = crate::to_fragment_kind(¯o_call.value); | ||
116 | 117 | ||
117 | // Note: | 118 | // Note: |
118 | // When `lazy_expand` is called, its *parent* file must be already exists. | 119 | // When `lazy_expand` is called, its *parent* file must be already exists. |
@@ -152,7 +153,7 @@ pub fn expand_eager_macro( | |||
152 | arg_or_expansion: Arc::new(expanded.subtree), | 153 | arg_or_expansion: Arc::new(expanded.subtree), |
153 | included_file: expanded.included_file, | 154 | included_file: expanded.included_file, |
154 | }), | 155 | }), |
155 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment: expanded.fragment }, | 156 | kind: MacroCallKind::FnLike { ast_id: call_id, fragment }, |
156 | }; | 157 | }; |
157 | 158 | ||
158 | Ok(db.intern_macro(loc)) | 159 | Ok(db.intern_macro(loc)) |
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs index 6588aa46c..7647bb08b 100644 --- a/crates/hir_ty/src/tests/macros.rs +++ b/crates/hir_ty/src/tests/macros.rs | |||
@@ -752,6 +752,24 @@ fn bar() -> u32 {0} | |||
752 | } | 752 | } |
753 | 753 | ||
754 | #[test] | 754 | #[test] |
755 | fn infer_builtin_macros_include_expression() { | ||
756 | check_types( | ||
757 | r#" | ||
758 | //- /main.rs | ||
759 | #[rustc_builtin_macro] | ||
760 | macro_rules! include {() => {}} | ||
761 | fn main() { | ||
762 | let i = include!("bla.rs"); | ||
763 | i; | ||
764 | //^ i32 | ||
765 | } | ||
766 | //- /bla.rs | ||
767 | 0 | ||
768 | "#, | ||
769 | ) | ||
770 | } | ||
771 | |||
772 | #[test] | ||
755 | fn infer_builtin_macros_include_child_mod() { | 773 | fn infer_builtin_macros_include_child_mod() { |
756 | check_types( | 774 | check_types( |
757 | r#" | 775 | r#" |
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 | } | ||