@@ -291,6 +291,16 @@ class RefactoringChecker(checkers.BaseTokenChecker):
291
291
"Comprehension inside of 'any' or 'all' is unnecessary. "
292
292
"A generator would be sufficient and faster." ,
293
293
),
294
+ "R1730" : (
295
+ "Consider using '%s' instead of unnecessary if block" ,
296
+ "consider-using-min-builtin" ,
297
+ "Using the min builtin instead of a conditional improves readability and conciseness." ,
298
+ ),
299
+ "R1731" : (
300
+ "Consider using '%s' instead of unnecessary if block" ,
301
+ "consider-using-max-builtin" ,
302
+ "Using the max builtin instead of a conditional improves readability and conciseness." ,
303
+ ),
294
304
}
295
305
options = (
296
306
(
@@ -609,6 +619,84 @@ def visit_if(self, node):
609
619
self ._check_superfluous_else_break (node )
610
620
self ._check_superfluous_else_continue (node )
611
621
self ._check_consider_get (node )
622
+ self ._check_consider_using_min_max_builtin (node )
623
+
624
+ def _check_consider_using_min_max_builtin (self , node : astroid .If ):
625
+ """Check if the given if node can be refactored as an min/max python builtin."""
626
+ if self ._is_actual_elif (node ) or node .orelse :
627
+ # Not interested in if statements with multiple branches.
628
+ return
629
+
630
+ if len (node .body ) != 1 :
631
+ return
632
+
633
+ body = node .body [0 ]
634
+ # Check if condition can be reduced.
635
+ if not hasattr (body , "targets" ) or len (body .targets ) != 1 :
636
+ return
637
+
638
+ target = body .targets [0 ]
639
+ if not (
640
+ isinstance (node .test , astroid .Compare )
641
+ and not isinstance (target , astroid .Subscript )
642
+ and not isinstance (node .test .left , astroid .Subscript )
643
+ and isinstance (body , astroid .Assign )
644
+ ):
645
+ return
646
+
647
+ # Check that the assignation is on the same variable.
648
+ if hasattr (node .test .left , "name" ):
649
+ left_operand = node .test .left .name
650
+ elif hasattr (node .test .left , "attrname" ):
651
+ left_operand = node .test .left .attrname
652
+ else :
653
+ return
654
+
655
+ if hasattr (target , "name" ):
656
+ target_assignation = target .name
657
+ elif hasattr (target , "attrname" ):
658
+ target_assignation = target .attrname
659
+ else :
660
+ return
661
+
662
+ if not (left_operand == target_assignation ):
663
+ return
664
+
665
+ if len (node .test .ops ) > 1 :
666
+ return
667
+
668
+ if not isinstance (body .value , (astroid .Name , astroid .Const )):
669
+ return
670
+
671
+ operator , right_statement = node .test .ops [0 ]
672
+ if isinstance (body .value , astroid .Name ):
673
+ body_value = body .value .name
674
+ else :
675
+ body_value = body .value .value
676
+
677
+ if isinstance (right_statement , astroid .Name ):
678
+ right_statement_value = right_statement .name
679
+ else :
680
+ right_statement_value = right_statement .value
681
+
682
+ # Verify the right part of the statement is the same.
683
+ if right_statement_value != body_value :
684
+ return
685
+
686
+ if operator in ("<" , "<=" ):
687
+ reduced_to = "{target} = max({target}, {item})" .format (
688
+ target = target_assignation , item = body_value
689
+ )
690
+ self .add_message (
691
+ "consider-using-max-builtin" , node = node , args = (reduced_to ,)
692
+ )
693
+ elif operator in (">" , ">=" ):
694
+ reduced_to = "{target} = min({target}, {item})" .format (
695
+ target = target_assignation , item = body_value
696
+ )
697
+ self .add_message (
698
+ "consider-using-min-builtin" , node = node , args = (reduced_to ,)
699
+ )
612
700
613
701
@utils .check_messages ("simplifiable-if-expression" )
614
702
def visit_ifexp (self , node ):
0 commit comments