Skip to content

Commit

Permalink
Fix bug where methods defined using lambdas were flagged by FURB118
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexWaygood committed Nov 27, 2024
1 parent 6fcbe8e commit 350dafd
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 19 deletions.
9 changes: 9 additions & 0 deletions crates/ruff_linter/resources/test/fixtures/refurb/FURB118.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,12 @@ def add(x, y):

# Without a slice, trivia is retained
op_itemgetter = lambda x: x[1, 2]


# All methods in classes are ignored, even those defined using lambdas:
class Foo:
def x(self, other):
return self == other

class Bar:
y = lambda selfff, other: self == other
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ruff_python_ast::Expr;

use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::rules::{flake8_builtins, flake8_pie, pylint, refurb};
use crate::rules::{flake8_builtins, flake8_pie, pylint};

/// Run lint rules over all deferred lambdas in the [`SemanticModel`].
pub(crate) fn deferred_lambdas(checker: &mut Checker) {
Expand All @@ -21,9 +21,6 @@ pub(crate) fn deferred_lambdas(checker: &mut Checker) {
if checker.enabled(Rule::ReimplementedContainerBuiltin) {
flake8_pie::rules::reimplemented_container_builtin(checker, lambda);
}
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &lambda.into());
}
if checker.enabled(Rule::BuiltinLambdaArgumentShadowing) {
flake8_builtins::rules::builtin_lambda_argument_shadowing(checker, lambda);
}
Expand Down
5 changes: 5 additions & 0 deletions crates/ruff_linter/src/checkers/ast/analyze/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1650,6 +1650,11 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
ruff::rules::assignment_in_assert(checker, expr);
}
}
Expr::Lambda(lambda_expr) => {
if checker.enabled(Rule::ReimplementedOperator) {
refurb::rules::reimplemented_operator(checker, &lambda_expr.into());
}
}
_ => {}
};
}
34 changes: 20 additions & 14 deletions crates/ruff_linter/src/rules/refurb/rules/reimplemented_operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,7 @@ impl Violation for ReimplementedOperator {
#[derive_message_formats]
fn message(&self) -> String {
let ReimplementedOperator { operator, target } = self;
match target {
FunctionLikeKind::Function => {
format!("Use `operator.{operator}` instead of defining a function")
}
FunctionLikeKind::Lambda => {
format!("Use `operator.{operator}` instead of defining a lambda")
}
}
format!("Use `operator.{operator}` instead of defining a {target}")
}

fn fix_title(&self) -> Option<String> {
Expand All @@ -78,11 +71,9 @@ impl Violation for ReimplementedOperator {

/// FURB118
pub(crate) fn reimplemented_operator(checker: &mut Checker, target: &FunctionLike) {
// Ignore methods.
if target.kind() == FunctionLikeKind::Function {
if checker.semantic().current_scope().kind.is_class() {
return;
}
// Ignore methods, whether defined using the `def` keyword or via a `lambda` assignment.
if checker.semantic().current_scope().kind.is_class() {
return;
}

let Some(params) = target.parameters() else {
Expand Down Expand Up @@ -327,12 +318,27 @@ fn get_operator(expr: &Expr, params: &Parameters, locator: &Locator) -> Option<O
}
}

#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum FunctionLikeKind {
Lambda,
Function,
}

impl FunctionLikeKind {
const fn as_str(self) -> &'static str {
match self {
Self::Lambda => "lambda",
Self::Function => "function",
}
}
}

impl Display for FunctionLikeKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}

/// Return the name of the `operator` implemented by the given unary expression.
fn unary_op(expr: &ast::ExprUnaryOp, params: &Parameters) -> Option<&'static str> {
let [arg] = params.args.as_slice() else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
---
source: crates/ruff_linter/src/rules/refurb/mod.rs
snapshot_kind: text
---
FURB118.py:2:13: FURB118 [*] Use `operator.invert` instead of defining a lambda
|
Expand Down Expand Up @@ -947,3 +946,6 @@ FURB118.py:95:17: FURB118 [*] Use `operator.itemgetter((1, 2))` instead
94 95 | # Without a slice, trivia is retained
95 |-op_itemgetter = lambda x: x[1, 2]
96 |+op_itemgetter = operator.itemgetter((1, 2))
96 97 |
97 98 |
98 99 | # All methods in classes are ignored, even those defined using lambdas:

0 comments on commit 350dafd

Please sign in to comment.