From b62143611a4713e4729ce9ecb6398f5f94d82f1a Mon Sep 17 00:00:00 2001 From: cherryblossom <31467609+cherryblossom000@users.noreply.github.com> Date: Wed, 29 Mar 2023 06:52:17 +1100 Subject: Fix `unnecessary-lambda` false positive for lambdas using its parameters in their body (#8498) Fixes #8496 --- doc/whatsnew/fragments/8496.false_positive | 5 +++++ pylint/checkers/base/basic_checker.py | 8 ++++++++ tests/functional/u/unnecessary/unnecessary_lambda.py | 11 +++++++++++ tests/functional/u/unnecessary/unnecessary_lambda.txt | 2 ++ 4 files changed, 26 insertions(+) create mode 100644 doc/whatsnew/fragments/8496.false_positive diff --git a/doc/whatsnew/fragments/8496.false_positive b/doc/whatsnew/fragments/8496.false_positive new file mode 100644 index 000000000..3ea0fca6c --- /dev/null +++ b/doc/whatsnew/fragments/8496.false_positive @@ -0,0 +1,5 @@ +``unnecessary-lambda`` no longer warns on lambdas which use its parameters in +their body (other than the final arguments), e.g. +``lambda foo: (bar if foo else baz)(foo)``. + +Closes #8496 diff --git a/pylint/checkers/base/basic_checker.py b/pylint/checkers/base/basic_checker.py index 252266109..0c685da56 100644 --- a/pylint/checkers/base/basic_checker.py +++ b/pylint/checkers/base/basic_checker.py @@ -519,6 +519,7 @@ class BasicChecker(_BasicChecker): ) @utils.only_required_for_messages("unnecessary-lambda") + # pylint: disable-next=too-many-return-statements def visit_lambda(self, node: nodes.Lambda) -> None: """Check whether the lambda is suspicious.""" # if the body of the lambda is a call expression with the same @@ -576,6 +577,13 @@ class BasicChecker(_BasicChecker): if arg.name != passed_arg.name: return + # The lambda is necessary if it uses its parameter in the function it is + # calling in the lambda's body + # e.g. lambda foo: (func1 if foo else func2)(foo) + for name in call.func.nodes_of_class(nodes.Name): + if name.lookup(name.name)[0] is node: + return + self.add_message("unnecessary-lambda", line=node.fromlineno, node=node) @utils.only_required_for_messages("dangerous-default-value") diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.py b/tests/functional/u/unnecessary/unnecessary_lambda.py index 3e5ece2b1..82571a444 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.py +++ b/tests/functional/u/unnecessary/unnecessary_lambda.py @@ -24,6 +24,12 @@ _ = lambda *args, **kwargs: _ANYARGS(*args, **kwargs) # +1: [unnecessary-lambda] _ = lambda x, y, z, *args, **kwargs: _ANYARGS(x, y, z, *args, **kwargs) +# These don't use their parameters in their body +# +1: [unnecessary-lambda] +_ = lambda x: z(lambda x: x)(x) +# +1: [unnecessary-lambda] +_ = lambda x, y: z(lambda x, y: x + y)(x, y) + # Lambdas that are *not* unnecessary and should *not* trigger warnings. _ = lambda x: x _ = lambda x: x() @@ -50,3 +56,8 @@ _ = lambda: _ANYARGS(func=42) _ = lambda: code().analysis() _ = lambda **kwargs: dict(bar=42, **kwargs) + +# These use the lambda parameters in their body +_ = lambda x: x(x) +_ = lambda x, y: x(x, y) +_ = lambda x: z(lambda y: x + y)(x) diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.txt b/tests/functional/u/unnecessary/unnecessary_lambda.txt index 1cfb149df..87f80872c 100644 --- a/tests/functional/u/unnecessary/unnecessary_lambda.txt +++ b/tests/functional/u/unnecessary/unnecessary_lambda.txt @@ -5,3 +5,5 @@ unnecessary-lambda:19:4:19:33::Lambda may not be necessary:UNDEFINED unnecessary-lambda:21:4:21:39::Lambda may not be necessary:UNDEFINED unnecessary-lambda:23:4:23:53::Lambda may not be necessary:UNDEFINED unnecessary-lambda:25:4:25:71::Lambda may not be necessary:UNDEFINED +unnecessary-lambda:29:4:29:31::Lambda may not be necessary:UNDEFINED +unnecessary-lambda:31:4:31:44::Lambda may not be necessary:UNDEFINED -- cgit v1.2.1