Repository: wemake-services/wemake-python-styleguide

Issue:
Stray WPS601 warning on class member reassignment
### What's wrong

Reassigning a value for dataclass member variable from a dataclass member function triggers a  stray WPS601 warning.

Here is a code snippet that shows the issue:

```python

from dataclasses import dataclass
from typing import Optional

@dataclass
class DataClass:
    string_value: Optional[str] = None

    def fun(self) -> None:
        self.string_value = self.string_value.strip() if self.string_value else None  # <- WPS601: Found shadowed class attribute: string_value
```

### How it should be

In the code snippet in question there is no shadowing happening, since all instances of `string_value` are scoped with `self`.

### Flake8 version and plugins

{
  "dependencies": [],
  "platform": {
    "python_implementation": "CPython",
    "python_version": "3.8.8",
    "system": "Darwin"
  },
  "plugins": [
    {
      "is_local": false,
      "plugin": "flake8-bandit",
      "version": "2.1.2"
    },
    {
      "is_local": false,
      "plugin": "flake8-broken-line",
      "version": "0.3.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-bugbear",
      "version": "20.11.1"
    },
    {
      "is_local": false,
      "plugin": "flake8-comprehensions",
      "version": "3.3.1"
    },
    {
      "is_local": false,
      "plugin": "flake8-darglint",
      "version": "1.7.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-debugger",
      "version": "4.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-docstrings",
      "version": "1.5.0, pydocstyle: 5.1.1"
    },
    {
      "is_local": false,
      "plugin": "flake8-eradicate",
      "version": "1.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8-string-format",
      "version": "0.3.0"
    },
    {
      "is_local": false,
      "plugin": "flake8_commas",
      "version": "2.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8_isort",
      "version": "4.0.0"
    },
    {
      "is_local": false,
      "plugin": "flake8_quotes",
      "version": "3.2.0"
    },
    {
      "is_local": false,
      "plugin": "mccabe",
      "version": "0.6.1"
    },
    {
      "is_local": false,
      "plugin": "naming",
      "version": "0.11.1"
    },
    {
      "is_local": false,
      "plugin": "pycodestyle",
      "version": "2.6.0"
    },
    {
      "is_local": false,
      "plugin": "pyflakes",
      "version": "2.2.0"
    },
    {
      "is_local": false,
      "plugin": "pylint",
      "version": "0.0.0"
    },
    {
      "is_local": false,
      "plugin": "rst-docstrings",
      "version": "0.0.14"
    },
    {
      "is_local": false,
      "plugin": "wemake_python_styleguide",
      "version": "0.15.2"
    }
  ],
  "version": "3.8.4"
}

### pip information

