diff options
-rw-r--r-- | crates/ide_assists/src/handlers/remove_dbg.rs | 105 |
1 files changed, 94 insertions, 11 deletions
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index 6114091f2..2862cfa9c 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use syntax::{ | 1 | use syntax::{ |
2 | ast::{self, AstNode}, | 2 | ast::{self, AstNode, AstToken}, |
3 | match_ast, SyntaxElement, TextRange, TextSize, T, | 3 | match_ast, SyntaxElement, TextRange, TextSize, T, |
4 | }; | 4 | }; |
5 | 5 | ||
@@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; | 24 | let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; |
25 | let new_contents = adjusted_macro_contents(¯o_call)?; | 25 | let new_contents = adjusted_macro_contents(¯o_call)?; |
26 | 26 | ||
27 | let macro_text_range = macro_call.syntax().text_range(); | 27 | let parent = macro_call.syntax().parent(); |
28 | |||
29 | let macro_text_range = if let Some(it) = parent.as_ref() { | ||
30 | if new_contents.is_empty() { | ||
31 | match_ast! { | ||
32 | match it { | ||
33 | ast::BlockExpr(it) => { | ||
34 | macro_call.syntax() | ||
35 | .prev_sibling_or_token() | ||
36 | .and_then(whitespace_start) | ||
37 | .map(|start| TextRange::new(start, macro_call.syntax().text_range().end())) | ||
38 | .unwrap_or(macro_call.syntax().text_range()) | ||
39 | }, | ||
40 | ast::ExprStmt(it) => { | ||
41 | let start = it | ||
42 | .syntax() | ||
43 | .prev_sibling_or_token() | ||
44 | .and_then(whitespace_start) | ||
45 | .unwrap_or(it.syntax().text_range().start()); | ||
46 | let end = it.syntax().text_range().end(); | ||
47 | |||
48 | TextRange::new(start, end) | ||
49 | }, | ||
50 | _ => macro_call.syntax().text_range() | ||
51 | } | ||
52 | } | ||
53 | } else { | ||
54 | macro_call.syntax().text_range() | ||
55 | } | ||
56 | } else { | ||
57 | macro_call.syntax().text_range() | ||
58 | }; | ||
59 | |||
28 | let macro_end = if macro_call.semicolon_token().is_some() { | 60 | let macro_end = if macro_call.semicolon_token().is_some() { |
29 | macro_text_range.end() - TextSize::of(';') | 61 | macro_text_range.end() - TextSize::of(';') |
30 | } else { | 62 | } else { |
@@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
36 | "Remove dbg!()", | 68 | "Remove dbg!()", |
37 | macro_text_range, | 69 | macro_text_range, |
38 | |builder| { | 70 | |builder| { |
39 | builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); | 71 | builder.replace( |
72 | TextRange::new(macro_text_range.start(), macro_end), | ||
73 | if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() { | ||
74 | ast::make::expr_unit().to_string() | ||
75 | } else { | ||
76 | new_contents | ||
77 | }, | ||
78 | ); | ||
40 | }, | 79 | }, |
41 | ) | 80 | ) |
42 | } | 81 | } |
43 | 82 | ||
83 | fn whitespace_start(it: SyntaxElement) -> Option<TextSize> { | ||
84 | Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start()) | ||
85 | } | ||
86 | |||
44 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { | 87 | fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { |
45 | let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; | 88 | let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; |
46 | let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); | 89 | let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); |
@@ -94,15 +137,11 @@ fn get_valid_macrocall_contents( | |||
94 | let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); | 137 | let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); |
95 | let last_child = contents_between_brackets.pop()?; | 138 | let last_child = contents_between_brackets.pop()?; |
96 | 139 | ||
97 | if contents_between_brackets.is_empty() { | 140 | match (first_child.kind(), last_child.kind()) { |
98 | None | 141 | (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => { |
99 | } else { | 142 | Some(contents_between_brackets) |
100 | match (first_child.kind(), last_child.kind()) { | ||
101 | (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => { | ||
102 | Some(contents_between_brackets) | ||
103 | } | ||
104 | _ => None, | ||
105 | } | 143 | } |
144 | _ => None, | ||
106 | } | 145 | } |
107 | } | 146 | } |
108 | 147 | ||
@@ -418,4 +457,48 @@ fn main() { | |||
418 | }"#, | 457 | }"#, |
419 | ); | 458 | ); |
420 | } | 459 | } |
460 | |||
461 | #[test] | ||
462 | fn test_remove_empty_dbg() { | ||
463 | check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#); | ||
464 | check_assist( | ||
465 | remove_dbg, | ||
466 | r#" | ||
467 | fn foo() { | ||
468 | $0dbg!(); | ||
469 | } | ||
470 | "#, | ||
471 | r#" | ||
472 | fn foo() { | ||
473 | } | ||
474 | "#, | ||
475 | ); | ||
476 | check_assist( | ||
477 | remove_dbg, | ||
478 | r#" | ||
479 | fn foo() { | ||
480 | let test = $0dbg!(); | ||
481 | }"#, | ||
482 | r#" | ||
483 | fn foo() { | ||
484 | let test = (); | ||
485 | }"#, | ||
486 | ); | ||
487 | check_assist( | ||
488 | remove_dbg, | ||
489 | r#" | ||
490 | fn foo() { | ||
491 | let t = { | ||
492 | println!("Hello, world"); | ||
493 | $0dbg!() | ||
494 | }; | ||
495 | }"#, | ||
496 | r#" | ||
497 | fn foo() { | ||
498 | let t = { | ||
499 | println!("Hello, world"); | ||
500 | }; | ||
501 | }"#, | ||
502 | ); | ||
503 | } | ||
421 | } | 504 | } |