|
1 | 1 | use crate::{LateContext, LateLintPass, LintContext};
|
2 | 2 | use rustc_ast as ast;
|
| 3 | +use rustc_errors::Applicability; |
3 | 4 | use rustc_hir as hir;
|
4 | 5 | use rustc_middle::ty;
|
| 6 | +use rustc_span::sym; |
5 | 7 |
|
6 | 8 | declare_lint! {
|
7 | 9 | /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal.
|
@@ -46,11 +48,26 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
|
46 | 48 | if let hir::ExprKind::Lit(lit) = &arg.kind {
|
47 | 49 | if let ast::LitKind::Str(sym, _) = lit.node {
|
48 | 50 | if sym.as_str().contains(&['{', '}'][..]) {
|
49 |
| - cx.struct_span_lint(PANIC_FMT, f.span, |lint| { |
50 |
| - lint.build("Panic message contains a brace") |
51 |
| - .note("This message is not used as a format string, but will be in a future Rust version") |
52 |
| - .emit(); |
53 |
| - }); |
| 51 | + let expn = f.span.ctxt().outer_expn_data(); |
| 52 | + if let Some(id) = expn.macro_def_id { |
| 53 | + if cx.tcx.is_diagnostic_item(sym::std_panic_macro, id) |
| 54 | + || cx.tcx.is_diagnostic_item(sym::core_panic_macro, id) |
| 55 | + { |
| 56 | + cx.struct_span_lint(PANIC_FMT, expn.call_site, |lint| { |
| 57 | + let mut l = lint.build("Panic message contains a brace"); |
| 58 | + l.note("This message is not used as a format string, but will be in a future Rust version"); |
| 59 | + if expn.call_site.contains(arg.span) { |
| 60 | + l.span_suggestion( |
| 61 | + arg.span.shrink_to_lo(), |
| 62 | + "add a \"{}\" format string to use the message literally", |
| 63 | + "\"{}\", ".into(), |
| 64 | + Applicability::MachineApplicable, |
| 65 | + ); |
| 66 | + } |
| 67 | + l.emit(); |
| 68 | + }); |
| 69 | + } |
| 70 | + } |
54 | 71 | }
|
55 | 72 | }
|
56 | 73 | }
|
|
0 commit comments