@@ -2107,23 +2107,18 @@ fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
2107
2107
}
2108
2108
}
2109
2109
2110
- // To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
2111
- // incremented exactly once in the loop body, and initialized to zero
2112
- // at the start of the loop.
2113
2110
#[ derive( Debug , PartialEq ) ]
2114
- enum VarState {
2111
+ enum IncrementVisitorVarState {
2115
2112
Initial , // Not examined yet
2116
2113
IncrOnce , // Incremented exactly once, may be a loop counter
2117
- Declared , // Declared but not (yet) initialized to zero
2118
- Warn ,
2119
2114
DontWarn ,
2120
2115
}
2121
2116
2122
2117
/// Scan a for loop for variables that are incremented exactly once and not used after that.
2123
2118
struct IncrementVisitor < ' a , ' tcx > {
2124
- cx : & ' a LateContext < ' tcx > , // context reference
2125
- states : FxHashMap < HirId , VarState > , // incremented variables
2126
- depth : u32 , // depth of conditional expressions
2119
+ cx : & ' a LateContext < ' tcx > , // context reference
2120
+ states : FxHashMap < HirId , IncrementVisitorVarState > , // incremented variables
2121
+ depth : u32 , // depth of conditional expressions
2127
2122
done : bool ,
2128
2123
}
2129
2124
@@ -2140,7 +2135,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
2140
2135
fn into_results ( self ) -> impl Iterator < Item = HirId > {
2141
2136
self . states
2142
2137
. into_iter ( )
2143
- . filter ( |( _, state) | * state == VarState :: IncrOnce )
2138
+ . filter ( |( _, state) | * state == IncrementVisitorVarState :: IncrOnce )
2144
2139
. map ( |( id, _) | id)
2145
2140
}
2146
2141
}
@@ -2156,9 +2151,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
2156
2151
// If node is a variable
2157
2152
if let Some ( def_id) = var_def_id ( self . cx , expr) {
2158
2153
if let Some ( parent) = get_parent_expr ( self . cx , expr) {
2159
- let state = self . states . entry ( def_id) . or_insert ( VarState :: Initial ) ;
2160
- if * state == VarState :: IncrOnce {
2161
- * state = VarState :: DontWarn ;
2154
+ let state = self . states . entry ( def_id) . or_insert ( IncrementVisitorVarState :: Initial ) ;
2155
+ if * state == IncrementVisitorVarState :: IncrOnce {
2156
+ * state = IncrementVisitorVarState :: DontWarn ;
2162
2157
return ;
2163
2158
}
2164
2159
@@ -2167,19 +2162,21 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
2167
2162
if lhs. hir_id == expr. hir_id {
2168
2163
* state = if op. node == BinOpKind :: Add
2169
2164
&& is_integer_const ( self . cx , rhs, 1 )
2170
- && * state == VarState :: Initial
2165
+ && * state == IncrementVisitorVarState :: Initial
2171
2166
&& self . depth == 0
2172
2167
{
2173
- VarState :: IncrOnce
2168
+ IncrementVisitorVarState :: IncrOnce
2174
2169
} else {
2175
2170
// Assigned some other value or assigned multiple times
2176
- VarState :: DontWarn
2171
+ IncrementVisitorVarState :: DontWarn
2177
2172
} ;
2178
2173
}
2179
2174
} ,
2180
- ExprKind :: Assign ( ref lhs, _, _) if lhs. hir_id == expr. hir_id => * state = VarState :: DontWarn ,
2175
+ ExprKind :: Assign ( ref lhs, _, _) if lhs. hir_id == expr. hir_id => {
2176
+ * state = IncrementVisitorVarState :: DontWarn
2177
+ } ,
2181
2178
ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) if mutability == Mutability :: Mut => {
2182
- * state = VarState :: DontWarn
2179
+ * state = IncrementVisitorVarState :: DontWarn
2183
2180
} ,
2184
2181
_ => ( ) ,
2185
2182
}
@@ -2201,13 +2198,20 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
2201
2198
}
2202
2199
}
2203
2200
2204
- /// Checks whether a variable is initialized to zero at the start of a loop.
2201
+ enum InitializeVisitorState {
2202
+ Initial , // Not examined yet
2203
+ Declared ( Symbol ) , // Declared but not (yet) initialized
2204
+ Initialized { name : Symbol } ,
2205
+ DontWarn ,
2206
+ }
2207
+
2208
+ /// Checks whether a variable is initialized to zero at the start of a loop and not modified
2209
+ /// and used after the loop.
2205
2210
struct InitializeVisitor < ' a , ' tcx > {
2206
2211
cx : & ' a LateContext < ' tcx > , // context reference
2207
2212
end_expr : & ' tcx Expr < ' tcx > , // the for loop. Stop scanning here.
2208
2213
var_id : HirId ,
2209
- state : VarState ,
2210
- name : Option < Symbol > ,
2214
+ state : InitializeVisitorState ,
2211
2215
depth : u32 , // depth of conditional expressions
2212
2216
past_loop : bool ,
2213
2217
}
@@ -2218,16 +2222,15 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
2218
2222
cx,
2219
2223
end_expr,
2220
2224
var_id,
2221
- state : VarState :: IncrOnce ,
2222
- name : None ,
2225
+ state : InitializeVisitorState :: Initial ,
2223
2226
depth : 0 ,
2224
2227
past_loop : false ,
2225
2228
}
2226
2229
}
2227
2230
2228
2231
fn get_result ( & self ) -> Option < Name > {
2229
- if self . state == VarState :: Warn {
2230
- self . name
2232
+ if let InitializeVisitorState :: Initialized { name } = self . state {
2233
+ Some ( name)
2231
2234
} else {
2232
2235
None
2233
2236
}
@@ -2244,23 +2247,24 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
2244
2247
if local. pat. hir_id == self . var_id;
2245
2248
if let PatKind :: Binding ( .., ident, _) = local. pat. kind;
2246
2249
then {
2247
- self . name = Some ( ident. name) ;
2248
2250
self . state = if_chain! {
2249
2251
if let Some ( ref init) = local. init;
2250
2252
if is_integer_const( & self . cx, init, 0 ) ;
2251
2253
then {
2252
- VarState :: Warn
2253
- } else {
2254
- VarState :: Declared
2254
+ InitializeVisitorState :: Initialized {
2255
+ name: ident. name
2255
2256
}
2257
+ } else {
2258
+ InitializeVisitorState :: Declared ( ident. name)
2256
2259
}
2257
2260
}
2258
2261
}
2262
+ }
2259
2263
walk_stmt ( self , stmt) ;
2260
2264
}
2261
2265
2262
2266
fn visit_expr ( & mut self , expr : & ' tcx Expr < ' _ > ) {
2263
- if self . state == VarState :: DontWarn {
2267
+ if matches ! ( self . state, InitializeVisitorState :: DontWarn ) {
2264
2268
return ;
2265
2269
}
2266
2270
if expr. hir_id == self . end_expr . hir_id {
@@ -2269,39 +2273,44 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
2269
2273
}
2270
2274
// No need to visit expressions before the variable is
2271
2275
// declared
2272
- if self . state == VarState :: IncrOnce {
2276
+ if matches ! ( self . state, InitializeVisitorState :: Initial ) {
2273
2277
return ;
2274
2278
}
2275
2279
2276
2280
// If node is the desired variable, see how it's used
2277
2281
if var_def_id ( self . cx , expr) == Some ( self . var_id ) {
2278
2282
if self . past_loop {
2279
- self . state = VarState :: DontWarn ;
2283
+ self . state = InitializeVisitorState :: DontWarn ;
2280
2284
return ;
2281
2285
}
2282
2286
2283
2287
if let Some ( parent) = get_parent_expr ( self . cx , expr) {
2284
2288
match parent. kind {
2285
2289
ExprKind :: AssignOp ( _, ref lhs, _) if lhs. hir_id == expr. hir_id => {
2286
- self . state = VarState :: DontWarn ;
2290
+ self . state = InitializeVisitorState :: DontWarn ;
2287
2291
} ,
2288
2292
ExprKind :: Assign ( ref lhs, ref rhs, _) if lhs. hir_id == expr. hir_id => {
2289
- self . state = if is_integer_const ( & self . cx , rhs, 0 ) && self . depth == 0 {
2290
- VarState :: Warn
2291
- } else {
2292
- VarState :: DontWarn
2293
+ self . state = if_chain ! {
2294
+ if is_integer_const( & self . cx, rhs, 0 ) && self . depth == 0 ;
2295
+ if let InitializeVisitorState :: Declared ( name)
2296
+ | InitializeVisitorState :: Initialized { name, ..} = self . state;
2297
+ then {
2298
+ InitializeVisitorState :: Initialized { name }
2299
+ } else {
2300
+ InitializeVisitorState :: DontWarn
2301
+ }
2293
2302
}
2294
2303
} ,
2295
2304
ExprKind :: AddrOf ( BorrowKind :: Ref , mutability, _) if mutability == Mutability :: Mut => {
2296
- self . state = VarState :: DontWarn
2305
+ self . state = InitializeVisitorState :: DontWarn
2297
2306
} ,
2298
2307
_ => ( ) ,
2299
2308
}
2300
2309
}
2301
2310
2302
2311
walk_expr ( self , expr) ;
2303
2312
} else if !self . past_loop && is_loop ( expr) {
2304
- self . state = VarState :: DontWarn ;
2313
+ self . state = InitializeVisitorState :: DontWarn ;
2305
2314
} else if is_conditional ( expr) {
2306
2315
self . depth += 1 ;
2307
2316
walk_expr ( self , expr) ;
0 commit comments