mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-31 23:38:45 +00:00
990c48cb0d
fix: Get rid of `$crate` in expansions shown to the user Be it "Expand Macro Recursively", "Inline macro" or few other things. We replace it with the crate name, as should've always been. Probably fixes some issues, but I don't know what they are.
332 lines
8.5 KiB
Rust
332 lines
8.5 KiB
Rust
//! Tests specific to declarative macros, aka macros by example. This covers
|
|
//! both stable `macro_rules!` macros as well as unstable `macro` macros.
|
|
// FIXME: Move more of the nameres independent tests from
|
|
// crates\hir-def\src\macro_expansion_tests\mod.rs to this
|
|
use expect_test::expect;
|
|
use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId};
|
|
use stdx::format_to;
|
|
use tt::{TextRange, TextSize};
|
|
|
|
use crate::DeclarativeMacro;
|
|
|
|
#[expect(deprecated)]
|
|
fn check_(
|
|
def_edition: Edition,
|
|
call_edition: Edition,
|
|
macro2: bool,
|
|
decl: &str,
|
|
arg: &str,
|
|
render_debug: bool,
|
|
expect: expect_test::Expect,
|
|
parse: parser::TopEntryPoint,
|
|
) {
|
|
let decl_tt = &syntax_bridge::parse_to_token_tree(
|
|
def_edition,
|
|
SpanAnchor {
|
|
file_id: EditionedFileId::new(FileId::from_raw(0), def_edition),
|
|
ast_id: ErasedFileAstId::from_raw(0),
|
|
},
|
|
SyntaxContextId::ROOT,
|
|
decl,
|
|
)
|
|
.unwrap();
|
|
let mac = if macro2 {
|
|
DeclarativeMacro::parse_macro2(None, decl_tt, |_| def_edition)
|
|
} else {
|
|
DeclarativeMacro::parse_macro_rules(decl_tt, |_| def_edition)
|
|
};
|
|
let call_anchor = SpanAnchor {
|
|
file_id: EditionedFileId::new(FileId::from_raw(1), call_edition),
|
|
ast_id: ErasedFileAstId::from_raw(0),
|
|
};
|
|
let arg_tt =
|
|
syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg)
|
|
.unwrap();
|
|
let res = mac.expand(
|
|
&arg_tt,
|
|
|_| (),
|
|
Span {
|
|
range: TextRange::up_to(TextSize::of(arg)),
|
|
anchor: call_anchor,
|
|
ctx: SyntaxContextId::ROOT,
|
|
},
|
|
def_edition,
|
|
);
|
|
let mut expect_res = String::new();
|
|
if let Some(err) = res.err {
|
|
format_to!(expect_res, "{err:#?}\n\n",);
|
|
}
|
|
if render_debug {
|
|
format_to!(expect_res, "{:#?}\n\n", res.value.0);
|
|
}
|
|
let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition);
|
|
format_to!(
|
|
expect_res,
|
|
"{}",
|
|
syntax_bridge::prettify_macro_expansion::prettify_macro_expansion(
|
|
node.syntax_node(),
|
|
&mut |it| it.clone()
|
|
)
|
|
);
|
|
expect.assert_eq(&expect_res);
|
|
}
|
|
|
|
fn check(
|
|
def_edition: Edition,
|
|
call_edition: Edition,
|
|
decl: &str,
|
|
arg: &str,
|
|
expect: expect_test::Expect,
|
|
) {
|
|
check_(
|
|
def_edition,
|
|
call_edition,
|
|
false,
|
|
decl,
|
|
arg,
|
|
true,
|
|
expect,
|
|
parser::TopEntryPoint::SourceFile,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn token_mapping_smoke_test() {
|
|
check(
|
|
Edition::CURRENT,
|
|
Edition::CURRENT,
|
|
r#"
|
|
( struct $ident:ident ) => {
|
|
struct $ident {
|
|
map: ::std::collections::HashSet<()>,
|
|
}
|
|
};
|
|
"#,
|
|
r#"
|
|
struct MyTraitMap2
|
|
"#,
|
|
expect![[r#"
|
|
SUBTREE $$ 1:0@0..20#0 1:0@0..20#0
|
|
IDENT struct 0:0@34..40#0
|
|
IDENT MyTraitMap2 1:0@8..19#0
|
|
SUBTREE {} 0:0@48..49#0 0:0@100..101#0
|
|
IDENT map 0:0@58..61#0
|
|
PUNCH : [alone] 0:0@61..62#0
|
|
PUNCH : [joint] 0:0@63..64#0
|
|
PUNCH : [alone] 0:0@64..65#0
|
|
IDENT std 0:0@65..68#0
|
|
PUNCH : [joint] 0:0@68..69#0
|
|
PUNCH : [alone] 0:0@69..70#0
|
|
IDENT collections 0:0@70..81#0
|
|
PUNCH : [joint] 0:0@81..82#0
|
|
PUNCH : [alone] 0:0@82..83#0
|
|
IDENT HashSet 0:0@83..90#0
|
|
PUNCH < [alone] 0:0@90..91#0
|
|
SUBTREE () 0:0@91..92#0 0:0@92..93#0
|
|
PUNCH > [joint] 0:0@93..94#0
|
|
PUNCH , [alone] 0:0@94..95#0
|
|
|
|
struct MyTraitMap2 {
|
|
map: ::std::collections::HashSet<()>,
|
|
}"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn token_mapping_floats() {
|
|
// Regression test for https://github.com/rust-lang/rust-analyzer/issues/12216
|
|
// (and related issues)
|
|
check(
|
|
Edition::CURRENT,
|
|
Edition::CURRENT,
|
|
r#"
|
|
($($tt:tt)*) => {
|
|
$($tt)*
|
|
};
|
|
"#,
|
|
r#"
|
|
fn main() {
|
|
1;
|
|
1.0;
|
|
((1,),).0.0;
|
|
let x = 1;
|
|
}
|
|
"#,
|
|
expect![[r#"
|
|
SUBTREE $$ 1:0@0..63#0 1:0@0..63#0
|
|
IDENT fn 1:0@1..3#0
|
|
IDENT main 1:0@4..8#0
|
|
SUBTREE () 1:0@8..9#0 1:0@9..10#0
|
|
SUBTREE {} 1:0@11..12#0 1:0@61..62#0
|
|
LITERAL Integer 1 1:0@17..18#0
|
|
PUNCH ; [alone] 1:0@18..19#0
|
|
LITERAL Float 1.0 1:0@24..27#0
|
|
PUNCH ; [alone] 1:0@27..28#0
|
|
SUBTREE () 1:0@33..34#0 1:0@39..40#0
|
|
SUBTREE () 1:0@34..35#0 1:0@37..38#0
|
|
LITERAL Integer 1 1:0@35..36#0
|
|
PUNCH , [alone] 1:0@36..37#0
|
|
PUNCH , [alone] 1:0@38..39#0
|
|
PUNCH . [alone] 1:0@40..41#0
|
|
LITERAL Float 0.0 1:0@41..44#0
|
|
PUNCH ; [alone] 1:0@44..45#0
|
|
IDENT let 1:0@50..53#0
|
|
IDENT x 1:0@54..55#0
|
|
PUNCH = [alone] 1:0@56..57#0
|
|
LITERAL Integer 1 1:0@58..59#0
|
|
PUNCH ; [alone] 1:0@59..60#0
|
|
|
|
fn main(){
|
|
1;
|
|
1.0;
|
|
((1,),).0.0;
|
|
let x = 1;
|
|
}"#]],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn expr_2021() {
|
|
check(
|
|
Edition::Edition2024,
|
|
Edition::Edition2024,
|
|
r#"
|
|
($($e:expr),* $(,)?) => {
|
|
$($e);* ;
|
|
};
|
|
"#,
|
|
r#"
|
|
_,
|
|
const { 1 },
|
|
"#,
|
|
expect![[r#"
|
|
SUBTREE $$ 1:0@0..25#0 1:0@0..25#0
|
|
IDENT _ 1:0@5..6#0
|
|
PUNCH ; [joint] 0:0@36..37#0
|
|
SUBTREE () 0:0@34..35#0 0:0@34..35#0
|
|
IDENT const 1:0@12..17#0
|
|
SUBTREE {} 1:0@18..19#0 1:0@22..23#0
|
|
LITERAL Integer 1 1:0@20..21#0
|
|
PUNCH ; [alone] 0:0@39..40#0
|
|
|
|
_;
|
|
(const {
|
|
1
|
|
});"#]],
|
|
);
|
|
check(
|
|
Edition::Edition2021,
|
|
Edition::Edition2024,
|
|
r#"
|
|
($($e:expr),* $(,)?) => {
|
|
$($e);* ;
|
|
};
|
|
"#,
|
|
r#"
|
|
_,
|
|
"#,
|
|
expect![[r#"
|
|
ExpandError {
|
|
inner: (
|
|
1:0@5..6#0,
|
|
NoMatchingRule,
|
|
),
|
|
}
|
|
|
|
SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
|
|
PUNCH ; [alone] 0:0@39..40#0
|
|
|
|
;"#]],
|
|
);
|
|
check(
|
|
Edition::Edition2021,
|
|
Edition::Edition2024,
|
|
r#"
|
|
($($e:expr),* $(,)?) => {
|
|
$($e);* ;
|
|
};
|
|
"#,
|
|
r#"
|
|
const { 1 },
|
|
"#,
|
|
expect![[r#"
|
|
ExpandError {
|
|
inner: (
|
|
1:0@5..10#0,
|
|
NoMatchingRule,
|
|
),
|
|
}
|
|
|
|
SUBTREE $$ 1:0@0..18#0 1:0@0..18#0
|
|
PUNCH ; [alone] 0:0@39..40#0
|
|
|
|
;"#]],
|
|
);
|
|
check(
|
|
Edition::Edition2024,
|
|
Edition::Edition2024,
|
|
r#"
|
|
($($e:expr_2021),* $(,)?) => {
|
|
$($e);* ;
|
|
};
|
|
"#,
|
|
r#"
|
|
4,
|
|
"literal",
|
|
funcall(),
|
|
future.await,
|
|
break 'foo bar,
|
|
"#,
|
|
expect![[r#"
|
|
SUBTREE $$ 1:0@0..76#0 1:0@0..76#0
|
|
LITERAL Integer 4 1:0@5..6#0
|
|
PUNCH ; [joint] 0:0@41..42#0
|
|
LITERAL Str literal 1:0@12..21#0
|
|
PUNCH ; [joint] 0:0@41..42#0
|
|
SUBTREE () 0:0@39..40#0 0:0@39..40#0
|
|
IDENT funcall 1:0@27..34#0
|
|
SUBTREE () 1:0@34..35#0 1:0@35..36#0
|
|
PUNCH ; [joint] 0:0@41..42#0
|
|
SUBTREE () 0:0@39..40#0 0:0@39..40#0
|
|
IDENT future 1:0@42..48#0
|
|
PUNCH . [alone] 1:0@48..49#0
|
|
IDENT await 1:0@49..54#0
|
|
PUNCH ; [joint] 0:0@41..42#0
|
|
SUBTREE () 0:0@39..40#0 0:0@39..40#0
|
|
IDENT break 1:0@60..65#0
|
|
PUNCH ' [joint] 1:0@66..67#0
|
|
IDENT foo 1:0@67..70#0
|
|
IDENT bar 1:0@71..74#0
|
|
PUNCH ; [alone] 0:0@44..45#0
|
|
|
|
4;
|
|
"literal";
|
|
(funcall());
|
|
(future.await);
|
|
(break 'foo bar);"#]],
|
|
);
|
|
check(
|
|
Edition::Edition2024,
|
|
Edition::Edition2024,
|
|
r#"
|
|
($($e:expr_2021),* $(,)?) => {
|
|
$($e);* ;
|
|
};
|
|
"#,
|
|
r#"
|
|
_,
|
|
"#,
|
|
expect![[r#"
|
|
ExpandError {
|
|
inner: (
|
|
1:0@5..6#0,
|
|
NoMatchingRule,
|
|
),
|
|
}
|
|
|
|
SUBTREE $$ 1:0@0..8#0 1:0@0..8#0
|
|
PUNCH ; [alone] 0:0@44..45#0
|
|
|
|
;"#]],
|
|
);
|
|
}
|