From 3fb249bebce995ec6fdb1a4a3f49cf1acd5c86b7 Mon Sep 17 00:00:00 2001 From: Goldstein Date: Mon, 1 Aug 2022 21:49:12 +0300 Subject: [PATCH 1/2] improve "try ignoring the field" diagnostic Closes #95795 --- compiler/rustc_passes/src/liveness.rs | 34 +++++++++++++++++-- .../dont-try-removing-the-field.rs | 17 ++++++++++ .../dont-try-removing-the-field.stderr | 10 ++++++ .../ui/suggestions/try-removing-the-field.rs | 17 ++++++++++ .../suggestions/try-removing-the-field.stderr | 12 +++++++ 5 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/suggestions/dont-try-removing-the-field.rs create mode 100644 src/test/ui/suggestions/dont-try-removing-the-field.stderr create mode 100644 src/test/ui/suggestions/try-removing-the-field.rs create mode 100644 src/test/ui/suggestions/try-removing-the-field.stderr diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 461dd52b9f2..7124b84bfef 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -98,7 +98,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; +use rustc_span::{BytePos, Span}; use std::collections::VecDeque; use std::io; @@ -1549,6 +1549,8 @@ impl<'tcx> Liveness<'_, 'tcx> { .or_insert_with(|| (ln, var, vec![id_and_sp])); }); + let can_remove = matches!(&pat.kind, hir::PatKind::Struct(_, _, true)); + for (_, (ln, var, hir_ids_and_spans)) in vars { if self.used_on_entry(ln, var) { let id = hir_ids_and_spans[0].0; @@ -1556,16 +1558,18 @@ impl<'tcx> Liveness<'_, 'tcx> { hir_ids_and_spans.into_iter().map(|(_, _, ident_span)| ident_span).collect(); on_used_on_entry(spans, id, ln, var); } else { - self.report_unused(hir_ids_and_spans, ln, var); + self.report_unused(hir_ids_and_spans, ln, var, can_remove); } } } + #[tracing::instrument(skip(self), level = "INFO")] fn report_unused( &self, hir_ids_and_spans: Vec<(HirId, Span, Span)>, ln: LiveNode, var: Variable, + can_remove: bool, ) { let first_hir_id = hir_ids_and_spans[0].0; @@ -1590,6 +1594,32 @@ impl<'tcx> Liveness<'_, 'tcx> { .emit(); }, ) + } else if can_remove { + self.ir.tcx.struct_span_lint_hir( + lint::builtin::UNUSED_VARIABLES, + first_hir_id, + hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::>(), + |lint| { + let mut err = lint.build(&format!("unused variable: `{}`", name)); + err.multipart_suggestion( + "try removing the field", + hir_ids_and_spans + .iter() + .map(|(_, pat_span, _)| { + let span = self + .ir + .tcx + .sess + .source_map() + .span_extend_to_next_char(*pat_span, ',', true); + (span.with_hi(BytePos(span.hi().0 + 1)), String::new()) + }) + .collect(), + Applicability::MachineApplicable, + ); + err.emit(); + }, + ); } else { let (shorthands, non_shorthands): (Vec<_>, Vec<_>) = hir_ids_and_spans.iter().copied().partition(|(hir_id, _, ident_span)| { diff --git a/src/test/ui/suggestions/dont-try-removing-the-field.rs b/src/test/ui/suggestions/dont-try-removing-the-field.rs new file mode 100644 index 00000000000..948aa2b94d9 --- /dev/null +++ b/src/test/ui/suggestions/dont-try-removing-the-field.rs @@ -0,0 +1,17 @@ +// run-pass + +#![allow(dead_code)] + +struct Foo { + foo: i32, + bar: i32, + baz: (), +} + +fn use_foo(x: Foo) -> (i32, i32) { + let Foo { foo, bar, baz } = x; //~ WARNING unused variable: `baz` + //~| help: try ignoring the field + return (foo, bar); +} + +fn main() {} diff --git a/src/test/ui/suggestions/dont-try-removing-the-field.stderr b/src/test/ui/suggestions/dont-try-removing-the-field.stderr new file mode 100644 index 00000000000..263171a4ac4 --- /dev/null +++ b/src/test/ui/suggestions/dont-try-removing-the-field.stderr @@ -0,0 +1,10 @@ +warning: unused variable: `baz` + --> $DIR/dont-try-removing-the-field.rs:12:25 + | +LL | let Foo { foo, bar, baz } = x; + | ^^^ help: try ignoring the field: `baz: _` + | + = note: `#[warn(unused_variables)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/suggestions/try-removing-the-field.rs b/src/test/ui/suggestions/try-removing-the-field.rs new file mode 100644 index 00000000000..9d0573ca255 --- /dev/null +++ b/src/test/ui/suggestions/try-removing-the-field.rs @@ -0,0 +1,17 @@ +// run-pass + +#![allow(dead_code)] + +struct Foo { + foo: i32, + bar: (), + baz: (), +} + +fn use_foo(x: Foo) -> i32 { + let Foo { foo, bar, .. } = x; //~ WARNING unused variable: `bar` + //~| help: try removing the field + return foo; +} + +fn main() {} diff --git a/src/test/ui/suggestions/try-removing-the-field.stderr b/src/test/ui/suggestions/try-removing-the-field.stderr new file mode 100644 index 00000000000..448a2c3d2ec --- /dev/null +++ b/src/test/ui/suggestions/try-removing-the-field.stderr @@ -0,0 +1,12 @@ +warning: unused variable: `bar` + --> $DIR/try-removing-the-field.rs:12:20 + | +LL | let Foo { foo, bar, .. } = x; + | ^^^- + | | + | help: try removing the field + | + = note: `#[warn(unused_variables)]` on by default + +warning: 1 warning emitted + From 3e0df4b5d743a5247a8d3174a3a4a55f635847a6 Mon Sep 17 00:00:00 2001 From: Goldstein Date: Sat, 13 Aug 2022 23:33:21 +0300 Subject: [PATCH 2/2] fix span_extend_to_next_char docs --- compiler/rustc_span/src/source_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 28381157d50..ad9f5ba85a1 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -722,7 +722,7 @@ impl SourceMap { }) } - /// Extends the given `Span` to just after the next occurrence of `c`. + /// Extends the given `Span` to just before the next occurrence of `c`. pub fn span_extend_to_next_char(&self, sp: Span, c: char, accept_newlines: bool) -> Span { if let Ok(next_source) = self.span_to_next_source(sp) { let next_source = next_source.split(c).next().unwrap_or("");