aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand')
-rw-r--r--crates/hir_expand/Cargo.toml6
-rw-r--r--crates/hir_expand/src/builtin_derive.rs66
-rw-r--r--crates/hir_expand/src/builtin_macro.rs92
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/hir_expand/src/quote.rs5
5 files changed, 87 insertions, 83 deletions
diff --git a/crates/hir_expand/Cargo.toml b/crates/hir_expand/Cargo.toml
index 5271110d2..f649ab925 100644
--- a/crates/hir_expand/Cargo.toml
+++ b/crates/hir_expand/Cargo.toml
@@ -16,9 +16,13 @@ rustc-hash = "1.0.0"
16la-arena = { version = "0.2.0", path = "../../lib/arena" } 16la-arena = { version = "0.2.0", path = "../../lib/arena" }
17 17
18base_db = { path = "../base_db", version = "0.0.0" } 18base_db = { path = "../base_db", version = "0.0.0" }
19cfg = { path = "../cfg", version = "0.0.0" }
19syntax = { path = "../syntax", version = "0.0.0" } 20syntax = { path = "../syntax", version = "0.0.0" }
20parser = { path = "../parser", version = "0.0.0" } 21parser = { path = "../parser", version = "0.0.0" }
21profile = { path = "../profile", version = "0.0.0" } 22profile = { path = "../profile", version = "0.0.0" }
22tt = { path = "../tt", version = "0.0.0" } 23tt = { path = "../tt", version = "0.0.0" }
23mbe = { path = "../mbe", version = "0.0.0" } 24mbe = { path = "../mbe", version = "0.0.0" }
24test_utils = { path = "../test_utils", version = "0.0.0" } 25
26[dev-dependencies]
27test_utils = { path = "../test_utils" }
28expect-test = "1.1"
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 eb57ea7d6..2a79c892b 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -5,6 +5,7 @@ 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_exprs_with_sep, parse_to_token_tree, ExpandResult}; 10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 11use parser::FragmentKind;
@@ -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,
@@ -258,6 +260,18 @@ fn asm_expand(
258 ExpandResult::ok(expanded) 260 ExpandResult::ok(expanded)
259} 261}
260 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
261fn unquote_str(lit: &tt::Literal) -> Option<String> { 275fn unquote_str(lit: &tt::Literal) -> Option<String> {
262 let lit = ast::make::tokens::literal(&lit.to_string()); 276 let lit = ast::make::tokens::literal(&lit.to_string());
263 let token = ast::String::cast(lit)?; 277 let token = ast::String::cast(lit)?;
@@ -477,6 +491,7 @@ mod tests {
477 MacroCallLoc, 491 MacroCallLoc,
478 }; 492 };
479 use base_db::{fixture::WithFixture, SourceDatabase}; 493 use base_db::{fixture::WithFixture, SourceDatabase};
494 use expect_test::{expect, Expect};
480 use std::sync::Arc; 495 use std::sync::Arc;
481 use syntax::ast::NameOwner; 496 use syntax::ast::NameOwner;
482 497
@@ -560,87 +575,86 @@ mod tests {
560 db.parse_or_expand(file_id).unwrap().to_string() 575 db.parse_or_expand(file_id).unwrap().to_string()
561 } 576 }
562 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
563 #[test] 583 #[test]
564 fn test_column_expand() { 584 fn test_column_expand() {
565 let expanded = expand_builtin_macro( 585 check_expansion(
566 r#" 586 r#"
567 #[rustc_builtin_macro] 587 #[rustc_builtin_macro]
568 macro_rules! column {() => {}} 588 macro_rules! column {() => {}}
569 column!() 589 column!()
570 "#, 590 "#,
591 expect![["0"]],
571 ); 592 );
572
573 assert_eq!(expanded, "0");
574 } 593 }
575 594
576 #[test] 595 #[test]
577 fn test_line_expand() { 596 fn test_line_expand() {
578 let expanded = expand_builtin_macro( 597 check_expansion(
579 r#" 598 r#"
580 #[rustc_builtin_macro] 599 #[rustc_builtin_macro]
581 macro_rules! line {() => {}} 600 macro_rules! line {() => {}}
582 line!() 601 line!()
583 "#, 602 "#,
603 expect![["0"]],
584 ); 604 );
585
586 assert_eq!(expanded, "0");
587 } 605 }
588 606
589 #[test] 607 #[test]
590 fn test_stringify_expand() { 608 fn test_stringify_expand() {
591 let expanded = expand_builtin_macro( 609 check_expansion(
592 r#" 610 r#"
593 #[rustc_builtin_macro] 611 #[rustc_builtin_macro]
594 macro_rules! stringify {() => {}} 612 macro_rules! stringify {() => {}}
595 stringify!(a b c) 613 stringify!(a b c)
596 "#, 614 "#,
615 expect![["\"a b c\""]],
597 ); 616 );
598
599 assert_eq!(expanded, "\"a b c\"");
600 } 617 }
601 618
602 #[test] 619 #[test]
603 fn test_env_expand() { 620 fn test_env_expand() {
604 let expanded = expand_builtin_macro( 621 check_expansion(
605 r#" 622 r#"
606 #[rustc_builtin_macro] 623 #[rustc_builtin_macro]
607 macro_rules! env {() => {}} 624 macro_rules! env {() => {}}
608 env!("TEST_ENV_VAR") 625 env!("TEST_ENV_VAR")
609 "#, 626 "#,
627 expect![["\"__RA_UNIMPLEMENTED__\""]],
610 ); 628 );
611
612 assert_eq!(expanded, "\"__RA_UNIMPLEMENTED__\"");
613 } 629 }
614 630
615 #[test] 631 #[test]
616 fn test_option_env_expand() { 632 fn test_option_env_expand() {
617 let expanded = expand_builtin_macro( 633 check_expansion(
618 r#" 634 r#"
619 #[rustc_builtin_macro] 635 #[rustc_builtin_macro]
620 macro_rules! option_env {() => {}} 636 macro_rules! option_env {() => {}}
621 option_env!("TEST_ENV_VAR") 637 option_env!("TEST_ENV_VAR")
622 "#, 638 "#,
639 expect![["std::option::Option::None:: < &str>"]],
623 ); 640 );
624
625 assert_eq!(expanded, "std::option::Option::None:: < &str>");
626 } 641 }
627 642
628 #[test] 643 #[test]
629 fn test_file_expand() { 644 fn test_file_expand() {
630 let expanded = expand_builtin_macro( 645 check_expansion(
631 r#" 646 r#"
632 #[rustc_builtin_macro] 647 #[rustc_builtin_macro]
633 macro_rules! file {() => {}} 648 macro_rules! file {() => {}}
634 file!() 649 file!()
635 "#, 650 "#,
651 expect![[r#""""#]],
636 ); 652 );
637
638 assert_eq!(expanded, "\"\"");
639 } 653 }
640 654
641 #[test] 655 #[test]
642 fn test_assert_expand() { 656 fn test_assert_expand() {
643 let expanded = expand_builtin_macro( 657 check_expansion(
644 r#" 658 r#"
645 #[rustc_builtin_macro] 659 #[rustc_builtin_macro]
646 macro_rules! assert { 660 macro_rules! assert {
@@ -649,14 +663,13 @@ mod tests {
649 } 663 }
650 assert!(true, "{} {:?}", arg1(a, b, c), arg2); 664 assert!(true, "{} {:?}", arg1(a, b, c), arg2);
651 "#, 665 "#,
666 expect![["{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}"]],
652 ); 667 );
653
654 assert_eq!(expanded, "{{(&(true), &(\"{} {:?}\"), &(arg1(a,b,c)), &(arg2),);}}");
655 } 668 }
656 669
657 #[test] 670 #[test]
658 fn test_compile_error_expand() { 671 fn test_compile_error_expand() {
659 let expanded = expand_builtin_macro( 672 check_expansion(
660 r#" 673 r#"
661 #[rustc_builtin_macro] 674 #[rustc_builtin_macro]
662 macro_rules! compile_error { 675 macro_rules! compile_error {
@@ -665,15 +678,14 @@ mod tests {
665 } 678 }
666 compile_error!("error!"); 679 compile_error!("error!");
667 "#, 680 "#,
681 // This expands to nothing (since it's in item position), but emits an error.
682 expect![[""]],
668 ); 683 );
669
670 // This expands to nothing (since it's in item position), but emits an error.
671 assert_eq!(expanded, "");
672 } 684 }
673 685
674 #[test] 686 #[test]
675 fn test_format_args_expand() { 687 fn test_format_args_expand() {
676 let expanded = expand_builtin_macro( 688 check_expansion(
677 r#" 689 r#"
678 #[rustc_builtin_macro] 690 #[rustc_builtin_macro]
679 macro_rules! format_args { 691 macro_rules! format_args {
@@ -682,17 +694,15 @@ mod tests {
682 } 694 }
683 format_args!("{} {:?}", arg1(a, b, c), arg2); 695 format_args!("{} {:?}", arg1(a, b, c), arg2);
684 "#, 696 "#,
685 ); 697 expect![[
686 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),])"#
687 assert_eq!( 699 ]],
688 expanded,
689 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),])"#
690 ); 700 );
691 } 701 }
692 702
693 #[test] 703 #[test]
694 fn test_format_args_expand_with_comma_exprs() { 704 fn test_format_args_expand_with_comma_exprs() {
695 let expanded = expand_builtin_macro( 705 check_expansion(
696 r#" 706 r#"
697 #[rustc_builtin_macro] 707 #[rustc_builtin_macro]
698 macro_rules! format_args { 708 macro_rules! format_args {
@@ -701,17 +711,15 @@ mod tests {
701 } 711 }
702 format_args!("{} {:?}", a::<A,B>(), b); 712 format_args!("{} {:?}", a::<A,B>(), b);
703 "#, 713 "#,
704 ); 714 expect![[
705 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),])"#
706 assert_eq!( 716 ]],
707 expanded,
708 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),])"#
709 ); 717 );
710 } 718 }
711 719
712 #[test] 720 #[test]
713 fn test_include_bytes_expand() { 721 fn test_include_bytes_expand() {
714 let expanded = expand_builtin_macro( 722 check_expansion(
715 r#" 723 r#"
716 #[rustc_builtin_macro] 724 #[rustc_builtin_macro]
717 macro_rules! include_bytes { 725 macro_rules! include_bytes {
@@ -720,21 +728,19 @@ mod tests {
720 } 728 }
721 include_bytes("foo"); 729 include_bytes("foo");
722 "#, 730 "#,
731 expect![[r#"b"""#]],
723 ); 732 );
724
725 assert_eq!(expanded, r#"b"""#);
726 } 733 }
727 734
728 #[test] 735 #[test]
729 fn test_concat_expand() { 736 fn test_concat_expand() {
730 let expanded = expand_builtin_macro( 737 check_expansion(
731 r##" 738 r##"
732 #[rustc_builtin_macro] 739 #[rustc_builtin_macro]
733 macro_rules! concat {} 740 macro_rules! concat {}
734 concat!("foo", "r", 0, r#"bar"#, false); 741 concat!("foo", "r", 0, r#"bar"#, false);
735 "##, 742 "##,
743 expect![[r#""foor0barfalse""#]],
736 ); 744 );
737
738 assert_eq!(expanded, r#""foor0barfalse""#);
739 } 745 }
740} 746}
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 };