diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2021-02-14 18:52:47 +0100 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2021-02-14 18:52:47 +0100 |
| commit | a428ab17abc310c17ca13eeb6f74b3c5bddff940 (patch) | |
| tree | 6a5ef88b0890d44fc2286d9bbf58d5952e7da575 /compiler/rustc_lint/src | |
| parent | 1abc1e2a43c116a87bd430fa14a86e67617b861a (diff) | |
Improve suggestion for panic!(format!(..)).
Diffstat (limited to 'compiler/rustc_lint/src')
| -rw-r--r-- | compiler/rustc_lint/src/non_fmt_panic.rs | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index 0c5456cf619..7432f476d7c 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -72,18 +72,38 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc // Find the span of the argument to `panic!()`, before expansion in the // case of `panic!(some_macro!())`. let mut arg_span = arg.span; + let mut arg_macro = None; while !span.contains(arg_span) { let expn = arg_span.ctxt().outer_expn_data(); if expn.is_root() { break; } + arg_macro = expn.macro_def_id; arg_span = expn.call_site; } cx.struct_span_lint(NON_FMT_PANIC, arg_span, |lint| { let mut l = lint.build("panic message is not a string literal"); l.note("this is no longer accepted in Rust 2021"); - if span.contains(arg_span) { + if !span.contains(arg_span) { + // No clue where this argument is coming from. + l.emit(); + return; + } + if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { + // A case of `panic!(format!(..))`. + l.note("the panic!() macro supports formatting, so there's no need for the format!() macro here"); + if let Some(inner) = find_inner_span(cx, arg_span) { + l.multipart_suggestion( + "remove the `format!(..)` macro call", + vec![ + (arg_span.until(inner), "".into()), + (inner.between(arg_span.shrink_to_hi()), "".into()), + ], + Applicability::MachineApplicable, + ); + } + } else { l.span_suggestion_verbose( arg_span.shrink_to_lo(), "add a \"{}\" format string to Display the message", @@ -186,6 +206,15 @@ fn check_panic_str<'tcx>( } } +/// Given the span of `some_macro!(args)`, gives the span of `args`. +fn find_inner_span<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<Span> { + let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?; + Some(span.from_inner(InnerSpan { + start: snippet.find(&['(', '{', '['][..])? + 1, + end: snippet.rfind(&[')', '}', ']'][..])?, + })) +} + fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol) { let mut expn = f.span.ctxt().outer_expn_data(); |
