mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
lint: while immutable condition: refactor to use hir::Visitor
This commit is contained in:
parent
5c1be4a4ba
commit
37eca59438
2 changed files with 43 additions and 41 deletions
|
@ -689,46 +689,6 @@ fn check_for_loop<'a, 'tcx>(
|
||||||
detect_manual_memcpy(cx, pat, arg, body, expr);
|
detect_manual_memcpy(cx, pat, arg, body, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_mutable_vars<'a, 'tcx> (
|
|
||||||
cx: &LateContext<'a, 'tcx>,
|
|
||||||
ex: &'tcx Expr,
|
|
||||||
acc: &mut Vec<NodeId>,
|
|
||||||
) -> bool {
|
|
||||||
match ex.node {
|
|
||||||
ExprBinary(_, ref a, ref b) =>
|
|
||||||
search_mutable_vars(cx, a, acc) && search_mutable_vars(cx, b, acc),
|
|
||||||
|
|
||||||
ExprUnary(_, ref a) => search_mutable_vars(cx, a, acc),
|
|
||||||
ExprPath(_) => {
|
|
||||||
if let Some(node_id) = check_for_mutability(cx, &ex) {
|
|
||||||
acc.push(node_id);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
ExprLit(_) => true,
|
|
||||||
|
|
||||||
// Skip if any method or function call is encountered
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_infinite_loop<'a, 'tcx>(
|
|
||||||
cx: &LateContext<'a, 'tcx>,
|
|
||||||
cond: &'tcx Expr,
|
|
||||||
_block: &'tcx Block,
|
|
||||||
_expr: &'tcx Expr,
|
|
||||||
) {
|
|
||||||
let mut mutable_vars = Vec::new();
|
|
||||||
if search_mutable_vars(cx, cond, &mut mutable_vars) && mutable_vars.len() == 0 {
|
|
||||||
span_lint(
|
|
||||||
cx,
|
|
||||||
WHILE_IMMUTABLE_CONDITION,
|
|
||||||
cond.span,
|
|
||||||
"all variables in condition are immutable. This might lead to infinite loops."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> bool {
|
fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr, var: ast::NodeId) -> bool {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprPath(ref qpath) = expr.node;
|
if let ExprPath(ref qpath) = expr.node;
|
||||||
|
@ -2179,3 +2139,45 @@ fn path_name(e: &Expr) -> Option<Name> {
|
||||||
};
|
};
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, _block: &'tcx Block, _expr: &'tcx Expr) {
|
||||||
|
let mut mut_var_visitor = MutableVarsVisitor {
|
||||||
|
cx,
|
||||||
|
ids: HashSet::new(),
|
||||||
|
skip: false,
|
||||||
|
};
|
||||||
|
walk_expr(&mut mut_var_visitor, cond);
|
||||||
|
if !mut_var_visitor.skip && mut_var_visitor.ids.len() == 0 {
|
||||||
|
span_lint(
|
||||||
|
cx,
|
||||||
|
WHILE_IMMUTABLE_CONDITION,
|
||||||
|
cond.span,
|
||||||
|
"all variables in condition are immutable. This might lead to infinite loops.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MutableVarsVisitor<'a, 'tcx: 'a> {
|
||||||
|
cx: &'a LateContext<'a, 'tcx>,
|
||||||
|
ids: HashSet<NodeId>,
|
||||||
|
skip: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'tcx> Visitor<'tcx> for MutableVarsVisitor<'a, 'tcx> {
|
||||||
|
fn visit_expr(&mut self, ex: &'tcx Expr) {
|
||||||
|
match ex.node {
|
||||||
|
ExprPath(_) => if let Some(node_id) = check_for_mutability(self.cx, &ex) {
|
||||||
|
self.ids.insert(node_id);
|
||||||
|
},
|
||||||
|
|
||||||
|
// If there is any fuction/method call… we just stop analysis
|
||||||
|
ExprCall(_, _) | ExprMethodCall(_, _, _) => self.skip = true,
|
||||||
|
|
||||||
|
_ => walk_expr(self, ex),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||||
|
NestedVisitorMap::None
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,8 +77,8 @@ fn used_immutable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
while i < 3 {
|
while i < 3 {
|
||||||
fn_mutref(&mut i);
|
|
||||||
println!("OK - passed by mutable reference");
|
println!("OK - passed by mutable reference");
|
||||||
|
fn_mutref(&mut i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue