We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
WPS324 false-positive with nested functions
# Bug report

<!--
Hi, thanks for submitting a bug. We appreciate that.

But, we will need some information about what's wrong to help you.
-->

## What's wrong

This code produces false positive `WPS324`:

```python
def test():
    def decorator():
        return
    return decorator
```

<!-- Describe what is not working. Please, attach a traceback. -->

## How is that should be

These two returns are completely different cases. We should check `.wps_context` of the node.
See: 
- https://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/visitors/ast/keywords.py#L133
- https://github.com/wemake-services/wemake-python-styleguide/blob/b43e738c4527219f03c2eec420fe2e20cfd4c8cc/wemake_python_styleguide/logic/nodes.py#L29

<!--

  Love wemake-python-styleguide? ❤️
  Do you want your bugs to be solved faster?

  Please consider supporting our collective:
👉  https://opencollective.com/wemake-python-styleguide/donate

-->


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wemake_python_styleguide/visitors/ast/keywords.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 import ast
4 from collections import defaultdict
5 from contextlib import suppress
6 from typing import ClassVar, Dict, List, Tuple, Type, Union
7 
8 from typing_extensions import final
9 
10 from wemake_python_styleguide.compat.aliases import FunctionNodes
11 from wemake_python_styleguide.logic import walk
12 from wemake_python_styleguide.logic.exceptions import get_exception_name
13 from wemake_python_styleguide.logic.nodes import get_context, get_parent
14 from wemake_python_styleguide.logic.variables import (
15     is_valid_block_variable_definition,
16 )
17 from wemake_python_styleguide.types import AnyFunctionDef, AnyNodes, AnyWith
18 from wemake_python_styleguide.violations.best_practices import (
19     ContextManagerVariableDefinitionViolation,
20     RaiseNotImplementedViolation,
21     WrongKeywordConditionViolation,
22     WrongKeywordViolation,
23 )
24 from wemake_python_styleguide.violations.consistency import (
25     InconsistentReturnVariableViolation,
26     InconsistentReturnViolation,
27     InconsistentYieldViolation,
28     MultipleContextManagerAssignmentsViolation,
29 )
30 from wemake_python_styleguide.visitors.base import BaseNodeVisitor
31 from wemake_python_styleguide.visitors.decorators import alias
32 
33 NamesAndReturns = Tuple[
34     Dict[str, List[ast.Name]],
35     Dict[str, ast.Return],
36 ]
37 ReturningViolations = Union[
38     Type[InconsistentReturnViolation],
39     Type[InconsistentYieldViolation],
40 ]
41 
42 
43 @final
44 class WrongRaiseVisitor(BaseNodeVisitor):
45     """Finds wrong ``raise`` keywords."""
46 
47     def visit_Raise(self, node: ast.Raise) -> None:
48         """
49         Checks how ``raise`` keyword is used.
50 
51         Raises:
52             RaiseNotImplementedViolation
53 
54         """
55         self._check_exception_type(node)
56         self.generic_visit(node)
57 
58     def _check_exception_type(self, node: ast.Raise) -> None:
59         exception_name = get_exception_name(node)
60         if exception_name == 'NotImplemented':
61             self.add_violation(RaiseNotImplementedViolation(node))
62 
63 
64 @final
65 @alias('visit_any_function', (
66     'visit_FunctionDef',
67     'visit_AsyncFunctionDef',
68 ))
69 class ConsistentReturningVisitor(BaseNodeVisitor):
70     """Finds incorrect and inconsistent ``return`` and ``yield`` nodes."""
71 
72     def visit_Return(self, node: ast.Return) -> None:
73         """
74         Checks ``return`` statements for consistency.
75 
76         Raises:
77             InconsistentReturnViolation
78 
79         """
80         self._check_last_return_in_function(node)
81         self.generic_visit(node)
82 
83     def visit_any_function(self, node: AnyFunctionDef) -> None:
84         """
85         Helper to get all ``return`` and ``yield`` nodes in a function at once.
86 
87         Raises:
88             InconsistentReturnViolation
89             InconsistentYieldViolation
90 
91         """
92         self._check_return_values(node)
93         self._check_yield_values(node)
94         self.generic_visit(node)
95 
96     def _check_last_return_in_function(self, node: ast.Return) -> None:
97         parent = get_parent(node)
98         if not isinstance(parent, FunctionNodes):
99             return
100 
101         returns = len(list(filter(
102             lambda return_node: return_node.value is not None,
103             walk.get_subnodes_by_type(parent, ast.Return),
104         )))
105 
106         last_value_return = (
107             len(parent.body) > 1 and
108             returns < 2 and
109             isinstance(node.value, ast.NameConstant) and
110             node.value.value is None
111         )
112         if node.value is None or last_value_return:
113             self.add_violation(InconsistentReturnViolation(node))
114 
115     def _iterate_returning_values(
116         self,
117         node: AnyFunctionDef,
118         returning_type,  # mypy is not ok with this type declaration
119         violation: ReturningViolations,
120     ):
121         returns: List[ast.Return] = []
122         has_values = False
123         for sub_node in ast.walk(node):
124             if isinstance(sub_node, returning_type):
125                 if sub_node.value:
126                     has_values = True
127                 returns.append(sub_node)
128 
129         for return_node in returns:
130             if not return_node.value and has_values:
131                 self.add_violation(violation(return_node))
132 
133     def _check_return_values(self, node: AnyFunctionDef) -> None:
134         self._iterate_returning_values(
135             node, ast.Return, InconsistentReturnViolation,
136         )
137 
138     def _check_yield_values(self, node: AnyFunctionDef) -> None:
139         self._iterate_returning_values(
140             node, ast.Yield, InconsistentYieldViolation,
141         )
142 
143 
144 @final
145 class WrongKeywordVisitor(BaseNodeVisitor):
146     """Finds wrong keywords."""
147 
148     _forbidden_keywords: ClassVar[AnyNodes] = (
149         ast.Pass,
150         ast.Delete,
151         ast.Global,
152         ast.Nonlocal,
153     )
154 
155     def visit(self, node: ast.AST) -> None:
156         """
157         Used to find wrong keywords.
158 
159         Raises:
160             WrongKeywordViolation
161 
162         """
163         self._check_keyword(node)
164         self.generic_visit(node)
165 
166     def _check_keyword(self, node: ast.AST) -> None:
167         if isinstance(node, self._forbidden_keywords):
168             if isinstance(node, ast.Delete):
169                 message = 'del'
170             else:
171                 message = node.__class__.__qualname__.lower()
172             self.add_violation(WrongKeywordViolation(node, text=message))
173 
174 
175 @final
176 @alias('visit_any_with', (
177     'visit_With',
178     'visit_AsyncWith',
179 ))
180 class WrongContextManagerVisitor(BaseNodeVisitor):
181     """Checks context managers."""
182 
183     def visit_withitem(self, node: ast.withitem) -> None:
184         """
185         Checks that all variables inside context managers defined correctly.
186 
187         Raises:
188             ContextManagerVariableDefinitionViolation
189 
190         """
191         self._check_variable_definitions(node)
192         self.generic_visit(node)
193 
194     def visit_any_with(self, node: AnyWith) -> None:
195         """
196         Checks the number of assignments for context managers.
197 
198         Raises:
199             MultipleContextManagerAssignmentsViolation
200 
201         """
202         self._check_target_assignment(node)
203         self.generic_visit(node)
204 
205     def _check_target_assignment(self, node: AnyWith):
206         if len(node.items) > 1:
207             self.add_violation(
208                 MultipleContextManagerAssignmentsViolation(node),
209             )
210 
211     def _check_variable_definitions(self, node: ast.withitem) -> None:
212         if node.optional_vars is None:
213             return
214 
215         if not is_valid_block_variable_definition(node.optional_vars):
216             self.add_violation(
217                 ContextManagerVariableDefinitionViolation(get_parent(node)),
218             )
219 
220 
221 @final
222 @alias('visit_return_variable', (
223     'visit_AsyncFunctionDef',
224     'visit_FunctionDef',
225 ))
226 class ConsistentReturningVariableVisitor(BaseNodeVisitor):
227     """Finds variables that are only used in `return` statements."""
228 
229     _checking_nodes: ClassVar[AnyNodes] = (
230         ast.Assign,
231         ast.AnnAssign,
232         ast.AugAssign,
233         ast.Return,
234         ast.Name,
235     )
236 
237     def visit_return_variable(self, node: AnyFunctionDef) -> None:
238         """
239         Helper to get all ``return`` variables in a function at once.
240 
241         Raises:
242             InconsistentReturnVariableViolation
243 
244         """
245         self._check_variables_for_return(node)
246         self.generic_visit(node)
247 
248     def _get_assign_node_variables(self, node: List[ast.AST]) -> List[str]:
249         assign = []
250         for sub_node in node:
251             if isinstance(sub_node, ast.Assign):
252                 if isinstance(sub_node.targets[0], ast.Name):
253                     assign.append(sub_node.targets[0].id)
254             if isinstance(sub_node, ast.AnnAssign):
255                 if isinstance(sub_node.target, ast.Name):
256                     assign.append(sub_node.target.id)
257         return assign
258 
259     def _get_name_nodes_variable(
260         self,
261         node: List[ast.AST],
262     ) -> Dict[str, List[ast.Name]]:
263         names: Dict[str, List[ast.Name]] = defaultdict(list)
264         for sub_node in node:
265             if isinstance(sub_node, ast.Name):
266                 if isinstance(sub_node.ctx, ast.Load):
267                     names[sub_node.id].append(sub_node)
268             if isinstance(sub_node, ast.AugAssign):
269                 if isinstance(sub_node.target, ast.Name):
270                     variable_name = sub_node.target.id
271                     names[variable_name].append(sub_node.target)
272         return names
273 
274     def _get_return_node_variables(
275         self,
276         node: List[ast.AST],
277     ) -> NamesAndReturns:
278         returns: Dict[str, List[ast.Name]] = defaultdict(list)
279         return_sub_nodes: Dict[str, ast.Return] = defaultdict()
280         for sub_node in node:
281             if isinstance(sub_node, ast.Return):
282                 if isinstance(sub_node.value, ast.Name):
283                     variable_name = sub_node.value.id
284                     returns[variable_name].append(sub_node.value)
285                     return_sub_nodes[variable_name] = sub_node
286         return returns, return_sub_nodes
287 
288     def _is_correct_return_node(
289         self,
290         node: AnyFunctionDef,
291         sub_node: ast.AST,
292     ) -> bool:
293         if get_context(sub_node) != node:
294             return False
295         return isinstance(sub_node, self._checking_nodes)
296 
297     def _check_variables_for_return(self, node: AnyFunctionDef) -> None:
298         nodes = list(
299             filter(
300                 lambda sub: self._is_correct_return_node(node, sub),
301                 ast.walk(node),
302             ),
303         )
304         assign = self._get_assign_node_variables(nodes)
305         names = self._get_name_nodes_variable(nodes)
306         returns, return_sub_nodes = self._get_return_node_variables(nodes)
307 
308         returns = {name: returns[name] for name in returns if name in assign}
309 
310         self._check_for_violations(names, return_sub_nodes, returns)
311 
312     def _check_for_violations(self, names, return_sub_nodes, returns) -> None:
313         for variable_name in returns:
314             if not set(names[variable_name]) - set(returns[variable_name]):
315                 self.add_violation(
316                     InconsistentReturnVariableViolation(
317                         return_sub_nodes[variable_name],
318                     ),
319                 )
320 
321 
322 @final
323 class ConstantKeywordVisitor(BaseNodeVisitor):
324     """Visits keyword definitions to detect contant conditions."""
325 
326     def visit_While(self, node: ast.While) -> None:
327         """
328         Visits ``while`` keyword and tests that loop will execute.
329 
330         Raises:
331             WrongKeywordConditionViolation
332 
333         """
334         self._check_condition(node.test)
335         self.generic_visit(node)
336 
337     def visit_Assert(self, node: ast.Assert) -> None:
338         """
339         Visits ``assert`` keyword and tests that condition is correct.
340 
341         Raises:
342             WrongKeywordConditionViolation
343 
344         """
345         self._check_condition(node.test)
346         self.generic_visit(node)
347 
348     def _check_condition(self, condition: ast.AST) -> None:
349         with suppress(ValueError):
350             constant = ast.literal_eval(condition)
351             if not bool(constant):
352                 self.add_violation(
353                     WrongKeywordConditionViolation(
354                         condition,
355                         text=str(constant) if constant != '' else '""',
356                     ),
357                 )
358
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/wemake_python_styleguide/visitors/ast/keywords.py b/wemake_python_styleguide/visitors/ast/keywords.py
--- a/wemake_python_styleguide/visitors/ast/keywords.py
+++ b/wemake_python_styleguide/visitors/ast/keywords.py
@@ -121,7 +121,8 @@
         returns: List[ast.Return] = []
         has_values = False
         for sub_node in ast.walk(node):
