summaryrefslogtreecommitdiff
path: root/pylint/extensions/comparison_placement.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylint/extensions/comparison_placement.py')
-rw-r--r--pylint/extensions/comparison_placement.py67
1 files changed, 67 insertions, 0 deletions
diff --git a/pylint/extensions/comparison_placement.py b/pylint/extensions/comparison_placement.py
new file mode 100644
index 000000000..64c8dee5e
--- /dev/null
+++ b/pylint/extensions/comparison_placement.py
@@ -0,0 +1,67 @@
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/main/LICENSE
+
+"""
+Checks for yoda comparisons (variable before constant)
+See https://en.wikipedia.org/wiki/Yoda_conditions
+"""
+
+
+from astroid import nodes
+
+from pylint.checkers import BaseChecker, utils
+from pylint.interfaces import IAstroidChecker
+
+REVERSED_COMPS = {"<": ">", "<=": ">=", ">": "<", ">=": "<="}
+COMPARISON_OPERATORS = frozenset(("==", "!=", "<", ">", "<=", ">="))
+
+
+class MisplacedComparisonConstantChecker(BaseChecker):
+ """Checks the placement of constants in comparisons"""
+
+ __implements__ = (IAstroidChecker,)
+
+ # configuration section name
+ name = "comparison-placement"
+ msgs = {
+ "C2201": (
+ "Comparison should be %s",
+ "misplaced-comparison-constant",
+ "Used when the constant is placed on the left side "
+ "of a comparison. It is usually clearer in intent to "
+ "place it in the right hand side of the comparison.",
+ {"old_names": [("C0122", "old-misplaced-comparison-constant")]},
+ )
+ }
+
+ options = ()
+
+ def _check_misplaced_constant(
+ self,
+ node: nodes.Compare,
+ left: nodes.NodeNG,
+ right: nodes.NodeNG,
+ operator: str,
+ ):
+ if isinstance(right, nodes.Const):
+ return
+ operator = REVERSED_COMPS.get(operator, operator)
+ suggestion = f"{right.as_string()} {operator} {left.value!r}"
+ self.add_message("misplaced-comparison-constant", node=node, args=(suggestion,))
+
+ @utils.check_messages("misplaced-comparison-constant")
+ def visit_compare(self, node: nodes.Compare) -> None:
+ # NOTE: this checker only works with binary comparisons like 'x == 42'
+ # but not 'x == y == 42'
+ if len(node.ops) != 1:
+ return
+
+ left = node.left
+ operator, right = node.ops[0]
+ if operator in COMPARISON_OPERATORS and isinstance(left, nodes.Const):
+ self._check_misplaced_constant(node, left, right, operator)
+
+
+def register(linter):
+ """Required method to auto register this checker."""
+ linter.register_checker(MisplacedComparisonConstantChecker(linter))