@@ -1148,6 +1148,48 @@ fn lint_or_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span: Spa
1148
1148
1149
1149
/// Checks for the `EXPECT_FUN_CALL` lint.
1150
1150
fn lint_expect_fun_call ( cx : & LateContext < ' _ , ' _ > , expr : & hir:: Expr , method_span : Span , name : & str , args : & [ hir:: Expr ] ) {
1151
+ // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
1152
+ // `&str`
1153
+ fn get_arg_root < ' a > ( cx : & LateContext < ' _ , ' _ > , arg : & ' a hir:: Expr ) -> & ' a hir:: Expr {
1154
+ let mut arg_root = arg;
1155
+ loop {
1156
+ arg_root = match & arg_root. node {
1157
+ hir:: ExprKind :: AddrOf ( _, expr) => expr,
1158
+ hir:: ExprKind :: MethodCall ( method_name, _, call_args) => {
1159
+ if call_args. len ( ) == 1
1160
+ && ( method_name. ident . name == "as_str" || method_name. ident . name == "as_ref" )
1161
+ && {
1162
+ let arg_type = cx. tables . expr_ty ( & call_args[ 0 ] ) ;
1163
+ let base_type = walk_ptrs_ty ( arg_type) ;
1164
+ base_type. sty == ty:: Str || match_type ( cx, base_type, & paths:: STRING )
1165
+ }
1166
+ {
1167
+ & call_args[ 0 ]
1168
+ } else {
1169
+ break ;
1170
+ }
1171
+ } ,
1172
+ _ => break ,
1173
+ } ;
1174
+ }
1175
+ arg_root
1176
+ }
1177
+
1178
+ // Only `&'static str` or `String` can be used directly in the `panic!`. Other types should be
1179
+ // converted to string.
1180
+ fn requires_to_string ( cx : & LateContext < ' _ , ' _ > , arg : & hir:: Expr ) -> bool {
1181
+ let arg_ty = cx. tables . expr_ty ( arg) ;
1182
+ if match_type ( cx, arg_ty, & paths:: STRING ) {
1183
+ return false ;
1184
+ }
1185
+ if let ty:: Ref ( ty:: ReStatic , ty, ..) = arg_ty. sty {
1186
+ if ty. sty == ty:: Str {
1187
+ return false ;
1188
+ }
1189
+ } ;
1190
+ true
1191
+ }
1192
+
1151
1193
fn generate_format_arg_snippet (
1152
1194
cx : & LateContext < ' _ , ' _ > ,
1153
1195
a : & hir:: Expr ,
@@ -1195,29 +1237,7 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
1195
1237
return ;
1196
1238
} ;
1197
1239
1198
- // Strip off `&`, `as_ref()` and `as_str()` until we're left with either a `String` or `&str`
1199
- // which we call `arg_root`.
1200
- let mut arg_root = & args[ 1 ] ;
1201
- loop {
1202
- arg_root = match & arg_root. node {
1203
- hir:: ExprKind :: AddrOf ( _, expr) => expr,
1204
- hir:: ExprKind :: MethodCall ( method_name, _, call_args) => {
1205
- if call_args. len ( ) == 1
1206
- && ( method_name. ident . name == "as_str" || method_name. ident . name == "as_ref" )
1207
- && {
1208
- let arg_type = cx. tables . expr_ty ( & call_args[ 0 ] ) ;
1209
- let base_type = walk_ptrs_ty ( arg_type) ;
1210
- base_type. sty == ty:: Str || match_type ( cx, base_type, & paths:: STRING )
1211
- }
1212
- {
1213
- & call_args[ 0 ]
1214
- } else {
1215
- break ;
1216
- }
1217
- } ,
1218
- _ => break ,
1219
- } ;
1220
- }
1240
+ let arg_root = get_arg_root ( cx, & args[ 1 ] ) ;
1221
1241
1222
1242
let span_replace_word = method_span. with_hi ( expr. span . hi ( ) ) ;
1223
1243
@@ -1230,7 +1250,6 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
1230
1250
let fmt_spec = & format_args[ 0 ] ;
1231
1251
let fmt_args = & format_args[ 1 ] ;
1232
1252
1233
- let mut applicability = Applicability :: MachineApplicable ;
1234
1253
let mut args = vec ! [ snippet( cx, fmt_spec. span, ".." ) . into_owned( ) ] ;
1235
1254
1236
1255
args. extend ( generate_format_arg_snippet ( cx, fmt_args, & mut applicability) ) ;
@@ -1252,18 +1271,8 @@ fn lint_expect_fun_call(cx: &LateContext<'_, '_>, expr: &hir::Expr, method_span:
1252
1271
}
1253
1272
}
1254
1273
1255
- // If root_arg is `&'static str` or `String` we can use it directly in the `panic!` call otherwise
1256
- // we must use `to_string` to convert it.
1257
1274
let mut arg_root_snippet: Cow < ' _ , _ > = snippet_with_applicability ( cx, arg_root. span , ".." , & mut applicability) ;
1258
- let arg_root_ty = cx. tables . expr_ty ( arg_root) ;
1259
- let mut requires_conv = !match_type ( cx, arg_root_ty, & paths:: STRING ) ;
1260
- if let ty:: Ref ( ty:: ReStatic , ty, ..) = arg_root_ty. sty {
1261
- if ty. sty == ty:: Str {
1262
- requires_conv = false ;
1263
- }
1264
- } ;
1265
-
1266
- if requires_conv {
1275
+ if requires_to_string ( cx, arg_root) {
1267
1276
arg_root_snippet. to_mut ( ) . push_str ( ".to_string()" ) ;
1268
1277
}
1269
1278
0 commit comments