aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_expand/src/builtin_macro.rs37
-rw-r--r--crates/hir_expand/src/eager.rs3
-rw-r--r--crates/hir_ty/src/tests/macros.rs18
-rw-r--r--crates/ide_completion/src/completions/attribute.rs26
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs38
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs33
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};
8use cfg::CfgExpr; 8use cfg::CfgExpr;
9use either::Either; 9use either::Either;
10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; 10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
11use parser::FragmentKind;
12use syntax::ast::{self, AstToken}; 11use syntax::ast::{self, AstToken};
13 12
14macro_rules! register_builtin { 13macro_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)]
65pub struct ExpandedEager { 64pub 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
72impl ExpandedEager { 70impl 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
346fn concat_expand( 344fn 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
377fn concat_idents_expand( 375fn 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
399fn relative_file( 397fn 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
478fn include_str_expand( 469fn 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
505fn get_env_inner(db: &dyn AstDatabase, arg_id: MacroCallId, key: &str) -> Option<String> { 496fn 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
541fn option_env_expand( 532fn 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(&macro_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(&macro_call)); 615 let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_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(&macro_call.value)); 115 let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(&macro_call.value));
116 let fragment = crate::to_fragment_kind(&macro_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]
755fn infer_builtin_macros_include_expression() {
756 check_types(
757 r#"
758//- /main.rs
759#[rustc_builtin_macro]
760macro_rules! include {() => {}}
761fn main() {
762 let i = include!("bla.rs");
763 i;
764 //^ i32
765}
766//- /bla.rs
7670
768 "#,
769 )
770}
771
772#[test]
755fn infer_builtin_macros_include_child_mod() { 773fn 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
6use std::mem;
7
8use once_cell::sync::Lazy; 6use once_cell::sync::Lazy;
9use rustc_hash::{FxHashMap, FxHashSet}; 7use rustc_hash::{FxHashMap, FxHashSet};
10use syntax::{ast, AstNode, NodeOrToken, SyntaxKind, T}; 8use syntax::{ast, AstNode, NodeOrToken, SyntaxKind, T};
@@ -272,27 +270,27 @@ const ATTRIBUTES: &[AttrCompletion] = &[
272fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Option<FxHashSet<String>> { 270fn 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
48fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> { 49fn 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)]
96struct 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#"
117struct 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)]
128struct 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)]
157mod 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}