pip 20.2.4 from /Users/agatti/Library/Caches/pypoetry/virtualenvs/gls-automator-iJPcva4U-py3.8/lib/python3.8/site-packages/pip (python 3.8)
appdirs @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/68/c7/33/ef0f6af8d1aa906f1a5641762fe5d6f47d565c5a4b3482f1c6fb0f5f20/appdirs-1.4.4-py2.py3-none-any.whl
astor @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/00/68/e3/b2c93c6b1eabbb453b7a288336d64a2bb9f32b6821173440843f97f64b/astor-0.8.1-py2.py3-none-any.whl
attrs @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/b7/28/6f/acdd2c0e759f1cda97abf00db7723a0ffb3a151696d8d96398aea16171/attrs-20.3.0-py2.py3-none-any.whl
bandit @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a2/02/ff/eaae30b6c44acbb38e05e07e4a685c781ebb46ec87a72eeafbc8ede15b/bandit-1.7.0-py3-none-any.whl
black @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/38/f4/61/550fd050005dc1c64850374a7f98dd941a4633d72e87f147bebf26bdc3/black-20.8b1.tar.gz
click @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/30/bc/bf/e00ffd8f0edf0294942e70e80e42a839bd2649d2c5b864e6389e526d2a/click-7.1.2-py2.py3-none-any.whl
colorama @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/b0/f3/a3/cf94f06cbe1d286a25116cfe54d5a75cb1c4b54d15b2b1b4fc03a7f657/colorama-0.4.4-py2.py3-none-any.whl
darglint @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/d8/74/e4/fdb46c6fd8fac9548f5ae89e42fe0ab76b22887eb67a8baf9d0cd942cd/darglint-1.7.0-py3-none-any.whl
docutils @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/9e/78/f1/81f20d21f3ed304c86fa5394fadbb173e75ad363029a8fefa635dadf2e/docutils-0.16-py2.py3-none-any.whl
entrypoints @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/27/67/42/5ca7438658f76c8700ff6c44ea1cf9dc128cf0862adb7de53d3a35266c/entrypoints-0.3-py2.py3-none-any.whl
eradicate @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/aa/5c/1b/1cc2c911d9f4ca4e28af5d060406e467cd44e84aa2104e58dcb2783545/eradicate-2.0.0.tar.gz
flake8 @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/5c/5b/91/23d9fee55905e042e829a14e2fa56ffd39c81246aba659e2840bab728b/flake8-3.8.4-py2.py3-none-any.whl
flake8-bandit @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/cc/6d/cf/94dc0d884687c0e10baebe95be53977448e1b59d7ad05e41a0f046cd7e/flake8_bandit-2.1.2.tar.gz
flake8-broken-line @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/8f/48/91/0d6bc500782a1a3e000937daf9757ae8a66b6eb6cfb37a205bf8b7f786/flake8_broken_line-0.3.0-py3-none-any.whl
flake8-bugbear @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/ee/34/92/1a1933902453517c848d54696c56cadd58a50e81e7b6822f86a1a8f14a/flake8_bugbear-20.11.1-py36.py37.py38-none-any.whl
flake8-commas @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/b7/aa/76/e620a68b0be70f4132be94bfbfdacb20b16c060174b33dc856818db92d/flake8_commas-2.0.0-py2.py3-none-any.whl
flake8-comprehensions @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/79/68/a1/ad2a93c936991789c7abe3cfaad2061386a4a605875dc6031c7bf68a96/flake8_comprehensions-3.3.1-py3-none-any.whl
flake8-debugger @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/53/fa/32/0169f891a8c8722d66ad761e363416818d8b0bcc7df8ac07903d7e92e7/flake8_debugger-4.0.0-py3-none-any.whl
flake8-docstrings @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/14/46/f1/42800107fb2815121aebf831e269f0af48a45c669a24dbcec60fbbac9f/flake8_docstrings-1.5.0-py2.py3-none-any.whl
flake8-eradicate @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/36/d5/cc/644a05fd3f5223a3cf18d54aa7aa552d16177044159cf71cdb7e277279/flake8_eradicate-1.0.0-py3-none-any.whl
flake8-isort @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/7f/ff/4b/ccb1bf1f070d294477259bb95f68c42dcffe931cbd8e9288d9f8bc2fe9/flake8_isort-4.0.0-py2.py3-none-any.whl
flake8-polyfill @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/37/d4/b9/446f3fe801eea4de2fdff2cd1e0be3fa836d08c04d62174d4ec65113f3/flake8_polyfill-1.0.2-py2.py3-none-any.whl
flake8-quotes @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/12/1f/f0/7623670ff6f28d435847081ac20cd7d4eacb100ab4cd318651dbd2ad1f/flake8-quotes-3.2.0.tar.gz
flake8-rst-docstrings @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/23/55/53/366c0609509a22c9af7a6593751dde0890159781e725e1ce828ada50ce/flake8-rst-docstrings-0.0.14.tar.gz
flake8-string-format @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/fd/52/74/3de7f09d54ed637290f8522dc409ca9af53673b8ddc0d4026f088e4c09/flake8_string_format-0.3.0-py2.py3-none-any.whl
flakehell @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/1e/20/33/c1828805fe5abe2bf39425e410b6dba1a14103fd4b7548af058ca13978/flakehell-0.9.0-py3-none-any.whl
gitdb @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/45/a9/94/d73ced00c6cf302a2e08bedd4f10d3424342b7a8a2fae6e4ccb7276641/gitdb-4.0.5-py3-none-any.whl
GitPython @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/4e/6c/4d/f8f6c8b848d0d99302eaa7a87f7a59e0926307bbce507550c64366d44d/GitPython-3.1.14-py3-none-any.whl
isort @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/c7/65/52/89112b51dedef2d5c6ae731072aace88c4bb499093e551cceec24f2b18/isort-5.7.0-py3-none-any.whl
loguru-mypy @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/0f/c7/77/58fd89282070a92550ea2a5a56db3a57cd8840475f43f9525298839f4b/loguru_mypy-0.0.3-py3-none-any.whl
mccabe @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/37/6e/69/4a33a4d6c80c775b1ee205face2c6e07b762c8602bb0f0d236ebe790c5/mccabe-0.6.1-py2.py3-none-any.whl
mypy @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a1/d7/a2/283d8c87c1f9fb228c2e9d33e51d9e099e5a66c6e95f516f77a82ce9f0/mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl
mypy-extensions @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/b6/a0/b0/a5dc9acd6fd12aba308634f21bb7cf0571448f20848797d7ecb327aa12/mypy_extensions-0.4.3-py2.py3-none-any.whl
pastel @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a3/82/78/1165702c3bd8d7effa892ab5af5542aba9bf145cbaca3c9ec10861de25/pastel-0.2.1-py2.py3-none-any.whl
pathspec @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/5d/98/c8/c7cd4decd7943aa5647824d8553b40e86f4e2ef814ca2a4e73ee708f7f/pathspec-0.8.1-py2.py3-none-any.whl
pbr @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/85/81/cf/9255f6df466921f8291c85ab33df01caeda1916c2745a5071ce06a963f/pbr-5.5.1-py2.py3-none-any.whl
pendulum @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/3d/b6/88/afe8e7e932d9131ebd9fe995f5fea4fd77d503f343f9b7da61290b17f8/pendulum-2.1.2-cp38-cp38-macosx_10_15_x86_64.whl
pep8-naming @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/e7/c8/00/b145306a40eba2961774c78d56e8fb9b09c08e44af6fd83642c5114bba/pep8_naming-0.11.1-py2.py3-none-any.whl
poethepoet @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/ea/33/99/b9c2234550c735d46af601efdeb043d629025a20eeb2d41d50198eeb28/poethepoet-0.10.0-py3-none-any.whl
pycodestyle @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/01/f4/cf/c7e34cb76e03e95d9eff28af16fe09ee8edd01cc985fc2b88453b6d311/pycodestyle-2.6.0-py2.py3-none-any.whl
pydocstyle @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a4/ef/58/498033174cb8c68875036ec5d8a3d9d2e169c51bec9d35866bd62ff5ac/pydocstyle-5.1.1-py3-none-any.whl
pyflakes @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/da/83/11/1e9a80c39638c6967e9b1117b17d8ec5f723ddd0a88251cc08dc0807b0/pyflakes-2.2.0-py2.py3-none-any.whl
Pygments @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/d8/89/8d/dd9d739214940ed315c7a6aa2fc949a9ed6257976b13c0e7d40e684012/Pygments-2.8.0-py3-none-any.whl
python-dateutil @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/1e/2c/dc/0e811c2299b40168ee1da03bc13c11762ce9fa96eb867ad22280db11fc/python_dateutil-2.8.1-py2.py3-none-any.whl
pytzdata @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/c6/0d/bc/7911b53cb0aa9ce069ef59cf2553c999a5dec47954f2d3c69bcb2dd621/pytzdata-2020.1-py2.py3-none-any.whl
PyYAML @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/99/c6/60/2baceb8eb743927ffda4f0184e9aea5339ca72c9a463509feeeb0d1668/PyYAML-5.4.1-cp38-cp38-macosx_10_9_x86_64.whl
regex @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/e0/83/12/fa2b876292757ada6c8e31db47fe4a424e2527810123e5ed316006f6d3/regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl
restructuredtext-lint @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/7b/45/5c/94b65fa89812c0d8701b8af07cdd43b8a91f5e8d84776984b12942b4cc/restructuredtext_lint-1.3.2.tar.gz
six @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/be/98/c7/69fe6fea7a59659af1c6260899226129565330b1e07c9c5b3769be76bf/six-1.15.0-py2.py3-none-any.whl
smmap @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/ab/27/f3/6ab65f7970ca4dbc0d01a73d5a79abe597252970bf3abc442a7084a6f5/smmap-3.0.5-py2.py3-none-any.whl
snowballstemmer @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a6/21/11/58b79c57cfc922455998165c2ecc503603be058fe178af058936deaf1f/snowballstemmer-2.1.0-py2.py3-none-any.whl
stevedore @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/df/1c/87/ee139e37999b53501924b31a04b30301f789c2944af24daea1ada94ceb/stevedore-3.3.0-py3-none-any.whl
testfixtures @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/33/ef/82/2cdf5deff816074815a062ea94bc53083040ae5ca90178494e082a6cc0/testfixtures-6.17.1-py2.py3-none-any.whl
toml @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/9f/8c/c3/7b4f6778d60f3c9fa11f8fd0e48243bbad25a04975e0a01006b6350594/toml-0.10.2-py2.py3-none-any.whl
tomlkit @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/db/c3/df/baf014ce3b04caffe7ac34bde699f5be82c4acbaf43f49db1ce681a500/tomlkit-0.7.0-py2.py3-none-any.whl
typed-ast @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/e5/b5/79/23ee82b09fc7da4721300ac1169f9245ef341c44d7abc2564330a69214/typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl
typing-extensions @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/ac/8f/3a/97dfae6ca13a6e156f19a5e8aa95fc250129d7e5e6cd0f7c76a1d45b4f/typing_extensions-3.7.4.3-py3-none-any.whl
urllib3 @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/a9/fc/7b/ab7ab6ea0d0cbf7347c6de7a3ab67af2f715357ebb539bdf464671b640/urllib3-1.26.3-py2.py3-none-any.whl
wemake-python-styleguide @ file:///Users/agatti/Library/Caches/pypoetry/artifacts/80/1a/f6/8845722373a0ecf2fad93ef5c639738d34e0c3bec1b3afd323226de1b3/wemake_python_styleguide-0.15.2-py3-none-any.whl

