@@ -1068,7 +1068,7 @@ fn check_for_loop_range<'a, 'tcx>(
10681068
10691069 // linting condition: we only indexed one variable, and indexed it directly
10701070 if visitor. indexed_indirectly . is_empty ( ) && visitor. indexed_directly . len ( ) == 1 {
1071- let ( indexed, indexed_extent) = visitor
1071+ let ( indexed, ( indexed_extent, indexed_ty ) ) = visitor
10721072 . indexed_directly
10731073 . into_iter ( )
10741074 . next ( )
@@ -1119,7 +1119,7 @@ fn check_for_loop_range<'a, 'tcx>(
11191119 }
11201120 }
11211121
1122- if is_len_call ( end, indexed) {
1122+ if is_len_call ( end, indexed) || is_end_eq_array_len ( cx , end , limits , indexed_ty ) {
11231123 String :: new ( )
11241124 } else {
11251125 match limits {
@@ -1207,6 +1207,28 @@ fn is_len_call(expr: &Expr, var: Name) -> bool {
12071207 false
12081208}
12091209
1210+ fn is_end_eq_array_len (
1211+ cx : & LateContext < ' _ , ' _ > ,
1212+ end : & Expr ,
1213+ limits : ast:: RangeLimits ,
1214+ indexed_ty : Ty < ' _ > ,
1215+ ) -> bool {
1216+ if_chain ! {
1217+ if let ExprKind :: Lit ( ref lit) = end. node;
1218+ if let ast:: LitKind :: Int ( end_int, _) = lit. node;
1219+ if let ty:: TyKind :: Array ( _, arr_len_const) = indexed_ty. sty;
1220+ if let Some ( arr_len) = arr_len_const. assert_usize( cx. tcx) ;
1221+ then {
1222+ return match limits {
1223+ ast:: RangeLimits :: Closed => end_int + 1 >= arr_len. into( ) ,
1224+ ast:: RangeLimits :: HalfOpen => end_int >= arr_len. into( ) ,
1225+ } ;
1226+ }
1227+ }
1228+
1229+ false
1230+ }
1231+
12101232fn check_for_loop_reverse_range < ' a , ' tcx > ( cx : & LateContext < ' a , ' tcx > , arg : & ' tcx Expr , expr : & ' tcx Expr ) {
12111233 // if this for loop is iterating over a two-sided range...
12121234 if let Some ( higher:: Range {
@@ -1678,7 +1700,7 @@ struct VarVisitor<'a, 'tcx: 'a> {
16781700 indexed_indirectly : FxHashMap < Name , Option < region:: Scope > > ,
16791701 /// subset of `indexed` of vars that are indexed directly: `v[i]`
16801702 /// this will not contain cases like `v[calc_index(i)]` or `v[(i + 4) % N]`
1681- indexed_directly : FxHashMap < Name , Option < region:: Scope > > ,
1703+ indexed_directly : FxHashMap < Name , ( Option < region:: Scope > , Ty < ' tcx > ) > ,
16821704 /// Any names that are used outside an index operation.
16831705 /// Used to detect things like `&mut vec` used together with `vec[i]`
16841706 referenced : FxHashSet < Name > ,
@@ -1725,7 +1747,10 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
17251747 self . indexed_indirectly. insert( seqvar. segments[ 0 ] . ident. name, Some ( extent) ) ;
17261748 }
17271749 if index_used_directly {
1728- self . indexed_directly. insert( seqvar. segments[ 0 ] . ident. name, Some ( extent) ) ;
1750+ self . indexed_directly. insert(
1751+ seqvar. segments[ 0 ] . ident. name,
1752+ ( Some ( extent) , self . cx. tables. node_id_to_type( seqexpr. hir_id) ) ,
1753+ ) ;
17291754 }
17301755 return false ; // no need to walk further *on the variable*
17311756 }
@@ -1734,7 +1759,10 @@ impl<'a, 'tcx> VarVisitor<'a, 'tcx> {
17341759 self . indexed_indirectly. insert( seqvar. segments[ 0 ] . ident. name, None ) ;
17351760 }
17361761 if index_used_directly {
1737- self . indexed_directly. insert( seqvar. segments[ 0 ] . ident. name, None ) ;
1762+ self . indexed_directly. insert(
1763+ seqvar. segments[ 0 ] . ident. name,
1764+ ( None , self . cx. tables. node_id_to_type( seqexpr. hir_id) ) ,
1765+ ) ;
17381766 }
17391767 return false ; // no need to walk further *on the variable*
17401768 }
0 commit comments