Skip to content

Commit c599e2f

Browse files
committed
Split VarState
1 parent 31cb110 commit c599e2f

File tree

1 file changed

+48
-39
lines changed

1 file changed

+48
-39
lines changed

clippy_lints/src/loops.rs

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2107,23 +2107,18 @@ fn is_simple_break_expr(expr: &Expr<'_>) -> bool {
21072107
}
21082108
}
21092109

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.
21132110
#[derive(Debug, PartialEq)]
2114-
enum VarState {
2111+
enum IncrementVisitorVarState {
21152112
Initial, // Not examined yet
21162113
IncrOnce, // Incremented exactly once, may be a loop counter
2117-
Declared, // Declared but not (yet) initialized to zero
2118-
Warn,
21192114
DontWarn,
21202115
}
21212116

21222117
/// Scan a for loop for variables that are incremented exactly once and not used after that.
21232118
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
21272122
done: bool,
21282123
}
21292124

@@ -2140,7 +2135,7 @@ impl<'a, 'tcx> IncrementVisitor<'a, 'tcx> {
21402135
fn into_results(self) -> impl Iterator<Item = HirId> {
21412136
self.states
21422137
.into_iter()
2143-
.filter(|(_, state)| *state == VarState::IncrOnce)
2138+
.filter(|(_, state)| *state == IncrementVisitorVarState::IncrOnce)
21442139
.map(|(id, _)| id)
21452140
}
21462141
}
@@ -2156,9 +2151,9 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
21562151
// If node is a variable
21572152
if let Some(def_id) = var_def_id(self.cx, expr) {
21582153
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;
21622157
return;
21632158
}
21642159

@@ -2167,19 +2162,21 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
21672162
if lhs.hir_id == expr.hir_id {
21682163
*state = if op.node == BinOpKind::Add
21692164
&& is_integer_const(self.cx, rhs, 1)
2170-
&& *state == VarState::Initial
2165+
&& *state == IncrementVisitorVarState::Initial
21712166
&& self.depth == 0
21722167
{
2173-
VarState::IncrOnce
2168+
IncrementVisitorVarState::IncrOnce
21742169
} else {
21752170
// Assigned some other value or assigned multiple times
2176-
VarState::DontWarn
2171+
IncrementVisitorVarState::DontWarn
21772172
};
21782173
}
21792174
},
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+
},
21812178
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
2182-
*state = VarState::DontWarn
2179+
*state = IncrementVisitorVarState::DontWarn
21832180
},
21842181
_ => (),
21852182
}
@@ -2201,13 +2198,20 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
22012198
}
22022199
}
22032200

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.
22052210
struct InitializeVisitor<'a, 'tcx> {
22062211
cx: &'a LateContext<'tcx>, // context reference
22072212
end_expr: &'tcx Expr<'tcx>, // the for loop. Stop scanning here.
22082213
var_id: HirId,
2209-
state: VarState,
2210-
name: Option<Symbol>,
2214+
state: InitializeVisitorState,
22112215
depth: u32, // depth of conditional expressions
22122216
past_loop: bool,
22132217
}
@@ -2218,16 +2222,15 @@ impl<'a, 'tcx> InitializeVisitor<'a, 'tcx> {
22182222
cx,
22192223
end_expr,
22202224
var_id,
2221-
state: VarState::IncrOnce,
2222-
name: None,
2225+
state: InitializeVisitorState::Initial,
22232226
depth: 0,
22242227
past_loop: false,
22252228
}
22262229
}
22272230

22282231
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)
22312234
} else {
22322235
None
22332236
}
@@ -2244,23 +2247,24 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
22442247
if local.pat.hir_id == self.var_id;
22452248
if let PatKind::Binding(.., ident, _) = local.pat.kind;
22462249
then {
2247-
self.name = Some(ident.name);
22482250
self.state = if_chain! {
22492251
if let Some(ref init) = local.init;
22502252
if is_integer_const(&self.cx, init, 0);
22512253
then {
2252-
VarState::Warn
2253-
} else {
2254-
VarState::Declared
2254+
InitializeVisitorState::Initialized {
2255+
name: ident.name
22552256
}
2257+
} else {
2258+
InitializeVisitorState::Declared(ident.name)
22562259
}
22572260
}
22582261
}
2262+
}
22592263
walk_stmt(self, stmt);
22602264
}
22612265

22622266
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
2263-
if self.state == VarState::DontWarn {
2267+
if matches!(self.state, InitializeVisitorState::DontWarn) {
22642268
return;
22652269
}
22662270
if expr.hir_id == self.end_expr.hir_id {
@@ -2269,39 +2273,44 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
22692273
}
22702274
// No need to visit expressions before the variable is
22712275
// declared
2272-
if self.state == VarState::IncrOnce {
2276+
if matches!(self.state, InitializeVisitorState::Initial) {
22732277
return;
22742278
}
22752279

22762280
// If node is the desired variable, see how it's used
22772281
if var_def_id(self.cx, expr) == Some(self.var_id) {
22782282
if self.past_loop {
2279-
self.state = VarState::DontWarn;
2283+
self.state = InitializeVisitorState::DontWarn;
22802284
return;
22812285
}
22822286

22832287
if let Some(parent) = get_parent_expr(self.cx, expr) {
22842288
match parent.kind {
22852289
ExprKind::AssignOp(_, ref lhs, _) if lhs.hir_id == expr.hir_id => {
2286-
self.state = VarState::DontWarn;
2290+
self.state = InitializeVisitorState::DontWarn;
22872291
},
22882292
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+
}
22932302
}
22942303
},
22952304
ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => {
2296-
self.state = VarState::DontWarn
2305+
self.state = InitializeVisitorState::DontWarn
22972306
},
22982307
_ => (),
22992308
}
23002309
}
23012310

23022311
walk_expr(self, expr);
23032312
} else if !self.past_loop && is_loop(expr) {
2304-
self.state = VarState::DontWarn;
2313+
self.state = InitializeVisitorState::DontWarn;
23052314
} else if is_conditional(expr) {
23062315
self.depth += 1;
23072316
walk_expr(self, expr);

0 commit comments

Comments
 (0)