### OS information

Darwin rotifer.local 19.6.0 Darwin Kernel Version 19.6.0: Tue Jan 12 22:13:05 PST 2021; root:xnu-6153.141.16~1/RELEASE_X86_64 x86_64



Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb9809ff..fbc0ba9f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -75,8 +75,6 @@ Semantic versioning in our case means:
 ## Features
 
 - Adds official `python3.13` support
-- Adds a new rule to find too complex `except` with too many exceptions
-- Adds a new rule to find too many PEP695 type params
 - Allows any compares in `assert` statements for `WPS520`, #3112
 - Allows walrus operator (`:=`) in comprehesions #3121
 - Allows `pass` in `case` bodies, #2642
@@ -85,10 +83,14 @@ Semantic versioning in our case means:
 - Allows using nested `import` in `try` for `WPS433` and `WPS440`, #2382
 - Does not count `self`, `cls`, and `mcs` as arguments
   for `WPS211` complexity check anymore, #2394
-- `WPS303`: Underscore (`_`) now only allowed with 3 digits after it, #3120
+- Allows underscores (`_`) with exactly 3 digits after it in `WPS303`, #3120
+- Allows class / instance attribute shadowing
+  in `@dataclass`es for `WPS601`, #1926
 - Adds new rule to forbid `lambda` assigns to special attributes, #1733
 - Adds new rule to check problematic function params, #1343
 - Adds new rule to detect duplicate conditions in `if`s and `elif`s, #2241
