diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs index 91f1058d65b..34a0038295f 100644 --- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs +++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs @@ -413,7 +413,7 @@ fn mutation_in_dead_code() { fn main() { return; let mut x = 2; - //^^^^^ warn: unused variable + //^^^^^ 💡 warn: unused variable &mut x; } "#, @@ -423,7 +423,7 @@ fn main() { fn main() { loop {} let mut x = 2; - //^^^^^ warn: unused variable + //^^^^^ 💡 warn: unused variable &mut x; } "#, @@ -444,7 +444,7 @@ fn main(b: bool) { g(); } let mut x = 2; - //^^^^^ warn: unused variable + //^^^^^ 💡 warn: unused variable &mut x; } "#, @@ -459,7 +459,7 @@ fn main(b: bool) { return; } let mut x = 2; - //^^^^^ warn: unused variable + //^^^^^ 💡 warn: unused variable &mut x; } "#, @@ -789,7 +789,7 @@ fn f() { //^^ 💡 error: cannot mutate immutable variable `x` _ = (x, y); let x = Foo; - //^ warn: unused variable + //^ 💡 warn: unused variable let x = Foo; let y: &mut (i32, u8) = &mut x; //^^^^^^ 💡 error: cannot mutate immutable variable `x` diff --git a/crates/ide-diagnostics/src/handlers/unused_variables.rs b/crates/ide-diagnostics/src/handlers/unused_variables.rs index 28ccf474b40..a9e1d07d7c5 100644 --- a/crates/ide-diagnostics/src/handlers/unused_variables.rs +++ b/crates/ide-diagnostics/src/handlers/unused_variables.rs @@ -1,3 +1,11 @@ +use ide_db::{ + assists::{Assist, AssistId, AssistKind}, + base_db::FileRange, + label::Label, + source_change::SourceChange, +}; +use text_edit::TextEdit; + use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; // Diagnostic: unused-variables @@ -8,18 +16,38 @@ pub(crate) fn unused_variables( d: &hir::UnusedVariable, ) -> Diagnostic { let ast = d.local.primary_source(ctx.sema.db).syntax_ptr(); + let diagnostic_range = ctx.sema.diagnostics_display_range(ast); + let var_name = d.local.primary_source(ctx.sema.db).syntax().to_string(); Diagnostic::new_with_syntax_node_ptr( ctx, DiagnosticCode::RustcLint("unused_variables"), "unused variable", ast, ) + .with_fixes(fixes(&var_name, diagnostic_range, ast.file_id.is_macro())) .experimental() } +fn fixes(var_name: &String, diagnostic_range: FileRange, is_in_marco: bool) -> Option> { + if is_in_marco { + return None; + } + Some(vec![Assist { + id: AssistId("unscore_unused_variable_name", AssistKind::QuickFix), + label: Label::new(format!("Rename unused {} to _{}", var_name, var_name)), + group: None, + target: diagnostic_range.range, + source_change: Some(SourceChange::from_text_edit( + diagnostic_range.file_id, + TextEdit::replace(diagnostic_range.range, format!("_{}", var_name)), + )), + trigger_signature_help: false, + }]) +} + #[cfg(test)] mod tests { - use crate::tests::check_diagnostics; + use crate::tests::{check_diagnostics, check_fix, check_no_fix}; #[test] fn unused_variables_simple() { @@ -29,23 +57,23 @@ fn unused_variables_simple() { struct Foo { f1: i32, f2: i64 } fn f(kkk: i32) {} - //^^^ warn: unused variable + //^^^ 💡 warn: unused variable fn main() { let a = 2; - //^ warn: unused variable + //^ 💡 warn: unused variable let b = 5; // note: `unused variable` implies `unused mut`, so we should not emit both at the same time. let mut c = f(b); - //^^^^^ warn: unused variable + //^^^^^ 💡 warn: unused variable let (d, e) = (3, 5); - //^ warn: unused variable + //^ 💡 warn: unused variable let _ = e; let f1 = 2; let f2 = 5; let f = Foo { f1, f2 }; match f { Foo { f1, f2 } => { - //^^ warn: unused variable + //^^ 💡 warn: unused variable _ = f2; } } @@ -53,7 +81,7 @@ fn main() { if g {} let h: fn() -> i32 = || 2; let i = h(); - //^ warn: unused variable + //^ 💡 warn: unused variable } "#, ); @@ -67,11 +95,11 @@ struct S { } impl S { fn owned_self(self, u: i32) {} - //^ warn: unused variable + //^ 💡 warn: unused variable fn ref_self(&self, u: i32) {} - //^ warn: unused variable + //^ 💡 warn: unused variable fn ref_mut_self(&mut self, u: i32) {} - //^ warn: unused variable + //^ 💡 warn: unused variable fn owned_mut_self(mut self) {} //^^^^^^^^ 💡 warn: variable does not need to be mutable @@ -103,7 +131,78 @@ fn main() { #[deny(unused)] fn main2() { let x = 2; - //^ error: unused variable + //^ 💡 error: unused variable +} +"#, + ); + } + + #[test] + fn fix_unused_variable() { + check_fix( + r#" +fn main() { + let x$0 = 2; +} +"#, + r#" +fn main() { + let _x = 2; +} +"#, + ); + + check_fix( + r#" +fn main() { + let ($0d, _e) = (3, 5); +} +"#, + r#" +fn main() { + let (_d, _e) = (3, 5); +} +"#, + ); + + check_fix( + r#" +struct Foo { f1: i32, f2: i64 } +fn main() { + let f = Foo { f1: 0, f2: 0 }; + match f { + Foo { f1$0, f2 } => { + _ = f2; + } + } +} +"#, + r#" +struct Foo { f1: i32, f2: i64 } +fn main() { + let f = Foo { f1: 0, f2: 0 }; + match f { + Foo { _f1, f2 } => { + _ = f2; + } + } +} +"#, + ); + } + + #[test] + fn no_fix_for_marco() { + check_no_fix( + r#" +macro_rules! my_macro { + () => { + let x = 3; + }; +} + +fn main() { + $0my_macro!(); } "#, );