Skip to content

Commit 16654ce

Browse files
committed
Create new inline_macro assist.
1 parent 7bf2a25 commit 16654ce

File tree

3 files changed

+277
-0
lines changed

3 files changed

+277
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
use syntax::ast::{self, AstNode};
2+
3+
use crate::{AssistContext, AssistId, AssistKind, Assists};
4+
5+
// Assist: inline_macro
6+
//
7+
// Takes a macro and inlines it one step.
8+
//
9+
// ```
10+
// macro_rules! num {
11+
// (+$($t:tt)+) => (1 + num!($($t )+));
12+
// (-$($t:tt)+) => (-1 + num!($($t )+));
13+
// (+) => (1);
14+
// (-) => (-1);
15+
// }
16+
//
17+
// fn main() {
18+
// let number = num$0!(+ + + - + +);
19+
// println!("{number}");
20+
// }
21+
// ```
22+
// ->
23+
// ```
24+
// macro_rules! num {
25+
// (+$($t:tt)+) => (1 + num!($($t )+));
26+
// (-$($t:tt)+) => (-1 + num!($($t )+));
27+
// (+) => (1);
28+
// (-) => (-1);
29+
// }
30+
//
31+
// fn main() {
32+
// let number = 1+num!(+ + - + +);
33+
// println!("{number}");
34+
// }
35+
// ```
36+
pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
37+
let tok = ctx.token_at_offset().right_biased()?;
38+
39+
let mut anc = tok.parent_ancestors();
40+
let (_name, expanded, unexpanded) = loop {
41+
let node = anc.next()?;
42+
if let Some(mac) = ast::MacroCall::cast(node.clone()) {
43+
break (
44+
mac.path()?.segment()?.name_ref()?.to_string(),
45+
ctx.sema.expand(&mac)?.clone_for_update(),
46+
node,
47+
);
48+
}
49+
};
50+
51+
acc.add(
52+
AssistId("inline_macro", AssistKind::RefactorRewrite),
53+
format!("Inline macro"),
54+
unexpanded.text_range(),
55+
|builder| builder.replace(unexpanded.text_range(), expanded.to_string()),
56+
)
57+
}
58+
59+
#[cfg(test)]
60+
mod tests {
61+
use super::*;
62+
63+
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
64+
65+
macro_rules! simple_macro {
66+
() => {
67+
r#"
68+
macro_rules! foo {
69+
(foo) => (true);
70+
() => (false);
71+
}
72+
"#
73+
};
74+
}
75+
macro_rules! double_macro {
76+
() => {
77+
r#"
78+
macro_rules! bar {
79+
(bar) => (true);
80+
($($tt:tt)?) => (false);
81+
}
82+
macro_rules! foo {
83+
(foo) => (true);
84+
(bar) => (bar!(bar));
85+
($($tt:tt)?) => (bar!($($tt)?));
86+
}
87+
"#
88+
};
89+
}
90+
91+
macro_rules! complex_macro {
92+
() => {
93+
r#"
94+
macro_rules! num {
95+
(+$($t:tt)+) => (1 + num!($($t )+));
96+
(-$($t:tt)+) => (-1 + num!($($t )+));
97+
(+) => (1);
98+
(-) => (-1);
99+
}
100+
"#
101+
};
102+
}
103+
#[test]
104+
fn inline_macro_target() {
105+
check_assist_target(
106+
inline_macro,
107+
concat!(simple_macro!(), r#"fn f() { let a = foo$0!(foo); }"#),
108+
"foo!(foo)",
109+
);
110+
}
111+
112+
#[test]
113+
fn inline_macro_target_start() {
114+
check_assist_target(
115+
inline_macro,
116+
concat!(simple_macro!(), r#"fn f() { let a = $0foo!(foo); }"#),
117+
"foo!(foo)",
118+
);
119+
}
120+
121+
#[test]
122+
fn inline_macro_target_end() {
123+
check_assist_target(
124+
inline_macro,
125+
concat!(simple_macro!(), r#"fn f() { let a = foo!(foo$0); }"#),
126+
"foo!(foo)",
127+
);
128+
}
129+
130+
#[test]
131+
fn inline_macro_simple_case1() {
132+
check_assist(
133+
inline_macro,
134+
concat!(simple_macro!(), r#"fn f() { let result = foo$0!(foo); }"#),
135+
concat!(simple_macro!(), r#"fn f() { let result = true; }"#),
136+
);
137+
}
138+
139+
#[test]
140+
fn inline_macro_simple_case2() {
141+
check_assist(
142+
inline_macro,
143+
concat!(simple_macro!(), r#"fn f() { let result = foo$0!(); }"#),
144+
concat!(simple_macro!(), r#"fn f() { let result = false; }"#),
145+
);
146+
}
147+
148+
#[test]
149+
fn inline_macro_simple_not_applicable() {
150+
check_assist_not_applicable(
151+
inline_macro,
152+
concat!(simple_macro!(), r#"fn f() { let result$0 = foo!(foo); }"#),
153+
);
154+
}
155+
156+
#[test]
157+
fn inline_macro_simple_not_applicable_broken_macro() {
158+
// FIXME: This is a bug. The macro should not expand, but it's
159+
// the same behaviour as the "Expand Macro Recursively" commmand
160+
// so it's presumably OK for the time being.
161+
check_assist(
162+
inline_macro,
163+
concat!(simple_macro!(), r#"fn f() { let result = foo$0!(asdfasdf); }"#),
164+
concat!(simple_macro!(), r#"fn f() { let result = true; }"#),
165+
);
166+
}
167+
168+
#[test]
169+
fn inline_macro_double_case1() {
170+
check_assist(
171+
inline_macro,
172+
concat!(double_macro!(), r#"fn f() { let result = foo$0!(bar); }"#),
173+
concat!(double_macro!(), r#"fn f() { let result = bar!(bar); }"#),
174+
);
175+
}
176+
177+
#[test]
178+
fn inline_macro_double_case2() {
179+
check_assist(
180+
inline_macro,
181+
concat!(double_macro!(), r#"fn f() { let result = foo$0!(asdf); }"#),
182+
concat!(double_macro!(), r#"fn f() { let result = bar!(asdf); }"#),
183+
);
184+
}
185+
186+
#[test]
187+
fn inline_macro_complex_case1() {
188+
check_assist(
189+
inline_macro,
190+
concat!(complex_macro!(), r#"fn f() { let result = num!(+ +$0 + - +); }"#),
191+
concat!(complex_macro!(), r#"fn f() { let result = 1+num!(+ + - +); }"#),
192+
);
193+
}
194+
195+
#[test]
196+
fn inline_macro_complex_case2() {
197+
check_assist(
198+
inline_macro,
199+
concat!(complex_macro!(), r#"fn f() { let result = n$0um!(- + + - +); }"#),
200+
concat!(complex_macro!(), r#"fn f() { let result = -1+num!(+ + - +); }"#),
201+
);
202+
}
203+
204+
#[test]
205+
fn inline_macro_recursive_macro() {
206+
check_assist(
207+
inline_macro,
208+
r#"
209+
macro_rules! foo {
210+
() => {foo!()}
211+
}
212+
fn f() { let result = foo$0!(); }
213+
"#,
214+
r#"
215+
macro_rules! foo {
216+
() => {foo!()}
217+
}
218+
fn f() { let result = foo!(); }
219+
"#,
220+
);
221+
}
222+
223+
#[test]
224+
fn inline_macro_unknown_macro() {
225+
check_assist_not_applicable(
226+
inline_macro,
227+
r#"
228+
fn f() { let result = foo$0!(); }
229+
"#,
230+
);
231+
}
232+
233+
#[test]
234+
fn inline_macro_function_call_not_applicable() {
235+
check_assist_not_applicable(
236+
inline_macro,
237+
r#"
238+
fn f() { let result = foo$0(); }
239+
"#,
240+
);
241+
}
242+
}

crates/ide-assists/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ mod handlers {
159159
mod add_return_type;
160160
mod inline_call;
161161
mod inline_local_variable;
162+
mod inline_macro;
162163
mod inline_type_alias;
163164
mod introduce_named_lifetime;
164165
mod invert_if;
@@ -255,6 +256,7 @@ mod handlers {
255256
inline_local_variable::inline_local_variable,
256257
inline_type_alias::inline_type_alias,
257258
inline_type_alias::inline_type_alias_uses,
259+
inline_macro::inline_macro,
258260
introduce_named_generic::introduce_named_generic,
259261
introduce_named_lifetime::introduce_named_lifetime,
260262
invert_if::invert_if,

crates/ide-assists/src/tests/generated.rs

+33
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,39 @@ fn main() {
14381438
)
14391439
}
14401440

1441+
#[test]
1442+
fn doctest_inline_macro() {
1443+
check_doc_test(
1444+
"inline_macro",
1445+
r#####"
1446+
macro_rules! num {
1447+
(+$($t:tt)+) => (1 + num!($($t )+));
1448+
(-$($t:tt)+) => (-1 + num!($($t )+));
1449+
(+) => (1);
1450+
(-) => (-1);
1451+
}
1452+
1453+
fn main() {
1454+
let number = num$0!(+ + + - + +);
1455+
println!("{number}");
1456+
}
1457+
"#####,
1458+
r#####"
1459+
macro_rules! num {
1460+
(+$($t:tt)+) => (1 + num!($($t )+));
1461+
(-$($t:tt)+) => (-1 + num!($($t )+));
1462+
(+) => (1);
1463+
(-) => (-1);
1464+
}
1465+
1466+
fn main() {
1467+
let number = 1+num!(+ + - + +);
1468+
println!("{number}");
1469+
}
1470+
"#####,
1471+
)
1472+
}
1473+
14411474
#[test]
14421475
fn doctest_inline_type_alias() {
14431476
check_doc_test(

0 commit comments

Comments
 (0)