@@ -130,6 +130,12 @@ class RefactoringChecker(checkers.BaseTokenChecker):
130
130
'at the end of function or method definition. This statement can safely be '
131
131
'removed because Python will implicitly return None'
132
132
),
133
+ 'R1712' : ('Consider using tuple unpacking for swapping variables' ,
134
+ 'consider-swap-variables' ,
135
+ 'You do not have to use a temporary variable in order to '
136
+ 'swap variables. Using "tuple unpacking" to directly swap '
137
+ 'variables makes the intention more clear.'
138
+ ),
133
139
}
134
140
options = (('max-nested-blocks' ,
135
141
{'default' : 5 , 'type' : 'int' , 'metavar' : '<int>' ,
@@ -157,6 +163,7 @@ def _init(self):
157
163
self ._nested_blocks = []
158
164
self ._elifs = []
159
165
self ._nested_blocks_msg = None
166
+ self ._reported_swap_nodes = set ()
160
167
161
168
def open (self ):
162
169
# do this in open since config not fully initialized in __init__
@@ -470,8 +477,35 @@ def visit_boolop(self, node):
470
477
node = node ,
471
478
args = (duplicated_name , ', ' .join (names )))
472
479
473
- @utils .check_messages ('simplify-boolean-expression' , 'consider-using-ternary' )
480
+ @staticmethod
481
+ def _is_simple_assignment (node ):
482
+ return (isinstance (node , astroid .Assign )
483
+ and len (node .targets ) == 1
484
+ and isinstance (node .targets [0 ], astroid .node_classes .AssignName )
485
+ and isinstance (node .value , astroid .node_classes .Name ))
486
+
487
+ def _check_swap_variables (self , node ):
488
+ if not node .next_sibling () or not node .next_sibling ().next_sibling ():
489
+ return
490
+ assignments = [
491
+ node , node .next_sibling (), node .next_sibling ().next_sibling ()
492
+ ]
493
+ if not all (self ._is_simple_assignment (node ) for node in assignments ):
494
+ return
495
+ if any (node in self ._reported_swap_nodes for node in assignments ):
496
+ return
497
+ left = [node .targets [0 ].name for node in assignments ]
498
+ right = [node .value .name for node in assignments ]
499
+ if left [0 ] == right [- 1 ] and left [1 :] == right [:- 1 ]:
500
+ self ._reported_swap_nodes .update (assignments )
501
+ message = 'consider-swap-variables'
502
+ self .add_message (message , node = node )
503
+
504
+ @utils .check_messages ('simplify-boolean-expression' ,
505
+ 'consider-using-ternary' ,
506
+ 'consider-swap-variables' )
474
507
def visit_assign (self , node ):
508
+ self ._check_swap_variables (node )
475
509
if self ._is_and_or_ternary (node .value ):
476
510
cond , truth_value , false_value = self ._and_or_ternary_arguments (node .value )
477
511
elif self ._is_seq_based_ternary (node .value ):
0 commit comments