1# Copyright (c) 2009-2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
2# Copyright (c) 2013-2020 Claudiu Popa <pcmanticore@gmail.com>
3# Copyright (c) 2013-2014 Google, Inc.
4# Copyright (c) 2014 Alexander Presnyakov <flagist0@gmail.com>
5# Copyright (c) 2014 Eevee (Alex Munroe) <amunroe@yelp.com>
6# Copyright (c) 2015-2016 Ceridwen <ceridwenv@gmail.com>
7# Copyright (c) 2016-2017 Derek Gustafson <degustaf@gmail.com>
8# Copyright (c) 2016 Jared Garst <jgarst@users.noreply.github.com>
9# Copyright (c) 2017 Hugo <hugovk@users.noreply.github.com>
10# Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
11# Copyright (c) 2017 rr- <rr-@sakuya.pl>
12# Copyright (c) 2018-2019 Ville Skyttä <ville.skytta@iki.fi>
13# Copyright (c) 2018 Tomas Gavenciak <gavento@ucw.cz>
14# Copyright (c) 2018 Serhiy Storchaka <storchaka@gmail.com>
15# Copyright (c) 2018 Nick Drozd <nicholasdrozd@gmail.com>
16# Copyright (c) 2018 Bryce Guinta <bryce.paul.guinta@gmail.com>
17# Copyright (c) 2019-2021 Ashley Whetter <ashley@awhetter.co.uk>
18# Copyright (c) 2019 Hugo van Kemenade <hugovk@users.noreply.github.com>
19# Copyright (c) 2019 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
20# Copyright (c) 2021 Marc Mueller <30130371+cdce8p@users.noreply.github.com>
21# Copyright (c) 2021 Daniël van Noord <13665637+DanielNoord@users.noreply.github.com>
22# Copyright (c) 2021 Pierre Sassoulas <pierre.sassoulas@gmail.com>
23# Copyright (c) 2021 Federico Bond <federicobond@gmail.com>
24# Copyright (c) 2021 hippo91 <guillaume.peillex@gmail.com>
25
26# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
27# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
28
29"""this module contains utilities for rebuilding an _ast tree in
30order to get a single Astroid representation
31"""
32
33import sys
34from typing import (
35    TYPE_CHECKING,
36    Callable,
37    Dict,
38    Generator,
39    List,
40    Optional,
41    Tuple,
42    Type,
43    TypeVar,
44    Union,
45    cast,
46    overload,
47)
48
49from astroid import nodes
50from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment
51from astroid.const import PY37_PLUS, PY38, PY38_PLUS, Context
52from astroid.manager import AstroidManager
53from astroid.nodes import NodeNG
54
55if sys.version_info >= (3, 8):
56    from typing import Final
57else:
58    from typing_extensions import Final
59
60if TYPE_CHECKING:
61    import ast
62
63
64REDIRECT: Final[Dict[str, str]] = {
65    "arguments": "Arguments",
66    "comprehension": "Comprehension",
67    "ListCompFor": "Comprehension",
68    "GenExprFor": "Comprehension",
69    "excepthandler": "ExceptHandler",
70    "keyword": "Keyword",
71    "match_case": "MatchCase",
72}
73
74
75T_Doc = TypeVar(
76    "T_Doc",
77    "ast.Module",
78    "ast.ClassDef",
79    Union["ast.FunctionDef", "ast.AsyncFunctionDef"],
80)
81T_Function = TypeVar("T_Function", nodes.FunctionDef, nodes.AsyncFunctionDef)
82T_For = TypeVar("T_For", nodes.For, nodes.AsyncFor)
83T_With = TypeVar("T_With", nodes.With, nodes.AsyncWith)
84
85
86# noinspection PyMethodMayBeStatic
87class TreeRebuilder:
88    """Rebuilds the _ast tree to become an Astroid tree"""
89
90    def __init__(
91        self, manager: AstroidManager, parser_module: Optional[ParserModule] = None
92    ):
93        self._manager = manager
94        self._global_names: List[Dict[str, List[nodes.Global]]] = []
95        self._import_from_nodes: List[nodes.ImportFrom] = []
96        self._delayed_assattr: List[nodes.AssignAttr] = []
97        self._visit_meths: Dict[
98            Type["ast.AST"], Callable[["ast.AST", NodeNG], NodeNG]
99        ] = {}
100
101        if parser_module is None:
102            self._parser_module = get_parser_module()
103        else:
104            self._parser_module = parser_module
105        self._module = self._parser_module.module
106
107    def _get_doc(self, node: T_Doc) -> Tuple[T_Doc, Optional[str]]:
108        try:
109            if PY37_PLUS and hasattr(node, "docstring"):
110                doc = node.docstring
111                return node, doc
112            if node.body and isinstance(node.body[0], self._module.Expr):
113
114                first_value = node.body[0].value
115                if isinstance(first_value, self._module.Str) or (
116                    PY38_PLUS
117                    and isinstance(first_value, self._module.Constant)
118                    and isinstance(first_value.value, str)
119                ):
120                    doc = first_value.value if PY38_PLUS else first_value.s
121                    node.body = node.body[1:]
122                    return node, doc
123        except IndexError:
124            pass  # ast built from scratch
125        return node, None
126
127    def _get_context(
128        self,
129        node: Union[
130            "ast.Attribute",
131            "ast.List",
132            "ast.Name",
133            "ast.Subscript",
134            "ast.Starred",
135            "ast.Tuple",
136        ],
137    ) -> Context:
138        return self._parser_module.context_classes.get(type(node.ctx), Context.Load)
139
140    def visit_module(
141        self, node: "ast.Module", modname: str, modpath: str, package: bool
142    ) -> nodes.Module:
143        """visit a Module node by returning a fresh instance of it
144
145        Note: Method not called by 'visit'
146        """
147        node, doc = self._get_doc(node)
148        newnode = nodes.Module(
149            name=modname,
150            doc=doc,
151            file=modpath,
152            path=[modpath],
153            package=package,
154            parent=None,
155        )
156        newnode.postinit([self.visit(child, newnode) for child in node.body])
157        return newnode
158
159    if sys.version_info >= (3, 10):
160
161        @overload
162        def visit(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName:
163            ...
164
165        @overload
166        def visit(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments:
167            ...
168
169        @overload
170        def visit(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert:
171            ...
172
173        @overload
174        def visit(
175            self, node: "ast.AsyncFunctionDef", parent: NodeNG
176        ) -> nodes.AsyncFunctionDef:
177            ...
178
179        @overload
180        def visit(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor:
181            ...
182
183        @overload
184        def visit(self, node: "ast.Await", parent: NodeNG) -> nodes.Await:
185            ...
186
187        @overload
188        def visit(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith:
189            ...
190
191        @overload
192        def visit(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign:
193            ...
194
195        @overload
196        def visit(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign:
197            ...
198
199        @overload
200        def visit(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign:
201            ...
202
203        @overload
204        def visit(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp:
205            ...
206
207        @overload
208        def visit(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp:
209            ...
210
211        @overload
212        def visit(self, node: "ast.Break", parent: NodeNG) -> nodes.Break:
213            ...
214
215        @overload
216        def visit(self, node: "ast.Call", parent: NodeNG) -> nodes.Call:
217            ...
218
219        @overload
220        def visit(self, node: "ast.ClassDef", parent: NodeNG) -> nodes.ClassDef:
221            ...
222
223        @overload
224        def visit(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue:
225            ...
226
227        @overload
228        def visit(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare:
229            ...
230
231        @overload
232        def visit(
233            self, node: "ast.comprehension", parent: NodeNG
234        ) -> nodes.Comprehension:
235            ...
236
237        @overload
238        def visit(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete:
239            ...
240
241        @overload
242        def visit(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict:
243            ...
244
245        @overload
246        def visit(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp:
247            ...
248
249        @overload
250        def visit(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr:
251            ...
252
253        # Not used in Python 3.8+
254        @overload
255        def visit(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const:
256            ...
257
258        @overload
259        def visit(
260            self, node: "ast.ExceptHandler", parent: NodeNG
261        ) -> nodes.ExceptHandler:
262            ...
263
264        # Not used in Python 3.9+
265        @overload
266        def visit(self, node: "ast.ExtSlice", parent: nodes.Subscript) -> nodes.Tuple:
267            ...
268
269        @overload
270        def visit(self, node: "ast.For", parent: NodeNG) -> nodes.For:
271            ...
272
273        @overload
274        def visit(self, node: "ast.ImportFrom", parent: NodeNG) -> nodes.ImportFrom:
275            ...
276
277        @overload
278        def visit(self, node: "ast.FunctionDef", parent: NodeNG) -> nodes.FunctionDef:
279            ...
280
281        @overload
282        def visit(self, node: "ast.GeneratorExp", parent: NodeNG) -> nodes.GeneratorExp:
283            ...
284
285        @overload
286        def visit(self, node: "ast.Attribute", parent: NodeNG) -> nodes.Attribute:
287            ...
288
289        @overload
290        def visit(self, node: "ast.Global", parent: NodeNG) -> nodes.Global:
291            ...
292
293        @overload
294        def visit(self, node: "ast.If", parent: NodeNG) -> nodes.If:
295            ...
296
297        @overload
298        def visit(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp:
299            ...
300
301        @overload
302        def visit(self, node: "ast.Import", parent: NodeNG) -> nodes.Import:
303            ...
304
305        @overload
306        def visit(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr:
307            ...
308
309        @overload
310        def visit(
311            self, node: "ast.FormattedValue", parent: NodeNG
312        ) -> nodes.FormattedValue:
313            ...
314
315        @overload
316        def visit(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr:
317            ...
318
319        # Not used in Python 3.9+
320        @overload
321        def visit(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG:
322            ...
323
324        @overload
325        def visit(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword:
326            ...
327
328        @overload
329        def visit(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda:
330            ...
331
332        @overload
333        def visit(self, node: "ast.List", parent: NodeNG) -> nodes.List:
334            ...
335
336        @overload
337        def visit(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp:
338            ...
339
340        @overload
341        def visit(
342            self, node: "ast.Name", parent: NodeNG
343        ) -> Union[nodes.Name, nodes.Const, nodes.AssignName, nodes.DelName]:
344            ...
345
346        # Not used in Python 3.8+
347        @overload
348        def visit(self, node: "ast.NameConstant", parent: NodeNG) -> nodes.Const:
349            ...
350
351        @overload
352        def visit(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal:
353            ...
354
355        # Not used in Python 3.8+
356        @overload
357        def visit(self, node: "ast.Str", parent: NodeNG) -> nodes.Const:
358            ...
359
360        # Not used in Python 3.8+
361        @overload
362        def visit(self, node: "ast.Bytes", parent: NodeNG) -> nodes.Const:
363            ...
364
365        # Not used in Python 3.8+
366        @overload
367        def visit(self, node: "ast.Num", parent: NodeNG) -> nodes.Const:
368            ...
369
370        @overload
371        def visit(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const:
372            ...
373
374        @overload
375        def visit(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass:
376            ...
377
378        @overload
379        def visit(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise:
380            ...
381
382        @overload
383        def visit(self, node: "ast.Return", parent: NodeNG) -> nodes.Return:
384            ...
385
386        @overload
387        def visit(self, node: "ast.Set", parent: NodeNG) -> nodes.Set:
388            ...
389
390        @overload
391        def visit(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp:
392            ...
393
394        @overload
395        def visit(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice:
396            ...
397
398        @overload
399        def visit(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript:
400            ...
401
402        @overload
403        def visit(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred:
404            ...
405
406        @overload
407        def visit(
408            self, node: "ast.Try", parent: NodeNG
409        ) -> Union[nodes.TryExcept, nodes.TryFinally]:
410            ...
411
412        @overload
413        def visit(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple:
414            ...
415
416        @overload
417        def visit(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp:
418            ...
419
420        @overload
421        def visit(self, node: "ast.While", parent: NodeNG) -> nodes.While:
422            ...
423
424        @overload
425        def visit(self, node: "ast.With", parent: NodeNG) -> nodes.With:
426            ...
427
428        @overload
429        def visit(self, node: "ast.Yield", parent: NodeNG) -> nodes.Yield:
430            ...
431
432        @overload
433        def visit(self, node: "ast.YieldFrom", parent: NodeNG) -> nodes.YieldFrom:
434            ...
435
436        @overload
437        def visit(self, node: "ast.Match", parent: NodeNG) -> nodes.Match:
438            ...
439
440        @overload
441        def visit(self, node: "ast.match_case", parent: NodeNG) -> nodes.MatchCase:
442            ...
443
444        @overload
445        def visit(self, node: "ast.MatchValue", parent: NodeNG) -> nodes.MatchValue:
446            ...
447
448        @overload
449        def visit(
450            self, node: "ast.MatchSingleton", parent: NodeNG
451        ) -> nodes.MatchSingleton:
452            ...
453
454        @overload
455        def visit(
456            self, node: "ast.MatchSequence", parent: NodeNG
457        ) -> nodes.MatchSequence:
458            ...
459
460        @overload
461        def visit(self, node: "ast.MatchMapping", parent: NodeNG) -> nodes.MatchMapping:
462            ...
463
464        @overload
465        def visit(self, node: "ast.MatchClass", parent: NodeNG) -> nodes.MatchClass:
466            ...
467
468        @overload
469        def visit(self, node: "ast.MatchStar", parent: NodeNG) -> nodes.MatchStar:
470            ...
471
472        @overload
473        def visit(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs:
474            ...
475
476        @overload
477        def visit(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr:
478            ...
479
480        @overload
481        def visit(self, node: "ast.pattern", parent: NodeNG) -> nodes.Pattern:
482            ...
483
484        @overload
485        def visit(self, node: "ast.AST", parent: NodeNG) -> NodeNG:
486            ...
487
488        @overload
489        def visit(self, node: None, parent: NodeNG) -> None:
490            ...
491
492        def visit(self, node: Optional["ast.AST"], parent: NodeNG) -> Optional[NodeNG]:
493            if node is None:
494                return None
495            cls = node.__class__
496            if cls in self._visit_meths:
497                visit_method = self._visit_meths[cls]
498            else:
499                cls_name = cls.__name__
500                visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower()
501                visit_method = getattr(self, visit_name)
502                self._visit_meths[cls] = visit_method
503            return visit_method(node, parent)
504
505    else:
506
507        @overload
508        def visit(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName:
509            ...
510
511        @overload
512        def visit(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments:
513            ...
514
515        @overload
516        def visit(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert:
517            ...
518
519        @overload
520        def visit(
521            self, node: "ast.AsyncFunctionDef", parent: NodeNG
522        ) -> nodes.AsyncFunctionDef:
523            ...
524
525        @overload
526        def visit(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor:
527            ...
528
529        @overload
530        def visit(self, node: "ast.Await", parent: NodeNG) -> nodes.Await:
531            ...
532
533        @overload
534        def visit(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith:
535            ...
536
537        @overload
538        def visit(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign:
539            ...
540
541        @overload
542        def visit(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign:
543            ...
544
545        @overload
546        def visit(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign:
547            ...
548
549        @overload
550        def visit(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp:
551            ...
552
553        @overload
554        def visit(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp:
555            ...
556
557        @overload
558        def visit(self, node: "ast.Break", parent: NodeNG) -> nodes.Break:
559            ...
560
561        @overload
562        def visit(self, node: "ast.Call", parent: NodeNG) -> nodes.Call:
563            ...
564
565        @overload
566        def visit(self, node: "ast.ClassDef", parent: NodeNG) -> nodes.ClassDef:
567            ...
568
569        @overload
570        def visit(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue:
571            ...
572
573        @overload
574        def visit(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare:
575            ...
576
577        @overload
578        def visit(
579            self, node: "ast.comprehension", parent: NodeNG
580        ) -> nodes.Comprehension:
581            ...
582
583        @overload
584        def visit(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete:
585            ...
586
587        @overload
588        def visit(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict:
589            ...
590
591        @overload
592        def visit(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp:
593            ...
594
595        @overload
596        def visit(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr:
597            ...
598
599        # Not used in Python 3.8+
600        @overload
601        def visit(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const:
602            ...
603
604        @overload
605        def visit(
606            self, node: "ast.ExceptHandler", parent: NodeNG
607        ) -> nodes.ExceptHandler:
608            ...
609
610        # Not used in Python 3.9+
611        @overload
612        def visit(self, node: "ast.ExtSlice", parent: nodes.Subscript) -> nodes.Tuple:
613            ...
614
615        @overload
616        def visit(self, node: "ast.For", parent: NodeNG) -> nodes.For:
617            ...
618
619        @overload
620        def visit(self, node: "ast.ImportFrom", parent: NodeNG) -> nodes.ImportFrom:
621            ...
622
623        @overload
624        def visit(self, node: "ast.FunctionDef", parent: NodeNG) -> nodes.FunctionDef:
625            ...
626
627        @overload
628        def visit(self, node: "ast.GeneratorExp", parent: NodeNG) -> nodes.GeneratorExp:
629            ...
630
631        @overload
632        def visit(self, node: "ast.Attribute", parent: NodeNG) -> nodes.Attribute:
633            ...
634
635        @overload
636        def visit(self, node: "ast.Global", parent: NodeNG) -> nodes.Global:
637            ...
638
639        @overload
640        def visit(self, node: "ast.If", parent: NodeNG) -> nodes.If:
641            ...
642
643        @overload
644        def visit(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp:
645            ...
646
647        @overload
648        def visit(self, node: "ast.Import", parent: NodeNG) -> nodes.Import:
649            ...
650
651        @overload
652        def visit(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr:
653            ...
654
655        @overload
656        def visit(
657            self, node: "ast.FormattedValue", parent: NodeNG
658        ) -> nodes.FormattedValue:
659            ...
660
661        @overload
662        def visit(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr:
663            ...
664
665        # Not used in Python 3.9+
666        @overload
667        def visit(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG:
668            ...
669
670        @overload
671        def visit(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword:
672            ...
673
674        @overload
675        def visit(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda:
676            ...
677
678        @overload
679        def visit(self, node: "ast.List", parent: NodeNG) -> nodes.List:
680            ...
681
682        @overload
683        def visit(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp:
684            ...
685
686        @overload
687        def visit(
688            self, node: "ast.Name", parent: NodeNG
689        ) -> Union[nodes.Name, nodes.Const, nodes.AssignName, nodes.DelName]:
690            ...
691
692        # Not used in Python 3.8+
693        @overload
694        def visit(self, node: "ast.NameConstant", parent: NodeNG) -> nodes.Const:
695            ...
696
697        @overload
698        def visit(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal:
699            ...
700
701        # Not used in Python 3.8+
702        @overload
703        def visit(self, node: "ast.Str", parent: NodeNG) -> nodes.Const:
704            ...
705
706        # Not used in Python 3.8+
707        @overload
708        def visit(self, node: "ast.Bytes", parent: NodeNG) -> nodes.Const:
709            ...
710
711        # Not used in Python 3.8+
712        @overload
713        def visit(self, node: "ast.Num", parent: NodeNG) -> nodes.Const:
714            ...
715
716        @overload
717        def visit(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const:
718            ...
719
720        @overload
721        def visit(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass:
722            ...
723
724        @overload
725        def visit(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise:
726            ...
727
728        @overload
729        def visit(self, node: "ast.Return", parent: NodeNG) -> nodes.Return:
730            ...
731
732        @overload
733        def visit(self, node: "ast.Set", parent: NodeNG) -> nodes.Set:
734            ...
735
736        @overload
737        def visit(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp:
738            ...
739
740        @overload
741        def visit(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice:
742            ...
743
744        @overload
745        def visit(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript:
746            ...
747
748        @overload
749        def visit(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred:
750            ...
751
752        @overload
753        def visit(
754            self, node: "ast.Try", parent: NodeNG
755        ) -> Union[nodes.TryExcept, nodes.TryFinally]:
756            ...
757
758        @overload
759        def visit(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple:
760            ...
761
762        @overload
763        def visit(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp:
764            ...
765
766        @overload
767        def visit(self, node: "ast.While", parent: NodeNG) -> nodes.While:
768            ...
769
770        @overload
771        def visit(self, node: "ast.With", parent: NodeNG) -> nodes.With:
772            ...
773
774        @overload
775        def visit(self, node: "ast.Yield", parent: NodeNG) -> nodes.Yield:
776            ...
777
778        @overload
779        def visit(self, node: "ast.YieldFrom", parent: NodeNG) -> nodes.YieldFrom:
780            ...
781
782        @overload
783        def visit(self, node: "ast.AST", parent: NodeNG) -> NodeNG:
784            ...
785
786        @overload
787        def visit(self, node: None, parent: NodeNG) -> None:
788            ...
789
790        def visit(self, node: Optional["ast.AST"], parent: NodeNG) -> Optional[NodeNG]:
791            if node is None:
792                return None
793            cls = node.__class__
794            if cls in self._visit_meths:
795                visit_method = self._visit_meths[cls]
796            else:
797                cls_name = cls.__name__
798                visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower()
799                visit_method = getattr(self, visit_name)
800                self._visit_meths[cls] = visit_method
801            return visit_method(node, parent)
802
803    def _save_assignment(self, node: Union[nodes.AssignName, nodes.DelName]) -> None:
804        """save assignment situation since node.parent is not available yet"""
805        if self._global_names and node.name in self._global_names[-1]:
806            node.root().set_local(node.name, node)
807        else:
808            node.parent.set_local(node.name, node)
809
810    def visit_arg(self, node: "ast.arg", parent: NodeNG) -> nodes.AssignName:
811        """visit an arg node by returning a fresh AssName instance"""
812        return self.visit_assignname(node, parent, node.arg)
813
814    def visit_arguments(self, node: "ast.arguments", parent: NodeNG) -> nodes.Arguments:
815        """visit an Arguments node by returning a fresh instance of it"""
816        vararg: Optional[str] = None
817        kwarg: Optional[str] = None
818        newnode = nodes.Arguments(
819            node.vararg.arg if node.vararg else None,
820            node.kwarg.arg if node.kwarg else None,
821            parent,
822        )
823        args = [self.visit(child, newnode) for child in node.args]
824        defaults = [self.visit(child, newnode) for child in node.defaults]
825        varargannotation: Optional[NodeNG] = None
826        kwargannotation: Optional[NodeNG] = None
827        posonlyargs: List[nodes.AssignName] = []
828        if node.vararg:
829            vararg = node.vararg.arg
830            varargannotation = self.visit(node.vararg.annotation, newnode)
831        if node.kwarg:
832            kwarg = node.kwarg.arg
833            kwargannotation = self.visit(node.kwarg.annotation, newnode)
834
835        if PY38:
836            # In Python 3.8 'end_lineno' and 'end_col_offset'
837            # for 'kwonlyargs' don't include the annotation.
838            for arg in node.kwonlyargs:
839                if arg.annotation is not None:
840                    arg.end_lineno = arg.annotation.end_lineno
841                    arg.end_col_offset = arg.annotation.end_col_offset
842
843        kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs]
844        kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults]
845        annotations = [self.visit(arg.annotation, newnode) for arg in node.args]
846        kwonlyargs_annotations = [
847            self.visit(arg.annotation, newnode) for arg in node.kwonlyargs
848        ]
849
850        posonlyargs_annotations: List[Optional[NodeNG]] = []
851        if PY38_PLUS:
852            posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs]
853            posonlyargs_annotations = [
854                self.visit(arg.annotation, newnode) for arg in node.posonlyargs
855            ]
856        type_comment_args = [
857            self.check_type_comment(child, parent=newnode) for child in node.args
858        ]
859        type_comment_kwonlyargs = [
860            self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs
861        ]
862        type_comment_posonlyargs: List[Optional[NodeNG]] = []
863        if PY38_PLUS:
864            type_comment_posonlyargs = [
865                self.check_type_comment(child, parent=newnode)
866                for child in node.posonlyargs
867            ]
868
869        newnode.postinit(
870            args=args,
871            defaults=defaults,
872            kwonlyargs=kwonlyargs,
873            posonlyargs=posonlyargs,
874            kw_defaults=kw_defaults,
875            annotations=annotations,
876            kwonlyargs_annotations=kwonlyargs_annotations,
877            posonlyargs_annotations=posonlyargs_annotations,
878            varargannotation=varargannotation,
879            kwargannotation=kwargannotation,
880            type_comment_args=type_comment_args,
881            type_comment_kwonlyargs=type_comment_kwonlyargs,
882            type_comment_posonlyargs=type_comment_posonlyargs,
883        )
884        # save argument names in locals:
885        if vararg:
886            newnode.parent.set_local(vararg, newnode)
887        if kwarg:
888            newnode.parent.set_local(kwarg, newnode)
889        return newnode
890
891    def visit_assert(self, node: "ast.Assert", parent: NodeNG) -> nodes.Assert:
892        """visit a Assert node by returning a fresh instance of it"""
893        if sys.version_info >= (3, 8):
894            newnode = nodes.Assert(
895                lineno=node.lineno,
896                col_offset=node.col_offset,
897                end_lineno=node.end_lineno,
898                end_col_offset=node.end_col_offset,
899                parent=parent,
900            )
901        else:
902            newnode = nodes.Assert(node.lineno, node.col_offset, parent)
903        msg: Optional[NodeNG] = None
904        if node.msg:
905            msg = self.visit(node.msg, newnode)
906        newnode.postinit(self.visit(node.test, newnode), msg)
907        return newnode
908
909    def check_type_comment(
910        self,
911        node: Union[
912            "ast.Assign",
913            "ast.arg",
914            "ast.For",
915            "ast.AsyncFor",
916            "ast.With",
917            "ast.AsyncWith",
918        ],
919        parent: Union[
920            nodes.Assign,
921            nodes.Arguments,
922            nodes.For,
923            nodes.AsyncFor,
924            nodes.With,
925            nodes.AsyncWith,
926        ],
927    ) -> Optional[NodeNG]:
928        type_comment = getattr(node, "type_comment", None)  # Added in Python 3.8
929        if not type_comment:
930            return None
931
932        try:
933            type_comment_ast = self._parser_module.parse(type_comment)
934        except SyntaxError:
935            # Invalid type comment, just skip it.
936            return None
937
938        type_object = self.visit(type_comment_ast.body[0], parent=parent)
939        if not isinstance(type_object, nodes.Expr):
940            return None
941
942        return type_object.value
943
944    def check_function_type_comment(
945        self, node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"], parent: NodeNG
946    ) -> Optional[Tuple[Optional[NodeNG], List[NodeNG]]]:
947        type_comment = getattr(node, "type_comment", None)  # Added in Python 3.8
948        if not type_comment:
949            return None
950
951        try:
952            type_comment_ast = parse_function_type_comment(type_comment)
953        except SyntaxError:
954            # Invalid type comment, just skip it.
955            return None
956
957        returns: Optional[NodeNG] = None
958        argtypes: List[NodeNG] = [
959            self.visit(elem, parent) for elem in (type_comment_ast.argtypes or [])
960        ]
961        if type_comment_ast.returns:
962            returns = self.visit(type_comment_ast.returns, parent)
963
964        return returns, argtypes
965
966    def visit_asyncfunctiondef(
967        self, node: "ast.AsyncFunctionDef", parent: NodeNG
968    ) -> nodes.AsyncFunctionDef:
969        return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent)
970
971    def visit_asyncfor(self, node: "ast.AsyncFor", parent: NodeNG) -> nodes.AsyncFor:
972        return self._visit_for(nodes.AsyncFor, node, parent)
973
974    def visit_await(self, node: "ast.Await", parent: NodeNG) -> nodes.Await:
975        if sys.version_info >= (3, 8):
976            newnode = nodes.Await(
977                lineno=node.lineno,
978                col_offset=node.col_offset,
979                end_lineno=node.end_lineno,
980                end_col_offset=node.end_col_offset,
981                parent=parent,
982            )
983        else:
984            newnode = nodes.Await(node.lineno, node.col_offset, parent)
985        newnode.postinit(value=self.visit(node.value, newnode))
986        return newnode
987
988    def visit_asyncwith(self, node: "ast.AsyncWith", parent: NodeNG) -> nodes.AsyncWith:
989        return self._visit_with(nodes.AsyncWith, node, parent)
990
991    def visit_assign(self, node: "ast.Assign", parent: NodeNG) -> nodes.Assign:
992        """visit a Assign node by returning a fresh instance of it"""
993        if sys.version_info >= (3, 8):
994            newnode = nodes.Assign(
995                lineno=node.lineno,
996                col_offset=node.col_offset,
997                end_lineno=node.end_lineno,
998                end_col_offset=node.end_col_offset,
999                parent=parent,
1000            )
1001        else:
1002            newnode = nodes.Assign(node.lineno, node.col_offset, parent)
1003        type_annotation = self.check_type_comment(node, parent=newnode)
1004        newnode.postinit(
1005            targets=[self.visit(child, newnode) for child in node.targets],
1006            value=self.visit(node.value, newnode),
1007            type_annotation=type_annotation,
1008        )
1009        return newnode
1010
1011    def visit_annassign(self, node: "ast.AnnAssign", parent: NodeNG) -> nodes.AnnAssign:
1012        """visit an AnnAssign node by returning a fresh instance of it"""
1013        if sys.version_info >= (3, 8):
1014            newnode = nodes.AnnAssign(
1015                lineno=node.lineno,
1016                col_offset=node.col_offset,
1017                end_lineno=node.end_lineno,
1018                end_col_offset=node.end_col_offset,
1019                parent=parent,
1020            )
1021        else:
1022            newnode = nodes.AnnAssign(node.lineno, node.col_offset, parent)
1023        newnode.postinit(
1024            target=self.visit(node.target, newnode),
1025            annotation=self.visit(node.annotation, newnode),
1026            simple=node.simple,
1027            value=self.visit(node.value, newnode),
1028        )
1029        return newnode
1030
1031    @overload
1032    def visit_assignname(
1033        self, node: "ast.AST", parent: NodeNG, node_name: str
1034    ) -> nodes.AssignName:
1035        ...
1036
1037    @overload
1038    def visit_assignname(
1039        self, node: "ast.AST", parent: NodeNG, node_name: None
1040    ) -> None:
1041        ...
1042
1043    def visit_assignname(
1044        self, node: "ast.AST", parent: NodeNG, node_name: Optional[str]
1045    ) -> Optional[nodes.AssignName]:
1046        """visit a node and return a AssignName node
1047
1048        Note: Method not called by 'visit'
1049        """
1050        if node_name is None:
1051            return None
1052        if sys.version_info >= (3, 8):
1053            newnode = nodes.AssignName(
1054                name=node_name,
1055                lineno=node.lineno,
1056                col_offset=node.col_offset,
1057                end_lineno=node.end_lineno,
1058                end_col_offset=node.end_col_offset,
1059                parent=parent,
1060            )
1061        else:
1062            newnode = nodes.AssignName(
1063                node_name,
1064                node.lineno,
1065                node.col_offset,
1066                parent,
1067            )
1068        self._save_assignment(newnode)
1069        return newnode
1070
1071    def visit_augassign(self, node: "ast.AugAssign", parent: NodeNG) -> nodes.AugAssign:
1072        """visit a AugAssign node by returning a fresh instance of it"""
1073        if sys.version_info >= (3, 8):
1074            newnode = nodes.AugAssign(
1075                op=self._parser_module.bin_op_classes[type(node.op)] + "=",
1076                lineno=node.lineno,
1077                col_offset=node.col_offset,
1078                end_lineno=node.end_lineno,
1079                end_col_offset=node.end_col_offset,
1080                parent=parent,
1081            )
1082        else:
1083            newnode = nodes.AugAssign(
1084                self._parser_module.bin_op_classes[type(node.op)] + "=",
1085                node.lineno,
1086                node.col_offset,
1087                parent,
1088            )
1089        newnode.postinit(
1090            self.visit(node.target, newnode), self.visit(node.value, newnode)
1091        )
1092        return newnode
1093
1094    def visit_binop(self, node: "ast.BinOp", parent: NodeNG) -> nodes.BinOp:
1095        """visit a BinOp node by returning a fresh instance of it"""
1096        if sys.version_info >= (3, 8):
1097            newnode = nodes.BinOp(
1098                op=self._parser_module.bin_op_classes[type(node.op)],
1099                lineno=node.lineno,
1100                col_offset=node.col_offset,
1101                end_lineno=node.end_lineno,
1102                end_col_offset=node.end_col_offset,
1103                parent=parent,
1104            )
1105        else:
1106            newnode = nodes.BinOp(
1107                self._parser_module.bin_op_classes[type(node.op)],
1108                node.lineno,
1109                node.col_offset,
1110                parent,
1111            )
1112        newnode.postinit(
1113            self.visit(node.left, newnode), self.visit(node.right, newnode)
1114        )
1115        return newnode
1116
1117    def visit_boolop(self, node: "ast.BoolOp", parent: NodeNG) -> nodes.BoolOp:
1118        """visit a BoolOp node by returning a fresh instance of it"""
1119        if sys.version_info >= (3, 8):
1120            newnode = nodes.BoolOp(
1121                op=self._parser_module.bool_op_classes[type(node.op)],
1122                lineno=node.lineno,
1123                col_offset=node.col_offset,
1124                end_lineno=node.end_lineno,
1125                end_col_offset=node.end_col_offset,
1126                parent=parent,
1127            )
1128        else:
1129            newnode = nodes.BoolOp(
1130                self._parser_module.bool_op_classes[type(node.op)],
1131                node.lineno,
1132                node.col_offset,
1133                parent,
1134            )
1135        newnode.postinit([self.visit(child, newnode) for child in node.values])
1136        return newnode
1137
1138    def visit_break(self, node: "ast.Break", parent: NodeNG) -> nodes.Break:
1139        """visit a Break node by returning a fresh instance of it"""
1140        if sys.version_info >= (3, 8):
1141            return nodes.Break(
1142                lineno=node.lineno,
1143                col_offset=node.col_offset,
1144                end_lineno=node.end_lineno,
1145                end_col_offset=node.end_col_offset,
1146                parent=parent,
1147            )
1148        return nodes.Break(node.lineno, node.col_offset, parent)
1149
1150    def visit_call(self, node: "ast.Call", parent: NodeNG) -> nodes.Call:
1151        """visit a CallFunc node by returning a fresh instance of it"""
1152        if sys.version_info >= (3, 8):
1153            newnode = nodes.Call(
1154                lineno=node.lineno,
1155                col_offset=node.col_offset,
1156                end_lineno=node.end_lineno,
1157                end_col_offset=node.end_col_offset,
1158                parent=parent,
1159            )
1160        else:
1161            newnode = nodes.Call(node.lineno, node.col_offset, parent)
1162        newnode.postinit(
1163            func=self.visit(node.func, newnode),
1164            args=[self.visit(child, newnode) for child in node.args],
1165            keywords=[self.visit(child, newnode) for child in node.keywords],
1166        )
1167        return newnode
1168
1169    def visit_classdef(
1170        self, node: "ast.ClassDef", parent: NodeNG, newstyle: bool = True
1171    ) -> nodes.ClassDef:
1172        """visit a ClassDef node to become astroid"""
1173        node, doc = self._get_doc(node)
1174        if sys.version_info >= (3, 8):
1175            newnode = nodes.ClassDef(
1176                name=node.name,
1177                doc=doc,
1178                lineno=node.lineno,
1179                col_offset=node.col_offset,
1180                end_lineno=node.end_lineno,
1181                end_col_offset=node.end_col_offset,
1182                parent=parent,
1183            )
1184        else:
1185            newnode = nodes.ClassDef(
1186                node.name, doc, node.lineno, node.col_offset, parent
1187            )
1188        metaclass = None
1189        for keyword in node.keywords:
1190            if keyword.arg == "metaclass":
1191                metaclass = self.visit(keyword, newnode).value
1192                break
1193        decorators = self.visit_decorators(node, newnode)
1194        newnode.postinit(
1195            [self.visit(child, newnode) for child in node.bases],
1196            [self.visit(child, newnode) for child in node.body],
1197            decorators,
1198            newstyle,
1199            metaclass,
1200            [
1201                self.visit(kwd, newnode)
1202                for kwd in node.keywords
1203                if kwd.arg != "metaclass"
1204            ],
1205        )
1206        return newnode
1207
1208    def visit_continue(self, node: "ast.Continue", parent: NodeNG) -> nodes.Continue:
1209        """visit a Continue node by returning a fresh instance of it"""
1210        if sys.version_info >= (3, 8):
1211            return nodes.Continue(
1212                lineno=node.lineno,
1213                col_offset=node.col_offset,
1214                end_lineno=node.end_lineno,
1215                end_col_offset=node.end_col_offset,
1216                parent=parent,
1217            )
1218        return nodes.Continue(node.lineno, node.col_offset, parent)
1219
1220    def visit_compare(self, node: "ast.Compare", parent: NodeNG) -> nodes.Compare:
1221        """visit a Compare node by returning a fresh instance of it"""
1222        if sys.version_info >= (3, 8):
1223            newnode = nodes.Compare(
1224                lineno=node.lineno,
1225                col_offset=node.col_offset,
1226                end_lineno=node.end_lineno,
1227                end_col_offset=node.end_col_offset,
1228                parent=parent,
1229            )
1230        else:
1231            newnode = nodes.Compare(node.lineno, node.col_offset, parent)
1232        newnode.postinit(
1233            self.visit(node.left, newnode),
1234            [
1235                (
1236                    self._parser_module.cmp_op_classes[op.__class__],
1237                    self.visit(expr, newnode),
1238                )
1239                for (op, expr) in zip(node.ops, node.comparators)
1240            ],
1241        )
1242        return newnode
1243
1244    def visit_comprehension(
1245        self, node: "ast.comprehension", parent: NodeNG
1246    ) -> nodes.Comprehension:
1247        """visit a Comprehension node by returning a fresh instance of it"""
1248        newnode = nodes.Comprehension(parent)
1249        newnode.postinit(
1250            self.visit(node.target, newnode),
1251            self.visit(node.iter, newnode),
1252            [self.visit(child, newnode) for child in node.ifs],
1253            bool(node.is_async),
1254        )
1255        return newnode
1256
1257    def visit_decorators(
1258        self,
1259        node: Union["ast.ClassDef", "ast.FunctionDef", "ast.AsyncFunctionDef"],
1260        parent: NodeNG,
1261    ) -> Optional[nodes.Decorators]:
1262        """visit a Decorators node by returning a fresh instance of it
1263
1264        Note: Method not called by 'visit'
1265        """
1266        if not node.decorator_list:
1267            return None
1268        # /!\ node is actually an _ast.FunctionDef node while
1269        # parent is an astroid.nodes.FunctionDef node
1270        if sys.version_info >= (3, 8):
1271            # Set the line number of the first decorator for Python 3.8+.
1272            lineno = node.decorator_list[0].lineno
1273            end_lineno = node.decorator_list[-1].end_lineno
1274            end_col_offset = node.decorator_list[-1].end_col_offset
1275        else:
1276            lineno = node.lineno
1277            end_lineno = None
1278            end_col_offset = None
1279        newnode = nodes.Decorators(
1280            lineno=lineno,
1281            col_offset=node.col_offset,
1282            end_lineno=end_lineno,
1283            end_col_offset=end_col_offset,
1284            parent=parent,
1285        )
1286        newnode.postinit([self.visit(child, newnode) for child in node.decorator_list])
1287        return newnode
1288
1289    def visit_delete(self, node: "ast.Delete", parent: NodeNG) -> nodes.Delete:
1290        """visit a Delete node by returning a fresh instance of it"""
1291        if sys.version_info >= (3, 8):
1292            newnode = nodes.Delete(
1293                lineno=node.lineno,
1294                col_offset=node.col_offset,
1295                end_lineno=node.end_lineno,
1296                end_col_offset=node.end_col_offset,
1297                parent=parent,
1298            )
1299        else:
1300            newnode = nodes.Delete(node.lineno, node.col_offset, parent)
1301        newnode.postinit([self.visit(child, newnode) for child in node.targets])
1302        return newnode
1303
1304    def _visit_dict_items(
1305        self, node: "ast.Dict", parent: NodeNG, newnode: nodes.Dict
1306    ) -> Generator[Tuple[NodeNG, NodeNG], None, None]:
1307        for key, value in zip(node.keys, node.values):
1308            rebuilt_key: NodeNG
1309            rebuilt_value = self.visit(value, newnode)
1310            if not key:
1311                # Extended unpacking
1312                if sys.version_info >= (3, 8):
1313                    rebuilt_key = nodes.DictUnpack(
1314                        lineno=rebuilt_value.lineno,
1315                        col_offset=rebuilt_value.col_offset,
1316                        end_lineno=rebuilt_value.end_lineno,
1317                        end_col_offset=rebuilt_value.end_col_offset,
1318                        parent=parent,
1319                    )
1320                else:
1321                    rebuilt_key = nodes.DictUnpack(
1322                        rebuilt_value.lineno, rebuilt_value.col_offset, parent
1323                    )
1324            else:
1325                rebuilt_key = self.visit(key, newnode)
1326            yield rebuilt_key, rebuilt_value
1327
1328    def visit_dict(self, node: "ast.Dict", parent: NodeNG) -> nodes.Dict:
1329        """visit a Dict node by returning a fresh instance of it"""
1330        if sys.version_info >= (3, 8):
1331            newnode = nodes.Dict(
1332                lineno=node.lineno,
1333                col_offset=node.col_offset,
1334                end_lineno=node.end_lineno,
1335                end_col_offset=node.end_col_offset,
1336                parent=parent,
1337            )
1338        else:
1339            newnode = nodes.Dict(node.lineno, node.col_offset, parent)
1340        items = list(self._visit_dict_items(node, parent, newnode))
1341        newnode.postinit(items)
1342        return newnode
1343
1344    def visit_dictcomp(self, node: "ast.DictComp", parent: NodeNG) -> nodes.DictComp:
1345        """visit a DictComp node by returning a fresh instance of it"""
1346        if sys.version_info >= (3, 8):
1347            newnode = nodes.DictComp(
1348                lineno=node.lineno,
1349                col_offset=node.col_offset,
1350                end_lineno=node.end_lineno,
1351                end_col_offset=node.end_col_offset,
1352                parent=parent,
1353            )
1354        else:
1355            newnode = nodes.DictComp(node.lineno, node.col_offset, parent)
1356        newnode.postinit(
1357            self.visit(node.key, newnode),
1358            self.visit(node.value, newnode),
1359            [self.visit(child, newnode) for child in node.generators],
1360        )
1361        return newnode
1362
1363    def visit_expr(self, node: "ast.Expr", parent: NodeNG) -> nodes.Expr:
1364        """visit a Expr node by returning a fresh instance of it"""
1365        if sys.version_info >= (3, 8):
1366            newnode = nodes.Expr(
1367                lineno=node.lineno,
1368                col_offset=node.col_offset,
1369                end_lineno=node.end_lineno,
1370                end_col_offset=node.end_col_offset,
1371                parent=parent,
1372            )
1373        else:
1374            newnode = nodes.Expr(node.lineno, node.col_offset, parent)
1375        newnode.postinit(self.visit(node.value, newnode))
1376        return newnode
1377
1378    # Not used in Python 3.8+.
1379    def visit_ellipsis(self, node: "ast.Ellipsis", parent: NodeNG) -> nodes.Const:
1380        """visit an Ellipsis node by returning a fresh instance of Const"""
1381        return nodes.Const(
1382            value=Ellipsis,
1383            lineno=node.lineno,
1384            col_offset=node.col_offset,
1385            parent=parent,
1386        )
1387
1388    def visit_excepthandler(
1389        self, node: "ast.ExceptHandler", parent: NodeNG
1390    ) -> nodes.ExceptHandler:
1391        """visit an ExceptHandler node by returning a fresh instance of it"""
1392        if sys.version_info >= (3, 8):
1393            newnode = nodes.ExceptHandler(
1394                lineno=node.lineno,
1395                col_offset=node.col_offset,
1396                end_lineno=node.end_lineno,
1397                end_col_offset=node.end_col_offset,
1398                parent=parent,
1399            )
1400        else:
1401            newnode = nodes.ExceptHandler(node.lineno, node.col_offset, parent)
1402        newnode.postinit(
1403            self.visit(node.type, newnode),
1404            self.visit_assignname(node, newnode, node.name),
1405            [self.visit(child, newnode) for child in node.body],
1406        )
1407        return newnode
1408
1409    # Not used in Python 3.9+.
1410    def visit_extslice(
1411        self, node: "ast.ExtSlice", parent: nodes.Subscript
1412    ) -> nodes.Tuple:
1413        """visit an ExtSlice node by returning a fresh instance of Tuple"""
1414        # ExtSlice doesn't have lineno or col_offset information
1415        newnode = nodes.Tuple(ctx=Context.Load, parent=parent)
1416        newnode.postinit([self.visit(dim, newnode) for dim in node.dims])  # type: ignore[attr-defined]
1417        return newnode
1418
1419    @overload
1420    def _visit_for(
1421        self, cls: Type[nodes.For], node: "ast.For", parent: NodeNG
1422    ) -> nodes.For:
1423        ...
1424
1425    @overload
1426    def _visit_for(
1427        self, cls: Type[nodes.AsyncFor], node: "ast.AsyncFor", parent: NodeNG
1428    ) -> nodes.AsyncFor:
1429        ...
1430
1431    def _visit_for(
1432        self, cls: Type[T_For], node: Union["ast.For", "ast.AsyncFor"], parent: NodeNG
1433    ) -> T_For:
1434        """visit a For node by returning a fresh instance of it"""
1435        if sys.version_info >= (3, 8):
1436            newnode = cls(
1437                lineno=node.lineno,
1438                col_offset=node.col_offset,
1439                end_lineno=node.end_lineno,
1440                end_col_offset=node.end_col_offset,
1441                parent=parent,
1442            )
1443        else:
1444            newnode = cls(node.lineno, node.col_offset, parent)
1445        type_annotation = self.check_type_comment(node, parent=newnode)
1446        newnode.postinit(
1447            target=self.visit(node.target, newnode),
1448            iter=self.visit(node.iter, newnode),
1449            body=[self.visit(child, newnode) for child in node.body],
1450            orelse=[self.visit(child, newnode) for child in node.orelse],
1451            type_annotation=type_annotation,
1452        )
1453        return newnode
1454
1455    def visit_for(self, node: "ast.For", parent: NodeNG) -> nodes.For:
1456        return self._visit_for(nodes.For, node, parent)
1457
1458    def visit_importfrom(
1459        self, node: "ast.ImportFrom", parent: NodeNG
1460    ) -> nodes.ImportFrom:
1461        """visit an ImportFrom node by returning a fresh instance of it"""
1462        names = [(alias.name, alias.asname) for alias in node.names]
1463        if sys.version_info >= (3, 8):
1464            newnode = nodes.ImportFrom(
1465                fromname=node.module or "",
1466                names=names,
1467                level=node.level or None,
1468                lineno=node.lineno,
1469                col_offset=node.col_offset,
1470                end_lineno=node.end_lineno,
1471                end_col_offset=node.end_col_offset,
1472                parent=parent,
1473            )
1474        else:
1475            newnode = nodes.ImportFrom(
1476                node.module or "",
1477                names,
1478                node.level or None,
1479                node.lineno,
1480                node.col_offset,
1481                parent,
1482            )
1483        # store From names to add them to locals after building
1484        self._import_from_nodes.append(newnode)
1485        return newnode
1486
1487    @overload
1488    def _visit_functiondef(
1489        self, cls: Type[nodes.FunctionDef], node: "ast.FunctionDef", parent: NodeNG
1490    ) -> nodes.FunctionDef:
1491        ...
1492
1493    @overload
1494    def _visit_functiondef(
1495        self,
1496        cls: Type[nodes.AsyncFunctionDef],
1497        node: "ast.AsyncFunctionDef",
1498        parent: NodeNG,
1499    ) -> nodes.AsyncFunctionDef:
1500        ...
1501
1502    def _visit_functiondef(
1503        self,
1504        cls: Type[T_Function],
1505        node: Union["ast.FunctionDef", "ast.AsyncFunctionDef"],
1506        parent: NodeNG,
1507    ) -> T_Function:
1508        """visit an FunctionDef node to become astroid"""
1509        self._global_names.append({})
1510        node, doc = self._get_doc(node)
1511
1512        lineno = node.lineno
1513        if PY38_PLUS and node.decorator_list:
1514            # Python 3.8 sets the line number of a decorated function
1515            # to be the actual line number of the function, but the
1516            # previous versions expected the decorator's line number instead.
1517            # We reset the function's line number to that of the
1518            # first decorator to maintain backward compatibility.
1519            # It's not ideal but this discrepancy was baked into
1520            # the framework for *years*.
1521            lineno = node.decorator_list[0].lineno
1522
1523        if sys.version_info >= (3, 8):
1524            newnode = cls(
1525                name=node.name,
1526                doc=doc,
1527                lineno=lineno,
1528                col_offset=node.col_offset,
1529                end_lineno=node.end_lineno,
1530                end_col_offset=node.end_col_offset,
1531                parent=parent,
1532            )
1533        else:
1534            newnode = cls(node.name, doc, lineno, node.col_offset, parent)
1535        decorators = self.visit_decorators(node, newnode)
1536        returns: Optional[NodeNG]
1537        if node.returns:
1538            returns = self.visit(node.returns, newnode)
1539        else:
1540            returns = None
1541
1542        type_comment_args = type_comment_returns = None
1543        type_comment_annotation = self.check_function_type_comment(node, newnode)
1544        if type_comment_annotation:
1545            type_comment_returns, type_comment_args = type_comment_annotation
1546        newnode.postinit(
1547            args=self.visit(node.args, newnode),
1548            body=[self.visit(child, newnode) for child in node.body],
1549            decorators=decorators,
1550            returns=returns,
1551            type_comment_returns=type_comment_returns,
1552            type_comment_args=type_comment_args,
1553        )
1554        self._global_names.pop()
1555        return newnode
1556
1557    def visit_functiondef(
1558        self, node: "ast.FunctionDef", parent: NodeNG
1559    ) -> nodes.FunctionDef:
1560        return self._visit_functiondef(nodes.FunctionDef, node, parent)
1561
1562    def visit_generatorexp(
1563        self, node: "ast.GeneratorExp", parent: NodeNG
1564    ) -> nodes.GeneratorExp:
1565        """visit a GeneratorExp node by returning a fresh instance of it"""
1566        if sys.version_info >= (3, 8):
1567            newnode = nodes.GeneratorExp(
1568                lineno=node.lineno,
1569                col_offset=node.col_offset,
1570                end_lineno=node.end_lineno,
1571                end_col_offset=node.end_col_offset,
1572                parent=parent,
1573            )
1574        else:
1575            newnode = nodes.GeneratorExp(node.lineno, node.col_offset, parent)
1576        newnode.postinit(
1577            self.visit(node.elt, newnode),
1578            [self.visit(child, newnode) for child in node.generators],
1579        )
1580        return newnode
1581
1582    def visit_attribute(
1583        self, node: "ast.Attribute", parent: NodeNG
1584    ) -> Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr]:
1585        """visit an Attribute node by returning a fresh instance of it"""
1586        context = self._get_context(node)
1587        newnode: Union[nodes.Attribute, nodes.AssignAttr, nodes.DelAttr]
1588        if context == Context.Del:
1589            # FIXME : maybe we should reintroduce and visit_delattr ?
1590            # for instance, deactivating assign_ctx
1591            if sys.version_info >= (3, 8):
1592                newnode = nodes.DelAttr(
1593                    attrname=node.attr,
1594                    lineno=node.lineno,
1595                    col_offset=node.col_offset,
1596                    end_lineno=node.end_lineno,
1597                    end_col_offset=node.end_col_offset,
1598                    parent=parent,
1599                )
1600            else:
1601                newnode = nodes.DelAttr(node.attr, node.lineno, node.col_offset, parent)
1602        elif context == Context.Store:
1603            if sys.version_info >= (3, 8):
1604                newnode = nodes.AssignAttr(
1605                    attrname=node.attr,
1606                    lineno=node.lineno,
1607                    col_offset=node.col_offset,
1608                    end_lineno=node.end_lineno,
1609                    end_col_offset=node.end_col_offset,
1610                    parent=parent,
1611                )
1612            else:
1613                newnode = nodes.AssignAttr(
1614                    node.attr, node.lineno, node.col_offset, parent
1615                )
1616            # Prohibit a local save if we are in an ExceptHandler.
1617            if not isinstance(parent, nodes.ExceptHandler):
1618                self._delayed_assattr.append(newnode)
1619        else:
1620            # pylint: disable-next=else-if-used
1621            # Preserve symmetry with other cases
1622            if sys.version_info >= (3, 8):
1623                newnode = nodes.Attribute(
1624                    attrname=node.attr,
1625                    lineno=node.lineno,
1626                    col_offset=node.col_offset,
1627                    end_lineno=node.end_lineno,
1628                    end_col_offset=node.end_col_offset,
1629                    parent=parent,
1630                )
1631            else:
1632                newnode = nodes.Attribute(
1633                    node.attr, node.lineno, node.col_offset, parent
1634                )
1635        newnode.postinit(self.visit(node.value, newnode))
1636        return newnode
1637
1638    def visit_global(self, node: "ast.Global", parent: NodeNG) -> nodes.Global:
1639        """visit a Global node to become astroid"""
1640        if sys.version_info >= (3, 8):
1641            newnode = nodes.Global(
1642                names=node.names,
1643                lineno=node.lineno,
1644                col_offset=node.col_offset,
1645                end_lineno=node.end_lineno,
1646                end_col_offset=node.end_col_offset,
1647                parent=parent,
1648            )
1649        else:
1650            newnode = nodes.Global(
1651                node.names,
1652                node.lineno,
1653                node.col_offset,
1654                parent,
1655            )
1656        if self._global_names:  # global at the module level, no effect
1657            for name in node.names:
1658                self._global_names[-1].setdefault(name, []).append(newnode)
1659        return newnode
1660
1661    def visit_if(self, node: "ast.If", parent: NodeNG) -> nodes.If:
1662        """visit an If node by returning a fresh instance of it"""
1663        if sys.version_info >= (3, 8):
1664            newnode = nodes.If(
1665                lineno=node.lineno,
1666                col_offset=node.col_offset,
1667                end_lineno=node.end_lineno,
1668                end_col_offset=node.end_col_offset,
1669                parent=parent,
1670            )
1671        else:
1672            newnode = nodes.If(node.lineno, node.col_offset, parent)
1673        newnode.postinit(
1674            self.visit(node.test, newnode),
1675            [self.visit(child, newnode) for child in node.body],
1676            [self.visit(child, newnode) for child in node.orelse],
1677        )
1678        return newnode
1679
1680    def visit_ifexp(self, node: "ast.IfExp", parent: NodeNG) -> nodes.IfExp:
1681        """visit a IfExp node by returning a fresh instance of it"""
1682        if sys.version_info >= (3, 8):
1683            newnode = nodes.IfExp(
1684                lineno=node.lineno,
1685                col_offset=node.col_offset,
1686                end_lineno=node.end_lineno,
1687                end_col_offset=node.end_col_offset,
1688                parent=parent,
1689            )
1690        else:
1691            newnode = nodes.IfExp(node.lineno, node.col_offset, parent)
1692        newnode.postinit(
1693            self.visit(node.test, newnode),
1694            self.visit(node.body, newnode),
1695            self.visit(node.orelse, newnode),
1696        )
1697        return newnode
1698
1699    def visit_import(self, node: "ast.Import", parent: NodeNG) -> nodes.Import:
1700        """visit a Import node by returning a fresh instance of it"""
1701        names = [(alias.name, alias.asname) for alias in node.names]
1702        if sys.version_info >= (3, 8):
1703            newnode = nodes.Import(
1704                names=names,
1705                lineno=node.lineno,
1706                col_offset=node.col_offset,
1707                end_lineno=node.end_lineno,
1708                end_col_offset=node.end_col_offset,
1709                parent=parent,
1710            )
1711        else:
1712            newnode = nodes.Import(
1713                names,
1714                node.lineno,
1715                node.col_offset,
1716                parent,
1717            )
1718        # save import names in parent's locals:
1719        for (name, asname) in newnode.names:
1720            name = asname or name
1721            parent.set_local(name.split(".")[0], newnode)
1722        return newnode
1723
1724    def visit_joinedstr(self, node: "ast.JoinedStr", parent: NodeNG) -> nodes.JoinedStr:
1725        if sys.version_info >= (3, 8):
1726            newnode = nodes.JoinedStr(
1727                lineno=node.lineno,
1728                col_offset=node.col_offset,
1729                end_lineno=node.end_lineno,
1730                end_col_offset=node.end_col_offset,
1731                parent=parent,
1732            )
1733        else:
1734            newnode = nodes.JoinedStr(node.lineno, node.col_offset, parent)
1735        newnode.postinit([self.visit(child, newnode) for child in node.values])
1736        return newnode
1737
1738    def visit_formattedvalue(
1739        self, node: "ast.FormattedValue", parent: NodeNG
1740    ) -> nodes.FormattedValue:
1741        if sys.version_info >= (3, 8):
1742            newnode = nodes.FormattedValue(
1743                lineno=node.lineno,
1744                col_offset=node.col_offset,
1745                end_lineno=node.end_lineno,
1746                end_col_offset=node.end_col_offset,
1747                parent=parent,
1748            )
1749        else:
1750            newnode = nodes.FormattedValue(node.lineno, node.col_offset, parent)
1751        newnode.postinit(
1752            self.visit(node.value, newnode),
1753            node.conversion,
1754            self.visit(node.format_spec, newnode),
1755        )
1756        return newnode
1757
1758    def visit_namedexpr(self, node: "ast.NamedExpr", parent: NodeNG) -> nodes.NamedExpr:
1759        if sys.version_info >= (3, 8):
1760            newnode = nodes.NamedExpr(
1761                lineno=node.lineno,
1762                col_offset=node.col_offset,
1763                end_lineno=node.end_lineno,
1764                end_col_offset=node.end_col_offset,
1765                parent=parent,
1766            )
1767        else:
1768            newnode = nodes.NamedExpr(node.lineno, node.col_offset, parent)
1769        newnode.postinit(
1770            self.visit(node.target, newnode), self.visit(node.value, newnode)
1771        )
1772        return newnode
1773
1774    # Not used in Python 3.9+.
1775    def visit_index(self, node: "ast.Index", parent: nodes.Subscript) -> NodeNG:
1776        """visit a Index node by returning a fresh instance of NodeNG"""
1777        return self.visit(node.value, parent)  # type: ignore[attr-defined]
1778
1779    def visit_keyword(self, node: "ast.keyword", parent: NodeNG) -> nodes.Keyword:
1780        """visit a Keyword node by returning a fresh instance of it"""
1781        if sys.version_info >= (3, 9):
1782            newnode = nodes.Keyword(
1783                arg=node.arg,
1784                lineno=node.lineno,
1785                col_offset=node.col_offset,
1786                end_lineno=node.end_lineno,
1787                end_col_offset=node.end_col_offset,
1788                parent=parent,
1789            )
1790        else:
1791            newnode = nodes.Keyword(node.arg, parent=parent)
1792        newnode.postinit(self.visit(node.value, newnode))
1793        return newnode
1794
1795    def visit_lambda(self, node: "ast.Lambda", parent: NodeNG) -> nodes.Lambda:
1796        """visit a Lambda node by returning a fresh instance of it"""
1797        if sys.version_info >= (3, 8):
1798            newnode = nodes.Lambda(
1799                lineno=node.lineno,
1800                col_offset=node.col_offset,
1801                end_lineno=node.end_lineno,
1802                end_col_offset=node.end_col_offset,
1803                parent=parent,
1804            )
1805        else:
1806            newnode = nodes.Lambda(node.lineno, node.col_offset, parent)
1807        newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode))
1808        return newnode
1809
1810    def visit_list(self, node: "ast.List", parent: NodeNG) -> nodes.List:
1811        """visit a List node by returning a fresh instance of it"""
1812        context = self._get_context(node)
1813        if sys.version_info >= (3, 8):
1814            newnode = nodes.List(
1815                ctx=context,
1816                lineno=node.lineno,
1817                col_offset=node.col_offset,
1818                end_lineno=node.end_lineno,
1819                end_col_offset=node.end_col_offset,
1820                parent=parent,
1821            )
1822        else:
1823            newnode = nodes.List(
1824                ctx=context,
1825                lineno=node.lineno,
1826                col_offset=node.col_offset,
1827                parent=parent,
1828            )
1829        newnode.postinit([self.visit(child, newnode) for child in node.elts])
1830        return newnode
1831
1832    def visit_listcomp(self, node: "ast.ListComp", parent: NodeNG) -> nodes.ListComp:
1833        """visit a ListComp node by returning a fresh instance of it"""
1834        if sys.version_info >= (3, 8):
1835            newnode = nodes.ListComp(
1836                lineno=node.lineno,
1837                col_offset=node.col_offset,
1838                end_lineno=node.end_lineno,
1839                end_col_offset=node.end_col_offset,
1840                parent=parent,
1841            )
1842        else:
1843            newnode = nodes.ListComp(node.lineno, node.col_offset, parent)
1844        newnode.postinit(
1845            self.visit(node.elt, newnode),
1846            [self.visit(child, newnode) for child in node.generators],
1847        )
1848        return newnode
1849
1850    def visit_name(
1851        self, node: "ast.Name", parent: NodeNG
1852    ) -> Union[nodes.Name, nodes.AssignName, nodes.DelName]:
1853        """visit a Name node by returning a fresh instance of it"""
1854        context = self._get_context(node)
1855        newnode: Union[nodes.Name, nodes.AssignName, nodes.DelName]
1856        if context == Context.Del:
1857            if sys.version_info >= (3, 8):
1858                newnode = nodes.DelName(
1859                    name=node.id,
1860                    lineno=node.lineno,
1861                    col_offset=node.col_offset,
1862                    end_lineno=node.end_lineno,
1863                    end_col_offset=node.end_col_offset,
1864                    parent=parent,
1865                )
1866            else:
1867                newnode = nodes.DelName(node.id, node.lineno, node.col_offset, parent)
1868        elif context == Context.Store:
1869            if sys.version_info >= (3, 8):
1870                newnode = nodes.AssignName(
1871                    name=node.id,
1872                    lineno=node.lineno,
1873                    col_offset=node.col_offset,
1874                    end_lineno=node.end_lineno,
1875                    end_col_offset=node.end_col_offset,
1876                    parent=parent,
1877                )
1878            else:
1879                newnode = nodes.AssignName(
1880                    node.id, node.lineno, node.col_offset, parent
1881                )
1882        else:
1883            # pylint: disable-next=else-if-used
1884            # Preserve symmetry with other cases
1885            if sys.version_info >= (3, 8):
1886                newnode = nodes.Name(
1887                    name=node.id,
1888                    lineno=node.lineno,
1889                    col_offset=node.col_offset,
1890                    end_lineno=node.end_lineno,
1891                    end_col_offset=node.end_col_offset,
1892                    parent=parent,
1893                )
1894            else:
1895                newnode = nodes.Name(node.id, node.lineno, node.col_offset, parent)
1896        # XXX REMOVE me :
1897        if context in (Context.Del, Context.Store):  # 'Aug' ??
1898            newnode = cast(Union[nodes.AssignName, nodes.DelName], newnode)
1899            self._save_assignment(newnode)
1900        return newnode
1901
1902    # Not used in Python 3.8+.
1903    def visit_nameconstant(
1904        self, node: "ast.NameConstant", parent: NodeNG
1905    ) -> nodes.Const:
1906        # For singleton values True / False / None
1907        return nodes.Const(
1908            node.value,
1909            node.lineno,
1910            node.col_offset,
1911            parent,
1912        )
1913
1914    def visit_nonlocal(self, node: "ast.Nonlocal", parent: NodeNG) -> nodes.Nonlocal:
1915        """visit a Nonlocal node and return a new instance of it"""
1916        if sys.version_info >= (3, 8):
1917            return nodes.Nonlocal(
1918                names=node.names,
1919                lineno=node.lineno,
1920                col_offset=node.col_offset,
1921                end_lineno=node.end_lineno,
1922                end_col_offset=node.end_col_offset,
1923                parent=parent,
1924            )
1925        return nodes.Nonlocal(
1926            node.names,
1927            node.lineno,
1928            node.col_offset,
1929            parent,
1930        )
1931
1932    def visit_constant(self, node: "ast.Constant", parent: NodeNG) -> nodes.Const:
1933        """visit a Constant node by returning a fresh instance of Const"""
1934        if sys.version_info >= (3, 8):
1935            return nodes.Const(
1936                value=node.value,
1937                kind=node.kind,
1938                lineno=node.lineno,
1939                col_offset=node.col_offset,
1940                end_lineno=node.end_lineno,
1941                end_col_offset=node.end_col_offset,
1942                parent=parent,
1943            )
1944        return nodes.Const(
1945            node.value,
1946            node.lineno,
1947            node.col_offset,
1948            parent,
1949            node.kind,
1950        )
1951
1952    # Not used in Python 3.8+.
1953    def visit_str(
1954        self, node: Union["ast.Str", "ast.Bytes"], parent: NodeNG
1955    ) -> nodes.Const:
1956        """visit a String/Bytes node by returning a fresh instance of Const"""
1957        return nodes.Const(
1958            node.s,
1959            node.lineno,
1960            node.col_offset,
1961            parent,
1962        )
1963
1964    # Not used in Python 3.8+
1965    visit_bytes = visit_str
1966
1967    # Not used in Python 3.8+.
1968    def visit_num(self, node: "ast.Num", parent: NodeNG) -> nodes.Const:
1969        """visit a Num node by returning a fresh instance of Const"""
1970        return nodes.Const(
1971            node.n,
1972            node.lineno,
1973            node.col_offset,
1974            parent,
1975        )
1976
1977    def visit_pass(self, node: "ast.Pass", parent: NodeNG) -> nodes.Pass:
1978        """visit a Pass node by returning a fresh instance of it"""
1979        if sys.version_info >= (3, 8):
1980            return nodes.Pass(
1981                lineno=node.lineno,
1982                col_offset=node.col_offset,
1983                end_lineno=node.end_lineno,
1984                end_col_offset=node.end_col_offset,
1985                parent=parent,
1986            )
1987        return nodes.Pass(node.lineno, node.col_offset, parent)
1988
1989    def visit_raise(self, node: "ast.Raise", parent: NodeNG) -> nodes.Raise:
1990        """visit a Raise node by returning a fresh instance of it"""
1991        if sys.version_info >= (3, 8):
1992            newnode = nodes.Raise(
1993                lineno=node.lineno,
1994                col_offset=node.col_offset,
1995                end_lineno=node.end_lineno,
1996                end_col_offset=node.end_col_offset,
1997                parent=parent,
1998            )
1999        else:
2000            newnode = nodes.Raise(node.lineno, node.col_offset, parent)
2001        # no traceback; anyway it is not used in Pylint
2002        newnode.postinit(
2003            exc=self.visit(node.exc, newnode),
2004            cause=self.visit(node.cause, newnode),
2005        )
2006        return newnode
2007
2008    def visit_return(self, node: "ast.Return", parent: NodeNG) -> nodes.Return:
2009        """visit a Return node by returning a fresh instance of it"""
2010        if sys.version_info >= (3, 8):
2011            newnode = nodes.Return(
2012                lineno=node.lineno,
2013                col_offset=node.col_offset,
2014                end_lineno=node.end_lineno,
2015                end_col_offset=node.end_col_offset,
2016                parent=parent,
2017            )
2018        else:
2019            newnode = nodes.Return(node.lineno, node.col_offset, parent)
2020        if node.value is not None:
2021            newnode.postinit(self.visit(node.value, newnode))
2022        return newnode
2023
2024    def visit_set(self, node: "ast.Set", parent: NodeNG) -> nodes.Set:
2025        """visit a Set node by returning a fresh instance of it"""
2026        if sys.version_info >= (3, 8):
2027            newnode = nodes.Set(
2028                lineno=node.lineno,
2029                col_offset=node.col_offset,
2030                end_lineno=node.end_lineno,
2031                end_col_offset=node.end_col_offset,
2032                parent=parent,
2033            )
2034        else:
2035            newnode = nodes.Set(node.lineno, node.col_offset, parent)
2036        newnode.postinit([self.visit(child, newnode) for child in node.elts])
2037        return newnode
2038
2039    def visit_setcomp(self, node: "ast.SetComp", parent: NodeNG) -> nodes.SetComp:
2040        """visit a SetComp node by returning a fresh instance of it"""
2041        if sys.version_info >= (3, 8):
2042            newnode = nodes.SetComp(
2043                lineno=node.lineno,
2044                col_offset=node.col_offset,
2045                end_lineno=node.end_lineno,
2046                end_col_offset=node.end_col_offset,
2047                parent=parent,
2048            )
2049        else:
2050            newnode = nodes.SetComp(node.lineno, node.col_offset, parent)
2051        newnode.postinit(
2052            self.visit(node.elt, newnode),
2053            [self.visit(child, newnode) for child in node.generators],
2054        )
2055        return newnode
2056
2057    def visit_slice(self, node: "ast.Slice", parent: nodes.Subscript) -> nodes.Slice:
2058        """visit a Slice node by returning a fresh instance of it"""
2059        if sys.version_info >= (3, 9):
2060            newnode = nodes.Slice(
2061                lineno=node.lineno,
2062                col_offset=node.col_offset,
2063                end_lineno=node.end_lineno,
2064                end_col_offset=node.end_col_offset,
2065                parent=parent,
2066            )
2067        else:
2068            newnode = nodes.Slice(parent=parent)
2069        newnode.postinit(
2070            lower=self.visit(node.lower, newnode),
2071            upper=self.visit(node.upper, newnode),
2072            step=self.visit(node.step, newnode),
2073        )
2074        return newnode
2075
2076    def visit_subscript(self, node: "ast.Subscript", parent: NodeNG) -> nodes.Subscript:
2077        """visit a Subscript node by returning a fresh instance of it"""
2078        context = self._get_context(node)
2079        if sys.version_info >= (3, 8):
2080            newnode = nodes.Subscript(
2081                ctx=context,
2082                lineno=node.lineno,
2083                col_offset=node.col_offset,
2084                end_lineno=node.end_lineno,
2085                end_col_offset=node.end_col_offset,
2086                parent=parent,
2087            )
2088        else:
2089            newnode = nodes.Subscript(
2090                ctx=context,
2091                lineno=node.lineno,
2092                col_offset=node.col_offset,
2093                parent=parent,
2094            )
2095        newnode.postinit(
2096            self.visit(node.value, newnode), self.visit(node.slice, newnode)
2097        )
2098        return newnode
2099
2100    def visit_starred(self, node: "ast.Starred", parent: NodeNG) -> nodes.Starred:
2101        """visit a Starred node and return a new instance of it"""
2102        context = self._get_context(node)
2103        if sys.version_info >= (3, 8):
2104            newnode = nodes.Starred(
2105                ctx=context,
2106                lineno=node.lineno,
2107                col_offset=node.col_offset,
2108                end_lineno=node.end_lineno,
2109                end_col_offset=node.end_col_offset,
2110                parent=parent,
2111            )
2112        else:
2113            newnode = nodes.Starred(
2114                ctx=context,
2115                lineno=node.lineno,
2116                col_offset=node.col_offset,
2117                parent=parent,
2118            )
2119        newnode.postinit(self.visit(node.value, newnode))
2120        return newnode
2121
2122    def visit_tryexcept(self, node: "ast.Try", parent: NodeNG) -> nodes.TryExcept:
2123        """visit a TryExcept node by returning a fresh instance of it"""
2124        if sys.version_info >= (3, 8):
2125            newnode = nodes.TryExcept(
2126                lineno=node.lineno,
2127                col_offset=node.col_offset,
2128                end_lineno=node.end_lineno,
2129                end_col_offset=node.end_col_offset,
2130                parent=parent,
2131            )
2132        else:
2133            newnode = nodes.TryExcept(node.lineno, node.col_offset, parent)
2134        newnode.postinit(
2135            [self.visit(child, newnode) for child in node.body],
2136            [self.visit(child, newnode) for child in node.handlers],
2137            [self.visit(child, newnode) for child in node.orelse],
2138        )
2139        return newnode
2140
2141    def visit_try(
2142        self, node: "ast.Try", parent: NodeNG
2143    ) -> Union[nodes.TryExcept, nodes.TryFinally, None]:
2144        # python 3.3 introduce a new Try node replacing
2145        # TryFinally/TryExcept nodes
2146        if node.finalbody:
2147            if sys.version_info >= (3, 8):
2148                newnode = nodes.TryFinally(
2149                    lineno=node.lineno,
2150                    col_offset=node.col_offset,
2151                    end_lineno=node.end_lineno,
2152                    end_col_offset=node.end_col_offset,
2153                    parent=parent,
2154                )
2155            else:
2156                newnode = nodes.TryFinally(node.lineno, node.col_offset, parent)
2157            body: Union[List[nodes.TryExcept], List[NodeNG]]
2158            if node.handlers:
2159                body = [self.visit_tryexcept(node, newnode)]
2160            else:
2161                body = [self.visit(child, newnode) for child in node.body]
2162            newnode.postinit(body, [self.visit(n, newnode) for n in node.finalbody])
2163            return newnode
2164        if node.handlers:
2165            return self.visit_tryexcept(node, parent)
2166        return None
2167
2168    def visit_tryfinally(self, node: "ast.Try", parent: NodeNG) -> nodes.TryFinally:
2169        """visit a TryFinally node by returning a fresh instance of it"""
2170        if sys.version_info >= (3, 8):
2171            newnode = nodes.TryFinally(
2172                lineno=node.lineno,
2173                col_offset=node.col_offset,
2174                end_lineno=node.end_lineno,
2175                end_col_offset=node.end_col_offset,
2176                parent=parent,
2177            )
2178        else:
2179            newnode = nodes.TryFinally(node.lineno, node.col_offset, parent)
2180        newnode.postinit(
2181            [self.visit(child, newnode) for child in node.body],
2182            [self.visit(n, newnode) for n in node.finalbody],
2183        )
2184        return newnode
2185
2186    def visit_tuple(self, node: "ast.Tuple", parent: NodeNG) -> nodes.Tuple:
2187        """visit a Tuple node by returning a fresh instance of it"""
2188        context = self._get_context(node)
2189        if sys.version_info >= (3, 8):
2190            newnode = nodes.Tuple(
2191                ctx=context,
2192                lineno=node.lineno,
2193                col_offset=node.col_offset,
2194                end_lineno=node.end_lineno,
2195                end_col_offset=node.end_col_offset,
2196                parent=parent,
2197            )
2198        else:
2199            newnode = nodes.Tuple(
2200                ctx=context,
2201                lineno=node.lineno,
2202                col_offset=node.col_offset,
2203                parent=parent,
2204            )
2205        newnode.postinit([self.visit(child, newnode) for child in node.elts])
2206        return newnode
2207
2208    def visit_unaryop(self, node: "ast.UnaryOp", parent: NodeNG) -> nodes.UnaryOp:
2209        """visit a UnaryOp node by returning a fresh instance of it"""
2210        if sys.version_info >= (3, 8):
2211            newnode = nodes.UnaryOp(
2212                op=self._parser_module.unary_op_classes[node.op.__class__],
2213                lineno=node.lineno,
2214                col_offset=node.col_offset,
2215                end_lineno=node.end_lineno,
2216                end_col_offset=node.end_col_offset,
2217                parent=parent,
2218            )
2219        else:
2220            newnode = nodes.UnaryOp(
2221                self._parser_module.unary_op_classes[node.op.__class__],
2222                node.lineno,
2223                node.col_offset,
2224                parent,
2225            )
2226        newnode.postinit(self.visit(node.operand, newnode))
2227        return newnode
2228
2229    def visit_while(self, node: "ast.While", parent: NodeNG) -> nodes.While:
2230        """visit a While node by returning a fresh instance of it"""
2231        if sys.version_info >= (3, 8):
2232            newnode = nodes.While(
2233                lineno=node.lineno,
2234                col_offset=node.col_offset,
2235                end_lineno=node.end_lineno,
2236                end_col_offset=node.end_col_offset,
2237                parent=parent,
2238            )
2239        else:
2240            newnode = nodes.While(node.lineno, node.col_offset, parent)
2241        newnode.postinit(
2242            self.visit(node.test, newnode),
2243            [self.visit(child, newnode) for child in node.body],
2244            [self.visit(child, newnode) for child in node.orelse],
2245        )
2246        return newnode
2247
2248    @overload
2249    def _visit_with(
2250        self, cls: Type[nodes.With], node: "ast.With", parent: NodeNG
2251    ) -> nodes.With:
2252        ...
2253
2254    @overload
2255    def _visit_with(
2256        self, cls: Type[nodes.AsyncWith], node: "ast.AsyncWith", parent: NodeNG
2257    ) -> nodes.AsyncWith:
2258        ...
2259
2260    def _visit_with(
2261        self,
2262        cls: Type[T_With],
2263        node: Union["ast.With", "ast.AsyncWith"],
2264        parent: NodeNG,
2265    ) -> T_With:
2266        if sys.version_info >= (3, 8):
2267            newnode = cls(
2268                lineno=node.lineno,
2269                col_offset=node.col_offset,
2270                end_lineno=node.end_lineno,
2271                end_col_offset=node.end_col_offset,
2272                parent=parent,
2273            )
2274        else:
2275            newnode = cls(node.lineno, node.col_offset, parent)
2276
2277        def visit_child(child: "ast.withitem") -> Tuple[NodeNG, Optional[NodeNG]]:
2278            expr = self.visit(child.context_expr, newnode)
2279            var = self.visit(child.optional_vars, newnode)
2280            return expr, var
2281
2282        type_annotation = self.check_type_comment(node, parent=newnode)
2283        newnode.postinit(
2284            items=[visit_child(child) for child in node.items],
2285            body=[self.visit(child, newnode) for child in node.body],
2286            type_annotation=type_annotation,
2287        )
2288        return newnode
2289
2290    def visit_with(self, node: "ast.With", parent: NodeNG) -> NodeNG:
2291        return self._visit_with(nodes.With, node, parent)
2292
2293    def visit_yield(self, node: "ast.Yield", parent: NodeNG) -> NodeNG:
2294        """visit a Yield node by returning a fresh instance of it"""
2295        if sys.version_info >= (3, 8):
2296            newnode = nodes.Yield(
2297                lineno=node.lineno,
2298                col_offset=node.col_offset,
2299                end_lineno=node.end_lineno,
2300                end_col_offset=node.end_col_offset,
2301                parent=parent,
2302            )
2303        else:
2304            newnode = nodes.Yield(node.lineno, node.col_offset, parent)
2305        if node.value is not None:
2306            newnode.postinit(self.visit(node.value, newnode))
2307        return newnode
2308
2309    def visit_yieldfrom(self, node: "ast.YieldFrom", parent: NodeNG) -> NodeNG:
2310        if sys.version_info >= (3, 8):
2311            newnode = nodes.YieldFrom(
2312                lineno=node.lineno,
2313                col_offset=node.col_offset,
2314                end_lineno=node.end_lineno,
2315                end_col_offset=node.end_col_offset,
2316                parent=parent,
2317            )
2318        else:
2319            newnode = nodes.YieldFrom(node.lineno, node.col_offset, parent)
2320        if node.value is not None:
2321            newnode.postinit(self.visit(node.value, newnode))
2322        return newnode
2323
2324    if sys.version_info >= (3, 10):
2325
2326        def visit_match(self, node: "ast.Match", parent: NodeNG) -> nodes.Match:
2327            newnode = nodes.Match(
2328                lineno=node.lineno,
2329                col_offset=node.col_offset,
2330                end_lineno=node.end_lineno,
2331                end_col_offset=node.end_col_offset,
2332                parent=parent,
2333            )
2334            newnode.postinit(
2335                subject=self.visit(node.subject, newnode),
2336                cases=[self.visit(case, newnode) for case in node.cases],
2337            )
2338            return newnode
2339
2340        def visit_matchcase(
2341            self, node: "ast.match_case", parent: NodeNG
2342        ) -> nodes.MatchCase:
2343            newnode = nodes.MatchCase(parent=parent)
2344            newnode.postinit(
2345                pattern=self.visit(node.pattern, newnode),
2346                guard=self.visit(node.guard, newnode),
2347                body=[self.visit(child, newnode) for child in node.body],
2348            )
2349            return newnode
2350
2351        def visit_matchvalue(
2352            self, node: "ast.MatchValue", parent: NodeNG
2353        ) -> nodes.MatchValue:
2354            newnode = nodes.MatchValue(
2355                lineno=node.lineno,
2356                col_offset=node.col_offset,
2357                end_lineno=node.end_lineno,
2358                end_col_offset=node.end_col_offset,
2359                parent=parent,
2360            )
2361            newnode.postinit(value=self.visit(node.value, newnode))
2362            return newnode
2363
2364        def visit_matchsingleton(
2365            self, node: "ast.MatchSingleton", parent: NodeNG
2366        ) -> nodes.MatchSingleton:
2367            return nodes.MatchSingleton(
2368                value=node.value,
2369                lineno=node.lineno,
2370                col_offset=node.col_offset,
2371                end_lineno=node.end_lineno,
2372                end_col_offset=node.end_col_offset,
2373                parent=parent,
2374            )
2375
2376        def visit_matchsequence(
2377            self, node: "ast.MatchSequence", parent: NodeNG
2378        ) -> nodes.MatchSequence:
2379            newnode = nodes.MatchSequence(
2380                lineno=node.lineno,
2381                col_offset=node.col_offset,
2382                end_lineno=node.end_lineno,
2383                end_col_offset=node.end_col_offset,
2384                parent=parent,
2385            )
2386            newnode.postinit(
2387                patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
2388            )
2389            return newnode
2390
2391        def visit_matchmapping(
2392            self, node: "ast.MatchMapping", parent: NodeNG
2393        ) -> nodes.MatchMapping:
2394            newnode = nodes.MatchMapping(
2395                lineno=node.lineno,
2396                col_offset=node.col_offset,
2397                end_lineno=node.end_lineno,
2398                end_col_offset=node.end_col_offset,
2399                parent=parent,
2400            )
2401            # Add AssignName node for 'node.name'
2402            # https://bugs.python.org/issue43994
2403            newnode.postinit(
2404                keys=[self.visit(child, newnode) for child in node.keys],
2405                patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
2406                rest=self.visit_assignname(node, newnode, node.rest),
2407            )
2408            return newnode
2409
2410        def visit_matchclass(
2411            self, node: "ast.MatchClass", parent: NodeNG
2412        ) -> nodes.MatchClass:
2413            newnode = nodes.MatchClass(
2414                lineno=node.lineno,
2415                col_offset=node.col_offset,
2416                end_lineno=node.end_lineno,
2417                end_col_offset=node.end_col_offset,
2418                parent=parent,
2419            )
2420            newnode.postinit(
2421                cls=self.visit(node.cls, newnode),
2422                patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
2423                kwd_attrs=node.kwd_attrs,
2424                kwd_patterns=[
2425                    self.visit(pattern, newnode) for pattern in node.kwd_patterns
2426                ],
2427            )
2428            return newnode
2429
2430        def visit_matchstar(
2431            self, node: "ast.MatchStar", parent: NodeNG
2432        ) -> nodes.MatchStar:
2433            newnode = nodes.MatchStar(
2434                lineno=node.lineno,
2435                col_offset=node.col_offset,
2436                end_lineno=node.end_lineno,
2437                end_col_offset=node.end_col_offset,
2438                parent=parent,
2439            )
2440            # Add AssignName node for 'node.name'
2441            # https://bugs.python.org/issue43994
2442            newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
2443            return newnode
2444
2445        def visit_matchas(self, node: "ast.MatchAs", parent: NodeNG) -> nodes.MatchAs:
2446            newnode = nodes.MatchAs(
2447                lineno=node.lineno,
2448                col_offset=node.col_offset,
2449                end_lineno=node.end_lineno,
2450                end_col_offset=node.end_col_offset,
2451                parent=parent,
2452            )
2453            # Add AssignName node for 'node.name'
2454            # https://bugs.python.org/issue43994
2455            newnode.postinit(
2456                pattern=self.visit(node.pattern, newnode),
2457                name=self.visit_assignname(node, newnode, node.name),
2458            )
2459            return newnode
2460
2461        def visit_matchor(self, node: "ast.MatchOr", parent: NodeNG) -> nodes.MatchOr:
2462            newnode = nodes.MatchOr(
2463                lineno=node.lineno,
2464                col_offset=node.col_offset,
2465                end_lineno=node.end_lineno,
2466                end_col_offset=node.end_col_offset,
2467                parent=parent,
2468            )
2469            newnode.postinit(
2470                patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
2471            )
2472            return newnode
2473