@@ -826,7 +826,7 @@ struct FixedOffsetVar<'hir> {
826
826
}
827
827
828
828
fn is_slice_like < ' tcx > ( cx : & LateContext < ' tcx > , ty : Ty < ' _ > ) -> bool {
829
- let is_slice = match ty. kind {
829
+ let is_slice = match ty. kind ( ) {
830
830
ty:: Ref ( _, subty, _) => is_slice_like ( cx, subty) ,
831
831
ty:: Slice ( ..) | ty:: Array ( ..) => true ,
832
832
_ => false ,
@@ -1003,7 +1003,7 @@ fn detect_manual_memcpy<'tcx>(
1003
1003
start : Some ( start) ,
1004
1004
end : Some ( end) ,
1005
1005
limits,
1006
- } ) = higher:: range ( cx , arg)
1006
+ } ) = higher:: range ( arg)
1007
1007
{
1008
1008
// the var must be a single name
1009
1009
if let PatKind :: Binding ( _, canonical_id, _, _) = pat. kind {
@@ -1140,23 +1140,95 @@ fn detect_same_item_push<'tcx>(
1140
1140
walk_expr ( & mut same_item_push_visitor, body) ;
1141
1141
if same_item_push_visitor. should_lint {
1142
1142
if let Some ( ( vec, pushed_item) ) = same_item_push_visitor. vec_push {
1143
- // Make sure that the push does not involve possibly mutating values
1144
- if mutated_variables ( pushed_item, cx) . map_or ( false , |mutvars| mutvars. is_empty ( ) ) {
1143
+ let vec_ty = cx. typeck_results ( ) . expr_ty ( vec) ;
1144
+ let ty = vec_ty. walk ( ) . nth ( 1 ) . unwrap ( ) . expect_ty ( ) ;
1145
+ if cx
1146
+ . tcx
1147
+ . lang_items ( )
1148
+ . clone_trait ( )
1149
+ . map_or ( false , |id| implements_trait ( cx, ty, id, & [ ] ) )
1150
+ {
1151
+ // Make sure that the push does not involve possibly mutating values
1145
1152
if let PatKind :: Wild = pat. kind {
1146
1153
let vec_str = snippet_with_macro_callsite ( cx, vec. span , "" ) ;
1147
1154
let item_str = snippet_with_macro_callsite ( cx, pushed_item. span , "" ) ;
1148
-
1149
- span_lint_and_help (
1150
- cx,
1151
- SAME_ITEM_PUSH ,
1152
- vec. span ,
1153
- "it looks like the same item is being pushed into this Vec" ,
1154
- None ,
1155
- & format ! (
1156
- "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})" ,
1157
- item_str, vec_str, item_str
1158
- ) ,
1159
- )
1155
+ if let ExprKind :: Path ( ref qpath) = pushed_item. kind {
1156
+ match qpath_res ( cx, qpath, pushed_item. hir_id ) {
1157
+ // immutable bindings that are initialized with literal or constant
1158
+ Res :: Local ( hir_id) => {
1159
+ if_chain ! {
1160
+ let node = cx. tcx. hir( ) . get( hir_id) ;
1161
+ if let Node :: Binding ( pat) = node;
1162
+ if let PatKind :: Binding ( bind_ann, ..) = pat. kind;
1163
+ if !matches!( bind_ann, BindingAnnotation :: RefMut | BindingAnnotation :: Mutable ) ;
1164
+ let parent_node = cx. tcx. hir( ) . get_parent_node( hir_id) ;
1165
+ if let Some ( Node :: Local ( parent_let_expr) ) = cx. tcx. hir( ) . find( parent_node) ;
1166
+ if let rustc_hir:: Local { init: Some ( init) , .. } = parent_let_expr;
1167
+ then {
1168
+ match init. kind {
1169
+ // immutable bindings that are initialized with literal
1170
+ ExprKind :: Lit ( ..) => {
1171
+ span_lint_and_help(
1172
+ cx,
1173
+ SAME_ITEM_PUSH ,
1174
+ vec. span,
1175
+ "it looks like the same item is being pushed into this Vec" ,
1176
+ None ,
1177
+ & format!(
1178
+ "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})" ,
1179
+ item_str, vec_str, item_str
1180
+ ) ,
1181
+ )
1182
+ } ,
1183
+ // immutable bindings that are initialized with constant
1184
+ ExprKind :: Path ( ref path) => {
1185
+ if let Res :: Def ( DefKind :: Const , ..) = qpath_res( cx, path, init. hir_id) {
1186
+ span_lint_and_help(
1187
+ cx,
1188
+ SAME_ITEM_PUSH ,
1189
+ vec. span,
1190
+ "it looks like the same item is being pushed into this Vec" ,
1191
+ None ,
1192
+ & format!(
1193
+ "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})" ,
1194
+ item_str, vec_str, item_str
1195
+ ) ,
1196
+ )
1197
+ }
1198
+ }
1199
+ _ => { } ,
1200
+ }
1201
+ }
1202
+ }
1203
+ } ,
1204
+ // constant
1205
+ Res :: Def ( DefKind :: Const , ..) => span_lint_and_help (
1206
+ cx,
1207
+ SAME_ITEM_PUSH ,
1208
+ vec. span ,
1209
+ "it looks like the same item is being pushed into this Vec" ,
1210
+ None ,
1211
+ & format ! (
1212
+ "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})" ,
1213
+ item_str, vec_str, item_str
1214
+ ) ,
1215
+ ) ,
1216
+ _ => { } ,
1217
+ }
1218
+ } else if let ExprKind :: Lit ( ..) = pushed_item. kind {
1219
+ // literal
1220
+ span_lint_and_help (
1221
+ cx,
1222
+ SAME_ITEM_PUSH ,
1223
+ vec. span ,
1224
+ "it looks like the same item is being pushed into this Vec" ,
1225
+ None ,
1226
+ & format ! (
1227
+ "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})" ,
1228
+ item_str, vec_str, item_str
1229
+ ) ,
1230
+ )
1231
+ }
1160
1232
}
1161
1233
}
1162
1234
}
@@ -1177,7 +1249,7 @@ fn check_for_loop_range<'tcx>(
1177
1249
start : Some ( start) ,
1178
1250
ref end,
1179
1251
limits,
1180
- } ) = higher:: range ( cx , arg)
1252
+ } ) = higher:: range ( arg)
1181
1253
{
1182
1254
// the var must be a single name
1183
1255
if let PatKind :: Binding ( _, canonical_id, ident, _) = pat. kind {
@@ -1355,7 +1427,7 @@ fn is_end_eq_array_len<'tcx>(
1355
1427
if_chain ! {
1356
1428
if let ExprKind :: Lit ( ref lit) = end. kind;
1357
1429
if let ast:: LitKind :: Int ( end_int, _) = lit. node;
1358
- if let ty:: Array ( _, arr_len_const) = indexed_ty. kind;
1430
+ if let ty:: Array ( _, arr_len_const) = indexed_ty. kind( ) ;
1359
1431
if let Some ( arr_len) = arr_len_const. try_eval_usize( cx. tcx, cx. param_env) ;
1360
1432
then {
1361
1433
return match limits {
@@ -1592,7 +1664,7 @@ fn check_for_loop_over_map_kv<'tcx>(
1592
1664
if let PatKind :: Tuple ( ref pat, _) = pat. kind {
1593
1665
if pat. len ( ) == 2 {
1594
1666
let arg_span = arg. span ;
1595
- let ( new_pat_span, kind, ty, mutbl) = match cx. typeck_results ( ) . expr_ty ( arg) . kind {
1667
+ let ( new_pat_span, kind, ty, mutbl) = match * cx. typeck_results ( ) . expr_ty ( arg) . kind ( ) {
1596
1668
ty:: Ref ( _, ty, mutbl) => match ( & pat[ 0 ] . kind , & pat[ 1 ] . kind ) {
1597
1669
( key, _) if pat_is_wild ( key, body) => ( pat[ 1 ] . span , "value" , ty, mutbl) ,
1598
1670
( _, value) if pat_is_wild ( value, body) => ( pat[ 0 ] . span , "key" , ty, Mutability :: Not ) ,
@@ -1679,7 +1751,7 @@ fn check_for_mut_range_bound(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'
1679
1751
start : Some ( start) ,
1680
1752
end : Some ( end) ,
1681
1753
..
1682
- } ) = higher:: range ( cx , arg)
1754
+ } ) = higher:: range ( arg)
1683
1755
{
1684
1756
let mut_ids = vec ! [ check_for_mutability( cx, start) , check_for_mutability( cx, end) ] ;
1685
1757
if mut_ids[ 0 ] . is_some ( ) || mut_ids[ 1 ] . is_some ( ) {
@@ -1920,7 +1992,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
1920
1992
for expr in args {
1921
1993
let ty = self . cx . typeck_results ( ) . expr_ty_adjusted ( expr) ;
1922
1994
self . prefer_mutable = false ;
1923
- if let ty:: Ref ( _, _, mutbl) = ty. kind {
1995
+ if let ty:: Ref ( _, _, mutbl) = * ty. kind ( ) {
1924
1996
if mutbl == Mutability :: Mut {
1925
1997
self . prefer_mutable = true ;
1926
1998
}
@@ -1932,7 +2004,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
1932
2004
let def_id = self . cx . typeck_results ( ) . type_dependent_def_id ( expr. hir_id ) . unwrap ( ) ;
1933
2005
for ( ty, expr) in self . cx . tcx . fn_sig ( def_id) . inputs ( ) . skip_binder ( ) . iter ( ) . zip ( args) {
1934
2006
self . prefer_mutable = false ;
1935
- if let ty:: Ref ( _, _, mutbl) = ty. kind {
2007
+ if let ty:: Ref ( _, _, mutbl) = * ty. kind ( ) {
1936
2008
if mutbl == Mutability :: Mut {
1937
2009
self . prefer_mutable = true ;
1938
2010
}
@@ -2030,7 +2102,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
2030
2102
2031
2103
fn is_iterable_array < ' tcx > ( ty : Ty < ' tcx > , cx : & LateContext < ' tcx > ) -> bool {
2032
2104
// IntoIterator is currently only implemented for array sizes <= 32 in rustc
2033
- match ty. kind {
2105
+ match ty. kind ( ) {
2034
2106
ty:: Array ( _, n) => n
2035
2107
. try_eval_usize ( cx. tcx , cx. param_env )
2036
2108
. map_or ( false , |val| ( 0 ..=32 ) . contains ( & val) ) ,
0 commit comments