summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-11-30 15:50:45 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2015-11-30 15:50:45 +0200
commit304ae035b9b5e42bb1eb65baecc58d5c9b5ab14d (patch)
tree288b376b968f1aa3d5df2592a11e53e8857ef2c6
parentf0e5799175980963b1dc8c2e3e068f022917c4bf (diff)
downloadpylint-304ae035b9b5e42bb1eb65baecc58d5c9b5ab14d.tar.gz
Fix a crash which occurred when old visit methods are encountered
in plugin modules. If a plugin uses an old visit method (visit_class for instance), this can lead to a crash in pylint's base checkers, because the logic in the PylintASTWalker assumes that all checkers have a visit_class / leave_class method. The patch fixes this by looking for both names. Closes issue #711.
-rw-r--r--ChangeLog3
-rw-r--r--pylint/test/unittest_lint.py19
-rw-r--r--pylint/utils.py16
3 files changed, 29 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index e53e79c..f97a547 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -10,6 +10,9 @@ ChangeLog for Pylint
emitted when item deletion is tried on an object which doesn't
have this ability. Closes issue #592.
+ * Fix a crash which occurred when old visit methods are encountered
+ in plugin modules. Closes issue #711.
+
* Added multiple warnings related to imports. 'wrong-import-order'
is emitted when PEP 8 recommendations regarding imports are not
respected (that is, standard imports should be followed by third-party
diff --git a/pylint/test/unittest_lint.py b/pylint/test/unittest_lint.py
index 3095108..5877d4c 100644
--- a/pylint/test/unittest_lint.py
+++ b/pylint/test/unittest_lint.py
@@ -33,6 +33,7 @@ from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, MSG_STA
from pylint.testutils import TestReporter
from pylint.reporters import text, html
from pylint import checkers
+from pylint.checkers.utils import check_messages
from pylint import interfaces
if os.name == 'java':
@@ -217,6 +218,22 @@ class PyLinterTC(unittest.TestCase):
linter.file_state = FileState('toto')
return linter
+ def test_pylint_visit_method_taken_in_account(self):
+ class CustomChecker(checkers.BaseChecker):
+ __implements__ = interfaces.IAstroidChecker
+ name = 'custom'
+ msgs = {'W9999': ('', 'custom', '')}
+
+ @check_messages('custom')
+ def visit_class(self, _):
+ pass
+
+ self.linter.register_checker(CustomChecker(self.linter))
+ self.linter.open()
+ out = six.moves.StringIO()
+ self.linter.set_reporter(text.TextReporter(out))
+ self.linter.check('abc')
+
def test_enable_message(self):
linter = self.init_linter()
self.assertTrue(linter.is_message_enabled('W0101'))
@@ -669,6 +686,6 @@ class MessagesStoreTC(unittest.TestCase):
self.assertEqual('msg-symbol',
self.store.check_message_id('old-symbol').symbol)
-
+
if __name__ == '__main__':
unittest.main()
diff --git a/pylint/utils.py b/pylint/utils.py
index 090b0a5..d2bca89 100644
--- a/pylint/utils.py
+++ b/pylint/utils.py
@@ -19,6 +19,7 @@ main pylint class
from __future__ import print_function
import collections
+import itertools
import os
from os.path import dirname, basename, splitext, exists, isdir, join, normpath
import re
@@ -904,15 +905,14 @@ class PyLintASTWalker(object):
# Detect if the node is a new name for a deprecated alias.
# In this case, favour the methods for the deprecated
# alias if any, in order to maintain backwards
- # compatibility. If both of them are present,
- # only the old ones will be called.
+ # compatibility.
old_cid = DEPRECATED_ALIASES.get(cid)
visit_events = ()
leave_events = ()
if old_cid:
- visit_events = self.visit_events.get(old_cid)
- leave_events = self.leave_events.get(old_cid)
+ visit_events = self.visit_events.get(old_cid, ())
+ leave_events = self.leave_events.get(old_cid, ())
if visit_events or leave_events:
msg = ("Implemented method {meth}_{old} instead of {meth}_{new}. "
"This will be supported until Pylint 2.0.")
@@ -923,10 +923,10 @@ class PyLintASTWalker(object):
warnings.warn(msg.format(meth="leave", old=old_cid, new=cid),
PendingDeprecationWarning)
- if not visit_events:
- visit_events = self.visit_events.get(cid)
- if not leave_events:
- leave_events = self.leave_events.get(cid)
+ visit_events = itertools.chain(visit_events,
+ self.visit_events.get(cid, ()))
+ leave_events = itertools.chain(leave_events,
+ self.leave_events.get(cid, ()))
if astroid.is_statement:
self.nbstatements += 1