]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide-assists / src / handlers / remove_dbg.rs
CommitLineData
064997fb
FG
1use itertools::Itertools;
2use syntax::{
3 ast::{self, AstNode, AstToken},
487cf647 4 match_ast, NodeOrToken, SyntaxElement, TextRange, TextSize, T,
064997fb
FG
5};
6
7use crate::{AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: remove_dbg
10//
11// Removes `dbg!()` macro call.
12//
13// ```
14// fn main() {
15// $0dbg!(92);
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// 92;
22// }
23// ```
24pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
487cf647
FG
25 let macro_calls = if ctx.has_empty_selection() {
26 vec![ctx.find_node_at_offset::<ast::MacroCall>()?]
27 } else {
28 ctx.covering_element()
29 .as_node()?
30 .descendants()
31 .filter(|node| ctx.selection_trimmed().contains_range(node.text_range()))
32 .filter_map(ast::MacroCall::cast)
33 .collect()
34 };
35
36 let replacements =
37 macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
38 if replacements.is_empty() {
39 return None;
40 }
41
42 acc.add(
43 AssistId("remove_dbg", AssistKind::Refactor),
44 "Remove dbg!()",
45 ctx.selection_trimmed(),
46 |builder| {
47 for (range, text) in replacements {
48 builder.replace(range, text);
49 }
50 },
51 )
52}
53
54fn compute_dbg_replacement(macro_call: ast::MacroCall) -> Option<(TextRange, String)> {
064997fb
FG
55 let tt = macro_call.token_tree()?;
56 let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?);
57 if macro_call.path()?.segment()?.name_ref()?.text() != "dbg"
58 || macro_call.excl_token().is_none()
59 {
60 return None;
61 }
62
63 let mac_input = tt.syntax().children_with_tokens().skip(1).take_while(|it| *it != r_delim);
64 let input_expressions = mac_input.group_by(|tok| tok.kind() == T![,]);
65 let input_expressions = input_expressions
66 .into_iter()
9c376795 67 .filter_map(|(is_sep, group)| (!is_sep).then_some(group))
064997fb
FG
68 .map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join("")))
69 .collect::<Option<Vec<ast::Expr>>>()?;
70
71 let macro_expr = ast::MacroExpr::cast(macro_call.syntax().parent()?)?;
72 let parent = macro_expr.syntax().parent()?;
487cf647 73 Some(match &*input_expressions {
064997fb
FG
74 // dbg!()
75 [] => {
76 match_ast! {
77 match parent {
78 ast::StmtList(__) => {
79 let range = macro_expr.syntax().text_range();
80 let range = match whitespace_start(macro_expr.syntax().prev_sibling_or_token()) {
81 Some(start) => range.cover_offset(start),
82 None => range,
83 };
84 (range, String::new())
85 },
86 ast::ExprStmt(it) => {
87 let range = it.syntax().text_range();
88 let range = match whitespace_start(it.syntax().prev_sibling_or_token()) {
89 Some(start) => range.cover_offset(start),
90 None => range,
91 };
92 (range, String::new())
93 },
94 _ => (macro_call.syntax().text_range(), "()".to_owned())
95 }
96 }
97 }
98 // dbg!(expr0)
99 [expr] => {
100 let wrap = match ast::Expr::cast(parent) {
101 Some(parent) => match (expr, parent) {
102 (ast::Expr::CastExpr(_), ast::Expr::CastExpr(_)) => false,
103 (
104 ast::Expr::BoxExpr(_) | ast::Expr::PrefixExpr(_) | ast::Expr::RefExpr(_),
105 ast::Expr::AwaitExpr(_)
106 | ast::Expr::CallExpr(_)
107 | ast::Expr::CastExpr(_)
108 | ast::Expr::FieldExpr(_)
109 | ast::Expr::IndexExpr(_)
110 | ast::Expr::MethodCallExpr(_)
111 | ast::Expr::RangeExpr(_)
112 | ast::Expr::TryExpr(_),
113 ) => true,
114 (
115 ast::Expr::BinExpr(_) | ast::Expr::CastExpr(_) | ast::Expr::RangeExpr(_),
116 ast::Expr::AwaitExpr(_)
117 | ast::Expr::BinExpr(_)
118 | ast::Expr::CallExpr(_)
119 | ast::Expr::CastExpr(_)
120 | ast::Expr::FieldExpr(_)
121 | ast::Expr::IndexExpr(_)
122 | ast::Expr::MethodCallExpr(_)
123 | ast::Expr::PrefixExpr(_)
124 | ast::Expr::RangeExpr(_)
125 | ast::Expr::RefExpr(_)
126 | ast::Expr::TryExpr(_),
127 ) => true,
128 _ => false,
129 },
130 None => false,
131 };
132 (
133 macro_call.syntax().text_range(),
487cf647 134 if wrap { format!("({expr})") } else { expr.to_string() },
064997fb
FG
135 )
136 }
137 // dbg!(expr0, expr1, ...)
138 exprs => (macro_call.syntax().text_range(), format!("({})", exprs.iter().format(", "))),
064997fb
FG
139 })
140}
141
142fn whitespace_start(it: Option<SyntaxElement>) -> Option<TextSize> {
143 Some(it?.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
144}
145
146#[cfg(test)]
147mod tests {
148 use crate::tests::{check_assist, check_assist_not_applicable};
149
150 use super::*;
151
152 fn check(ra_fixture_before: &str, ra_fixture_after: &str) {
153 check_assist(
154 remove_dbg,
487cf647
FG
155 &format!("fn main() {{\n{ra_fixture_before}\n}}"),
156 &format!("fn main() {{\n{ra_fixture_after}\n}}"),
064997fb
FG
157 );
158 }
159
160 #[test]
161 fn test_remove_dbg() {
162 check("$0dbg!(1 + 1)", "1 + 1");
163 check("dbg!$0(1 + 1)", "1 + 1");
164 check("dbg!(1 $0+ 1)", "1 + 1");
165 check("dbg![$01 + 1]", "1 + 1");
166 check("dbg!{$01 + 1}", "1 + 1");
167 }
168
169 #[test]
170 fn test_remove_dbg_not_applicable() {
171 check_assist_not_applicable(remove_dbg, "fn main() {$0vec![1, 2, 3]}");
172 check_assist_not_applicable(remove_dbg, "fn main() {$0dbg(5, 6, 7)}");
173 check_assist_not_applicable(remove_dbg, "fn main() {$0dbg!(5, 6, 7}");
174 }
175
176 #[test]
177 fn test_remove_dbg_keep_semicolon_in_let() {
178 // https://github.com/rust-lang/rust-analyzer/issues/5129#issuecomment-651399779
179 check(
180 r#"let res = $0dbg!(1 * 20); // needless comment"#,
181 r#"let res = 1 * 20; // needless comment"#,
182 );
183 check(r#"let res = $0dbg!(); // needless comment"#, r#"let res = (); // needless comment"#);
184 check(
185 r#"let res = $0dbg!(1, 2); // needless comment"#,
186 r#"let res = (1, 2); // needless comment"#,
187 );
188 }
189
190 #[test]
191 fn test_remove_dbg_cast_cast() {
192 check(r#"let res = $0dbg!(x as u32) as u32;"#, r#"let res = x as u32 as u32;"#);
193 }
194
195 #[test]
196 fn test_remove_dbg_prefix() {
197 check(r#"let res = $0dbg!(&result).foo();"#, r#"let res = (&result).foo();"#);
198 check(r#"let res = &$0dbg!(&result);"#, r#"let res = &&result;"#);
199 check(r#"let res = $0dbg!(!result) && true;"#, r#"let res = !result && true;"#);
200 }
201
202 #[test]
203 fn test_remove_dbg_post_expr() {
204 check(r#"let res = $0dbg!(fut.await).foo();"#, r#"let res = fut.await.foo();"#);
205 check(r#"let res = $0dbg!(result?).foo();"#, r#"let res = result?.foo();"#);
206 check(r#"let res = $0dbg!(foo as u32).foo();"#, r#"let res = (foo as u32).foo();"#);
207 check(r#"let res = $0dbg!(array[3]).foo();"#, r#"let res = array[3].foo();"#);
208 check(r#"let res = $0dbg!(tuple.3).foo();"#, r#"let res = tuple.3.foo();"#);
209 }
210
211 #[test]
212 fn test_remove_dbg_range_expr() {
213 check(r#"let res = $0dbg!(foo..bar).foo();"#, r#"let res = (foo..bar).foo();"#);
214 check(r#"let res = $0dbg!(foo..=bar).foo();"#, r#"let res = (foo..=bar).foo();"#);
215 }
216
217 #[test]
218 fn test_remove_empty_dbg() {
219 check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
220 check_assist(
221 remove_dbg,
222 r#"
223fn foo() {
224 $0dbg!();
225}
226"#,
227 r#"
228fn foo() {
229}
230"#,
231 );
232 check_assist(
233 remove_dbg,
234 r#"
235fn foo() {
236 let test = $0dbg!();
237}"#,
238 r#"
239fn foo() {
240 let test = ();
241}"#,
242 );
243 check_assist(
244 remove_dbg,
245 r#"
246fn foo() {
247 let t = {
248 println!("Hello, world");
249 $0dbg!()
250 };
251}"#,
252 r#"
253fn foo() {
254 let t = {
255 println!("Hello, world");
256 };
257}"#,
258 );
259 }
260
261 #[test]
262 fn test_remove_multi_dbg() {
263 check(r#"$0dbg!(0, 1)"#, r#"(0, 1)"#);
264 check(r#"$0dbg!(0, (1, 2))"#, r#"(0, (1, 2))"#);
265 }
487cf647
FG
266
267 #[test]
268 fn test_range() {
269 check(
270 r#"
271fn f() {
272 dbg!(0) + $0dbg!(1);
273 dbg!(())$0
274}
275"#,
276 r#"
277fn f() {
278 dbg!(0) + 1;
279 ()
280}
281"#,
282 );
283 }
284
285 #[test]
286 fn test_range_partial() {
287 check_assist_not_applicable(remove_dbg, r#"$0dbg$0!(0)"#);
288 check_assist_not_applicable(remove_dbg, r#"$0dbg!(0$0)"#);
289 }
064997fb 290}