summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaura M?dioni <laura.medioni@logilab.fr>2015-11-27 14:55:45 +0100
committerLaura M?dioni <laura.medioni@logilab.fr>2015-11-27 14:55:45 +0100
commita5165d34575a4d12a8235e5c090087bfd7814b40 (patch)
treef3a8d4257b24d3ee8a15e91507056515f0dbf28f
parent07253b750913858e119b8a31e055ddad4c3942f3 (diff)
downloadpylint-a5165d34575a4d12a8235e5c090087bfd7814b40.tar.gz
pylint extension to check for use of "else if" instead of "elsif"
related to issue #673
-rw-r--r--pylint/extensions/check_elif.py76
1 files changed, 76 insertions, 0 deletions
diff --git a/pylint/extensions/check_elif.py b/pylint/extensions/check_elif.py
new file mode 100644
index 0000000..e9f2dfa
--- /dev/null
+++ b/pylint/extensions/check_elif.py
@@ -0,0 +1,76 @@
+import astroid
+from pylint.checkers import BaseTokenChecker
+from pylint.checkers.utils import check_messages
+from pylint.interfaces import ITokenChecker, IAstroidChecker
+
+
+class ElseifUsedChecker(BaseTokenChecker):
+ """Checks for use of "else if" when a "elif" could be used
+ """
+
+ __implements__ = (ITokenChecker, IAstroidChecker)
+ name = 'elseifused'
+ msgs = {'R5501': ('Consider using "elif" instead of "else if"',
+ 'else-if-used',
+ 'Used when an else statement is immediately followed by '
+ 'an if statement and does not contain statements that '
+ 'would be unrelated to it.'),
+ }
+
+ def __init__(self, linter=None):
+ BaseTokenChecker.__init__(self, linter)
+ self._init()
+
+ def _init(self):
+ self._elifs = []
+ self._if_counter = 0
+
+ def _is_actual_elif(self, node):
+ """Check if the given node is an actual elif
+
+ This is a problem we're having with the builtin ast module,
+ which splits `elif` branches into a separate if statement.
+ Unfortunately we need to know the exact type in certain
+ cases.
+ """
+
+ if isinstance(node.parent, astroid.If):
+ orelse = node.parent.orelse
+ # current if node must directly follow a "else"
+ if orelse and orelse == [node]:
+ if self._elifs[self._if_counter]:
+ return True
+ return False
+
+ def process_tokens(self, tokens):
+ # Process tokens and look for 'if' or 'elif'
+ for _, token, _, _, _ in tokens:
+ self._elifs.append(True if token == 'elif' else False)
+
+ def leave_module(self, _):
+ self._init()
+
+ def visit_ifexp(self, _):
+ self._if_counter += 1
+
+ def visit_comprehension(self, node):
+ self._if_counter += len(node.ifs)
+
+ @check_messages('else-if-used')
+ def visit_if(self, node):
+ if isinstance(node.parent, astroid.If):
+ orelse = node.parent.orelse
+ # current if node must directly follow a "else"
+ if orelse and orelse == [node]:
+ if not self._elifs[self._if_counter]:
+ self.add_message('else-if-used', node=node)
+ self._if_counter += 1
+
+
+def register(linter):
+ """Required method to auto register this checker.
+
+ :param linter: Main interface object for Pylint plugins
+ :type linter: Pylint object
+ """
+ linter.register_checker(ElseifUsedChecker(linter))