-            if isinstance(sub_node, returning_type):
+            context_node = get_context(sub_node)
+            if isinstance(sub_node, returning_type) and context_node == node:
                 if sub_node.value:
                     has_values = True
                 returns.append(sub_node)

{"golden_diff": "diff --git a/wemake_python_styleguide/visitors/ast/keywords.py b/wemake_python_styleguide/visitors/ast/keywords.py\n--- a/wemake_python_styleguide/visitors/ast/keywords.py\n+++ b/wemake_python_styleguide/visitors/ast/keywords.py\n@@ -121,7 +121,8 @@\n         returns: List[ast.Return] = []\n         has_values = False\n         for sub_node in ast.walk(node):\n-            if isinstance(sub_node, returning_type):\n+            context_node = get_context(sub_node)\n+            if isinstance(sub_node, returning_type) and context_node == node:\n                 if sub_node.value:\n                     has_values = True\n                 returns.append(sub_node)\n", "issue": "WPS324 false-positive with nested functions\n# Bug report\r\n\r\n<!--\r\nHi, thanks for submitting a bug. We appreciate that.\r\n\r\nBut, we will need some information about what's wrong to help you.\r\n-->\r\n\r\n## What's wrong\r\n\r\nThis code produces false positive `WPS324`:\r\n\r\n```python\r\ndef test():\r\n    def decorator():\r\n        return\r\n    return decorator\r\n```\r\n\r\n<!-- Describe what is not working. Please, attach a traceback. -->\r\n\r\n## How is that should be\r\n\r\nThese two returns are completely different cases. We should check `.wps_context` of the node.\r\nSee: \r\n- https://github.com/wemake-services/wemake-python-styleguide/blob/master/wemake_python_styleguide/visitors/ast/keywords.py#L133\r\n- https://github.com/wemake-services/wemake-python-styleguide/blob/b43e738c4527219f03c2eec420fe2e20cfd4c8cc/wemake_python_styleguide/logic/nodes.py#L29\r\n\r\n<!--\r\n\r\n  Love wemake-python-styleguide? \u2764\ufe0f\r\n  Do you want your bugs to be solved faster?\r\n\r\n  Please consider supporting our collective:\r\n\ud83d\udc49  https://opencollective.com/wemake-python-styleguide/donate\r\n\r\n-->\r\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\nimport ast\nfrom collections import defaultdict\nfrom contextlib import suppress\nfrom typing import ClassVar, Dict, List, Tuple, Type, Union\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.compat.aliases import FunctionNodes\nfrom wemake_python_styleguide.logic import walk\nfrom wemake_python_styleguide.logic.exceptions import get_exception_name\nfrom wemake_python_styleguide.logic.nodes import get_context, get_parent\nfrom wemake_python_styleguide.logic.variables import (\n    is_valid_block_variable_definition,\n)\nfrom wemake_python_styleguide.types import AnyFunctionDef, AnyNodes, AnyWith\nfrom wemake_python_styleguide.violations.best_practices import (\n    ContextManagerVariableDefinitionViolation,\n    RaiseNotImplementedViolation,\n    WrongKeywordConditionViolation,\n    WrongKeywordViolation,\n)\nfrom wemake_python_styleguide.violations.consistency import (\n    InconsistentReturnVariableViolation,\n    InconsistentReturnViolation,\n    InconsistentYieldViolation,\n    MultipleContextManagerAssignmentsViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\nfrom wemake_python_styleguide.visitors.decorators import alias\n\nNamesAndReturns = Tuple[\n    Dict[str, List[ast.Name]],\n    Dict[str, ast.Return],\n]\nReturningViolations = Union[\n    Type[InconsistentReturnViolation],\n    Type[InconsistentYieldViolation],\n]\n\n\n@final\nclass WrongRaiseVisitor(BaseNodeVisitor):\n    \"\"\"Finds wrong ``raise`` keywords.\"\"\"\n\n    def visit_Raise(self, node: ast.Raise) -> None:\n        \"\"\"\n        Checks how ``raise`` keyword is used.\n\n        Raises:\n            RaiseNotImplementedViolation\n\n        \"\"\"\n        self._check_exception_type(node)\n        self.generic_visit(node)\n\n    def _check_exception_type(self, node: ast.Raise) -> None:\n        exception_name = get_exception_name(node)\n        if exception_name == 'NotImplemented':\n            self.add_violation(RaiseNotImplementedViolation(node))\n\n\n@final\n@alias('visit_any_function', (\n    'visit_FunctionDef',\n    'visit_AsyncFunctionDef',\n))\nclass ConsistentReturningVisitor(BaseNodeVisitor):\n    \"\"\"Finds incorrect and inconsistent ``return`` and ``yield`` nodes.\"\"\"\n\n    def visit_Return(self, node: ast.Return) -> None:\n        \"\"\"\n        Checks ``return`` statements for consistency.\n\n        Raises:\n            InconsistentReturnViolation\n\n        \"\"\"\n        self._check_last_return_in_function(node)\n        self.generic_visit(node)\n\n    def visit_any_function(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Helper to get all ``return`` and ``yield`` nodes in a function at once.\n\n        Raises:\n            InconsistentReturnViolation\n            InconsistentYieldViolation\n\n        \"\"\"\n        self._check_return_values(node)\n        self._check_yield_values(node)\n        self.generic_visit(node)\n\n    def _check_last_return_in_function(self, node: ast.Return) -> None:\n        parent = get_parent(node)\n        if not isinstance(parent, FunctionNodes):\n            return\n\n        returns = len(list(filter(\n            lambda return_node: return_node.value is not None,\n            walk.get_subnodes_by_type(parent, ast.Return),\n        )))\n\n        last_value_return = (\n            len(parent.body) > 1 and\n            returns < 2 and\n            isinstance(node.value, ast.NameConstant) and\n            node.value.value is None\n        )\n        if node.value is None or last_value_return:\n            self.add_violation(InconsistentReturnViolation(node))\n\n    def _iterate_returning_values(\n        self,\n        node: AnyFunctionDef,\n        returning_type,  # mypy is not ok with this type declaration\n        violation: ReturningViolations,\n    ):\n        returns: List[ast.Return] = []\n        has_values = False\n        for sub_node in ast.walk(node):\n            if isinstance(sub_node, returning_type):\n                if sub_node.value:\n                    has_values = True\n                returns.append(sub_node)\n\n        for return_node in returns:\n            if not return_node.value and has_values:\n                self.add_violation(violation(return_node))\n\n    def _check_return_values(self, node: AnyFunctionDef) -> None:\n        self._iterate_returning_values(\n            node, ast.Return, InconsistentReturnViolation,\n        )\n\n    def _check_yield_values(self, node: AnyFunctionDef) -> None:\n        self._iterate_returning_values(\n            node, ast.Yield, InconsistentYieldViolation,\n        )\n\n\n@final\nclass WrongKeywordVisitor(BaseNodeVisitor):\n    \"\"\"Finds wrong keywords.\"\"\"\n\n    _forbidden_keywords: ClassVar[AnyNodes] = (\n        ast.Pass,\n        ast.Delete,\n        ast.Global,\n        ast.Nonlocal,\n    )\n\n    def visit(self, node: ast.AST) -> None:\n        \"\"\"\n        Used to find wrong keywords.\n\n        Raises:\n            WrongKeywordViolation\n\n        \"\"\"\n        self._check_keyword(node)\n        self.generic_visit(node)\n\n    def _check_keyword(self, node: ast.AST) -> None:\n        if isinstance(node, self._forbidden_keywords):\n            if isinstance(node, ast.Delete):\n                message = 'del'\n            else:\n                message = node.__class__.__qualname__.lower()\n            self.add_violation(WrongKeywordViolation(node, text=message))\n\n\n@final\n@alias('visit_any_with', (\n    'visit_With',\n    'visit_AsyncWith',\n))\nclass WrongContextManagerVisitor(BaseNodeVisitor):\n    \"\"\"Checks context managers.\"\"\"\n\n    def visit_withitem(self, node: ast.withitem) -> None:\n        \"\"\"\n        Checks that all variables inside context managers defined correctly.\n\n        Raises:\n            ContextManagerVariableDefinitionViolation\n\n        \"\"\"\n        self._check_variable_definitions(node)\n        self.generic_visit(node)\n\n    def visit_any_with(self, node: AnyWith) -> None:\n        \"\"\"\n        Checks the number of assignments for context managers.\n\n        Raises:\n            MultipleContextManagerAssignmentsViolation\n\n        \"\"\"\n        self._check_target_assignment(node)\n        self.generic_visit(node)\n\n    def _check_target_assignment(self, node: AnyWith):\n        if len(node.items) > 1:\n            self.add_violation(\n                MultipleContextManagerAssignmentsViolation(node),\n            )\n\n    def _check_variable_definitions(self, node: ast.withitem) -> None:\n        if node.optional_vars is None:\n            return\n\n        if not is_valid_block_variable_definition(node.optional_vars):\n            self.add_violation(\n                ContextManagerVariableDefinitionViolation(get_parent(node)),\n            )\n\n\n@final\n@alias('visit_return_variable', (\n    'visit_AsyncFunctionDef',\n    'visit_FunctionDef',\n))\nclass ConsistentReturningVariableVisitor(BaseNodeVisitor):\n    \"\"\"Finds variables that are only used in `return` statements.\"\"\"\n\n    _checking_nodes: ClassVar[AnyNodes] = (\n        ast.Assign,\n        ast.AnnAssign,\n        ast.AugAssign,\n        ast.Return,\n        ast.Name,\n    )\n\n    def visit_return_variable(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Helper to get all ``return`` variables in a function at once.\n\n        Raises:\n            InconsistentReturnVariableViolation\n\n        \"\"\"\n        self._check_variables_for_return(node)\n        self.generic_visit(node)\n\n    def _get_assign_node_variables(self, node: List[ast.AST]) -> List[str]:\n        assign = []\n        for sub_node in node:\n            if isinstance(sub_node, ast.Assign):\n                if isinstance(sub_node.targets[0], ast.Name):\n                    assign.append(sub_node.targets[0].id)\n            if isinstance(sub_node, ast.AnnAssign):\n                if isinstance(sub_node.target, ast.Name):\n                    assign.append(sub_node.target.id)\n        return assign\n\n    def _get_name_nodes_variable(\n        self,\n        node: List[ast.AST],\n    ) -> Dict[str, List[ast.Name]]:\n        names: Dict[str, List[ast.Name]] = defaultdict(list)\n        for sub_node in node:\n            if isinstance(sub_node, ast.Name):\n                if isinstance(sub_node.ctx, ast.Load):\n                    names[sub_node.id].append(sub_node)\n            if isinstance(sub_node, ast.AugAssign):\n                if isinstance(sub_node.target, ast.Name):\n                    variable_name = sub_node.target.id\n                    names[variable_name].append(sub_node.target)\n        return names\n\n    def _get_return_node_variables(\n        self,\n        node: List[ast.AST],\n    ) -> NamesAndReturns:\n        returns: Dict[str, List[ast.Name]] = defaultdict(list)\n        return_sub_nodes: Dict[str, ast.Return] = defaultdict()\n        for sub_node in node:\n            if isinstance(sub_node, ast.Return):\n                if isinstance(sub_node.value, ast.Name):\n                    variable_name = sub_node.value.id\n                    returns[variable_name].append(sub_node.value)\n                    return_sub_nodes[variable_name] = sub_node\n        return returns, return_sub_nodes\n\n    def _is_correct_return_node(\n        self,\n        node: AnyFunctionDef,\n        sub_node: ast.AST,\n    ) -> bool:\n        if get_context(sub_node) != node:\n            return False\n        return isinstance(sub_node, self._checking_nodes)\n\n    def _check_variables_for_return(self, node: AnyFunctionDef) -> None:\n        nodes = list(\n            filter(\n                lambda sub: self._is_correct_return_node(node, sub),\n                ast.walk(node),\n            ),\n        )\n        assign = self._get_assign_node_variables(nodes)\n        names = self._get_name_nodes_variable(nodes)\n        returns, return_sub_nodes = self._get_return_node_variables(nodes)\n\n        returns = {name: returns[name] for name in returns if name in assign}\n\n        self._check_for_violations(names, return_sub_nodes, returns)\n\n    def _check_for_violations(self, names, return_sub_nodes, returns) -> None:\n        for variable_name in returns:\n            if not set(names[variable_name]) - set(returns[variable_name]):\n                self.add_violation(\n                    InconsistentReturnVariableViolation(\n                        return_sub_nodes[variable_name],\n                    ),\n                )\n\n\n@final\nclass ConstantKeywordVisitor(BaseNodeVisitor):\n    \"\"\"Visits keyword definitions to detect contant conditions.\"\"\"\n\n    def visit_While(self, node: ast.While) -> None:\n        \"\"\"\n        Visits ``while`` keyword and tests that loop will execute.\n\n        Raises:\n            WrongKeywordConditionViolation\n\n        \"\"\"\n        self._check_condition(node.test)\n        self.generic_visit(node)\n\n    def visit_Assert(self, node: ast.Assert) -> None:\n        \"\"\"\n        Visits ``assert`` keyword and tests that condition is correct.\n\n        Raises:\n            WrongKeywordConditionViolation\n\n        \"\"\"\n        self._check_condition(node.test)\n        self.generic_visit(node)\n\n    def _check_condition(self, condition: ast.AST) -> None:\n        with suppress(ValueError):\n            constant = ast.literal_eval(condition)\n            if not bool(constant):\n                self.add_violation(\n                    WrongKeywordConditionViolation(\n                        condition,\n                        text=str(constant) if constant != '' else '\"\"',\n                    ),\n                )\n", "path": "wemake_python_styleguide/visitors/ast/keywords.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\nimport ast\nfrom collections import defaultdict\nfrom contextlib import suppress\nfrom typing import ClassVar, Dict, List, Tuple, Type, Union\n\nfrom typing_extensions import final\n\nfrom wemake_python_styleguide.compat.aliases import FunctionNodes\nfrom wemake_python_styleguide.logic import walk\nfrom wemake_python_styleguide.logic.exceptions import get_exception_name\nfrom wemake_python_styleguide.logic.nodes import get_context, get_parent\nfrom wemake_python_styleguide.logic.variables import (\n    is_valid_block_variable_definition,\n)\nfrom wemake_python_styleguide.types import AnyFunctionDef, AnyNodes, AnyWith\nfrom wemake_python_styleguide.violations.best_practices import (\n    ContextManagerVariableDefinitionViolation,\n    RaiseNotImplementedViolation,\n    WrongKeywordConditionViolation,\n    WrongKeywordViolation,\n)\nfrom wemake_python_styleguide.violations.consistency import (\n    InconsistentReturnVariableViolation,\n    InconsistentReturnViolation,\n    InconsistentYieldViolation,\n    MultipleContextManagerAssignmentsViolation,\n)\nfrom wemake_python_styleguide.visitors.base import BaseNodeVisitor\nfrom wemake_python_styleguide.visitors.decorators import alias\n\nNamesAndReturns = Tuple[\n    Dict[str, List[ast.Name]],\n    Dict[str, ast.Return],\n]\nReturningViolations = Union[\n    Type[InconsistentReturnViolation],\n    Type[InconsistentYieldViolation],\n]\n\n\n@final\nclass WrongRaiseVisitor(BaseNodeVisitor):\n    \"\"\"Finds wrong ``raise`` keywords.\"\"\"\n\n    def visit_Raise(self, node: ast.Raise) -> None:\n        \"\"\"\n        Checks how ``raise`` keyword is used.\n\n        Raises:\n            RaiseNotImplementedViolation\n\n        \"\"\"\n        self._check_exception_type(node)\n        self.generic_visit(node)\n\n    def _check_exception_type(self, node: ast.Raise) -> None:\n        exception_name = get_exception_name(node)\n        if exception_name == 'NotImplemented':\n            self.add_violation(RaiseNotImplementedViolation(node))\n\n\n@final\n@alias('visit_any_function', (\n    'visit_FunctionDef',\n    'visit_AsyncFunctionDef',\n))\nclass ConsistentReturningVisitor(BaseNodeVisitor):\n    \"\"\"Finds incorrect and inconsistent ``return`` and ``yield`` nodes.\"\"\"\n\n    def visit_Return(self, node: ast.Return) -> None:\n        \"\"\"\n        Checks ``return`` statements for consistency.\n\n        Raises:\n            InconsistentReturnViolation\n\n        \"\"\"\n        self._check_last_return_in_function(node)\n        self.generic_visit(node)\n\n    def visit_any_function(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Helper to get all ``return`` and ``yield`` nodes in a function at once.\n\n        Raises:\n            InconsistentReturnViolation\n            InconsistentYieldViolation\n\n        \"\"\"\n        self._check_return_values(node)\n        self._check_yield_values(node)\n        self.generic_visit(node)\n\n    def _check_last_return_in_function(self, node: ast.Return) -> None:\n        parent = get_parent(node)\n        if not isinstance(parent, FunctionNodes):\n            return\n\n        returns = len(list(filter(\n            lambda return_node: return_node.value is not None,\n            walk.get_subnodes_by_type(parent, ast.Return),\n        )))\n\n        last_value_return = (\n            len(parent.body) > 1 and\n            returns < 2 and\n            isinstance(node.value, ast.NameConstant) and\n            node.value.value is None\n        )\n        if node.value is None or last_value_return:\n            self.add_violation(InconsistentReturnViolation(node))\n\n    def _iterate_returning_values(\n        self,\n        node: AnyFunctionDef,\n        returning_type,  # mypy is not ok with this type declaration\n        violation: ReturningViolations,\n    ):\n        returns: List[ast.Return] = []\n        has_values = False\n        for sub_node in ast.walk(node):\n            context_node = get_context(sub_node)\n            if isinstance(sub_node, returning_type) and context_node == node:\n                if sub_node.value:\n                    has_values = True\n                returns.append(sub_node)\n\n        for return_node in returns:\n            if not return_node.value and has_values:\n                self.add_violation(violation(return_node))\n\n    def _check_return_values(self, node: AnyFunctionDef) -> None:\n        self._iterate_returning_values(\n            node, ast.Return, InconsistentReturnViolation,\n        )\n\n    def _check_yield_values(self, node: AnyFunctionDef) -> None:\n        self._iterate_returning_values(\n            node, ast.Yield, InconsistentYieldViolation,\n        )\n\n\n@final\nclass WrongKeywordVisitor(BaseNodeVisitor):\n    \"\"\"Finds wrong keywords.\"\"\"\n\n    _forbidden_keywords: ClassVar[AnyNodes] = (\n        ast.Pass,\n        ast.Delete,\n        ast.Global,\n        ast.Nonlocal,\n    )\n\n    def visit(self, node: ast.AST) -> None:\n        \"\"\"\n        Used to find wrong keywords.\n\n        Raises:\n            WrongKeywordViolation\n\n        \"\"\"\n        self._check_keyword(node)\n        self.generic_visit(node)\n\n    def _check_keyword(self, node: ast.AST) -> None:\n        if isinstance(node, self._forbidden_keywords):\n            if isinstance(node, ast.Delete):\n                message = 'del'\n            else:\n                message = node.__class__.__qualname__.lower()\n            self.add_violation(WrongKeywordViolation(node, text=message))\n\n\n@final\n@alias('visit_any_with', (\n    'visit_With',\n    'visit_AsyncWith',\n))\nclass WrongContextManagerVisitor(BaseNodeVisitor):\n    \"\"\"Checks context managers.\"\"\"\n\n    def visit_withitem(self, node: ast.withitem) -> None:\n        \"\"\"\n        Checks that all variables inside context managers defined correctly.\n\n        Raises:\n            ContextManagerVariableDefinitionViolation\n\n        \"\"\"\n        self._check_variable_definitions(node)\n        self.generic_visit(node)\n\n    def visit_any_with(self, node: AnyWith) -> None:\n        \"\"\"\n        Checks the number of assignments for context managers.\n\n        Raises:\n            MultipleContextManagerAssignmentsViolation\n\n        \"\"\"\n        self._check_target_assignment(node)\n        self.generic_visit(node)\n\n    def _check_target_assignment(self, node: AnyWith):\n        if len(node.items) > 1:\n            self.add_violation(\n                MultipleContextManagerAssignmentsViolation(node),\n            )\n\n    def _check_variable_definitions(self, node: ast.withitem) -> None:\n        if node.optional_vars is None:\n            return\n\n        if not is_valid_block_variable_definition(node.optional_vars):\n            self.add_violation(\n                ContextManagerVariableDefinitionViolation(get_parent(node)),\n            )\n\n\n@final\n@alias('visit_return_variable', (\n    'visit_AsyncFunctionDef',\n    'visit_FunctionDef',\n))\nclass ConsistentReturningVariableVisitor(BaseNodeVisitor):\n    \"\"\"Finds variables that are only used in `return` statements.\"\"\"\n\n    _checking_nodes: ClassVar[AnyNodes] = (\n        ast.Assign,\n        ast.AnnAssign,\n        ast.AugAssign,\n        ast.Return,\n        ast.Name,\n    )\n\n    def visit_return_variable(self, node: AnyFunctionDef) -> None:\n        \"\"\"\n        Helper to get all ``return`` variables in a function at once.\n\n        Raises:\n            InconsistentReturnVariableViolation\n\n        \"\"\"\n        self._check_variables_for_return(node)\n        self.generic_visit(node)\n\n    def _get_assign_node_variables(self, node: List[ast.AST]) -> List[str]:\n        assign = []\n        for sub_node in node:\n            if isinstance(sub_node, ast.Assign):\n                if isinstance(sub_node.targets[0], ast.Name):\n                    assign.append(sub_node.targets[0].id)\n            if isinstance(sub_node, ast.AnnAssign):\n                if isinstance(sub_node.target, ast.Name):\n                    assign.append(sub_node.target.id)\n        return assign\n\n    def _get_name_nodes_variable(\n        self,\n        node: List[ast.AST],\n    ) -> Dict[str, List[ast.Name]]:\n        names: Dict[str, List[ast.Name]] = defaultdict(list)\n        for sub_node in node:\n            if isinstance(sub_node, ast.Name):\n                if isinstance(sub_node.ctx, ast.Load):\n                    names[sub_node.id].append(sub_node)\n            if isinstance(sub_node, ast.AugAssign):\n                if isinstance(sub_node.target, ast.Name):\n                    variable_name = sub_node.target.id\n                    names[variable_name].append(sub_node.target)\n        return names\n\n    def _get_return_node_variables(\n        self,\n        node: List[ast.AST],\n    ) -> NamesAndReturns:\n        returns: Dict[str, List[ast.Name]] = defaultdict(list)\n        return_sub_nodes: Dict[str, ast.Return] = defaultdict()\n        for sub_node in node:\n            if isinstance(sub_node, ast.Return):\n                if isinstance(sub_node.value, ast.Name):\n                    variable_name = sub_node.value.id\n                    returns[variable_name].append(sub_node.value)\n                    return_sub_nodes[variable_name] = sub_node\n        return returns, return_sub_nodes\n\n    def _is_correct_return_node(\n        self,\n        node: AnyFunctionDef,\n        sub_node: ast.AST,\n    ) -> bool:\n        if get_context(sub_node) != node:\n            return False\n        return isinstance(sub_node, self._checking_nodes)\n\n    def _check_variables_for_return(self, node: AnyFunctionDef) -> None:\n        nodes = list(\n            filter(\n                lambda sub: self._is_correct_return_node(node, sub),\n                ast.walk(node),\n            ),\n        )\n        assign = self._get_assign_node_variables(nodes)\n        names = self._get_name_nodes_variable(nodes)\n        returns, return_sub_nodes = self._get_return_node_variables(nodes)\n\n        returns = {name: returns[name] for name in returns if name in assign}\n\n        self._check_for_violations(names, return_sub_nodes, returns)\n\n    def _check_for_violations(self, names, return_sub_nodes, returns) -> None:\n        for variable_name in returns:\n            if not set(names[variable_name]) - set(returns[variable_name]):\n                self.add_violation(\n                    InconsistentReturnVariableViolation(\n                        return_sub_nodes[variable_name],\n                    ),\n                )\n\n\n@final\nclass ConstantKeywordVisitor(BaseNodeVisitor):\n    \"\"\"Visits keyword definitions to detect contant conditions.\"\"\"\n\n    def visit_While(self, node: ast.While) -> None:\n        \"\"\"\n        Visits ``while`` keyword and tests that loop will execute.\n\n        Raises:\n            WrongKeywordConditionViolation\n\n        \"\"\"\n        self._check_condition(node.test)\n        self.generic_visit(node)\n\n    def visit_Assert(self, node: ast.Assert) -> None:\n        \"\"\"\n        Visits ``assert`` keyword and tests that condition is correct.\n\n        Raises:\n            WrongKeywordConditionViolation\n\n        \"\"\"\n        self._check_condition(node.test)\n        self.generic_visit(node)\n\n    def _check_condition(self, condition: ast.AST) -> None:\n        with suppress(ValueError):\n            constant = ast.literal_eval(condition)\n            if not bool(constant):\n                self.add_violation(\n                    WrongKeywordConditionViolation(\n                        condition,\n                        text=str(constant) if constant != '' else '\"\"',\n                    ),\n                )\n", "path": "wemake_python_styleguide/visitors/ast/keywords.py"}]}