Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement autofix for unnecessary-lambda (PLW0108) #8621

Merged
merged 1 commit into from
Nov 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions crates/ruff_linter/src/rules/pylint/rules/unnecessary_lambda.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::helpers::contains_effect;
use ruff_python_ast::visitor::Visitor;
use ruff_python_ast::{self as ast, visitor, Expr, ExprLambda, Parameter, ParameterWithDefault};
use ruff_text_size::Ranged;
Expand All @@ -24,14 +25,29 @@ use crate::checkers::ast::Checker;
/// ```python
/// df.apply(str)
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe in cases in which the lambda body itself
/// contains an effect.
///
/// For example, replacing `lambda x, y: (func()(x, y))` with `func()` would
/// lead to a change in behavior, as `func()` would be evaluated eagerly when
/// defining the lambda, rather than when the lambda is called.
///
/// When the lambda body contains no visible effects, the fix is considered
/// safe.
#[violation]
pub struct UnnecessaryLambda;

impl Violation for UnnecessaryLambda {
impl AlwaysFixableViolation for UnnecessaryLambda {
#[derive_message_formats]
fn message(&self) -> String {
format!("Lambda may be unnecessary; consider inlining inner function")
}

fn fix_title(&self) -> String {
"Inline function call".to_string()
}
}

/// PLW0108
Expand Down Expand Up @@ -184,9 +200,19 @@ pub(crate) fn unnecessary_lambda(checker: &mut Checker, lambda: &ExprLambda) {
}
}

checker
.diagnostics
.push(Diagnostic::new(UnnecessaryLambda, lambda.range()));
let mut diagnostic = Diagnostic::new(UnnecessaryLambda, lambda.range());
diagnostic.set_fix(Fix::applicable_edit(
Edit::range_replacement(
checker.locator().slice(func.as_ref()).to_string(),
lambda.range(),
),
if contains_effect(func.as_ref(), |id| checker.semantic().is_builtin(id)) {
Applicability::Unsafe
} else {
Applicability::Safe
},
));
checker.diagnostics.push(diagnostic);
}

/// Identify all `Expr::Name` nodes in an AST.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
---
source: crates/ruff_linter/src/rules/pylint/mod.rs
---
unnecessary_lambda.py:1:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
unnecessary_lambda.py:1:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
1 | _ = lambda: print() # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^ PLW0108
2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
|
= help: Inline function call

unnecessary_lambda.py:2:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
ℹ Safe fix
1 |-_ = lambda: print() # [unnecessary-lambda]
1 |+_ = print # [unnecessary-lambda]
2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
3 3 |
4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda]

unnecessary_lambda.py:2:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
1 | _ = lambda: print() # [unnecessary-lambda]
2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^^^^^^^^ PLW0108
3 |
4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
|
= help: Inline function call

ℹ Safe fix
1 1 | _ = lambda: print() # [unnecessary-lambda]
2 |-_ = lambda x, y: min(x, y) # [unnecessary-lambda]
2 |+_ = min # [unnecessary-lambda]
3 3 |
4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]

unnecessary_lambda.py:4:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
unnecessary_lambda.py:4:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
3 |
Expand All @@ -26,26 +43,59 @@ unnecessary_lambda.py:4:5: PLW0108 Lambda may be unnecessary; consider inlining
5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
|
= help: Inline function call

unnecessary_lambda.py:5:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
ℹ Safe fix
1 1 | _ = lambda: print() # [unnecessary-lambda]
2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
3 3 |
4 |-_ = lambda *args: f(*args) # [unnecessary-lambda]
4 |+_ = f # [unnecessary-lambda]
5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
7 7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]

unnecessary_lambda.py:5:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW0108
6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
|
= help: Inline function call

ℹ Safe fix
2 2 | _ = lambda x, y: min(x, y) # [unnecessary-lambda]
3 3 |
4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 |-_ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
5 |+_ = f # [unnecessary-lambda]
6 6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
7 7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
8 8 |

unnecessary_lambda.py:6:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
unnecessary_lambda.py:6:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW0108
7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
|
= help: Inline function call

unnecessary_lambda.py:7:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
ℹ Safe fix
3 3 |
4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 |-_ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
6 |+_ = f # [unnecessary-lambda]
7 7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
8 8 |
9 9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]

unnecessary_lambda.py:7:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
Expand All @@ -54,23 +104,56 @@ unnecessary_lambda.py:7:5: PLW0108 Lambda may be unnecessary; consider inlining
8 |
9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
|
= help: Inline function call

ℹ Safe fix
4 4 | _ = lambda *args: f(*args) # [unnecessary-lambda]
5 5 | _ = lambda **kwargs: f(**kwargs) # [unnecessary-lambda]
6 6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
7 |-_ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
7 |+_ = f # [unnecessary-lambda]
8 8 |
9 9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
10 10 | _ = lambda x, y: f(lambda x, y: x + y)(x, y) # [unnecessary-lambda]

unnecessary_lambda.py:9:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
unnecessary_lambda.py:9:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
8 |
9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW0108
10 | _ = lambda x, y: f(lambda x, y: x + y)(x, y) # [unnecessary-lambda]
|
= help: Inline function call

unnecessary_lambda.py:10:5: PLW0108 Lambda may be unnecessary; consider inlining inner function
ℹ Unsafe fix
6 6 | _ = lambda *args, **kwargs: f(*args, **kwargs) # [unnecessary-lambda]
7 7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
8 8 |
9 |-_ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
9 |+_ = f(lambda x: x) # [unnecessary-lambda]
10 10 | _ = lambda x, y: f(lambda x, y: x + y)(x, y) # [unnecessary-lambda]
11 11 |
12 12 | # default value in lambda parameters

unnecessary_lambda.py:10:5: PLW0108 [*] Lambda may be unnecessary; consider inlining inner function
|
9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
10 | _ = lambda x, y: f(lambda x, y: x + y)(x, y) # [unnecessary-lambda]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLW0108
11 |
12 | # default value in lambda parameters
|
= help: Inline function call

ℹ Unsafe fix
7 7 | _ = lambda x, y, z, *args, **kwargs: f(x, y, z, *args, **kwargs) # [unnecessary-lambda]
8 8 |
9 9 | _ = lambda x: f(lambda x: x)(x) # [unnecessary-lambda]
10 |-_ = lambda x, y: f(lambda x, y: x + y)(x, y) # [unnecessary-lambda]
10 |+_ = f(lambda x, y: x + y) # [unnecessary-lambda]
11 11 |
12 12 | # default value in lambda parameters
13 13 | _ = lambda x=42: print(x)


Loading