Skip to content

Commit

Permalink
[unused-private-member] add logic for checking nested functions
Browse files Browse the repository at this point in the history
also, improve error message for nested functions
  • Loading branch information
yushao2 committed Aug 1, 2021
1 parent 8ceb26d commit 712dc2b
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -169,6 +169,10 @@ Release date: 2021-07-20

Closes #4723

* Fix false-positive of ``unused-private-member`` when using nested functions in a class

Closes #4673


What's New in Pylint 2.9.3?
===========================
Expand Down
16 changes: 15 additions & 1 deletion pylint/checkers/classes.py
Expand Up @@ -909,6 +909,13 @@ def _check_unused_private_functions(self, node: astroid.ClassDef) -> None:
function_def = cast(astroid.FunctionDef, function_def)
if not is_attr_private(function_def.name):
continue
if isinstance(function_def.parent.scope(), astroid.FunctionDef):
# Handle nested functions
outer_fn = function_def.parent.scope()
if function_def.name in [
n.name for n in outer_fn.nodes_of_class(astroid.Name)
]:
continue
for attribute in node.nodes_of_class(astroid.Attribute):
attribute = cast(astroid.Attribute, attribute)
if (
Expand All @@ -931,11 +938,18 @@ def _check_unused_private_functions(self, node: astroid.ClassDef) -> None:
):
break
else:
name_stack = ""
curr = function_def.parent.scope()
# Generate proper names for nested functions
while curr != node:
name_stack = f"{curr.name}." + name_stack
curr = curr.parent.scope()

function_repr = f"{function_def.name}({function_def.args.as_string()})"
self.add_message(
"unused-private-member",
node=function_def,
args=(node.name, function_repr),
args=(node.name, name_stack + function_repr),
)

def _check_unused_private_variables(self, node: astroid.ClassDef) -> None:
Expand Down
43 changes: 43 additions & 0 deletions tests/functional/u/unused/unused_private_member.py
Expand Up @@ -136,6 +136,7 @@ def attr_c(self):
"""Get c."""
return cls.__attr_c # [undefined-variable]

<<<<<<< HEAD

# Test cases for false-positive reported in #4668
# https://github.com/PyCQA/pylint/issues/4668
Expand All @@ -160,3 +161,45 @@ def __new__(cls, func, *args):
def exec(self):
print(self.__secret_bool)
return self.func(*self.__args)
=======
# Test cases for false-positive reported in #4673
# https://github.com/PyCQA/pylint/issues/4673

class FalsePositive4673:
""" The testing class """

def __init__(self, in_thing):
self.thing = False
self.do_thing(in_thing)

def do_thing(self, in_thing):
""" Checks the false-positive condition, sets a property. """
def __false_positive(in_thing):
print(in_thing)

def __true_positive(in_thing): # [unused-private-member]
print(in_thing)

__false_positive(in_thing)
self.thing = True

def undo_thing(self):
""" Unsets a property. """
self.thing = False

def complicated_example(self, flag):
def __inner_1():
pass

def __inner_2():
pass

def __inner_3(fn):
return fn

def __inner_4(): # [unused-private-member]
pass

fn_to_return = __inner_1 if flag else __inner_3(__inner_2)
return fn_to_return
>>>>>>> 82fd4e90... [unused-private-member] add logic for checking nested functions
2 changes: 2 additions & 0 deletions tests/functional/u/unused/unused_private_member.txt
Expand Up @@ -7,3 +7,5 @@ unused-private-member:34:4:HasUnusedInClass.__test:Unused private member `HasUnu
unused-private-member:55:4:HasUnusedInClass.__test_recursive:Unused private member `HasUnusedInClass.__test_recursive(self)`:HIGH
unused-private-member:132:8:FalsePositive4657.__init__:Unused private member `FalsePositive4657.__attr_c`:HIGH
undefined-variable:137:15:FalsePositive4657.attr_c:Undefined variable 'cls':HIGH
unused-private-member:154:8:FalsePositive4673.do_thing.__true_positive:Unused private member `FalsePositive4673.do_thing.__true_positive(in_thing)`:HIGH
unused-private-member:174:8:FalsePositive4673.complicated_example.__inner_4:Unused private member `FalsePositive4673.complicated_example.__inner_4()`:HIGH

0 comments on commit 712dc2b

Please sign in to comment.