+- Adds a new rule to find too complex `except` with too many exceptions
+- Adds a new rule to find too many PEP695 type params
 - Adds support to run `wemake-python-styleguide` as a `pre-commit` hook, #2588
 - GitHub Action can now use `cwd:` parameter to specify
   where your configuration file is, #2474
diff --git a/wemake_python_styleguide/logic/tree/classes.py b/wemake_python_styleguide/logic/tree/classes.py
index 75f25d3a..851a4627 100644
--- a/wemake_python_styleguide/logic/tree/classes.py
+++ b/wemake_python_styleguide/logic/tree/classes.py
@@ -1,13 +1,35 @@
 import ast
+from typing import Final, TypeAlias
 
 from wemake_python_styleguide.compat.aliases import AssignNodes
 from wemake_python_styleguide.constants import ALLOWED_BUILTIN_CLASSES
-from wemake_python_styleguide.logic import nodes
+from wemake_python_styleguide.logic import nodes, source
 from wemake_python_styleguide.logic.naming.builtins import is_builtin_name
 from wemake_python_styleguide.types import AnyAssign
 
 #: Type alias for the attributes we return from class inspection.
-_AllAttributes = tuple[list[AnyAssign], list[ast.Attribute]]
+_AllAttributes: TypeAlias = tuple[list[AnyAssign], list[ast.Attribute]]
+
+#: Names that can define a dataclass.
+_DATACLASS_NAMES: Final = frozenset((
+    # stdlib:
+    'dataclasses.dataclass',
+    # attrs:
+    'attrs.define',
+    'attrs.frozen',
+    'attrs.mutable',
+    'attr.s',
+    'attr.attrs',
+    'attr.attributes',
+    'attr.frozen',
+    'attr.mutable',
+    # pydantic also has `dataclass` and `dataclasses.dataclass`
+))
+
+#: Short form of dataclass decorators without module names.
+_SHORT_DATACLASS_NAMES: Final = frozenset(
+    dataclass_name.split('.')[1] for dataclass_name in _DATACLASS_NAMES
+)
 
 
 def is_forbidden_super_class(class_name: str | None) -> bool:
