Skip to content

Commit

Permalink
add generator/compehrension expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
diceroll123 committed Oct 22, 2023
1 parent 6f30786 commit f2d1f1e
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@


def fix_these():
[letters[index] for index, letter in enumerate(letters)] # PLR1736
{letters[index] for index, letter in enumerate(letters)} # PLR1736
{letter: letters[index] for index, letter in enumerate(letters)} # PLR1736

for index, letter in enumerate(letters):
print(letters[index]) # PLR1736
blah = letters[index] # PLR1736
Expand All @@ -16,6 +20,10 @@ def dont_fix_these():


def value_intentionally_unused():
[letters[index] for index, _ in enumerate(letters)] # PLR1736
{letters[index] for index, _ in enumerate(letters)} # PLR1736
{index: letters[index] for index, _ in enumerate(letters)} # PLR1736

for index, _ in enumerate(letters):
print(letters[index]) # Ok
blah = letters[index] # Ok
Expand Down
12 changes: 12 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1295,6 +1295,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
range: _,
},
) => {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_list_set_comprehension(
checker, expr, elt, generators,
Expand All @@ -1319,6 +1322,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
range: _,
},
) => {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_list_set_comprehension(
checker, expr, elt, generators,
Expand All @@ -1342,6 +1348,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
generators,
range: _,
}) => {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::UnnecessaryComprehension) {
flake8_comprehensions::rules::unnecessary_dict_comprehension(
checker, expr, key, value, generators,
Expand All @@ -1366,6 +1375,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
range: _,
},
) => {
if checker.enabled(Rule::UnnecessaryListIndexLookup) {
pylint::rules::unnecessary_list_index_lookup_comprehension(checker, expr);
}
if checker.enabled(Rule::FunctionUsesLoopVariable) {
flake8_bugbear::rules::function_uses_loop_variable(checker, &Node::Expr(expr));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,63 +102,119 @@ impl<'a> Visitor<'_> for SubscriptVisitor<'a> {

/// PLR1736
pub(crate) fn unnecessary_list_index_lookup(checker: &mut Checker, stmt_for: &StmtFor) {
let Some((sequence, index_name, value_name)) =
enumerate_items(checker, &stmt_for.iter, &stmt_for.target)
else {
return;
};

let mut visitor = SubscriptVisitor::new(&sequence, &index_name);

visitor.visit_body(&stmt_for.body);
visitor.visit_body(&stmt_for.orelse);

for range in visitor.diagnostic_ranges {
let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range);

diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
value_name.clone(),
range,
)));

checker.diagnostics.push(diagnostic);
}
}

/// PLR1736
pub(crate) fn unnecessary_list_index_lookup_comprehension(checker: &mut Checker, expr: &Expr) {
match expr {
Expr::GeneratorExp(ast::ExprGeneratorExp {
elt, generators, ..
})
| Expr::DictComp(ast::ExprDictComp {
value: elt,
generators,
..
})
| Expr::SetComp(ast::ExprSetComp {
elt, generators, ..
})
| Expr::ListComp(ast::ExprListComp {
elt, generators, ..
}) => {
for comp in generators {
if let Some((sequence, index_name, value_name)) =
enumerate_items(checker, &comp.iter, &comp.target)
{
let mut visitor = SubscriptVisitor::new(&sequence, &index_name);

visitor.visit_expr(elt.as_ref());

for range in visitor.diagnostic_ranges {
let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range);

diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
value_name.clone(),
range,
)));

checker.diagnostics.push(diagnostic);
}
}
}
}
_ => (),
}
}

fn enumerate_items(
checker: &mut Checker,
call_expr: &Expr,
tuple_expr: &Expr,
) -> Option<(String, String, String)> {
let Expr::Call(ast::ExprCall {
func, arguments, ..
}) = stmt_for.iter.as_ref()
}) = call_expr
else {
return;
return None;
};

// Check that the function is the `enumerate` builtin.
let Expr::Name(ast::ExprName { id, .. }) = func.as_ref() else {
return;
return None;
};
if id != "enumerate" {
return;
return None;
};
if !checker.semantic().is_builtin("enumerate") {
return;
return None;
};

let Expr::Tuple(ast::ExprTuple { elts, .. }) = stmt_for.target.as_ref() else {
return;
let Expr::Tuple(ast::ExprTuple { elts, .. }) = tuple_expr else {
return None;
};
let [index, value] = elts.as_slice() else {
return;
return None;
};

// Grab the variable names
let Expr::Name(ast::ExprName { id: index_name, .. }) = index else {
return;
return None;
};

let Expr::Name(ast::ExprName { id: value_name, .. }) = value else {
return;
return None;
};

// If either of the variable names are intentionally ignored by naming them `_`, then don't emit
if index_name == "_" || value_name == "_" {
return;
return None;
}

// Get the first argument of the enumerate call
let Some(Expr::Name(ast::ExprName { id: sequence, .. })) = arguments.args.first() else {
return;
return None;
};

let mut visitor = SubscriptVisitor::new(sequence, index_name);

visitor.visit_body(&stmt_for.body);
visitor.visit_body(&stmt_for.orelse);

for range in visitor.diagnostic_ranges {
let mut diagnostic = Diagnostic::new(UnnecessaryListIndexLookup, range);

diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
value_name.clone(),
range,
)));

checker.diagnostics.push(diagnostic);
}
Some((sequence.clone(), index_name.clone(), value_name.clone()))
}
Loading

0 comments on commit f2d1f1e

Please sign in to comment.