summaryrefslogtreecommitdiff
path: root/pylint/extensions/confusing_elif.py
diff options
context:
space:
mode:
Diffstat (limited to 'pylint/extensions/confusing_elif.py')
-rw-r--r--pylint/extensions/confusing_elif.py55
1 files changed, 55 insertions, 0 deletions
diff --git a/pylint/extensions/confusing_elif.py b/pylint/extensions/confusing_elif.py
new file mode 100644
index 000000000..f61be02f9
--- /dev/null
+++ b/pylint/extensions/confusing_elif.py
@@ -0,0 +1,55 @@
+# Copyright (c) 2021 Andreas Finkler <andi.finkler@gmail.com>
+
+# Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+# For details: https://github.com/PyCQA/pylint/blob/master/COPYING
+
+import astroid
+
+from pylint.checkers import BaseChecker
+from pylint.checkers.utils import check_messages
+from pylint.interfaces import IAstroidChecker
+from pylint.lint import PyLinter
+
+
+class ConfusingConsecutiveElifChecker(BaseChecker):
+ """Checks if "elif" is used right after an indented block that finishes with "if" or "elif" itself."""
+
+ __implements__ = IAstroidChecker
+
+ name = "confusing-elif-checker"
+ priority = -1
+ msgs = {
+ "R5601": (
+ "Consecutive elif with differing indentation level, consider creating a function to separate the inner elif",
+ "confusing-consecutive-elif",
+ "Used when an elif statement follows right after an indented block which itself ends with if or elif. "
+ "It may not be ovious if the elif statement was willingly or mistakenly unindented. "
+ "Extracting the indented if statement into a separate function might avoid confusion and prevent errors.",
+ )
+ }
+
+ @check_messages("confusing-consecutive-elif")
+ def visit_if(self, node: astroid.If):
+ body_ends_with_if = isinstance(
+ node.body[-1], astroid.If
+ ) and self._has_no_else_clause(node.body[-1])
+ if node.has_elif_block() and body_ends_with_if:
+ self.add_message("confusing-consecutive-elif", node=node.orelse[0])
+
+ @staticmethod
+ def _has_no_else_clause(node: astroid.If):
+ orelse = node.orelse
+ while orelse and isinstance(orelse[0], astroid.If):
+ orelse = orelse[0].orelse
+ if not orelse or isinstance(orelse[0], astroid.If):
+ return True
+ return False
+
+
+def register(linter: PyLinter):
+ """This required method auto registers the checker.
+
+ :param linter: The linter to register the checker to.
+ :type linter: pylint.lint.PyLinter
+ """
+ linter.register_checker(ConfusingConsecutiveElifChecker(linter))