diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs index 6114091f24..2862cfa9c2 100644 --- a/crates/ide_assists/src/handlers/remove_dbg.rs +++ b/crates/ide_assists/src/handlers/remove_dbg.rs @@ -1,5 +1,5 @@ use syntax::{ - ast::{self, AstNode}, + ast::{self, AstNode, AstToken}, match_ast, SyntaxElement, TextRange, TextSize, T, }; @@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { let macro_call = ctx.find_node_at_offset::()?; let new_contents = adjusted_macro_contents(¯o_call)?; - let macro_text_range = macro_call.syntax().text_range(); + let parent = macro_call.syntax().parent(); + + let macro_text_range = if let Some(it) = parent.as_ref() { + if new_contents.is_empty() { + match_ast! { + match it { + ast::BlockExpr(it) => { + macro_call.syntax() + .prev_sibling_or_token() + .and_then(whitespace_start) + .map(|start| TextRange::new(start, macro_call.syntax().text_range().end())) + .unwrap_or(macro_call.syntax().text_range()) + }, + ast::ExprStmt(it) => { + let start = it + .syntax() + .prev_sibling_or_token() + .and_then(whitespace_start) + .unwrap_or(it.syntax().text_range().start()); + let end = it.syntax().text_range().end(); + + TextRange::new(start, end) + }, + _ => macro_call.syntax().text_range() + } + } + } else { + macro_call.syntax().text_range() + } + } else { + macro_call.syntax().text_range() + }; + let macro_end = if macro_call.semicolon_token().is_some() { macro_text_range.end() - TextSize::of(';') } else { @@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { "Remove dbg!()", macro_text_range, |builder| { - builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); + builder.replace( + TextRange::new(macro_text_range.start(), macro_end), + if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() { + ast::make::expr_unit().to_string() + } else { + new_contents + }, + ); }, ) } +fn whitespace_start(it: SyntaxElement) -> Option { + Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start()) +} + fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option { let contents = get_valid_macrocall_contents(¯o_call, "dbg")?; let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); @@ -94,15 +137,11 @@ fn get_valid_macrocall_contents( let mut contents_between_brackets = children_with_tokens.collect::>(); let last_child = contents_between_brackets.pop()?; - if contents_between_brackets.is_empty() { - None - } else { - match (first_child.kind(), last_child.kind()) { - (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => { - Some(contents_between_brackets) - } - _ => None, + match (first_child.kind(), last_child.kind()) { + (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => { + Some(contents_between_brackets) } + _ => None, } } @@ -415,6 +454,50 @@ fn main() { }"#, r#"fn foo() { match &x {} +}"#, + ); + } + + #[test] + fn test_remove_empty_dbg() { + check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#); + check_assist( + remove_dbg, + r#" +fn foo() { + $0dbg!(); +} +"#, + r#" +fn foo() { +} +"#, + ); + check_assist( + remove_dbg, + r#" +fn foo() { + let test = $0dbg!(); +}"#, + r#" +fn foo() { + let test = (); +}"#, + ); + check_assist( + remove_dbg, + r#" +fn foo() { + let t = { + println!("Hello, world"); + $0dbg!() + }; +}"#, + r#" +fn foo() { + let t = { + println!("Hello, world"); + }; }"#, ); }