Skip to content

Commit

Permalink
Added a new check, self-assigning-variable
Browse files Browse the repository at this point in the history
This check is emitted when we detect that a variable is assigned
to itself, which might indicate a potential bug in the code application.
Close #2930
  • Loading branch information
PCManticore committed Jul 17, 2019
1 parent a636569 commit 26e11c0
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 1 deletion.
6 changes: 6 additions & 0 deletions ChangeLog
Expand Up @@ -7,6 +7,12 @@ What's New in Pylint 2.4.0?

Release date: TBA

* Added a new check, ``self-assigning-variable``

This check is emitted when we detect that a variable is assigned
to itself, which might indicate a potential bug in the code application.
Close #2930

* Added a new check, ``property-with-parameters``.

This check is emitted when we detect that a defined property also
Expand Down
16 changes: 16 additions & 0 deletions doc/whatsnew/2.4.rst
Expand Up @@ -20,6 +20,22 @@ New checkers

Close #2905

* Added a new check, ``self-assigning-variable``

This check is emitted when we detect that a variable is assigned
to itself, which might indicate a potential bug in the code application.

For example, the following would raise this warning::

def new_a(attr, attr2):
a_inst = Aclass()
a_inst.attr2 = attr2
# should be: a_inst.attr = attr, but have a typo
attr = attr
return a_inst

Close #2930

* Added a new check ``property-with-parameters`` which detects when a property
has more than a single argument.

Expand Down
37 changes: 37 additions & 0 deletions pylint/checkers/base.py
Expand Up @@ -981,6 +981,11 @@ class BasicChecker(_BasicChecker):
"Emitted when a conditional statement (If or ternary if) "
"seems to wrongly call a function due to missing parentheses",
),
"W0127": (
"Assigning the same variable %r to itself",
"self-assigning-variable",
"Emitted when we detect that a variable is assigned to itself",
),
"E0111": (
"The first reversed() argument is not a sequence",
"bad-reversed-sequence",
Expand Down Expand Up @@ -1497,6 +1502,38 @@ def visit_with(self, node):
# we assume it's a nested "with"
self.add_message("confusing-with-statement", node=node)

@utils.check_messages("self-assigning-variable")
def visit_assign(self, node):

# Detect assigning to the same variable.
rhs_names = []
targets = node.targets
if isinstance(targets[0], astroid.Tuple):
if len(targets) != 1:
# A complex assignment, so bail out early.
return
targets = targets[0].elts

if isinstance(node.value, astroid.Name):
if len(targets) != 1:
return
rhs_names = [node.value]
elif isinstance(node.value, astroid.Tuple):
rhs_count = len(node.value.elts)
if len(targets) != rhs_count or rhs_count == 1:
return
rhs_names = node.value.elts

for target, lhs_name in zip(targets, rhs_names):
if not isinstance(lhs_name, astroid.Name):
continue
if not isinstance(target, astroid.AssignName):
continue
if target.name == lhs_name.name:
self.add_message(
"self-assigning-variable", args=(target.name,), node=target
)


KNOWN_NAME_TYPES = {
"module",
Expand Down
20 changes: 20 additions & 0 deletions tests/functional/self_assigning_variable.py
@@ -0,0 +1,20 @@
# pylint: disable=missing-docstring,too-few-public-methods
# pylint: disable=unpacking-non-sequence,attribute-defined-outside-init,invalid-name

class Class:
pass

CLS = Class()
FIRST = 1
# Not enough values on the right hand side
FIRST, SECOND = FIRST
# Not enough values on the left hand side
FIRST = FIRST, SECOND
# Not equivalent to a self assignment
FIRST = (FIRST, )
# Not assigning to an attribute
CLS.FIRST = FIRST
# Not a name on the right hand side
FIRST = Class()
FIRST = FIRST # [self-assigning-variable]
FIRST, SECOND = FIRST, CLS.FIRST # [self-assigning-variable]
2 changes: 2 additions & 0 deletions tests/functional/self_assigning_variable.txt
@@ -0,0 +1,2 @@
self-assigning-variable:19::Assigning the same variable 'FIRST' to itself
self-assigning-variable:20::Assigning the same variable 'FIRST' to itself
2 changes: 1 addition & 1 deletion tests/functional/unused_import.py
Expand Up @@ -9,7 +9,7 @@
from collections import deque, OrderedDict, Counter
import re, html.parser # [unused-import]
DATA = Counter()

# pylint: disable=self-assigning-variable
from fake import SomeName, SomeOtherName # [unused-import]
class SomeClass(object):
SomeName = SomeName # https://bitbucket.org/logilab/pylint/issue/475
Expand Down

0 comments on commit 26e11c0

Please sign in to comment.