@@ -40,6 +62,24 @@ def is_forbidden_super_class(class_name: str | None) -> bool:
     return is_builtin_name(class_name)
 
 
+def is_dataclass(node: ast.ClassDef) -> bool:
+    """Checks if some class is defined as a dataclass using popular libs."""
+    for decorator in node.decorator_list:
+        if isinstance(decorator, ast.Call):
+            decorator = decorator.func
+
+        if not isinstance(decorator, ast.Name | ast.Attribute):
+            continue
+
+        decorator_code = source.node_to_string(decorator)
+        if (
+            decorator_code in _DATACLASS_NAMES
+            or decorator_code in _SHORT_DATACLASS_NAMES
+        ):
+            return True
+    return False
+
+
 def get_attributes(
     node: ast.ClassDef,
     *,
diff --git a/wemake_python_styleguide/violations/best_practices.py b/wemake_python_styleguide/violations/best_practices.py
index a2a5219f..36269df3 100644
--- a/wemake_python_styleguide/violations/best_practices.py
+++ b/wemake_python_styleguide/violations/best_practices.py
@@ -946,6 +946,8 @@ class WrongKeywordViolation(ASTViolation):
         ``global`` and ``nonlocal`` usages should be refactored.
 
     .. versionadded:: 0.1.0
+    .. versionchanged:: 1.0.0
+       Allows ``pass`` in ``case`` bodies.
 
     """
 
@@ -1430,6 +1432,8 @@ class NestedImportViolation(ASTViolation):
 
     .. versionadded:: 0.1.0
     .. versionchanged:: 0.11.0
+    .. versionchanged:: 1.0.0
+       Allows nested imports in ``try: except:`` block on top level.
 
     See also:
         https://github.com/seddonym/layer_linter
@@ -1680,6 +1684,8 @@ class BlockAndLocalOverlapViolation(ASTViolation):
         https://github.com/satwikkansal/wtfPython#-explanation-20
 
     .. versionadded:: 0.12.0
+    .. versionchanged:: 1.0.0
+       Allows nested imports in ``try: except:`` block on top level.
 
     """
 
@@ -1722,6 +1728,8 @@ class ControlVarUsedAfterBlockViolation(ASTViolation):
 
     .. versionadded:: 0.12.0
     .. versionchanged:: 0.14.0
+    .. versionchanged:: 1.0.0
+       Allows using variables after blocks in ``assert`` statements.
 
     """
 
diff --git a/wemake_python_styleguide/violations/complexity.py b/wemake_python_styleguide/violations/complexity.py
index ab2ee540..c93da9b9 100644
--- a/wemake_python_styleguide/violations/complexity.py
+++ b/wemake_python_styleguide/violations/complexity.py
@@ -384,6 +384,8 @@ class TooManyArgumentsViolation(ASTViolation):
         Default: :str:`wemake_python_styleguide.options.defaults.MAX_ARGUMENTS`
 
     .. versionadded:: 0.1.0
+    .. versionchanged:: 1.0.0
+       Does not count special ``self``, ``cls``, and ``mcs`` as parameters.
 
     """
 
diff --git a/wemake_python_styleguide/violations/consistency.py b/wemake_python_styleguide/violations/consistency.py
index fc6532b4..7ecb92da 100644
--- a/wemake_python_styleguide/violations/consistency.py
+++ b/wemake_python_styleguide/violations/consistency.py
@@ -288,7 +288,7 @@ class UnderscoredNumberViolation(TokenizeViolation):
 
     .. versionadded:: 0.1.0
     .. versionchanged:: 1.0.0
-       Underscore (_) now only allowed with 3 digits after it
+       Underscore ``_`` is now allowed with exactly 3 digits after it.
 
     """
 
@@ -1453,6 +1453,8 @@ class WalrusViolation(ASTViolation):
             print(some)
 
     .. versionadded:: 0.14.0
+    .. versionchanged:: 1.0.0
+       Allows ``:=`` inside comprehensions.
 
     """
 
diff --git a/wemake_python_styleguide/violations/oop.py b/wemake_python_styleguide/violations/oop.py
index c843fff5..fcafbad3 100644
--- a/wemake_python_styleguide/violations/oop.py
+++ b/wemake_python_styleguide/violations/oop.py
@@ -91,6 +91,8 @@ class BuiltinSubclassViolation(ASTViolation):
 
     .. versionadded:: 0.10.0
     .. versionchanged:: 0.11.0
+    .. versionchanged:: 1.0.0
+       Allows subclassing builtins in ``enum.Enum`` definitions.
 
     """
 
@@ -143,6 +145,9 @@ class ShadowedClassAttributeViolation(ASTViolation):
     .. versionadded:: 0.10.0
     .. versionchanged:: 0.11.0
     .. versionchanged:: 0.14.0
+    .. versionchanged:: 1.0.0
+       Allow to shadow class attribute names in ``@dataclass`` classes.
+
     .. _mypyc: https://github.com/python/mypy/tree/master/mypyc
 
     """
diff --git a/wemake_python_styleguide/violations/refactoring.py b/wemake_python_styleguide/violations/refactoring.py
index 2badcf6f..d4fa95ed 100644
--- a/wemake_python_styleguide/violations/refactoring.py
+++ b/wemake_python_styleguide/violations/refactoring.py
@@ -883,6 +883,7 @@ class FalsyConstantCompareViolation(ASTViolation):
 
     .. versionadded:: 0.12.0
     .. versionchanged:: 1.0.0
+       Allows any compares in ``assert`` statements.
 
     """
 
diff --git a/wemake_python_styleguide/visitors/ast/classes.py b/wemake_python_styleguide/visitors/ast/classes.py
index b9292ff1..63d5b81f 100644
--- a/wemake_python_styleguide/visitors/ast/classes.py
+++ b/wemake_python_styleguide/visitors/ast/classes.py
@@ -365,6 +365,11 @@ class ClassAttributeVisitor(base.BaseNodeVisitor):
         self.generic_visit(node)
 
     def _check_attributes_shadowing(self, node: ast.ClassDef) -> None:
+        if classes.is_dataclass(node):
+            # dataclasses by its nature allow class-level attributes
+            # shadowing from instance level.
+            return
+
         class_attributes, instance_attributes = classes.get_attributes(
             node,
             include_annotated=False,
diff --git a/wemake_python_styleguide/visitors/ast/keywords.py b/wemake_python_styleguide/visitors/ast/keywords.py
index 338ebe4b..0a9f644e 100644
--- a/wemake_python_styleguide/visitors/ast/keywords.py
+++ b/wemake_python_styleguide/visitors/ast/keywords.py
@@ -155,24 +155,24 @@ class ConsistentReturningVisitor(BaseNodeVisitor):
 
 
 @final
+@alias(
+    'visit_forbidden_keyword',
+    (
+        'visit_Pass',
+        'visit_Delete',
+        'visit_Global',
+        'visit_Nonlocal',
+    ),
+)
 class WrongKeywordVisitor(BaseNodeVisitor):
     """Finds wrong keywords."""
 
-    _forbidden_keywords: ClassVar[AnyNodes] = (
-        ast.Pass,
-        ast.Delete,
-        ast.Global,
-        ast.Nonlocal,
-    )
-
-    def visit(self, node: ast.AST) -> None:
+    def visit_forbidden_keyword(self, node: ast.AST) -> None:
         """Used to find wrong keywords."""
         self._check_keyword(node)
         self.generic_visit(node)
 
     def _check_keyword(self, node: ast.AST) -> None:
-        if not isinstance(node, self._forbidden_keywords):
-            return
         if isinstance(node, ast.Pass) and walk.get_closest_parent(
             node, ast.match_case
         ):


Test patch:
diff --git a/tests/test_visitors/test_ast/test_classes/test_class_attributes/test_shadow_attributes.py b/tests/test_visitors/test_ast/test_classes/test_class_attributes/test_shadow_attributes.py
index 718313b8..846c7a9e 100644
--- a/tests/test_visitors/test_ast/test_classes/test_class_attributes/test_shadow_attributes.py
+++ b/tests/test_visitors/test_ast/test_classes/test_class_attributes/test_shadow_attributes.py
@@ -48,6 +48,24 @@ class ClassWithAttrs:
         self.{1} = 2
 """
 
+class_with_unrelated_decorator1 = """
+@not_a_dataclass
+class ClassWithAttrs:
+    {0}: int = 0
+
+    def __post_init__(self) -> None:
+        self.{1} = 2
+"""
+
+class_with_unrelated_decorator2 = """
+@not_dataclasses[0]
+class ClassWithAttrs:
+    {0}: int = 0
+
+    def __post_init__(self) -> None:
+        self.{1} = 2
+"""
+
 # Safe:
 
 class_annotation = """
@@ -98,6 +116,24 @@ class ClassWithAttrs:
         self.{1} = 2
 """
 
+class_with_dataclass_decorator1 = """
+@dataclass
+class ClassWithAttrs:
+    {0}: int = 0
+
+    def __post_init__(self) -> None:
+        self.{1} = 2
+"""
+
+class_with_dataclass_decorator2 = """
+@dataclass(slots=True)
+class ClassWithAttrs:
+    {0}: int = 0
+
+    def __post_init__(self) -> None:
+        self.{1} = 2
+"""
+
 regular_assigns = """
 {0} = 0
 {1} = 2
@@ -112,6 +148,8 @@ regular_assigns = """
         class_attribute_runtime,
         class_attribute_annotated,
         class_attribute_logic,
+        class_with_unrelated_decorator1,
+        class_with_unrelated_decorator2,
     ],
 )
 @pytest.mark.parametrize(
@@ -154,6 +192,10 @@ def test_incorrect_fields(
         class_attribute_logic,
         class_attribute_regular_assign,
         class_attribute_with_other,
+        class_with_unrelated_decorator1,
+        class_with_unrelated_decorator2,
+        class_with_dataclass_decorator1,
+        class_with_dataclass_decorator2,
         regular_assigns,
     ],
 )
@@ -191,6 +233,8 @@ def test_correct_fields(
         regular_assigns,
         class_complex_attribute,
         class_complex_attribute_annotated,
+        class_with_dataclass_decorator1,
+        class_with_dataclass_decorator2,
     ],
 )
 @pytest.mark.parametrize(