@@ -47,24 +47,52 @@ impl<'tcx> LateLintPass<'tcx> for PanicFmt {
47
47
fn check_panic < ' tcx > ( cx : & LateContext < ' tcx > , f : & ' tcx hir:: Expr < ' tcx > , arg : & ' tcx hir:: Expr < ' tcx > ) {
48
48
if let hir:: ExprKind :: Lit ( lit) = & arg. kind {
49
49
if let ast:: LitKind :: Str ( sym, _) = lit. node {
50
- if sym. as_str ( ) . contains ( & [ '{' , '}' ] [ ..] ) {
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
- let expn = {
57
- // Unwrap another level of macro expansion if this
58
- // panic!() was expanded from assert!().
59
- let parent = expn. call_site . ctxt ( ) . outer_expn_data ( ) ;
60
- if parent. macro_def_id . map_or ( false , |id| {
61
- cx. tcx . is_diagnostic_item ( sym:: assert_macro, id)
62
- } ) {
63
- parent
64
- } else {
65
- expn
50
+ let s = sym. as_str ( ) ;
51
+ let open = s. find ( '{' ) ;
52
+ let close = s[ open. unwrap_or ( 0 ) ..] . find ( '}' ) ;
53
+ let looks_like_placeholder = match ( open, close) {
54
+ ( Some ( _) , Some ( _) ) => true ,
55
+ ( Some ( _) , None ) | ( None , Some ( _) ) => false ,
56
+ ( None , None ) => return // OK, no braces.
57
+ } ;
58
+ let expn = f. span . ctxt ( ) . outer_expn_data ( ) ;
59
+ if let Some ( id) = expn. macro_def_id {
60
+ if cx. tcx . is_diagnostic_item ( sym:: std_panic_macro, id)
61
+ || cx. tcx . is_diagnostic_item ( sym:: core_panic_macro, id)
62
+ {
63
+ let expn = {
64
+ // Unwrap another level of macro expansion if this
65
+ // panic!() was expanded from assert!().
66
+ let parent = expn. call_site . ctxt ( ) . outer_expn_data ( ) ;
67
+ if parent. macro_def_id . map_or ( false , |id| {
68
+ cx. tcx . is_diagnostic_item ( sym:: assert_macro, id)
69
+ } ) {
70
+ parent
71
+ } else {
72
+ expn
73
+ }
74
+ } ;
75
+ if looks_like_placeholder {
76
+ cx. struct_span_lint ( PANIC_FMT , arg. span . source_callsite ( ) , |lint| {
77
+ let mut l = lint. build ( "Panic message contains an unused formatting placeholder" ) ;
78
+ l. note ( "This message is not used as a format string when given without arguments, but will be in a future Rust version" ) ;
79
+ if expn. call_site . contains ( arg. span ) {
80
+ l. span_suggestion (
81
+ arg. span . shrink_to_hi ( ) ,
82
+ "add the missing argument(s)" ,
83
+ ", argument" . into ( ) ,
84
+ Applicability :: HasPlaceholders ,
85
+ ) ;
86
+ l. span_suggestion (
87
+ arg. span . shrink_to_lo ( ) ,
88
+ "or add a \" {}\" format string to use the message literally" ,
89
+ "\" {}\" , " . into ( ) ,
90
+ Applicability :: MaybeIncorrect ,
91
+ ) ;
66
92
}
67
- } ;
93
+ l. emit ( ) ;
94
+ } ) ;
95
+ } else {
68
96
cx. struct_span_lint ( PANIC_FMT , expn. call_site , |lint| {
69
97
let mut l = lint. build ( "Panic message contains a brace" ) ;
70
98
l. note ( "This message is not used as a format string, but will be in a future Rust version" ) ;
0 commit comments