mirror of
https://fuchsia.googlesource.com/third_party/github.com/pylint-dev/pylint
synced 2024-09-21 16:19:21 +00:00
211d81f84f
This was changed automatically in #894, but apparently we need to have the copyright notice somewhere.
89 lines
3.0 KiB
Python
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))
|