|
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