summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Hofer <hofrob@protonmail.com>2022-10-30 16:26:07 +0100
committerDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2022-11-09 20:39:00 +0100
commit0507ee37f45cb3c9dcaf64036dd1b7f3c88ae690 (patch)
tree7ec3b2adc6e9841ec73d7f4aa5ac58ce36e24808
parent5ae5842fa02021e086d66218d326c708e6433318 (diff)
downloadpylint-git-0507ee37f45cb3c9dcaf64036dd1b7f3c88ae690.tar.gz
Add R1737 use-dict-literal-without-kwargs
-rw-r--r--doc/data/messages/u/use-dict-literal/bad.py2
-rw-r--r--doc/data/messages/u/use-dict-literal/details.rst4
-rw-r--r--doc/data/messages/u/use-dict-literal/good.py6
-rw-r--r--doc/user_guide/checkers/features.rst6
-rw-r--r--doc/whatsnew/fragments/7690.new_check3
-rw-r--r--pylint/checkers/refactoring/refactoring_checker.py48
-rw-r--r--pylint/pyreverse/dot_printer.py16
-rw-r--r--pylint/pyreverse/main.py220
-rw-r--r--pylint/pyreverse/vcg_printer.py35
-rw-r--r--script/.contributors_aliases.json4
-rw-r--r--tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py2
-rw-r--r--tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py2
-rw-r--r--tests/functional/i/iterable_context.py1
-rw-r--r--tests/functional/i/iterable_context.txt20
-rw-r--r--tests/functional/m/mapping_context.py2
-rw-r--r--tests/functional/u/unidiomatic_typecheck.py2
-rw-r--r--tests/functional/u/unnecessary/unnecessary_lambda.py2
-rw-r--r--tests/functional/u/unsubscriptable_value.py1
-rw-r--r--tests/functional/u/unsubscriptable_value.txt30
-rw-r--r--tests/functional/u/unsupported/unsupported_assignment_operation.py2
-rw-r--r--tests/functional/u/unsupported/unsupported_delete_operation.py2
-rw-r--r--tests/functional/u/use/use_literal_dict.py43
-rw-r--r--tests/functional/u/use/use_literal_dict.txt8
23 files changed, 286 insertions, 175 deletions
diff --git a/doc/data/messages/u/use-dict-literal/bad.py b/doc/data/messages/u/use-dict-literal/bad.py
index 6c3056b6f..2d90a91e8 100644
--- a/doc/data/messages/u/use-dict-literal/bad.py
+++ b/doc/data/messages/u/use-dict-literal/bad.py
@@ -1 +1,3 @@
empty_dict = dict() # [use-dict-literal]
+new_dict = dict(foo="bar") # [use-dict-literal]
+new_dict = dict(**another_dict) # [use-dict-literal]
diff --git a/doc/data/messages/u/use-dict-literal/details.rst b/doc/data/messages/u/use-dict-literal/details.rst
new file mode 100644
index 000000000..f07532ead
--- /dev/null
+++ b/doc/data/messages/u/use-dict-literal/details.rst
@@ -0,0 +1,4 @@
+https://gist.github.com/hofrob/ad143aaa84c096f42489c2520a3875f9
+
+This example script shows an 18% increase in performance when using a literal over the
+constructor in python version 3.10.6.
diff --git a/doc/data/messages/u/use-dict-literal/good.py b/doc/data/messages/u/use-dict-literal/good.py
index 5f7d64deb..237d2c881 100644
--- a/doc/data/messages/u/use-dict-literal/good.py
+++ b/doc/data/messages/u/use-dict-literal/good.py
@@ -1 +1,7 @@
empty_dict = {}
+
+# create using a literal dict
+new_dict = {"foo": "bar"}
+
+# shallow copy a dict
+new_dict = {**another_dict}
diff --git a/doc/user_guide/checkers/features.rst b/doc/user_guide/checkers/features.rst
index 916f8c8f4..07d48d34f 100644
--- a/doc/user_guide/checkers/features.rst
+++ b/doc/user_guide/checkers/features.rst
@@ -781,9 +781,9 @@ Refactoring checker Messages
:consider-swap-variables (R1712): *Consider using tuple unpacking for swapping variables*
You do not have to use a temporary variable in order to swap variables. Using
"tuple unpacking" to directly swap variables makes the intention more clear.
-:use-dict-literal (R1735): *Consider using {} instead of dict()*
- Emitted when using dict() to create an empty dictionary instead of the
- literal {}. The literal is faster as it avoids an additional function call.
+:use-dict-literal (R1735): *Consider using '%s' instead.*
+ Emitted when using dict() to create a dictionary instead of a literal '{ ... }'.
+ The literal is faster as it avoids an additional function call.
:trailing-comma-tuple (R1707): *Disallow trailing comma tuple*
In Python, a tuple is actually created by the comma symbol, not by the
parentheses. Unfortunately, one can actually create a tuple by misplacing a
diff --git a/doc/whatsnew/fragments/7690.new_check b/doc/whatsnew/fragments/7690.new_check
new file mode 100644
index 000000000..2969428ed
--- /dev/null
+++ b/doc/whatsnew/fragments/7690.new_check
@@ -0,0 +1,3 @@
+Extended ``use-dict-literal`` to also warn about call to ``dict()`` when passing keyword arguments.
+
+Closes #7690
diff --git a/pylint/checkers/refactoring/refactoring_checker.py b/pylint/checkers/refactoring/refactoring_checker.py
index 34856749f..df3c3bccc 100644
--- a/pylint/checkers/refactoring/refactoring_checker.py
+++ b/pylint/checkers/refactoring/refactoring_checker.py
@@ -464,9 +464,9 @@ class RefactoringChecker(checkers.BaseTokenChecker):
"The literal is faster as it avoids an additional function call.",
),
"R1735": (
- "Consider using {} instead of dict()",
+ "Consider using '%s' instead of a call to 'dict'.",
"use-dict-literal",
- "Emitted when using dict() to create an empty dictionary instead of the literal {}. "
+ "Emitted when using dict() to create a dictionary instead of a literal '{ ... }'. "
"The literal is faster as it avoids an additional function call.",
),
"R1736": (
@@ -1074,7 +1074,8 @@ class RefactoringChecker(checkers.BaseTokenChecker):
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)
+ self._check_use_list_literal(node)
+ self._check_use_dict_literal(node)
@staticmethod
def _has_exit_in_scope(scope: nodes.LocalsDictNodeNG) -> bool:
@@ -1590,15 +1591,46 @@ class RefactoringChecker(checkers.BaseTokenChecker):
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: nodes.Call) -> None:
- """Check if empty list or dict is created by using the literal [] or {}."""
- if node.as_string() in {"list()", "dict()"}:
+ def _check_use_list_literal(self, node: nodes.Call) -> None:
+ """Check if empty list is created by using the literal []."""
+ if node.as_string() == "list()":
inferred = utils.safe_infer(node.func)
if isinstance(inferred, nodes.ClassDef) and not node.args:
if inferred.qname() == "builtins.list":
self.add_message("use-list-literal", node=node)
- elif inferred.qname() == "builtins.dict" and not node.keywords:
- self.add_message("use-dict-literal", node=node)
+
+ def _check_use_dict_literal(self, node: nodes.Call) -> None:
+ """Check if dict is created by using the literal {}."""
+ if not isinstance(node.func, astroid.Name) or node.func.name != "dict":
+ return
+ inferred = utils.safe_infer(node.func)
+ if (
+ isinstance(inferred, nodes.ClassDef)
+ and inferred.qname() == "builtins.dict"
+ and not node.args
+ ):
+ self.add_message(
+ "use-dict-literal",
+ args=(self._dict_literal_suggestion(node),),
+ node=node,
+ confidence=INFERENCE,
+ )
+
+ @staticmethod
+ def _dict_literal_suggestion(node: nodes.Call) -> str:
+ """Return a suggestion of reasonable length."""
+ elements: list[str] = []
+ for keyword in node.keywords:
+ if len(", ".join(elements)) >= 64:
+ break
+ if keyword not in node.kwargs:
+ elements.append(f'"{keyword.arg}": {keyword.value.as_string()}')
+ for keyword in node.kwargs:
+ if len(", ".join(elements)) >= 64:
+ break
+ elements.append(f"**{keyword.value.as_string()}")
+ suggestion = ", ".join(elements)
+ return f"{{{suggestion}{', ... ' if len(suggestion) > 64 else ''}}}"
def _check_consider_using_join(self, aug_assign: nodes.AugAssign) -> None:
"""We start with the augmented assignment and work our way upwards.
diff --git a/pylint/pyreverse/dot_printer.py b/pylint/pyreverse/dot_printer.py
index 5ec5858fc..7579d2877 100644
--- a/pylint/pyreverse/dot_printer.py
+++ b/pylint/pyreverse/dot_printer.py
@@ -29,13 +29,17 @@ SHAPES: dict[NodeType, str] = {
NodeType.INTERFACE: "record",
NodeType.CLASS: "record",
}
+# pylint: disable-next=consider-using-namedtuple-or-dataclass
ARROWS: dict[EdgeType, dict[str, str]] = {
- EdgeType.INHERITS: dict(arrowtail="none", arrowhead="empty"),
- EdgeType.IMPLEMENTS: dict(arrowtail="node", arrowhead="empty", style="dashed"),
- EdgeType.ASSOCIATION: dict(
- fontcolor="green", arrowtail="none", arrowhead="diamond", style="solid"
- ),
- EdgeType.USES: dict(arrowtail="none", arrowhead="open"),
+ EdgeType.INHERITS: {"arrowtail": "none", "arrowhead": "empty"},
+ EdgeType.IMPLEMENTS: {"arrowtail": "node", "arrowhead": "empty", "style": "dashed"},
+ EdgeType.ASSOCIATION: {
+ "fontcolor": "green",
+ "arrowtail": "none",
+ "arrowhead": "diamond",
+ "style": "solid",
+ },
+ EdgeType.USES: {"arrowtail": "none", "arrowhead": "open"},
}
diff --git a/pylint/pyreverse/main.py b/pylint/pyreverse/main.py
index 043e2a3f3..010ce47e9 100644
--- a/pylint/pyreverse/main.py
+++ b/pylint/pyreverse/main.py
@@ -36,14 +36,14 @@ DIRECTLY_SUPPORTED_FORMATS = (
OPTIONS: Options = (
(
"filter-mode",
- dict(
- short="f",
- default="PUB_ONLY",
- dest="mode",
- type="string",
- action="store",
- metavar="<mode>",
- help="""filter attributes and functions according to
+ {
+ "short": "f",
+ "default": "PUB_ONLY",
+ "dest": "mode",
+ "type": "string",
+ "action": "store",
+ "metavar": "<mode>",
+ "help": """filter attributes and functions according to
<mode>. Correct modes are :
'PUB_ONLY' filter all non public attributes
[DEFAULT], equivalent to PRIVATE+SPECIAL_A
@@ -52,154 +52,154 @@ OPTIONS: Options = (
except constructor
'OTHER' filter protected and private
attributes""",
- ),
+ },
),
(
"class",
- dict(
- short="c",
- action="extend",
- metavar="<class>",
- type="csv",
- dest="classes",
- default=None,
- help="create a class diagram with all classes related to <class>;\
+ {
+ "short": "c",
+ "action": "extend",
+ "metavar": "<class>",
+ "type": "csv",
+ "dest": "classes",
+ "default": None,
+ "help": "create a class diagram with all classes related to <class>;\
this uses by default the options -ASmy",
- ),
+ },
),
(
"show-ancestors",
- dict(
- short="a",
- action="store",
- metavar="<ancestor>",
- type="int",
- default=None,
- help="show <ancestor> generations of ancestor classes not in <projects>",
- ),
+ {
+ "short": "a",
+ "action": "store",
+ "metavar": "<ancestor>",
+ "type": "int",
+ "default": None,
+ "help": "show <ancestor> generations of ancestor classes not in <projects>",
+ },
),
(
"all-ancestors",
- dict(
- short="A",
- default=None,
- action="store_true",
- help="show all ancestors off all classes in <projects>",
- ),
+ {
+ "short": "A",
+ "default": None,
+ "action": "store_true",
+ "help": "show all ancestors off all classes in <projects>",
+ },
),
(
"show-associated",
- dict(
- short="s",
- action="store",
- metavar="<association_level>",
- type="int",
- default=None,
- help="show <association_level> levels of associated classes not in <projects>",
- ),
+ {
+ "short": "s",
+ "action": "store",
+ "metavar": "<association_level>",
+ "type": "int",
+ "default": None,
+ "help": "show <association_level> levels of associated classes not in <projects>",
+ },
),
(
"all-associated",
- dict(
- short="S",
- default=None,
- action="store_true",
- help="show recursively all associated off all associated classes",
- ),
+ {
+ "short": "S",
+ "default": None,
+ "action": "store_true",
+ "help": "show recursively all associated off all associated classes",
+ },
),
(
"show-builtin",
- dict(
- short="b",
- action="store_true",
- default=False,
- help="include builtin objects in representation of classes",
- ),
+ {
+ "short": "b",
+ "action": "store_true",
+ "default": False,
+ "help": "include builtin objects in representation of classes",
+ },
),
(
"module-names",
- dict(
- short="m",
- default=None,
- type="yn",
- metavar="<y or n>",
- help="include module name in representation of classes",
- ),
+ {
+ "short": "m",
+ "default": None,
+ "type": "yn",
+ "metavar": "<y or n>",
+ "help": "include module name in representation of classes",
+ },
),
(
"only-classnames",
- dict(
- short="k",
- action="store_true",
- default=False,
- help="don't show attributes and methods in the class boxes; this disables -f values",
- ),
+ {
+ "short": "k",
+ "action": "store_true",
+ "default": False,
+ "help": "don't show attributes and methods in the class boxes; this disables -f values",
+ },
),
(
"output",
- dict(
- short="o",
- dest="output_format",
- action="store",
- default="dot",
- metavar="<format>",
- type="string",
- help=(
+ {
+ "short": "o",
+ "dest": "output_format",
+ "action": "store",
+ "default": "dot",
+ "metavar": "<format>",
+ "type": "string",
+ "help": (
f"create a *.<format> output file if format is available. Available formats are: {', '.join(DIRECTLY_SUPPORTED_FORMATS)}. "
f"Any other format will be tried to create by means of the 'dot' command line tool, which requires a graphviz installation."
),
- ),
+ },
),
(
"colorized",
- dict(
- dest="colorized",
- action="store_true",
- default=False,
- help="Use colored output. Classes/modules of the same package get the same color.",
- ),
+ {
+ "dest": "colorized",
+ "action": "store_true",
+ "default": False,
+ "help": "Use colored output. Classes/modules of the same package get the same color.",
+ },
),
(
"max-color-depth",
- dict(
- dest="max_color_depth",
- action="store",
- default=2,
- metavar="<depth>",
- type="int",
- help="Use separate colors up to package depth of <depth>",
- ),
+ {
+ "dest": "max_color_depth",
+ "action": "store",
+ "default": 2,
+ "metavar": "<depth>",
+ "type": "int",
+ "help": "Use separate colors up to package depth of <depth>",
+ },
),
(
"ignore",
- dict(
- type="csv",
- metavar="<file[,file...]>",
- dest="ignore_list",
- default=constants.DEFAULT_IGNORE_LIST,
- help="Files or directories to be skipped. They should be base names, not paths.",
- ),
+ {
+ "type": "csv",
+ "metavar": "<file[,file...]>",
+ "dest": "ignore_list",
+ "default": constants.DEFAULT_IGNORE_LIST,
+ "help": "Files or directories to be skipped. They should be base names, not paths.",
+ },
),
(
"project",
- dict(
- default="",
- type="string",
- short="p",
- metavar="<project name>",
- help="set the project name.",
- ),
+ {
+ "default": "",
+ "type": "string",
+ "short": "p",
+ "metavar": "<project name>",
+ "help": "set the project name.",
+ },
),
(
"output-directory",
- dict(
- default="",
- type="path",
- short="d",
- action="store",
- metavar="<output_directory>",
- help="set the output directory path.",
- ),
+ {
+ "default": "",
+ "type": "path",
+ "short": "d",
+ "action": "store",
+ "metavar": "<output_directory>",
+ "help": "set the output directory path.",
+ },
),
)
diff --git a/pylint/pyreverse/vcg_printer.py b/pylint/pyreverse/vcg_printer.py
index 7a1d2d02d..6f28a24e8 100644
--- a/pylint/pyreverse/vcg_printer.py
+++ b/pylint/pyreverse/vcg_printer.py
@@ -154,20 +154,29 @@ SHAPES: dict[NodeType, str] = {
NodeType.CLASS: "box",
NodeType.INTERFACE: "ellipse",
}
+# pylint: disable-next=consider-using-namedtuple-or-dataclass
ARROWS: dict[EdgeType, dict[str, str | int]] = {
- EdgeType.USES: dict(arrowstyle="solid", backarrowstyle="none", backarrowsize=0),
- EdgeType.INHERITS: dict(
- arrowstyle="solid", backarrowstyle="none", backarrowsize=10
- ),
- EdgeType.IMPLEMENTS: dict(
- arrowstyle="solid",
- backarrowstyle="none",
- linestyle="dotted",
- backarrowsize=10,
- ),
- EdgeType.ASSOCIATION: dict(
- arrowstyle="solid", backarrowstyle="none", textcolor="green"
- ),
+ EdgeType.USES: {
+ "arrowstyle": "solid",
+ "backarrowstyle": "none",
+ "backarrowsize": 0,
+ },
+ EdgeType.INHERITS: {
+ "arrowstyle": "solid",
+ "backarrowstyle": "none",
+ "backarrowsize": 10,
+ },
+ EdgeType.IMPLEMENTS: {
+ "arrowstyle": "solid",
+ "backarrowstyle": "none",
+ "linestyle": "dotted",
+ "backarrowsize": 10,
+ },
+ EdgeType.ASSOCIATION: {
+ "arrowstyle": "solid",
+ "backarrowstyle": "none",
+ "textcolor": "green",
+ },
}
ORIENTATION: dict[Layout, str] = {
Layout.LEFT_TO_RIGHT: "left_to_right",
diff --git a/script/.contributors_aliases.json b/script/.contributors_aliases.json
index 6563c71d4..44ca36e20 100644
--- a/script/.contributors_aliases.json
+++ b/script/.contributors_aliases.json
@@ -602,5 +602,9 @@
"yileiyang@google.com": {
"mails": ["yileiyang@google.com"],
"name": "Yilei \"Dolee\" Yang"
+ },
+ "hofrob@protonmail.com": {
+ "mails": ["hofrob@protonmail.com"],
+ "name": "Robert Hofer"
}
}
diff --git a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py
index 5614674c3..efe6ba25f 100644
--- a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py
+++ b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_ex_returned.py
@@ -1,6 +1,6 @@
"""Check invalid value returned by __getnewargs_ex__ """
-# pylint: disable=too-few-public-methods,missing-docstring,import-error,use-dict-literal,unnecessary-lambda-assignment
+# pylint: disable=too-few-public-methods,missing-docstring,import-error,use-dict-literal,unnecessary-lambda-assignment,use-dict-literal
import six
from missing import Missing
diff --git a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py
index 49fe7b602..06cd81dd0 100644
--- a/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py
+++ b/tests/functional/i/invalid/invalid_getnewargs/invalid_getnewargs_returned.py
@@ -1,6 +1,6 @@
"""Check invalid value returned by __getnewargs__ """
-# pylint: disable=too-few-public-methods,missing-docstring,import-error,unnecessary-lambda-assignment
+# pylint: disable=too-few-public-methods,missing-docstring,import-error,unnecessary-lambda-assignment,use-dict-literal
import six
from missing import Missing
diff --git a/tests/functional/i/iterable_context.py b/tests/functional/i/iterable_context.py
index bc77ade34..fb035c4df 100644
--- a/tests/functional/i/iterable_context.py
+++ b/tests/functional/i/iterable_context.py
@@ -4,6 +4,7 @@ iterating/mapping context.
"""
# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,unused-argument,bad-mcs-method-argument,
# pylint: disable=wrong-import-position,no-else-return, unnecessary-comprehension,redundant-u-string-prefix
+# pylint: disable=use-dict-literal
# primitives
numbers = [1, 2, 3]
diff --git a/tests/functional/i/iterable_context.txt b/tests/functional/i/iterable_context.txt
index e0ca8c4fe..ef59b379c 100644
--- a/tests/functional/i/iterable_context.txt
+++ b/tests/functional/i/iterable_context.txt
@@ -1,10 +1,10 @@
-not-an-iterable:57:9:57:22::Non-iterable value powers_of_two is used in an iterating context:UNDEFINED
-not-an-iterable:92:6:92:9::Non-iterable value A() is used in an iterating context:UNDEFINED
-not-an-iterable:94:6:94:7::Non-iterable value B is used in an iterating context:UNDEFINED
-not-an-iterable:95:9:95:12::Non-iterable value A() is used in an iterating context:UNDEFINED
-not-an-iterable:99:9:99:10::Non-iterable value B is used in an iterating context:UNDEFINED
-not-an-iterable:102:9:102:14::Non-iterable value range is used in an iterating context:UNDEFINED
-not-an-iterable:106:9:106:13::Non-iterable value True is used in an iterating context:UNDEFINED
-not-an-iterable:109:9:109:13::Non-iterable value None is used in an iterating context:UNDEFINED
-not-an-iterable:112:9:112:12::Non-iterable value 8.5 is used in an iterating context:UNDEFINED
-not-an-iterable:115:9:115:11::Non-iterable value 10 is used in an iterating context:UNDEFINED
+not-an-iterable:58:9:58:22::Non-iterable value powers_of_two is used in an iterating context:UNDEFINED
+not-an-iterable:93:6:93:9::Non-iterable value A() is used in an iterating context:UNDEFINED
+not-an-iterable:95:6:95:7::Non-iterable value B is used in an iterating context:UNDEFINED
+not-an-iterable:96:9:96:12::Non-iterable value A() is used in an iterating context:UNDEFINED
+not-an-iterable:100:9:100:10::Non-iterable value B is used in an iterating context:UNDEFINED
+not-an-iterable:103:9:103:14::Non-iterable value range is used in an iterating context:UNDEFINED
+not-an-iterable:107:9:107:13::Non-iterable value True is used in an iterating context:UNDEFINED
+not-an-iterable:110:9:110:13::Non-iterable value None is used in an iterating context:UNDEFINED
+not-an-iterable:113:9:113:12::Non-iterable value 8.5 is used in an iterating context:UNDEFINED
+not-an-iterable:116:9:116:11::Non-iterable value 10 is used in an iterating context:UNDEFINED
diff --git a/tests/functional/m/mapping_context.py b/tests/functional/m/mapping_context.py
index 1d8a46afc..8dc6b3b72 100644
--- a/tests/functional/m/mapping_context.py
+++ b/tests/functional/m/mapping_context.py
@@ -1,7 +1,7 @@
"""
Checks that only valid values are used in a mapping context.
"""
-# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,wrong-import-position
+# pylint: disable=missing-docstring,invalid-name,too-few-public-methods,import-error,wrong-import-position,use-dict-literal
def test(**kwargs):
diff --git a/tests/functional/u/unidiomatic_typecheck.py b/tests/functional/u/unidiomatic_typecheck.py
index 1e7642046..2a1957d75 100644
--- a/tests/functional/u/unidiomatic_typecheck.py
+++ b/tests/functional/u/unidiomatic_typecheck.py
@@ -1,5 +1,5 @@
"""Warnings for using type(x) == Y or type(x) is Y instead of isinstance(x, Y)."""
-# pylint: disable=missing-docstring,expression-not-assigned,redefined-builtin,invalid-name,unnecessary-lambda-assignment
+# pylint: disable=missing-docstring,expression-not-assigned,redefined-builtin,invalid-name,unnecessary-lambda-assignment,use-dict-literal
def simple_positives():
type(42) is int # [unidiomatic-typecheck]
diff --git a/tests/functional/u/unnecessary/unnecessary_lambda.py b/tests/functional/u/unnecessary/unnecessary_lambda.py
index c12e30bc7..3e5ece2b1 100644
--- a/tests/functional/u/unnecessary/unnecessary_lambda.py
+++ b/tests/functional/u/unnecessary/unnecessary_lambda.py
@@ -1,4 +1,4 @@
-# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment
+# pylint: disable=undefined-variable, use-list-literal, unnecessary-lambda-assignment, use-dict-literal
"""test suspicious lambda expressions
"""
diff --git a/tests/functional/u/unsubscriptable_value.py b/tests/functional/u/unsubscriptable_value.py
index 2a40d647f..79e17903b 100644
--- a/tests/functional/u/unsubscriptable_value.py
+++ b/tests/functional/u/unsubscriptable_value.py
@@ -4,6 +4,7 @@ Checks that value used in a subscript supports subscription
"""
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position, unnecessary-comprehension
# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order, redundant-u-string-prefix
+# pylint: disable=use-dict-literal
# primitives
numbers = [1, 2, 3]
diff --git a/tests/functional/u/unsubscriptable_value.txt b/tests/functional/u/unsubscriptable_value.txt
index 24209a64a..d0833b600 100644
--- a/tests/functional/u/unsubscriptable_value.txt
+++ b/tests/functional/u/unsubscriptable_value.txt
@@ -1,15 +1,15 @@
-unsubscriptable-object:31:0:31:18::Value 'NonSubscriptable()' is unsubscriptable:UNDEFINED
-unsubscriptable-object:32:0:32:16::Value 'NonSubscriptable' is unsubscriptable:UNDEFINED
-unsubscriptable-object:34:0:34:13::Value 'Subscriptable' is unsubscriptable:UNDEFINED
-unsubscriptable-object:43:0:43:15::Value 'powers_of_two()' is unsubscriptable:UNDEFINED
-unsubscriptable-object:44:0:44:13::Value 'powers_of_two' is unsubscriptable:UNDEFINED
-unsubscriptable-object:48:0:48:4::Value 'True' is unsubscriptable:UNDEFINED
-unsubscriptable-object:49:0:49:4::Value 'None' is unsubscriptable:UNDEFINED
-unsubscriptable-object:50:0:50:3::Value '8.5' is unsubscriptable:UNDEFINED
-unsubscriptable-object:51:0:51:2::Value '10' is unsubscriptable:UNDEFINED
-unsubscriptable-object:54:0:54:27::Value '{x**2 for x in range(10)}' is unsubscriptable:UNDEFINED
-unsubscriptable-object:55:0:55:12::Value 'set(numbers)' is unsubscriptable:UNDEFINED
-unsubscriptable-object:56:0:56:18::Value 'frozenset(numbers)' is unsubscriptable:UNDEFINED
-unsubscriptable-object:76:0:76:20::Value 'SubscriptableClass()' is unsubscriptable:UNDEFINED
-unsubscriptable-object:83:0:83:4::Value 'test' is unsubscriptable:UNDEFINED
-unsubscriptable-object:126:11:126:18:test_one:Value 'var_one' is unsubscriptable:UNDEFINED
+unsubscriptable-object:32:0:32:18::Value 'NonSubscriptable()' is unsubscriptable:UNDEFINED
+unsubscriptable-object:33:0:33:16::Value 'NonSubscriptable' is unsubscriptable:UNDEFINED
+unsubscriptable-object:35:0:35:13::Value 'Subscriptable' is unsubscriptable:UNDEFINED
+unsubscriptable-object:44:0:44:15::Value 'powers_of_two()' is unsubscriptable:UNDEFINED
+unsubscriptable-object:45:0:45:13::Value 'powers_of_two' is unsubscriptable:UNDEFINED
+unsubscriptable-object:49:0:49:4::Value 'True' is unsubscriptable:UNDEFINED
+unsubscriptable-object:50:0:50:4::Value 'None' is unsubscriptable:UNDEFINED
+unsubscriptable-object:51:0:51:3::Value '8.5' is unsubscriptable:UNDEFINED
+unsubscriptable-object:52:0:52:2::Value '10' is unsubscriptable:UNDEFINED
+unsubscriptable-object:55:0:55:27::Value '{x**2 for x in range(10)}' is unsubscriptable:UNDEFINED
+unsubscriptable-object:56:0:56:12::Value 'set(numbers)' is unsubscriptable:UNDEFINED
+unsubscriptable-object:57:0:57:18::Value 'frozenset(numbers)' is unsubscriptable:UNDEFINED
+unsubscriptable-object:77:0:77:20::Value 'SubscriptableClass()' is unsubscriptable:UNDEFINED
+unsubscriptable-object:84:0:84:4::Value 'test' is unsubscriptable:UNDEFINED
+unsubscriptable-object:127:11:127:18:test_one:Value 'var_one' is unsubscriptable:UNDEFINED
diff --git a/tests/functional/u/unsupported/unsupported_assignment_operation.py b/tests/functional/u/unsupported/unsupported_assignment_operation.py
index 2cac693dd..93e84c020 100644
--- a/tests/functional/u/unsupported/unsupported_assignment_operation.py
+++ b/tests/functional/u/unsupported/unsupported_assignment_operation.py
@@ -3,7 +3,7 @@ Checks that value used in a subscript support assignments
(i.e. defines __setitem__ method).
"""
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position,unnecessary-comprehension
-# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order
+# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order,use-dict-literal
# primitives
numbers = [1, 2, 3]
diff --git a/tests/functional/u/unsupported/unsupported_delete_operation.py b/tests/functional/u/unsupported/unsupported_delete_operation.py
index 56a457324..c33a6eb89 100644
--- a/tests/functional/u/unsupported/unsupported_delete_operation.py
+++ b/tests/functional/u/unsupported/unsupported_delete_operation.py
@@ -3,7 +3,7 @@ Checks that value used in a subscript support deletion
(i.e. defines __delitem__ method).
"""
# pylint: disable=missing-docstring,pointless-statement,expression-not-assigned,wrong-import-position,unnecessary-comprehension
-# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order
+# pylint: disable=too-few-public-methods,import-error,invalid-name,wrong-import-order,use-dict-literal
# primitives
numbers = [1, 2, 3]
diff --git a/tests/functional/u/use/use_literal_dict.py b/tests/functional/u/use/use_literal_dict.py
index 3377b4e63..598b382bd 100644
--- a/tests/functional/u/use/use_literal_dict.py
+++ b/tests/functional/u/use/use_literal_dict.py
@@ -1,7 +1,46 @@
-# pylint: disable=missing-docstring, invalid-name
+# pylint: disable=missing-docstring, invalid-name, disallowed-name, unused-argument, too-few-public-methods
x = dict() # [use-dict-literal]
-x = dict(a="1", b=None, c=3)
+x = dict(a="1", b=None, c=3) # [use-dict-literal]
x = dict(zip(["a", "b", "c"], [1, 2, 3]))
x = {}
x = {"a": 1, "b": 2, "c": 3}
+x = dict(**x) # [use-dict-literal]
+
+def bar(boo: bool = False):
+ return 1
+
+x = dict(foo=bar()) # [use-dict-literal]
+
+baz = {"e": 9, "f": 1}
+
+dict( # [use-dict-literal]
+ **baz,
+ suggestions=list(
+ bar(
+ boo=True,
+ )
+ ),
+)
+
+class SomeClass:
+ prop: dict = {"a": 1}
+
+inst = SomeClass()
+
+dict( # [use-dict-literal]
+ url="/foo",
+ **inst.prop,
+)
+
+dict( # [use-dict-literal]
+ Lorem="ipsum",
+ dolor="sit",
+ amet="consectetur",
+ adipiscing="elit",
+ sed="do",
+ eiusmod="tempor",
+ incididunt="ut",
+ labore="et",
+ dolore="magna",
+)
diff --git a/tests/functional/u/use/use_literal_dict.txt b/tests/functional/u/use/use_literal_dict.txt
index cbcb83f24..145766479 100644
--- a/tests/functional/u/use/use_literal_dict.txt
+++ b/tests/functional/u/use/use_literal_dict.txt
@@ -1 +1,7 @@
-use-dict-literal:3:4:3:10::Consider using {} instead of dict():UNDEFINED
+use-dict-literal:3:4:3:10::Consider using '{}' instead of a call to 'dict'.:INFERENCE
+use-dict-literal:4:4:4:28::"Consider using '{""a"": '1', ""b"": None, ""c"": 3}' instead of a call to 'dict'.":INFERENCE
+use-dict-literal:8:4:8:13::Consider using '{**x}' instead of a call to 'dict'.:INFERENCE
+use-dict-literal:13:4:13:19::"Consider using '{""foo"": bar()}' instead of a call to 'dict'.":INFERENCE
+use-dict-literal:17:0:24:1::"Consider using '{""suggestions"": list(bar(boo=True)), **baz}' instead of a call to 'dict'.":INFERENCE
+use-dict-literal:31:0:34:1::"Consider using '{""url"": '/foo', **inst.prop}' instead of a call to 'dict'.":INFERENCE
+use-dict-literal:36:0:46:1::"Consider using '{""Lorem"": 'ipsum', ""dolor"": 'sit', ""amet"": 'consectetur', ""adipiscing"": 'elit', ... }' instead of a call to 'dict'.":INFERENCE