third_party.pylibs.pylint.src/pylint/checkers/refactoring.py
Claudiu Popa 211d81f84f Keep a consistent copyright notice across the board.
This was changed automatically in #894, but apparently
we need to have the copyright notice somewhere.
2016-07-19 17:42:07 +03:00

89 lines
3.0 KiB
Python

# Copyright (c) 2003-2016 LOGILAB S.A. (Paris, FRANCE).
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
# 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
"""Looks for code which can be refactored."""
import collections
import astroid
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
from pylint.checkers.utils import check_messages, is_builtin_object, safe_infer
class RefactoringChecker(BaseChecker):
"""Looks for code which can be refactored."""
__implements__ = (IAstroidChecker,)
name = 'refactoring'
msgs = {
'R1701': (
"Consider merging these isinstance calls to isinstance(%s, (%s))",
"consider-merging-isinstance",
"Usen when multiple consecutive isinstance calls can be merged into one."),
}
priority = 0
@staticmethod
def _duplicated_isinstance_types(node):
"""Get the duplicated types from the underlying isinstance calls.
:param astroid.BoolOp node: Node which should contain a bunch of isinstance calls.
:returns: Dictionary of the comparison objects from the isinstance calls,
to duplicate values from consecutive calls.
:rtype: dict
"""
duplicated_objects = set()
all_types = collections.defaultdict(set)
for call in node.values:
if not isinstance(call, astroid.Call) or len(call.args) != 2:
continue
inferred = safe_infer(call.func)
if not inferred or not is_builtin_object(inferred):
continue
if inferred.name != 'isinstance':
continue
isinstance_object = call.args[0].as_string()
isinstance_types = call.args[1]
if isinstance_object in all_types:
duplicated_objects.add(isinstance_object)
if isinstance(isinstance_types, astroid.Tuple):
elems = [class_type.as_string() for class_type in isinstance_types.itered()]
else:
elems = [isinstance_types.as_string()]
all_types[isinstance_object].update(elems)
# Remove all keys which not duplicated
return {key: value for key, value in all_types.items()
if key in duplicated_objects}
@check_messages('consider-merging-isinstance')
def visit_boolop(self, node):
'''Check isinstance calls which can be merged together.'''
if node.op != 'or':
return
first_args = self._duplicated_isinstance_types(node)
for duplicated_name, class_names in first_args.items():
names = sorted(name for name in class_names)
self.add_message('consider-merging-isinstance',
node=node,
args=(duplicated_name, ', '.join(names)))
def register(linter):
"""Required method to auto register this checker."""
linter.register_checker(RefactoringChecker(linter))