summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Sassoulas <pierre.sassoulas@gmail.com>2023-01-09 21:27:44 +0100
committerGitHub <noreply@github.com>2023-01-09 21:27:44 +0100
commit87c81c2faadaa44ae98d325dbfcb06b873bb5d6a (patch)
treefa4785b425e03ff4783efb48345a77d952703888
parent4d67f9f8c82dd29acde8e5157da28fd464acfae1 (diff)
downloadpylint-git-87c81c2faadaa44ae98d325dbfcb06b873bb5d6a.tar.gz
[consider-using-augmented-assign] Do not warn for non-commutative operators (#8037)
Or rather, only warn for known commutative operators. Closes #7639 Co-authored-by: Nick Drozd <nicholasdrozd@gmail.com> Co-authored-by: Mark Byrne <31762852+mbyrnepr2@users.noreply.github.com>
-rw-r--r--pylint/checkers/utils.py7
-rw-r--r--tests/functional/ext/code_style/cs_consider_using_augmented_assign.py56
-rw-r--r--tests/functional/ext/code_style/cs_consider_using_augmented_assign.txt46
3 files changed, 82 insertions, 27 deletions
diff --git a/pylint/checkers/utils.py b/pylint/checkers/utils.py
index 68b103b53..27042653b 100644
--- a/pylint/checkers/utils.py
+++ b/pylint/checkers/utils.py
@@ -51,6 +51,7 @@ ABC_METHODS = {
TYPING_PROTOCOLS = frozenset(
{"typing.Protocol", "typing_extensions.Protocol", ".Protocol"}
)
+COMMUTATIVE_OPERATORS = frozenset({"*", "+", "^", "&", "|"})
ITER_METHOD = "__iter__"
AITER_METHOD = "__aiter__"
NEXT_METHOD = "__next__"
@@ -2120,7 +2121,11 @@ def is_augmented_assign(node: nodes.Assign) -> tuple[bool, str]:
if _is_target_name_in_binop_side(target, binop.left):
return True, binop.op
- if _is_target_name_in_binop_side(target, binop.right):
+ if (
+ # Unless an operator is commutative, we should not raise (i.e. x = 3/x)
+ binop.op in COMMUTATIVE_OPERATORS
+ and _is_target_name_in_binop_side(target, binop.right)
+ ):
inferred_left = safe_infer(binop.left)
if isinstance(inferred_left, nodes.Const) and isinstance(
inferred_left.value, int
diff --git a/tests/functional/ext/code_style/cs_consider_using_augmented_assign.py b/tests/functional/ext/code_style/cs_consider_using_augmented_assign.py
index e4af95686..806ca3f23 100644
--- a/tests/functional/ext/code_style/cs_consider_using_augmented_assign.py
+++ b/tests/functional/ext/code_style/cs_consider_using_augmented_assign.py
@@ -5,12 +5,16 @@
from unknown import Unknown
x = 1
-x = x + 1 # [consider-using-augmented-assign]
-x = 1 + x # [consider-using-augmented-assign]
+
+# summation is commutative (for integer and float, but not for string)
+x = x + 3 # [consider-using-augmented-assign]
+x = 3 + x # [consider-using-augmented-assign]
+x = x + "3" # [consider-using-augmented-assign]
+x = "3" + x
+
+# We don't warn on intricate expressions as we lack knowledge of simplifying such
+# expressions which is necessary to see if they can become augmented
x, y = 1 + x, 2 + x
-# We don't warn on intricate expressions as we lack knowledge
-# of simplifying such expressions which is necessary to see
-# if they can become augmented
x = 1 + x - 2
x = 1 + x + 2
@@ -52,7 +56,6 @@ def return_str() -> str:
# Currently we disregard all calls
my_str = return_str() + my_str
-
my_str = my_str % return_str()
my_str = my_str % 1 # [consider-using-augmented-assign]
my_str = my_str % (1, 2) # [consider-using-augmented-assign]
@@ -61,17 +64,58 @@ my_str = return_str() % my_str
my_str = Unknown % my_str
my_str = my_str % Unknown # [consider-using-augmented-assign]
+# subtraction is anti-commutative
x = x - 3 # [consider-using-augmented-assign]
+x = 3 - x
+
+# multiplication is commutative
x = x * 3 # [consider-using-augmented-assign]
+x = 3 * x # [consider-using-augmented-assign]
+
+# division is not commutative
x = x / 3 # [consider-using-augmented-assign]
+x = 3 / x
+
+# integer division is not commutative
x = x // 3 # [consider-using-augmented-assign]
+x = 3 // x
+
+# Left shift operator is not commutative
x = x << 3 # [consider-using-augmented-assign]
+x = 3 << x
+
+# Right shift operator is not commutative
x = x >> 3 # [consider-using-augmented-assign]
+x = 3 >> x
+
+# modulo is not commutative
x = x % 3 # [consider-using-augmented-assign]
+x = 3 % x
+
+# exponential is not commutative
x = x**3 # [consider-using-augmented-assign]
+x = 3**x
+
+# XOR is commutative
x = x ^ 3 # [consider-using-augmented-assign]
+x = 3 ^ x # [consider-using-augmented-assign]
+
+# Bitwise AND operator is commutative
x = x & 3 # [consider-using-augmented-assign]
+x = 3 & x # [consider-using-augmented-assign]
+
+# Bitwise OR operator is commutative
+x = x | 3 # [consider-using-augmented-assign]
+x = 3 | x # [consider-using-augmented-assign]
+
x = x > 3
+x = 3 > x
+
x = x < 3
+x = 3 < x
+
x = x >= 3
+x = 3 >= x
+
x = x <= 3
+x = 3 <= x
diff --git a/tests/functional/ext/code_style/cs_consider_using_augmented_assign.txt b/tests/functional/ext/code_style/cs_consider_using_augmented_assign.txt
index 1684953e9..5bcbb6b34 100644
--- a/tests/functional/ext/code_style/cs_consider_using_augmented_assign.txt
+++ b/tests/functional/ext/code_style/cs_consider_using_augmented_assign.txt
@@ -1,20 +1,26 @@
-consider-using-augmented-assign:8:0:8:9::Use '+=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:9:0:9:9::Use '+=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:28:8:28:27:MyClass.__init__:Use '+=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:29:8:29:27:MyClass.__init__:Use '+=' to do an augmented assign directly:INFERENCE
-redefined-outer-name:31:8:31:9:MyClass.__init__:Redefining name 'x' from outer scope (line 7):UNDEFINED
-consider-using-augmented-assign:40:0:40:23::Use '+=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:44:0:44:28::Use '+=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:57:0:57:19::Use '%=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:58:0:58:24::Use '%=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:62:0:62:25::Use '%=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:64:0:64:9::Use '-=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:65:0:65:9::Use '*=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:66:0:66:9::Use '/=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:67:0:67:10::Use '//=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:68:0:68:10::Use '<<=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:69:0:69:10::Use '>>=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:70:0:70:9::Use '%=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:71:0:71:8::Use '**=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:72:0:72:9::Use '^=' to do an augmented assign directly:INFERENCE
-consider-using-augmented-assign:73:0:73:9::Use '&=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:10:0:10:9::Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:11:0:11:9::Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:12:0:12:11::Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:32:8:32:27:MyClass.__init__:Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:33:8:33:27:MyClass.__init__:Use '+=' to do an augmented assign directly:INFERENCE
+redefined-outer-name:35:8:35:9:MyClass.__init__:Redefining name 'x' from outer scope (line 7):UNDEFINED
+consider-using-augmented-assign:44:0:44:23::Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:48:0:48:28::Use '+=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:60:0:60:19::Use '%=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:61:0:61:24::Use '%=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:65:0:65:25::Use '%=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:68:0:68:9::Use '-=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:72:0:72:9::Use '*=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:73:0:73:9::Use '*=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:76:0:76:9::Use '/=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:80:0:80:10::Use '//=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:84:0:84:10::Use '<<=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:88:0:88:10::Use '>>=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:92:0:92:9::Use '%=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:96:0:96:8::Use '**=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:100:0:100:9::Use '^=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:101:0:101:9::Use '^=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:104:0:104:9::Use '&=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:105:0:105:9::Use '&=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:108:0:108:9::Use '|=' to do an augmented assign directly:INFERENCE
+consider-using-augmented-assign:109:0:109:9::Use '|=' to do an augmented assign directly:INFERENCE