diff --git a/ChangeLog b/ChangeLog index 43886103f6f..bf760f82bd3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,13 @@ Release date: TBA Closes #3878 +* Added ``use-list-literal``: Emitted when ``list()`` is called with no arguments instead of using ``[]`` + + Closes #4365 + +* Added ``use-dict-literal``: Emitted when ``dict()`` is called with no arguments instead of using ``{}`` + + Closes #4365 What's New in Pylint 2.9.6? diff --git a/doc/whatsnew/2.10.rst b/doc/whatsnew/2.10.rst index 7d7312153ff..2105ad8d2bb 100644 --- a/doc/whatsnew/2.10.rst +++ b/doc/whatsnew/2.10.rst @@ -16,6 +16,14 @@ New checkers Closes #3826 +* Added ``use-list-literal``: Emitted when ``list()`` is called with no arguments instead of using ``[]`` + + Closes #4365 + +* Added ``use-dict-literal``: Emitted when ``dict()`` is called with no arguments instead of using ``{}`` + + Closes #4365 + Other Changes ============= diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py index 3512451aca4..9e974571145 100644 --- a/pylint/checkers/refactoring/refactoring_checker.py +++ b/pylint/checkers/refactoring/refactoring_checker.py @@ -413,6 +413,18 @@ class RefactoringChecker(checkers.BaseTokenChecker): "value by index lookup. " "The value can be accessed directly instead.", ), + "R1734": ( + "Consider using [] instead of list()", + "use-list-literal", + "Emitted when using list() to create an empty list instead of the literal []. " + "The literal is faster as it avoids an additional function call.", + ), + "R1735": ( + "Consider using {} instead of dict()", + "use-dict-literal", + "Emitted when using dict() to create an empty dictionary instead of the literal {}. " + "The literal is faster as it avoids an additional function call.", + ), } options = ( ( @@ -964,6 +976,8 @@ def _check_consider_using_generator(self, node): "super-with-arguments", "consider-using-generator", "consider-using-with", + "use-list-literal", + "use-dict-literal", ) def visit_call(self, node): self._check_raising_stopiteration_in_generator_next_call(node) @@ -972,6 +986,7 @@ def visit_call(self, node): self._check_super_with_arguments(node) self._check_consider_using_generator(node) self._check_consider_using_with(node) + self._check_use_list_or_dict_literal(node) @staticmethod def _has_exit_in_scope(scope): @@ -1454,6 +1469,20 @@ def _check_consider_using_with(self, node: astroid.Call): if could_be_used_in_with and not _will_be_released_automatically(node): self.add_message("consider-using-with", node=node) + def _check_use_list_or_dict_literal(self, node: astroid.Call) -> None: + """Check if empty list or dict is created by using the literal [] or {}""" + try: + for inferred in node.func.infer(): + if inferred is astroid.Uninferable: + continue + if isinstance(inferred, astroid.ClassDef) and node.args == []: + if inferred.name == "list": + self.add_message("use-list-literal", node=node) + if inferred.name == "dict": + self.add_message("use-dict-literal", node=node) + except astroid.InferenceError: + pass + def _check_consider_using_join(self, aug_assign): """ We start with the augmented assignment and work our way upwards. diff --git a/tests/functional/u/use/use_dict_literal.py b/tests/functional/u/use/use_dict_literal.py new file mode 100644 index 00000000000..a8a714b960d --- /dev/null +++ b/tests/functional/u/use/use_dict_literal.py @@ -0,0 +1,6 @@ +# pylint: disable=missing-docstring, invalid-name + +x = dict() # [use-dict-literal] +x = dict(zip(["a", "b", "c"], [1, 2, 3])) +x = {} +x = {"a": 1, "b": 2, "c": 3} diff --git a/tests/functional/u/use/use_dict_literal.txt b/tests/functional/u/use/use_dict_literal.txt new file mode 100644 index 00000000000..eede5530dcb --- /dev/null +++ b/tests/functional/u/use/use_dict_literal.txt @@ -0,0 +1 @@ +use-dict-literal:3:4::"Consider using {} instead of dict()" diff --git a/tests/functional/u/use/use_list_literal.py b/tests/functional/u/use/use_list_literal.py new file mode 100644 index 00000000000..78614a49dda --- /dev/null +++ b/tests/functional/u/use/use_list_literal.py @@ -0,0 +1,9 @@ +# pylint: disable=missing-docstring, invalid-name + +x = list() # [use-list-literal] +x = list("string") +x = list(range(3)) +x = [] +x = ["string"] +x = [1, 2, 3] +x = [range(3)] diff --git a/tests/functional/u/use/use_list_literal.txt b/tests/functional/u/use/use_list_literal.txt new file mode 100644 index 00000000000..07987027d04 --- /dev/null +++ b/tests/functional/u/use/use_list_literal.txt @@ -0,0 +1 @@ +use-list-literal:3:4::"Consider using [] instead of list()"