“it is more concise to loop over references to containers instead of using explicit iteration methods” https://rust-lang.github.io/rust-clippy/master/index.html#explicit_iter_loop Signed-off-by: Anders Kaseorg <andersk@mit.edu>
65 lines
1.8 KiB
Rust
65 lines
1.8 KiB
Rust
use rustc_hash::FxHashMap;
|
|
use rustpython_ast::{Expr, ExprKind};
|
|
|
|
use crate::ast::types::Range;
|
|
use crate::ast::visitor;
|
|
use crate::ast::visitor::Visitor;
|
|
use crate::check_ast::Checker;
|
|
use crate::checks::{Check, CheckKind};
|
|
|
|
#[derive(Default)]
|
|
struct NameFinder<'a> {
|
|
names: FxHashMap<&'a str, &'a Expr>,
|
|
}
|
|
|
|
impl<'a, 'b> Visitor<'b> for NameFinder<'a>
|
|
where
|
|
'b: 'a,
|
|
{
|
|
fn visit_expr(&mut self, expr: &'b Expr) {
|
|
match &expr.node {
|
|
ExprKind::Name { id, .. } => {
|
|
self.names.insert(id, expr);
|
|
}
|
|
ExprKind::ListComp { generators, .. }
|
|
| ExprKind::DictComp { generators, .. }
|
|
| ExprKind::SetComp { generators, .. }
|
|
| ExprKind::GeneratorExp { generators, .. } => {
|
|
for comp in generators {
|
|
self.visit_expr(&comp.iter);
|
|
}
|
|
}
|
|
ExprKind::Lambda { args, body } => {
|
|
visitor::walk_expr(self, body);
|
|
for arg in &args.args {
|
|
self.names.remove(arg.node.arg.as_str());
|
|
}
|
|
}
|
|
_ => visitor::walk_expr(self, expr),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// B020
|
|
pub fn loop_variable_overrides_iterator(checker: &mut Checker, target: &Expr, iter: &Expr) {
|
|
let target_names = {
|
|
let mut target_finder = NameFinder::default();
|
|
target_finder.visit_expr(target);
|
|
target_finder.names
|
|
};
|
|
let iter_names = {
|
|
let mut iter_finder = NameFinder::default();
|
|
iter_finder.visit_expr(iter);
|
|
iter_finder.names
|
|
};
|
|
|
|
for (name, expr) in target_names {
|
|
if iter_names.contains_key(name) {
|
|
checker.add_check(Check::new(
|
|
CheckKind::LoopVariableOverridesIterator(name.to_string()),
|
|
Range::from_located(expr),
|
|
));
|
|
}
|
|
}
|
|
}
|