aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src')
-rw-r--r--crates/hir_expand/src/builtin_derive.rs66
-rw-r--r--crates/hir_expand/src/builtin_macro.rs140
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/hir_expand/src/quote.rs5
5 files changed, 103 insertions, 111 deletions
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index b7f1aae8f..dfdb9cf59 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -267,13 +267,14 @@ fn partial_ord_expand(
267#[cfg(test)] 267#[cfg(test)]
268mod tests { 268mod tests {
269 use base_db::{fixture::WithFixture, CrateId, SourceDatabase}; 269 use base_db::{fixture::WithFixture, CrateId, SourceDatabase};
270 use expect_test::{expect, Expect};
270 use name::{known, Name}; 271 use name::{known, Name};
271 272
272 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; 273 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc};
273 274
274 use super::*; 275 use super::*;
275 276
276 fn expand_builtin_derive(s: &str, name: Name) -> String { 277 fn expand_builtin_derive(ra_fixture: &str, name: Name) -> String {
277 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); 278 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
278 let fixture = format!( 279 let fixture = format!(
279 r#"//- /main.rs crate:main deps:core 280 r#"//- /main.rs crate:main deps:core
@@ -282,7 +283,7 @@ $0
282//- /lib.rs crate:core 283//- /lib.rs crate:core
283// empty 284// empty
284"#, 285"#,
285 s 286 ra_fixture
286 ); 287 );
287 288
288 let (db, file_pos) = TestDB::with_position(&fixture); 289 let (db, file_pos) = TestDB::with_position(&fixture);
@@ -314,66 +315,57 @@ $0
314 parsed.text().to_string() 315 parsed.text().to_string()
315 } 316 }
316 317
318 fn check_derive(ra_fixture: &str, name: Name, expected: Expect) {
319 let expanded = expand_builtin_derive(ra_fixture, name);
320 expected.assert_eq(&expanded);
321 }
322
317 #[test] 323 #[test]
318 fn test_copy_expand_simple() { 324 fn test_copy_expand_simple() {
319 let expanded = expand_builtin_derive( 325 check_derive(
320 r#" 326 r#"
321 #[derive(Copy)] 327 #[derive(Copy)]
322 struct Foo; 328 struct Foo;
323"#, 329 "#,
324 known::Copy, 330 known::Copy,
331 expect![["impl< >core::marker::CopyforFoo< >{}"]],
325 ); 332 );
326
327 assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}");
328 } 333 }
329 334
330 #[test] 335 #[test]
331 fn test_copy_expand_with_type_params() { 336 fn test_copy_expand_with_type_params() {
332 let expanded = expand_builtin_derive( 337 check_derive(
333 r#" 338 r#"
334 #[derive(Copy)] 339 #[derive(Copy)]
335 struct Foo<A, B>; 340 struct Foo<A, B>;
336"#, 341 "#,
337 known::Copy, 342 known::Copy,
338 ); 343 expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
339
340 assert_eq!(
341 expanded,
342 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
343 ); 344 );
344 } 345 }
345 346
346 #[test] 347 #[test]
347 fn test_copy_expand_with_lifetimes() { 348 fn test_copy_expand_with_lifetimes() {
348 let expanded = expand_builtin_derive( 349 check_derive(
349 r#" 350 r#"
350 #[derive(Copy)] 351 #[derive(Copy)]
351 struct Foo<A, B, 'a, 'b>; 352 struct Foo<A, B, 'a, 'b>;
352"#, 353 "#,
353 known::Copy, 354 known::Copy,
354 ); 355 // We currently just ignore lifetimes
355 356 expect![["impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"]],
356 // We currently just ignore lifetimes
357
358 assert_eq!(
359 expanded,
360 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
361 ); 357 );
362 } 358 }
363 359
364 #[test] 360 #[test]
365 fn test_clone_expand() { 361 fn test_clone_expand() {
366 let expanded = expand_builtin_derive( 362 check_derive(
367 r#" 363 r#"
368 #[derive(Clone)] 364 #[derive(Clone)]
369 struct Foo<A, B>; 365 struct Foo<A, B>;
370"#, 366 "#,
371 known::Clone, 367 known::Clone,
372 ); 368 expect![["impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"]],
373
374 assert_eq!(
375 expanded,
376 "impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"
377 ); 369 );
378 } 370 }
379} 371}
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 57bc6fbd7..2a79c892b 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -5,8 +5,9 @@ use crate::{
5}; 5};
6 6
7use base_db::{AnchoredPath, FileId}; 7use base_db::{AnchoredPath, FileId};
8use cfg::CfgExpr;
8use either::Either; 9use either::Either;
9use mbe::{parse_to_token_tree, ExpandResult}; 10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 11use parser::FragmentKind;
11use syntax::ast::{self, AstToken}; 12use syntax::ast::{self, AstToken};
12 13
@@ -97,6 +98,7 @@ register_builtin! {
97 (format_args_nl, FormatArgsNl) => format_args_expand, 98 (format_args_nl, FormatArgsNl) => format_args_expand,
98 (llvm_asm, LlvmAsm) => asm_expand, 99 (llvm_asm, LlvmAsm) => asm_expand,
99 (asm, Asm) => asm_expand, 100 (asm, Asm) => asm_expand,
101 (cfg, Cfg) => cfg_expand,
100 102
101 EAGER: 103 EAGER:
102 (compile_error, CompileError) => compile_error_expand, 104 (compile_error, CompileError) => compile_error_expand,
@@ -182,25 +184,10 @@ fn assert_expand(
182 // ```, 184 // ```,
183 // which is wrong but useful. 185 // which is wrong but useful.
184 186
185 let mut args = Vec::new(); 187 let args = parse_exprs_with_sep(tt, ',');
186 let mut current = Vec::new();
187 for tt in tt.token_trees.iter().cloned() {
188 match tt {
189 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
190 args.push(current);
191 current = Vec::new();
192 }
193 _ => {
194 current.push(tt);
195 }
196 }
197 }
198 if !current.is_empty() {
199 args.push(current);
200 }
201 188
202 let arg_tts = args.into_iter().flat_map(|arg| { 189 let arg_tts = args.into_iter().flat_map(|arg| {
203 quote! { &(##arg), } 190 quote! { &(#arg), }
204 }.token_trees).collect::<Vec<_>>(); 191 }.token_trees).collect::<Vec<_>>();
205 192
206 let expanded = quote! { 193 let expanded = quote! {
@@ -238,35 +225,21 @@ fn format_args_expand(
238 // ]) 225 // ])
239 // ```, 226 // ```,
240 // which is still not really correct, but close enough for now 227 // which is still not really correct, but close enough for now
241 let mut args = Vec::new(); 228 let mut args = parse_exprs_with_sep(tt, ',');
242 let mut current = Vec::new(); 229
243 for tt in tt.token_trees.iter().cloned() {
244 match tt {
245 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
246 args.push(current);
247 current = Vec::new();
248 }
249 _ => {
250 current.push(tt);
251 }
252 }
253 }
254 if !current.is_empty() {
255 args.push(current);
256 }
257 if args.is_empty() { 230 if args.is_empty() {
258 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); 231 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule);
259 } 232 }
260 for arg in &mut args { 233 for arg in &mut args {
261 // Remove `key =`. 234 // Remove `key =`.
262 if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) 235 if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint)
263 { 236 {
264 arg.drain(..2); 237 arg.token_trees.drain(..2);
265 } 238 }
266 } 239 }
267 let _format_string = args.remove(0); 240 let _format_string = args.remove(0);
268 let arg_tts = args.into_iter().flat_map(|arg| { 241 let arg_tts = args.into_iter().flat_map(|arg| {
269 quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), } 242 quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
270 }.token_trees).collect::<Vec<_>>(); 243 }.token_trees).collect::<Vec<_>>();
271 let expanded = quote! { 244 let expanded = quote! {
272 std::fmt::Arguments::new_v1(&[], &[##arg_tts]) 245 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
@@ -287,6 +260,18 @@ fn asm_expand(
287 ExpandResult::ok(expanded) 260 ExpandResult::ok(expanded)
288} 261}
289 262
263fn cfg_expand(
264 db: &dyn AstDatabase,
265 id: LazyMacroId,
266 tt: &tt::Subtree,
267) -> ExpandResult<tt::Subtree> {
268 let loc = db.lookup_intern_macro(id);
269 let expr = CfgExpr::parse(tt);
270 let enabled = db.crate_graph()[loc.krate].cfg_options.check(&expr) != Some(false);
271 let expanded = if enabled { quote!(true) } else { quote!(false) };
272 ExpandResult::ok(expanded)
273}
274
290fn unquote_str(lit: &tt::Literal) -> Option<String> { 275fn unquote_str(lit: &tt::Literal) -> Option<String> {
291 let lit = ast::make::tokens::literal(&lit.to_string()); 276 let lit = ast::make::tokens::literal(&lit.to_string());
292 let token = ast::String::cast(lit)?; 277 let token = ast::String::cast(lit)?;
@@ -506,6 +491,7 @@ mod tests {
506 MacroCallLoc, 491 MacroCallLoc,
507 }; 492 };
508 use base_db::{fixture::WithFixture, SourceDatabase}; 493 use base_db::{fixture::WithFixture, SourceDatabase};
494 use expect_test::{expect, Expect};
509 use std::sync::Arc; 495 use std::sync::Arc;
510 use syntax::ast::NameOwner; 496 use syntax::ast::NameOwner;
511 497
@@ -589,87 +575,86 @@ mod tests {
589 db.parse_or_expand(file_id).unwrap().to_string() 575 db.parse_or_expand(file_id).unwrap().to_string()
590 } 576 }
591 577
578 fn check_expansion(ra_fixture: &str, expect: Expect) {
579 let expansion = expand_builtin_macro(ra_fixture);
580 expect.assert_eq(&expansion);
581 }
582
592 #[test] 583 #[test]
593 fn test_column_expand() { 584 fn test_column_expand() {
594 let expanded = expand_builtin_macro( 585 check_expansion(
595 r#" 586 r#"
596 #[rustc_builtin_macro] 587 #[rustc_builtin_macro]
597 macro_rules! column {() => {}} 588 macro_rules! column {() => {}}
598 column!() 589 column!()
599 "#, 590 "#,
591 expect![["0"]],
600 ); 592 );
601
602 assert_eq!(expanded, "0");
603 } 593 }
604 594
605 #[test] 595 #[test]
606 fn test_line_expand() { 596 fn test_line_expand() {
607 let expanded = expand_builtin_macro( 597 check_expansion(
608 r#" 598 r#"
609 #[rustc_builtin_macro] 599 #[rustc_builtin_macro]
610 macro_rules! line {() => {}} 600 macro_rules! line {() => {}}
611 line!() 601 line!()
612 "#, 602 "#,
603 expect![["0"]],
613 ); 604 );
614
615 assert_eq!(expanded, "0");
616 } 605 }
617 606
618 #[test] 607 #[test]
619 fn test_stringify_expand() { 608 fn test_stringify_expand() {
620 let expanded = expand_builtin_macro( 609 check_expansion(
621 r#" 610 r#"
622 #[rustc_builtin_macro] 611 #[rustc_builtin_macro]
623 macro_rules! stringify {() => {}} 612 macro_rules! stringify {() => {}}
624 stringify!(a b c) 613 stringify!(a b c)
625 "#, 614 "#,
615 expect![["\"a b c\""]],
626 ); 616 );
627
628 assert_eq!(expanded, "\"a b c\"");
629 } 617 }
630 618
631 #[test] 619 #[test]
632 fn test_env_expand() { 620 fn test_env_expand() {
633 let expanded = expand_builtin_macro( 621 check_expansion(
634 r#" 622 r#"
635 #[rustc_builtin_macro] 623 #[rustc_builtin_macro]
636 macro_rules! env {() => {}} 624 macro_rules! env {() => {}}
637 env!("TEST_ENV_VAR") 625 env!("TEST_ENV_VAR")
638 "#, 626 "#,
627 expect![["\"__RA_UNIMPLEMENTED__\""]],
639 ); 628 );
640
641 assert_eq!(expanded, "\"__RA_UNIMPLEMENTED__\"");
642 } 629 }
643 630
644 #[test] 631 #[test]
645 fn test_option_env_expand() { 632 fn test_option_env_expand() {
646 let expanded = expand_builtin_macro( 633 check_expansion(
647 r#" 634 r#"
648 #[rustc_builtin_macro] 635 #[rustc_builtin_macro]
649 macro_rules! option_env {() => {}} 636 macro_rules! option_env {() => {}}
650 option_env!("TEST_ENV_VAR") 637 option_env!("TEST_ENV_VAR")
651 "#, 638 "#,
639 expect![["std::option::Option::None:: < &str>"]],
652 ); 640 );
653
654 assert_eq!(expanded, "std::option::Option::None:: < &str>");
655 } 641 }
656 642
657 #[test] 643 #[test]
658 fn test_file_expand() { 644 fn test_file_expand() {
659 let expanded = expand_builtin_macro( 645 check_expansion(
660 r#" 646 r#"
661 #[rustc_builtin_macro] 647 #[rustc_builtin_macro]
662 macro_rules! file {() => {}} 648 macro_rules! file {() => {}}
663 file!() 649 file!()
664 "#, 650 "#,
651 expect![[r#""""#]],
665 ); 652 );
666
667 assert_eq!(expanded, "\"\"");
668 } 653 }
669 654
670 #[test] 655 #[test]
671 fn test_assert_expand() { 656 fn test_assert_expand() {
672 let expanded = expand_builtin_macro( 657 check_expansion(
673 r#" 658 r#"
674 #[rustc_builtin_macro] 659 #[rustc_builtin_macro]
675 macro_rules! assert { 660 macro_rules! assert {
@@ -678,14 +663,13 @@ mod tests {
678 } 663 }
679 assert!(true, "{} {:?}", arg1(a, b, c), arg2); 664 assert!(true, "{} {:?}", arg1(a, b, c), arg2);
680 "#, 665 "#,
666 expect![["{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}"]],
681 ); 667 );
682
683 assert_eq!(expanded, "{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}");
684 } 668 }
685 669
686 #[test] 670 #[test]
687 fn test_compile_error_expand() { 671 fn test_compile_error_expand() {
688 let expanded = expand_builtin_macro( 672 check_expansion(
689 r#" 673 r#"
690 #[rustc_builtin_macro] 674 #[rustc_builtin_macro]
691 macro_rules! compile_error { 675 macro_rules! compile_error {
@@ -694,15 +678,14 @@ mod tests {
694 } 678 }
695 compile_error!("error!"); 679 compile_error!("error!");
696 "#, 680 "#,
681 // This expands to nothing (since it's in item position), but emits an error.
682 expect![[""]],
697 ); 683 );
698
699 // This expands to nothing (since it's in item position), but emits an error.
700 assert_eq!(expanded, "");
701 } 684 }
702 685
703 #[test] 686 #[test]
704 fn test_format_args_expand() { 687 fn test_format_args_expand() {
705 let expanded = expand_builtin_macro( 688 check_expansion(
706 r#" 689 r#"
707 #[rustc_builtin_macro] 690 #[rustc_builtin_macro]
708 macro_rules! format_args { 691 macro_rules! format_args {
@@ -711,17 +694,32 @@ mod tests {
711 } 694 }
712 format_args!("{} {:?}", arg1(a, b, c), arg2); 695 format_args!("{} {:?}", arg1(a, b, c), arg2);
713 "#, 696 "#,
697 expect![[
698 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
699 ]],
714 ); 700 );
701 }
715 702
716 assert_eq!( 703 #[test]
717 expanded, 704 fn test_format_args_expand_with_comma_exprs() {
718 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"# 705 check_expansion(
706 r#"
707 #[rustc_builtin_macro]
708 macro_rules! format_args {
709 ($fmt:expr) => ({ /* compiler built-in */ });
710 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
711 }
712 format_args!("{} {:?}", a::<A,B>(), b);
713 "#,
714 expect![[
715 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"#
716 ]],
719 ); 717 );
720 } 718 }
721 719
722 #[test] 720 #[test]
723 fn test_include_bytes_expand() { 721 fn test_include_bytes_expand() {
724 let expanded = expand_builtin_macro( 722 check_expansion(
725 r#" 723 r#"
726 #[rustc_builtin_macro] 724 #[rustc_builtin_macro]
727 macro_rules! include_bytes { 725 macro_rules! include_bytes {
@@ -730,21 +728,19 @@ mod tests {
730 } 728 }
731 include_bytes("foo"); 729 include_bytes("foo");
732 "#, 730 "#,
731 expect![[r#"b"""#]],
733 ); 732 );
734
735 assert_eq!(expanded, r#"b"""#);
736 } 733 }
737 734
738 #[test] 735 #[test]
739 fn test_concat_expand() { 736 fn test_concat_expand() {
740 let expanded = expand_builtin_macro( 737 check_expansion(
741 r##" 738 r##"
742 #[rustc_builtin_macro] 739 #[rustc_builtin_macro]
743 macro_rules! concat {} 740 macro_rules! concat {}
744 concat!("foo", "r", 0, r#"bar"#, false); 741 concat!("foo", "r", 0, r#"bar"#, false);
745 "##, 742 "##,
743 expect![[r#""foor0barfalse""#]],
746 ); 744 );
747
748 assert_eq!(expanded, r#""foor0barfalse""#);
749 } 745 }
750} 746}
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index cb6e23320..9086e6c17 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -340,6 +340,8 @@ fn parse_macro_with_arg(
340 None => return ExpandResult { value: None, err: result.err }, 340 None => return ExpandResult { value: None, err: result.err },
341 }; 341 };
342 342
343 log::debug!("expanded = {}", tt.as_debug_string());
344
343 let fragment_kind = to_fragment_kind(db, macro_call_id); 345 let fragment_kind = to_fragment_kind(db, macro_call_id);
344 346
345 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { 347 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index c94fb580a..e833e032c 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -154,6 +154,7 @@ pub mod known {
154 macro_rules, 154 macro_rules,
155 derive, 155 derive,
156 doc, 156 doc,
157 cfg,
157 cfg_attr, 158 cfg_attr,
158 // Components of known path (value or mod name) 159 // Components of known path (value or mod name)
159 std, 160 std,
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs
index 219bc2097..08bc5aa49 100644
--- a/crates/hir_expand/src/quote.rs
+++ b/crates/hir_expand/src/quote.rs
@@ -188,8 +188,9 @@ macro_rules! impl_to_to_tokentrees {
188 188
189impl_to_to_tokentrees! { 189impl_to_to_tokentrees! {
190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} }; 190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}}; 191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}}; 192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
193 bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
193 tt::Leaf => self { self }; 194 tt::Leaf => self { self };
194 tt::Literal => self { self }; 195 tt::Literal => self { self };
195 tt::Ident => self { self }; 196 tt::Ident => self { self };