rebuilder.py 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996
  1. # Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
  2. # For details: https://github.com/pylint-dev/astroid/blob/main/LICENSE
  3. # Copyright (c) https://github.com/pylint-dev/astroid/blob/main/CONTRIBUTORS.txt
  4. """This module contains utilities for rebuilding an _ast tree in
  5. order to get a single Astroid representation.
  6. """
  7. from __future__ import annotations
  8. import ast
  9. import sys
  10. import token
  11. from collections.abc import Callable, Collection, Generator
  12. from io import StringIO
  13. from tokenize import TokenInfo, generate_tokens
  14. from typing import TYPE_CHECKING, Final, TypeVar, cast, overload
  15. from astroid import nodes
  16. from astroid._ast import ParserModule, get_parser_module, parse_function_type_comment
  17. from astroid.const import PY312_PLUS, PY313_PLUS, Context
  18. from astroid.nodes.utils import Position
  19. from astroid.typing import InferenceResult
  20. if TYPE_CHECKING:
  21. from astroid.manager import AstroidManager
  22. T_Doc = TypeVar(
  23. "T_Doc",
  24. ast.Module,
  25. ast.ClassDef,
  26. ast.FunctionDef | ast.AsyncFunctionDef,
  27. )
  28. _FunctionT = TypeVar("_FunctionT", nodes.FunctionDef, nodes.AsyncFunctionDef)
  29. _ForT = TypeVar("_ForT", nodes.For, nodes.AsyncFor)
  30. _WithT = TypeVar("_WithT", nodes.With, nodes.AsyncWith)
  31. NodesWithDocsType = nodes.Module | nodes.ClassDef | nodes.FunctionDef
  32. REDIRECT: Final[dict[str, str]] = {
  33. "arguments": "Arguments",
  34. "comprehension": "Comprehension",
  35. "ListCompFor": "Comprehension",
  36. "GenExprFor": "Comprehension",
  37. "excepthandler": "ExceptHandler",
  38. "keyword": "Keyword",
  39. "match_case": "MatchCase",
  40. }
  41. # noinspection PyMethodMayBeStatic
  42. class TreeRebuilder:
  43. """Rebuilds the _ast tree to become an Astroid tree."""
  44. def __init__(
  45. self,
  46. manager: AstroidManager,
  47. parser_module: ParserModule | None = None,
  48. data: str | None = None,
  49. ) -> None:
  50. self._manager = manager
  51. self._data = data.split("\n") if data else None
  52. self._global_names: list[dict[str, list[nodes.Global]]] = []
  53. self._import_from_nodes: list[tuple[nodes.ImportFrom, Collection[str]]] = []
  54. self._delayed_assattr: list[nodes.AssignAttr] = []
  55. self._visit_meths: dict[
  56. type[ast.AST], Callable[[ast.AST, nodes.NodeNG], nodes.NodeNG]
  57. ] = {}
  58. if parser_module is None:
  59. self._parser_module = get_parser_module()
  60. else:
  61. self._parser_module = parser_module
  62. def _get_doc(self, node: T_Doc) -> tuple[T_Doc, ast.Constant | None]:
  63. """Return the doc ast node."""
  64. try:
  65. if node.body and isinstance(node.body[0], ast.Expr):
  66. first_value = node.body[0].value
  67. if isinstance(first_value, ast.Constant) and isinstance(
  68. first_value.value, str
  69. ):
  70. doc_ast_node = first_value
  71. node.body = node.body[1:]
  72. return node, doc_ast_node
  73. except IndexError:
  74. pass # ast built from scratch
  75. return node, None
  76. def _get_context(
  77. self,
  78. node: (
  79. ast.Attribute
  80. | ast.List
  81. | ast.Name
  82. | ast.Subscript
  83. | ast.Starred
  84. | ast.Tuple
  85. ),
  86. ) -> Context:
  87. return self._parser_module.context_classes.get(type(node.ctx), Context.Load)
  88. def _get_position_info(
  89. self,
  90. node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef,
  91. parent: nodes.ClassDef | nodes.FunctionDef | nodes.AsyncFunctionDef,
  92. ) -> Position | None:
  93. """Return position information for ClassDef and FunctionDef nodes.
  94. In contrast to AST positions, these only include the actual keyword(s)
  95. and the class / function name.
  96. >>> @decorator
  97. >>> async def some_func(var: int) -> None:
  98. >>> ^^^^^^^^^^^^^^^^^^^
  99. """
  100. if not self._data:
  101. return None
  102. end_lineno = node.end_lineno
  103. if node.body:
  104. end_lineno = node.body[0].lineno
  105. # pylint: disable-next=unsubscriptable-object
  106. data = "\n".join(self._data[node.lineno - 1 : end_lineno])
  107. start_token: TokenInfo | None = None
  108. keyword_tokens: tuple[int, ...] = (token.NAME,)
  109. if isinstance(parent, nodes.AsyncFunctionDef):
  110. search_token = "async"
  111. elif isinstance(parent, nodes.FunctionDef):
  112. search_token = "def"
  113. else:
  114. search_token = "class"
  115. for t in generate_tokens(StringIO(data).readline):
  116. if (
  117. start_token is not None
  118. and t.type == token.NAME
  119. and t.string == node.name
  120. ):
  121. break
  122. if t.type in keyword_tokens:
  123. if t.string == search_token:
  124. start_token = t
  125. continue
  126. if t.string in {"def"}:
  127. continue
  128. start_token = None
  129. else:
  130. return None
  131. return Position(
  132. lineno=node.lineno + start_token.start[0] - 1,
  133. col_offset=start_token.start[1],
  134. end_lineno=node.lineno + t.end[0] - 1,
  135. end_col_offset=t.end[1],
  136. )
  137. def visit_module(
  138. self, node: ast.Module, modname: str, modpath: str, package: bool
  139. ) -> nodes.Module:
  140. """Visit a Module node by returning a fresh instance of it.
  141. Note: Method not called by 'visit'
  142. """
  143. node, doc_ast_node = self._get_doc(node)
  144. newnode = nodes.Module(
  145. name=modname,
  146. file=modpath,
  147. path=[modpath],
  148. package=package,
  149. )
  150. newnode.postinit(
  151. [self.visit(child, newnode) for child in node.body],
  152. doc_node=self.visit(doc_ast_node, newnode),
  153. )
  154. return newnode
  155. if TYPE_CHECKING: # noqa: C901
  156. @overload
  157. def visit(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName: ...
  158. @overload
  159. def visit(
  160. self, node: ast.arguments, parent: nodes.NodeNG
  161. ) -> nodes.Arguments: ...
  162. @overload
  163. def visit(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert: ...
  164. @overload
  165. def visit(
  166. self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
  167. ) -> nodes.AsyncFunctionDef: ...
  168. @overload
  169. def visit(self, node: ast.AsyncFor, parent: nodes.NodeNG) -> nodes.AsyncFor: ...
  170. @overload
  171. def visit(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await: ...
  172. @overload
  173. def visit(
  174. self, node: ast.AsyncWith, parent: nodes.NodeNG
  175. ) -> nodes.AsyncWith: ...
  176. @overload
  177. def visit(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign: ...
  178. @overload
  179. def visit(
  180. self, node: ast.AnnAssign, parent: nodes.NodeNG
  181. ) -> nodes.AnnAssign: ...
  182. @overload
  183. def visit(
  184. self, node: ast.AugAssign, parent: nodes.NodeNG
  185. ) -> nodes.AugAssign: ...
  186. @overload
  187. def visit(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp: ...
  188. @overload
  189. def visit(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp: ...
  190. @overload
  191. def visit(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break: ...
  192. @overload
  193. def visit(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call: ...
  194. @overload
  195. def visit(self, node: ast.ClassDef, parent: nodes.NodeNG) -> nodes.ClassDef: ...
  196. @overload
  197. def visit(self, node: ast.Continue, parent: nodes.NodeNG) -> nodes.Continue: ...
  198. @overload
  199. def visit(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare: ...
  200. @overload
  201. def visit(
  202. self, node: ast.comprehension, parent: nodes.NodeNG
  203. ) -> nodes.Comprehension: ...
  204. @overload
  205. def visit(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete: ...
  206. @overload
  207. def visit(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict: ...
  208. @overload
  209. def visit(self, node: ast.DictComp, parent: nodes.NodeNG) -> nodes.DictComp: ...
  210. @overload
  211. def visit(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr: ...
  212. @overload
  213. def visit(
  214. self, node: ast.ExceptHandler, parent: nodes.NodeNG
  215. ) -> nodes.ExceptHandler: ...
  216. @overload
  217. def visit(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For: ...
  218. @overload
  219. def visit(
  220. self, node: ast.ImportFrom, parent: nodes.NodeNG
  221. ) -> nodes.ImportFrom: ...
  222. @overload
  223. def visit(
  224. self, node: ast.FunctionDef, parent: nodes.NodeNG
  225. ) -> nodes.FunctionDef: ...
  226. @overload
  227. def visit(
  228. self, node: ast.GeneratorExp, parent: nodes.NodeNG
  229. ) -> nodes.GeneratorExp: ...
  230. @overload
  231. def visit(
  232. self, node: ast.Attribute, parent: nodes.NodeNG
  233. ) -> nodes.Attribute: ...
  234. @overload
  235. def visit(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global: ...
  236. @overload
  237. def visit(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If: ...
  238. @overload
  239. def visit(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp: ...
  240. @overload
  241. def visit(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import: ...
  242. @overload
  243. def visit(
  244. self, node: ast.JoinedStr, parent: nodes.NodeNG
  245. ) -> nodes.JoinedStr: ...
  246. @overload
  247. def visit(
  248. self, node: ast.FormattedValue, parent: nodes.NodeNG
  249. ) -> nodes.FormattedValue: ...
  250. @overload
  251. def visit(
  252. self, node: ast.NamedExpr, parent: nodes.NodeNG
  253. ) -> nodes.NamedExpr: ...
  254. @overload
  255. def visit(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword: ...
  256. @overload
  257. def visit(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda: ...
  258. @overload
  259. def visit(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List: ...
  260. @overload
  261. def visit(self, node: ast.ListComp, parent: nodes.NodeNG) -> nodes.ListComp: ...
  262. @overload
  263. def visit(
  264. self, node: ast.Name, parent: nodes.NodeNG
  265. ) -> nodes.Name | nodes.Const | nodes.AssignName | nodes.DelName: ...
  266. @overload
  267. def visit(self, node: ast.Nonlocal, parent: nodes.NodeNG) -> nodes.Nonlocal: ...
  268. @overload
  269. def visit(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const: ...
  270. if sys.version_info >= (3, 12):
  271. @overload
  272. def visit(
  273. self, node: ast.ParamSpec, parent: nodes.NodeNG
  274. ) -> nodes.ParamSpec: ...
  275. @overload
  276. def visit(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass: ...
  277. @overload
  278. def visit(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise: ...
  279. @overload
  280. def visit(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return: ...
  281. @overload
  282. def visit(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set: ...
  283. @overload
  284. def visit(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp: ...
  285. @overload
  286. def visit(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice: ...
  287. @overload
  288. def visit(
  289. self, node: ast.Subscript, parent: nodes.NodeNG
  290. ) -> nodes.Subscript: ...
  291. @overload
  292. def visit(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred: ...
  293. @overload
  294. def visit(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try: ...
  295. if sys.version_info >= (3, 11):
  296. @overload
  297. def visit(
  298. self, node: ast.TryStar, parent: nodes.NodeNG
  299. ) -> nodes.TryStar: ...
  300. @overload
  301. def visit(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple: ...
  302. if sys.version_info >= (3, 12):
  303. @overload
  304. def visit(
  305. self, node: ast.TypeAlias, parent: nodes.NodeNG
  306. ) -> nodes.TypeAlias: ...
  307. @overload
  308. def visit(
  309. self, node: ast.TypeVar, parent: nodes.NodeNG
  310. ) -> nodes.TypeVar: ...
  311. @overload
  312. def visit(
  313. self, node: ast.TypeVarTuple, parent: nodes.NodeNG
  314. ) -> nodes.TypeVarTuple: ...
  315. @overload
  316. def visit(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp: ...
  317. @overload
  318. def visit(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While: ...
  319. @overload
  320. def visit(self, node: ast.With, parent: nodes.NodeNG) -> nodes.With: ...
  321. @overload
  322. def visit(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.Yield: ...
  323. @overload
  324. def visit(
  325. self, node: ast.YieldFrom, parent: nodes.NodeNG
  326. ) -> nodes.YieldFrom: ...
  327. @overload
  328. def visit(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match: ...
  329. @overload
  330. def visit(
  331. self, node: ast.match_case, parent: nodes.NodeNG
  332. ) -> nodes.MatchCase: ...
  333. @overload
  334. def visit(
  335. self, node: ast.MatchValue, parent: nodes.NodeNG
  336. ) -> nodes.MatchValue: ...
  337. @overload
  338. def visit(
  339. self, node: ast.MatchSingleton, parent: nodes.NodeNG
  340. ) -> nodes.MatchSingleton: ...
  341. @overload
  342. def visit(
  343. self, node: ast.MatchSequence, parent: nodes.NodeNG
  344. ) -> nodes.MatchSequence: ...
  345. @overload
  346. def visit(
  347. self, node: ast.MatchMapping, parent: nodes.NodeNG
  348. ) -> nodes.MatchMapping: ...
  349. @overload
  350. def visit(
  351. self, node: ast.MatchClass, parent: nodes.NodeNG
  352. ) -> nodes.MatchClass: ...
  353. @overload
  354. def visit(
  355. self, node: ast.MatchStar, parent: nodes.NodeNG
  356. ) -> nodes.MatchStar: ...
  357. @overload
  358. def visit(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs: ...
  359. @overload
  360. def visit(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr: ...
  361. @overload
  362. def visit(self, node: ast.pattern, parent: nodes.NodeNG) -> nodes.Pattern: ...
  363. if sys.version_info >= (3, 14):
  364. @overload
  365. def visit(
  366. self, node: ast.TemplateStr, parent: nodes.NodeNG
  367. ) -> nodes.TemplateStr: ...
  368. @overload
  369. def visit(
  370. self, node: ast.Interpolation, parent: nodes.NodeNG
  371. ) -> nodes.Interpolation: ...
  372. @overload
  373. def visit(self, node: ast.AST, parent: nodes.NodeNG) -> nodes.NodeNG: ...
  374. @overload
  375. def visit(self, node: None, parent: nodes.NodeNG) -> None: ...
  376. def visit(self, node: ast.AST | None, parent: nodes.NodeNG) -> nodes.NodeNG | None:
  377. if node is None:
  378. return None
  379. cls = node.__class__
  380. if cls in self._visit_meths:
  381. visit_method = self._visit_meths[cls]
  382. else:
  383. cls_name = cls.__name__
  384. visit_name = "visit_" + REDIRECT.get(cls_name, cls_name).lower()
  385. visit_method = getattr(self, visit_name)
  386. self._visit_meths[cls] = visit_method
  387. return visit_method(node, parent)
  388. def _save_assignment(self, node: nodes.AssignName | nodes.DelName) -> None:
  389. """Save assignment situation since node.parent is not available yet."""
  390. if self._global_names and node.name in self._global_names[-1]:
  391. node.root().set_local(node.name, node)
  392. else:
  393. assert node.parent
  394. assert node.name
  395. node.parent.set_local(node.name, node)
  396. def visit_arg(self, node: ast.arg, parent: nodes.NodeNG) -> nodes.AssignName:
  397. """Visit an arg node by returning a fresh AssignName instance."""
  398. return self.visit_assignname(node, parent, node.arg)
  399. def visit_arguments(
  400. self, node: ast.arguments, parent: nodes.NodeNG
  401. ) -> nodes.Arguments:
  402. """Visit an Arguments node by returning a fresh instance of it."""
  403. vararg: str | None = None
  404. kwarg: str | None = None
  405. vararg_node = node.vararg
  406. kwarg_node = node.kwarg
  407. newnode = nodes.Arguments(
  408. node.vararg.arg if node.vararg else None,
  409. node.kwarg.arg if node.kwarg else None,
  410. parent,
  411. (
  412. nodes.AssignName(
  413. vararg_node.arg,
  414. vararg_node.lineno,
  415. vararg_node.col_offset,
  416. parent,
  417. end_lineno=vararg_node.end_lineno,
  418. end_col_offset=vararg_node.end_col_offset,
  419. )
  420. if vararg_node
  421. else None
  422. ),
  423. (
  424. nodes.AssignName(
  425. kwarg_node.arg,
  426. kwarg_node.lineno,
  427. kwarg_node.col_offset,
  428. parent,
  429. end_lineno=kwarg_node.end_lineno,
  430. end_col_offset=kwarg_node.end_col_offset,
  431. )
  432. if kwarg_node
  433. else None
  434. ),
  435. )
  436. args = [self.visit(child, newnode) for child in node.args]
  437. defaults = [self.visit(child, newnode) for child in node.defaults]
  438. varargannotation: nodes.NodeNG | None = None
  439. kwargannotation: nodes.NodeNG | None = None
  440. if node.vararg:
  441. vararg = node.vararg.arg
  442. varargannotation = self.visit(node.vararg.annotation, newnode)
  443. if node.kwarg:
  444. kwarg = node.kwarg.arg
  445. kwargannotation = self.visit(node.kwarg.annotation, newnode)
  446. kwonlyargs = [self.visit(child, newnode) for child in node.kwonlyargs]
  447. kw_defaults = [self.visit(child, newnode) for child in node.kw_defaults]
  448. annotations = [self.visit(arg.annotation, newnode) for arg in node.args]
  449. kwonlyargs_annotations = [
  450. self.visit(arg.annotation, newnode) for arg in node.kwonlyargs
  451. ]
  452. posonlyargs = [self.visit(child, newnode) for child in node.posonlyargs]
  453. posonlyargs_annotations = [
  454. self.visit(arg.annotation, newnode) for arg in node.posonlyargs
  455. ]
  456. type_comment_args = [
  457. self.check_type_comment(child, parent=newnode) for child in node.args
  458. ]
  459. type_comment_kwonlyargs = [
  460. self.check_type_comment(child, parent=newnode) for child in node.kwonlyargs
  461. ]
  462. type_comment_posonlyargs = [
  463. self.check_type_comment(child, parent=newnode) for child in node.posonlyargs
  464. ]
  465. newnode.postinit(
  466. args=args,
  467. defaults=defaults,
  468. kwonlyargs=kwonlyargs,
  469. posonlyargs=posonlyargs,
  470. kw_defaults=kw_defaults,
  471. annotations=annotations,
  472. kwonlyargs_annotations=kwonlyargs_annotations,
  473. posonlyargs_annotations=posonlyargs_annotations,
  474. varargannotation=varargannotation,
  475. kwargannotation=kwargannotation,
  476. type_comment_args=type_comment_args,
  477. type_comment_kwonlyargs=type_comment_kwonlyargs,
  478. type_comment_posonlyargs=type_comment_posonlyargs,
  479. )
  480. # save argument names in locals:
  481. assert newnode.parent
  482. if vararg:
  483. newnode.parent.set_local(vararg, newnode)
  484. if kwarg:
  485. newnode.parent.set_local(kwarg, newnode)
  486. return newnode
  487. def visit_assert(self, node: ast.Assert, parent: nodes.NodeNG) -> nodes.Assert:
  488. """Visit a Assert node by returning a fresh instance of it."""
  489. newnode = nodes.Assert(
  490. lineno=node.lineno,
  491. col_offset=node.col_offset,
  492. end_lineno=node.end_lineno,
  493. end_col_offset=node.end_col_offset,
  494. parent=parent,
  495. )
  496. msg: nodes.NodeNG | None = None
  497. if node.msg:
  498. msg = self.visit(node.msg, newnode)
  499. newnode.postinit(self.visit(node.test, newnode), msg)
  500. return newnode
  501. def check_type_comment(
  502. self,
  503. node: ast.Assign | ast.arg | ast.For | ast.AsyncFor | ast.With | ast.AsyncWith,
  504. parent: (
  505. nodes.Assign
  506. | nodes.Arguments
  507. | nodes.For
  508. | nodes.AsyncFor
  509. | nodes.With
  510. | nodes.AsyncWith
  511. ),
  512. ) -> nodes.NodeNG | None:
  513. if not node.type_comment:
  514. return None
  515. try:
  516. type_comment_ast = self._parser_module.parse(node.type_comment)
  517. except SyntaxError:
  518. # Invalid type comment, just skip it.
  519. return None
  520. # For '# type: # any comment' ast.parse returns a Module node,
  521. # without any nodes in the body.
  522. if not type_comment_ast.body:
  523. return None
  524. type_object = self.visit(type_comment_ast.body[0], parent=parent)
  525. if not isinstance(type_object, nodes.Expr):
  526. return None
  527. return type_object.value
  528. def check_function_type_comment(
  529. self, node: ast.FunctionDef | ast.AsyncFunctionDef, parent: nodes.NodeNG
  530. ) -> tuple[nodes.NodeNG | None, list[nodes.NodeNG]] | None:
  531. if not node.type_comment:
  532. return None
  533. try:
  534. type_comment_ast = parse_function_type_comment(node.type_comment)
  535. except SyntaxError:
  536. # Invalid type comment, just skip it.
  537. return None
  538. if not type_comment_ast:
  539. return None
  540. returns: nodes.NodeNG | None = None
  541. argtypes: list[nodes.NodeNG] = [
  542. self.visit(elem, parent) for elem in (type_comment_ast.argtypes or [])
  543. ]
  544. if type_comment_ast.returns:
  545. returns = self.visit(type_comment_ast.returns, parent)
  546. return returns, argtypes
  547. def visit_asyncfunctiondef(
  548. self, node: ast.AsyncFunctionDef, parent: nodes.NodeNG
  549. ) -> nodes.AsyncFunctionDef:
  550. return self._visit_functiondef(nodes.AsyncFunctionDef, node, parent)
  551. def visit_asyncfor(
  552. self, node: ast.AsyncFor, parent: nodes.NodeNG
  553. ) -> nodes.AsyncFor:
  554. return self._visit_for(nodes.AsyncFor, node, parent)
  555. def visit_await(self, node: ast.Await, parent: nodes.NodeNG) -> nodes.Await:
  556. newnode = nodes.Await(
  557. lineno=node.lineno,
  558. col_offset=node.col_offset,
  559. end_lineno=node.end_lineno,
  560. end_col_offset=node.end_col_offset,
  561. parent=parent,
  562. )
  563. newnode.postinit(value=self.visit(node.value, newnode))
  564. return newnode
  565. def visit_asyncwith(
  566. self, node: ast.AsyncWith, parent: nodes.NodeNG
  567. ) -> nodes.AsyncWith:
  568. return self._visit_with(nodes.AsyncWith, node, parent)
  569. def visit_assign(self, node: ast.Assign, parent: nodes.NodeNG) -> nodes.Assign:
  570. """Visit a Assign node by returning a fresh instance of it."""
  571. newnode = nodes.Assign(
  572. lineno=node.lineno,
  573. col_offset=node.col_offset,
  574. end_lineno=node.end_lineno,
  575. end_col_offset=node.end_col_offset,
  576. parent=parent,
  577. )
  578. type_annotation = self.check_type_comment(node, parent=newnode)
  579. newnode.postinit(
  580. targets=[self.visit(child, newnode) for child in node.targets],
  581. value=self.visit(node.value, newnode),
  582. type_annotation=type_annotation,
  583. )
  584. return newnode
  585. def visit_annassign(
  586. self, node: ast.AnnAssign, parent: nodes.NodeNG
  587. ) -> nodes.AnnAssign:
  588. """Visit an AnnAssign node by returning a fresh instance of it."""
  589. newnode = nodes.AnnAssign(
  590. lineno=node.lineno,
  591. col_offset=node.col_offset,
  592. end_lineno=node.end_lineno,
  593. end_col_offset=node.end_col_offset,
  594. parent=parent,
  595. )
  596. newnode.postinit(
  597. target=self.visit(node.target, newnode),
  598. annotation=self.visit(node.annotation, newnode),
  599. simple=node.simple,
  600. value=self.visit(node.value, newnode),
  601. )
  602. return newnode
  603. @overload
  604. def visit_assignname(
  605. self, node: ast.AST, parent: nodes.NodeNG, node_name: str
  606. ) -> nodes.AssignName: ...
  607. @overload
  608. def visit_assignname(
  609. self, node: ast.AST, parent: nodes.NodeNG, node_name: None
  610. ) -> None: ...
  611. def visit_assignname(
  612. self, node: ast.AST, parent: nodes.NodeNG, node_name: str | None
  613. ) -> nodes.AssignName | None:
  614. """Visit a node and return a AssignName node.
  615. Note: Method not called by 'visit'
  616. """
  617. if node_name is None:
  618. return None
  619. newnode = nodes.AssignName(
  620. name=node_name,
  621. lineno=node.lineno,
  622. col_offset=node.col_offset,
  623. end_lineno=node.end_lineno,
  624. end_col_offset=node.end_col_offset,
  625. parent=parent,
  626. )
  627. self._save_assignment(newnode)
  628. return newnode
  629. def visit_augassign(
  630. self, node: ast.AugAssign, parent: nodes.NodeNG
  631. ) -> nodes.AugAssign:
  632. """Visit a AugAssign node by returning a fresh instance of it."""
  633. newnode = nodes.AugAssign(
  634. op=self._parser_module.bin_op_classes[type(node.op)] + "=",
  635. lineno=node.lineno,
  636. col_offset=node.col_offset,
  637. end_lineno=node.end_lineno,
  638. end_col_offset=node.end_col_offset,
  639. parent=parent,
  640. )
  641. newnode.postinit(
  642. self.visit(node.target, newnode), self.visit(node.value, newnode)
  643. )
  644. return newnode
  645. def visit_binop(self, node: ast.BinOp, parent: nodes.NodeNG) -> nodes.BinOp:
  646. """Visit a BinOp node by returning a fresh instance of it."""
  647. newnode = nodes.BinOp(
  648. op=self._parser_module.bin_op_classes[type(node.op)],
  649. lineno=node.lineno,
  650. col_offset=node.col_offset,
  651. end_lineno=node.end_lineno,
  652. end_col_offset=node.end_col_offset,
  653. parent=parent,
  654. )
  655. newnode.postinit(
  656. self.visit(node.left, newnode), self.visit(node.right, newnode)
  657. )
  658. return newnode
  659. def visit_boolop(self, node: ast.BoolOp, parent: nodes.NodeNG) -> nodes.BoolOp:
  660. """Visit a BoolOp node by returning a fresh instance of it."""
  661. newnode = nodes.BoolOp(
  662. op=self._parser_module.bool_op_classes[type(node.op)],
  663. lineno=node.lineno,
  664. col_offset=node.col_offset,
  665. end_lineno=node.end_lineno,
  666. end_col_offset=node.end_col_offset,
  667. parent=parent,
  668. )
  669. newnode.postinit([self.visit(child, newnode) for child in node.values])
  670. return newnode
  671. def visit_break(self, node: ast.Break, parent: nodes.NodeNG) -> nodes.Break:
  672. """Visit a Break node by returning a fresh instance of it."""
  673. return nodes.Break(
  674. lineno=node.lineno,
  675. col_offset=node.col_offset,
  676. end_lineno=node.end_lineno,
  677. end_col_offset=node.end_col_offset,
  678. parent=parent,
  679. )
  680. def visit_call(self, node: ast.Call, parent: nodes.NodeNG) -> nodes.Call:
  681. """Visit a CallFunc node by returning a fresh instance of it."""
  682. newnode = nodes.Call(
  683. lineno=node.lineno,
  684. col_offset=node.col_offset,
  685. end_lineno=node.end_lineno,
  686. end_col_offset=node.end_col_offset,
  687. parent=parent,
  688. )
  689. newnode.postinit(
  690. func=self.visit(node.func, newnode),
  691. args=[self.visit(child, newnode) for child in node.args],
  692. keywords=[self.visit(child, newnode) for child in node.keywords],
  693. )
  694. return newnode
  695. def visit_classdef(
  696. self, node: ast.ClassDef, parent: nodes.NodeNG, newstyle: bool = True
  697. ) -> nodes.ClassDef:
  698. """Visit a ClassDef node to become astroid."""
  699. node, doc_ast_node = self._get_doc(node)
  700. newnode = nodes.ClassDef(
  701. name=node.name,
  702. lineno=node.lineno,
  703. col_offset=node.col_offset,
  704. end_lineno=node.end_lineno,
  705. end_col_offset=node.end_col_offset,
  706. parent=parent,
  707. )
  708. metaclass = None
  709. for keyword in node.keywords:
  710. if keyword.arg == "metaclass":
  711. metaclass = self.visit(keyword, newnode).value
  712. break
  713. decorators = self.visit_decorators(node, newnode)
  714. newnode.postinit(
  715. [self.visit(child, newnode) for child in node.bases],
  716. [self.visit(child, newnode) for child in node.body],
  717. decorators,
  718. newstyle,
  719. metaclass,
  720. [
  721. self.visit(kwd, newnode)
  722. for kwd in node.keywords
  723. if kwd.arg != "metaclass"
  724. ],
  725. position=self._get_position_info(node, newnode),
  726. doc_node=self.visit(doc_ast_node, newnode),
  727. type_params=(
  728. [self.visit(param, newnode) for param in node.type_params]
  729. if PY312_PLUS
  730. else []
  731. ),
  732. )
  733. parent.set_local(newnode.name, newnode)
  734. return newnode
  735. def visit_continue(
  736. self, node: ast.Continue, parent: nodes.NodeNG
  737. ) -> nodes.Continue:
  738. """Visit a Continue node by returning a fresh instance of it."""
  739. return nodes.Continue(
  740. lineno=node.lineno,
  741. col_offset=node.col_offset,
  742. end_lineno=node.end_lineno,
  743. end_col_offset=node.end_col_offset,
  744. parent=parent,
  745. )
  746. def visit_compare(self, node: ast.Compare, parent: nodes.NodeNG) -> nodes.Compare:
  747. """Visit a Compare node by returning a fresh instance of it."""
  748. newnode = nodes.Compare(
  749. lineno=node.lineno,
  750. col_offset=node.col_offset,
  751. end_lineno=node.end_lineno,
  752. end_col_offset=node.end_col_offset,
  753. parent=parent,
  754. )
  755. newnode.postinit(
  756. self.visit(node.left, newnode),
  757. [
  758. (
  759. self._parser_module.cmp_op_classes[op.__class__],
  760. self.visit(expr, newnode),
  761. )
  762. for (op, expr) in zip(node.ops, node.comparators)
  763. ],
  764. )
  765. return newnode
  766. def visit_comprehension(
  767. self, node: ast.comprehension, parent: nodes.NodeNG
  768. ) -> nodes.Comprehension:
  769. """Visit a Comprehension node by returning a fresh instance of it."""
  770. newnode = nodes.Comprehension(
  771. parent=parent,
  772. # Comprehension nodes don't have these attributes
  773. # see https://docs.python.org/3/library/ast.html#abstract-grammar
  774. lineno=None,
  775. col_offset=None,
  776. end_lineno=None,
  777. end_col_offset=None,
  778. )
  779. newnode.postinit(
  780. self.visit(node.target, newnode),
  781. self.visit(node.iter, newnode),
  782. [self.visit(child, newnode) for child in node.ifs],
  783. bool(node.is_async),
  784. )
  785. return newnode
  786. def visit_decorators(
  787. self,
  788. node: ast.ClassDef | ast.FunctionDef | ast.AsyncFunctionDef,
  789. parent: nodes.NodeNG,
  790. ) -> nodes.Decorators | None:
  791. """Visit a Decorators node by returning a fresh instance of it.
  792. Note: Method not called by 'visit'
  793. """
  794. if not node.decorator_list:
  795. return None
  796. # /!\ node is actually an _ast.FunctionDef node while
  797. # parent is an astroid.nodes.FunctionDef node
  798. # Set the line number of the first decorator for Python 3.8+.
  799. lineno = node.decorator_list[0].lineno
  800. end_lineno = node.decorator_list[-1].end_lineno
  801. end_col_offset = node.decorator_list[-1].end_col_offset
  802. newnode = nodes.Decorators(
  803. lineno=lineno,
  804. col_offset=node.col_offset,
  805. end_lineno=end_lineno,
  806. end_col_offset=end_col_offset,
  807. parent=parent,
  808. )
  809. newnode.postinit([self.visit(child, newnode) for child in node.decorator_list])
  810. return newnode
  811. def visit_delete(self, node: ast.Delete, parent: nodes.NodeNG) -> nodes.Delete:
  812. """Visit a Delete node by returning a fresh instance of it."""
  813. newnode = nodes.Delete(
  814. lineno=node.lineno,
  815. col_offset=node.col_offset,
  816. end_lineno=node.end_lineno,
  817. end_col_offset=node.end_col_offset,
  818. parent=parent,
  819. )
  820. newnode.postinit([self.visit(child, newnode) for child in node.targets])
  821. return newnode
  822. def _visit_dict_items(
  823. self, node: ast.Dict, parent: nodes.NodeNG, newnode: nodes.Dict
  824. ) -> Generator[tuple[nodes.NodeNG, nodes.NodeNG]]:
  825. for key, value in zip(node.keys, node.values):
  826. rebuilt_key: nodes.NodeNG
  827. rebuilt_value = self.visit(value, newnode)
  828. if not key:
  829. # Extended unpacking
  830. rebuilt_key = nodes.DictUnpack(
  831. lineno=rebuilt_value.lineno,
  832. col_offset=rebuilt_value.col_offset,
  833. end_lineno=rebuilt_value.end_lineno,
  834. end_col_offset=rebuilt_value.end_col_offset,
  835. parent=parent,
  836. )
  837. else:
  838. rebuilt_key = self.visit(key, newnode)
  839. yield rebuilt_key, rebuilt_value
  840. def visit_dict(self, node: ast.Dict, parent: nodes.NodeNG) -> nodes.Dict:
  841. """Visit a Dict node by returning a fresh instance of it."""
  842. newnode = nodes.Dict(
  843. lineno=node.lineno,
  844. col_offset=node.col_offset,
  845. end_lineno=node.end_lineno,
  846. end_col_offset=node.end_col_offset,
  847. parent=parent,
  848. )
  849. items: list[tuple[InferenceResult, InferenceResult]] = list(
  850. self._visit_dict_items(node, parent, newnode)
  851. )
  852. newnode.postinit(items)
  853. return newnode
  854. def visit_dictcomp(
  855. self, node: ast.DictComp, parent: nodes.NodeNG
  856. ) -> nodes.DictComp:
  857. """Visit a DictComp node by returning a fresh instance of it."""
  858. newnode = nodes.DictComp(
  859. lineno=node.lineno,
  860. col_offset=node.col_offset,
  861. end_lineno=node.end_lineno,
  862. end_col_offset=node.end_col_offset,
  863. parent=parent,
  864. )
  865. newnode.postinit(
  866. self.visit(node.key, newnode),
  867. self.visit(node.value, newnode),
  868. [self.visit(child, newnode) for child in node.generators],
  869. )
  870. return newnode
  871. def visit_expr(self, node: ast.Expr, parent: nodes.NodeNG) -> nodes.Expr:
  872. """Visit a Expr node by returning a fresh instance of it."""
  873. newnode = nodes.Expr(
  874. lineno=node.lineno,
  875. col_offset=node.col_offset,
  876. end_lineno=node.end_lineno,
  877. end_col_offset=node.end_col_offset,
  878. parent=parent,
  879. )
  880. newnode.postinit(self.visit(node.value, newnode))
  881. return newnode
  882. def visit_excepthandler(
  883. self, node: ast.ExceptHandler, parent: nodes.NodeNG
  884. ) -> nodes.ExceptHandler:
  885. """Visit an ExceptHandler node by returning a fresh instance of it."""
  886. newnode = nodes.ExceptHandler(
  887. lineno=node.lineno,
  888. col_offset=node.col_offset,
  889. end_lineno=node.end_lineno,
  890. end_col_offset=node.end_col_offset,
  891. parent=parent,
  892. )
  893. newnode.postinit(
  894. self.visit(node.type, newnode),
  895. self.visit_assignname(node, newnode, node.name),
  896. [self.visit(child, newnode) for child in node.body],
  897. )
  898. return newnode
  899. @overload
  900. def _visit_for(
  901. self, cls: type[nodes.For], node: ast.For, parent: nodes.NodeNG
  902. ) -> nodes.For: ...
  903. @overload
  904. def _visit_for(
  905. self, cls: type[nodes.AsyncFor], node: ast.AsyncFor, parent: nodes.NodeNG
  906. ) -> nodes.AsyncFor: ...
  907. def _visit_for(
  908. self, cls: type[_ForT], node: ast.For | ast.AsyncFor, parent: nodes.NodeNG
  909. ) -> _ForT:
  910. """Visit a For node by returning a fresh instance of it."""
  911. newnode = cls(
  912. lineno=node.lineno,
  913. col_offset=node.col_offset,
  914. end_lineno=node.end_lineno,
  915. end_col_offset=node.end_col_offset,
  916. parent=parent,
  917. )
  918. type_annotation = self.check_type_comment(node, parent=newnode)
  919. newnode.postinit(
  920. target=self.visit(node.target, newnode),
  921. iter=self.visit(node.iter, newnode),
  922. body=[self.visit(child, newnode) for child in node.body],
  923. orelse=[self.visit(child, newnode) for child in node.orelse],
  924. type_annotation=type_annotation,
  925. )
  926. return newnode
  927. def visit_for(self, node: ast.For, parent: nodes.NodeNG) -> nodes.For:
  928. return self._visit_for(nodes.For, node, parent)
  929. def visit_importfrom(
  930. self, node: ast.ImportFrom, parent: nodes.NodeNG
  931. ) -> nodes.ImportFrom:
  932. """Visit an ImportFrom node by returning a fresh instance of it."""
  933. names = [(alias.name, alias.asname) for alias in node.names]
  934. newnode = nodes.ImportFrom(
  935. fromname=node.module or "",
  936. names=names,
  937. level=node.level or None,
  938. lineno=node.lineno,
  939. col_offset=node.col_offset,
  940. end_lineno=node.end_lineno,
  941. end_col_offset=node.end_col_offset,
  942. parent=parent,
  943. )
  944. # store From names to add them to locals after building
  945. self._import_from_nodes.append(
  946. (newnode, self._global_names[-1].keys() if self._global_names else ())
  947. )
  948. return newnode
  949. @overload
  950. def _visit_functiondef(
  951. self, cls: type[nodes.FunctionDef], node: ast.FunctionDef, parent: nodes.NodeNG
  952. ) -> nodes.FunctionDef: ...
  953. @overload
  954. def _visit_functiondef(
  955. self,
  956. cls: type[nodes.AsyncFunctionDef],
  957. node: ast.AsyncFunctionDef,
  958. parent: nodes.NodeNG,
  959. ) -> nodes.AsyncFunctionDef: ...
  960. def _visit_functiondef(
  961. self,
  962. cls: type[_FunctionT],
  963. node: ast.FunctionDef | ast.AsyncFunctionDef,
  964. parent: nodes.NodeNG,
  965. ) -> _FunctionT:
  966. """Visit an FunctionDef node to become astroid."""
  967. self._global_names.append({})
  968. node, doc_ast_node = self._get_doc(node)
  969. lineno = node.lineno
  970. if node.decorator_list:
  971. # Python 3.8 sets the line number of a decorated function
  972. # to be the actual line number of the function, but the
  973. # previous versions expected the decorator's line number instead.
  974. # We reset the function's line number to that of the
  975. # first decorator to maintain backward compatibility.
  976. # It's not ideal but this discrepancy was baked into
  977. # the framework for *years*.
  978. lineno = node.decorator_list[0].lineno
  979. newnode = cls(
  980. name=node.name,
  981. lineno=lineno,
  982. col_offset=node.col_offset,
  983. end_lineno=node.end_lineno,
  984. end_col_offset=node.end_col_offset,
  985. parent=parent,
  986. )
  987. decorators = self.visit_decorators(node, newnode)
  988. returns: nodes.NodeNG | None
  989. if node.returns:
  990. returns = self.visit(node.returns, newnode)
  991. else:
  992. returns = None
  993. type_comment_args = type_comment_returns = None
  994. type_comment_annotation = self.check_function_type_comment(node, newnode)
  995. if type_comment_annotation:
  996. type_comment_returns, type_comment_args = type_comment_annotation
  997. newnode.postinit(
  998. args=self.visit(node.args, newnode),
  999. body=[self.visit(child, newnode) for child in node.body],
  1000. decorators=decorators,
  1001. returns=returns,
  1002. type_comment_returns=type_comment_returns,
  1003. type_comment_args=type_comment_args,
  1004. position=self._get_position_info(node, newnode),
  1005. doc_node=self.visit(doc_ast_node, newnode),
  1006. type_params=(
  1007. [self.visit(param, newnode) for param in node.type_params]
  1008. if PY312_PLUS
  1009. else []
  1010. ),
  1011. )
  1012. self._global_names.pop()
  1013. parent.set_local(newnode.name, newnode)
  1014. return newnode
  1015. def visit_functiondef(
  1016. self, node: ast.FunctionDef, parent: nodes.NodeNG
  1017. ) -> nodes.FunctionDef:
  1018. return self._visit_functiondef(nodes.FunctionDef, node, parent)
  1019. def visit_generatorexp(
  1020. self, node: ast.GeneratorExp, parent: nodes.NodeNG
  1021. ) -> nodes.GeneratorExp:
  1022. """Visit a GeneratorExp node by returning a fresh instance of it."""
  1023. newnode = nodes.GeneratorExp(
  1024. lineno=node.lineno,
  1025. col_offset=node.col_offset,
  1026. end_lineno=node.end_lineno,
  1027. end_col_offset=node.end_col_offset,
  1028. parent=parent,
  1029. )
  1030. newnode.postinit(
  1031. self.visit(node.elt, newnode),
  1032. [self.visit(child, newnode) for child in node.generators],
  1033. )
  1034. return newnode
  1035. def visit_attribute(
  1036. self, node: ast.Attribute, parent: nodes.NodeNG
  1037. ) -> nodes.Attribute | nodes.AssignAttr | nodes.DelAttr:
  1038. """Visit an Attribute node by returning a fresh instance of it."""
  1039. context = self._get_context(node)
  1040. newnode: nodes.Attribute | nodes.AssignAttr | nodes.DelAttr
  1041. if context == Context.Del:
  1042. # FIXME : maybe we should reintroduce and visit_delattr ?
  1043. # for instance, deactivating assign_ctx
  1044. newnode = nodes.DelAttr(
  1045. attrname=node.attr,
  1046. lineno=node.lineno,
  1047. col_offset=node.col_offset,
  1048. end_lineno=node.end_lineno,
  1049. end_col_offset=node.end_col_offset,
  1050. parent=parent,
  1051. )
  1052. elif context == Context.Store:
  1053. newnode = nodes.AssignAttr(
  1054. attrname=node.attr,
  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. # Prohibit a local save if we are in an ExceptHandler.
  1062. if not isinstance(parent, nodes.ExceptHandler):
  1063. # mypy doesn't recognize that newnode has to be AssignAttr because it
  1064. # doesn't support ParamSpec
  1065. # See https://github.com/python/mypy/issues/8645
  1066. self._delayed_assattr.append(newnode) # type: ignore[arg-type]
  1067. else:
  1068. newnode = nodes.Attribute(
  1069. attrname=node.attr,
  1070. lineno=node.lineno,
  1071. col_offset=node.col_offset,
  1072. end_lineno=node.end_lineno,
  1073. end_col_offset=node.end_col_offset,
  1074. parent=parent,
  1075. )
  1076. newnode.postinit(self.visit(node.value, newnode))
  1077. return newnode
  1078. def visit_global(self, node: ast.Global, parent: nodes.NodeNG) -> nodes.Global:
  1079. """Visit a Global node to become astroid."""
  1080. newnode = nodes.Global(
  1081. names=node.names,
  1082. lineno=node.lineno,
  1083. col_offset=node.col_offset,
  1084. end_lineno=node.end_lineno,
  1085. end_col_offset=node.end_col_offset,
  1086. parent=parent,
  1087. )
  1088. if self._global_names: # global at the module level, no effect
  1089. for name in node.names:
  1090. self._global_names[-1].setdefault(name, []).append(newnode)
  1091. return newnode
  1092. def visit_if(self, node: ast.If, parent: nodes.NodeNG) -> nodes.If:
  1093. """Visit an If node by returning a fresh instance of it."""
  1094. newnode = nodes.If(
  1095. lineno=node.lineno,
  1096. col_offset=node.col_offset,
  1097. end_lineno=node.end_lineno,
  1098. end_col_offset=node.end_col_offset,
  1099. parent=parent,
  1100. )
  1101. newnode.postinit(
  1102. self.visit(node.test, newnode),
  1103. [self.visit(child, newnode) for child in node.body],
  1104. [self.visit(child, newnode) for child in node.orelse],
  1105. )
  1106. return newnode
  1107. def visit_ifexp(self, node: ast.IfExp, parent: nodes.NodeNG) -> nodes.IfExp:
  1108. """Visit a IfExp node by returning a fresh instance of it."""
  1109. newnode = nodes.IfExp(
  1110. lineno=node.lineno,
  1111. col_offset=node.col_offset,
  1112. end_lineno=node.end_lineno,
  1113. end_col_offset=node.end_col_offset,
  1114. parent=parent,
  1115. )
  1116. newnode.postinit(
  1117. self.visit(node.test, newnode),
  1118. self.visit(node.body, newnode),
  1119. self.visit(node.orelse, newnode),
  1120. )
  1121. return newnode
  1122. def visit_import(self, node: ast.Import, parent: nodes.NodeNG) -> nodes.Import:
  1123. """Visit a Import node by returning a fresh instance of it."""
  1124. names = [(alias.name, alias.asname) for alias in node.names]
  1125. newnode = nodes.Import(
  1126. names=names,
  1127. lineno=node.lineno,
  1128. col_offset=node.col_offset,
  1129. end_lineno=node.end_lineno,
  1130. end_col_offset=node.end_col_offset,
  1131. parent=parent,
  1132. )
  1133. # save import names in parent's locals:
  1134. for name, asname in newnode.names:
  1135. name = (asname or name).split(".")[0]
  1136. if self._global_names and name in self._global_names[-1]:
  1137. parent.root().set_local(name, newnode)
  1138. else:
  1139. parent.set_local(name, newnode)
  1140. return newnode
  1141. def visit_joinedstr(
  1142. self, node: ast.JoinedStr, parent: nodes.NodeNG
  1143. ) -> nodes.JoinedStr:
  1144. newnode = nodes.JoinedStr(
  1145. lineno=node.lineno,
  1146. col_offset=node.col_offset,
  1147. end_lineno=node.end_lineno,
  1148. end_col_offset=node.end_col_offset,
  1149. parent=parent,
  1150. )
  1151. newnode.postinit([self.visit(child, newnode) for child in node.values])
  1152. return newnode
  1153. def visit_formattedvalue(
  1154. self, node: ast.FormattedValue, parent: nodes.NodeNG
  1155. ) -> nodes.FormattedValue:
  1156. newnode = nodes.FormattedValue(
  1157. lineno=node.lineno,
  1158. col_offset=node.col_offset,
  1159. end_lineno=node.end_lineno,
  1160. end_col_offset=node.end_col_offset,
  1161. parent=parent,
  1162. )
  1163. newnode.postinit(
  1164. value=self.visit(node.value, newnode),
  1165. conversion=node.conversion,
  1166. format_spec=self.visit(node.format_spec, newnode),
  1167. )
  1168. return newnode
  1169. def visit_namedexpr(
  1170. self, node: ast.NamedExpr, parent: nodes.NodeNG
  1171. ) -> nodes.NamedExpr:
  1172. newnode = nodes.NamedExpr(
  1173. lineno=node.lineno,
  1174. col_offset=node.col_offset,
  1175. end_lineno=node.end_lineno,
  1176. end_col_offset=node.end_col_offset,
  1177. parent=parent,
  1178. )
  1179. newnode.postinit(
  1180. self.visit(node.target, newnode), self.visit(node.value, newnode)
  1181. )
  1182. return newnode
  1183. def visit_keyword(self, node: ast.keyword, parent: nodes.NodeNG) -> nodes.Keyword:
  1184. """Visit a Keyword node by returning a fresh instance of it."""
  1185. newnode = nodes.Keyword(
  1186. arg=node.arg,
  1187. # position attributes added in 3.9
  1188. lineno=getattr(node, "lineno", None),
  1189. col_offset=getattr(node, "col_offset", None),
  1190. end_lineno=getattr(node, "end_lineno", None),
  1191. end_col_offset=getattr(node, "end_col_offset", None),
  1192. parent=parent,
  1193. )
  1194. newnode.postinit(self.visit(node.value, newnode))
  1195. return newnode
  1196. def visit_lambda(self, node: ast.Lambda, parent: nodes.NodeNG) -> nodes.Lambda:
  1197. """Visit a Lambda node by returning a fresh instance of it."""
  1198. newnode = nodes.Lambda(
  1199. lineno=node.lineno,
  1200. col_offset=node.col_offset,
  1201. end_lineno=node.end_lineno,
  1202. end_col_offset=node.end_col_offset,
  1203. parent=parent,
  1204. )
  1205. newnode.postinit(self.visit(node.args, newnode), self.visit(node.body, newnode))
  1206. return newnode
  1207. def visit_list(self, node: ast.List, parent: nodes.NodeNG) -> nodes.List:
  1208. """Visit a List node by returning a fresh instance of it."""
  1209. context = self._get_context(node)
  1210. newnode = nodes.List(
  1211. ctx=context,
  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. newnode.postinit([self.visit(child, newnode) for child in node.elts])
  1219. return newnode
  1220. def visit_listcomp(
  1221. self, node: ast.ListComp, parent: nodes.NodeNG
  1222. ) -> nodes.ListComp:
  1223. """Visit a ListComp node by returning a fresh instance of it."""
  1224. newnode = nodes.ListComp(
  1225. lineno=node.lineno,
  1226. col_offset=node.col_offset,
  1227. end_lineno=node.end_lineno,
  1228. end_col_offset=node.end_col_offset,
  1229. parent=parent,
  1230. )
  1231. newnode.postinit(
  1232. self.visit(node.elt, newnode),
  1233. [self.visit(child, newnode) for child in node.generators],
  1234. )
  1235. return newnode
  1236. def visit_name(
  1237. self, node: ast.Name, parent: nodes.NodeNG
  1238. ) -> nodes.Name | nodes.AssignName | nodes.DelName:
  1239. """Visit a Name node by returning a fresh instance of it."""
  1240. context = self._get_context(node)
  1241. newnode: nodes.Name | nodes.AssignName | nodes.DelName
  1242. if context == Context.Del:
  1243. newnode = nodes.DelName(
  1244. name=node.id,
  1245. lineno=node.lineno,
  1246. col_offset=node.col_offset,
  1247. end_lineno=node.end_lineno,
  1248. end_col_offset=node.end_col_offset,
  1249. parent=parent,
  1250. )
  1251. elif context == Context.Store:
  1252. newnode = nodes.AssignName(
  1253. name=node.id,
  1254. lineno=node.lineno,
  1255. col_offset=node.col_offset,
  1256. end_lineno=node.end_lineno,
  1257. end_col_offset=node.end_col_offset,
  1258. parent=parent,
  1259. )
  1260. else:
  1261. newnode = nodes.Name(
  1262. name=node.id,
  1263. lineno=node.lineno,
  1264. col_offset=node.col_offset,
  1265. end_lineno=node.end_lineno,
  1266. end_col_offset=node.end_col_offset,
  1267. parent=parent,
  1268. )
  1269. # XXX REMOVE me :
  1270. if context in (Context.Del, Context.Store): # 'Aug' ??
  1271. newnode = cast((nodes.AssignName | nodes.DelName), newnode)
  1272. self._save_assignment(newnode)
  1273. return newnode
  1274. def visit_nonlocal(
  1275. self, node: ast.Nonlocal, parent: nodes.NodeNG
  1276. ) -> nodes.Nonlocal:
  1277. """Visit a Nonlocal node and return a new instance of it."""
  1278. return nodes.Nonlocal(
  1279. names=node.names,
  1280. lineno=node.lineno,
  1281. col_offset=node.col_offset,
  1282. end_lineno=node.end_lineno,
  1283. end_col_offset=node.end_col_offset,
  1284. parent=parent,
  1285. )
  1286. def visit_constant(self, node: ast.Constant, parent: nodes.NodeNG) -> nodes.Const:
  1287. """Visit a Constant node by returning a fresh instance of Const."""
  1288. return nodes.Const(
  1289. value=node.value,
  1290. kind=node.kind,
  1291. lineno=node.lineno,
  1292. col_offset=node.col_offset,
  1293. end_lineno=node.end_lineno,
  1294. end_col_offset=node.end_col_offset,
  1295. parent=parent,
  1296. )
  1297. def visit_paramspec(
  1298. self, node: ast.ParamSpec, parent: nodes.NodeNG
  1299. ) -> nodes.ParamSpec:
  1300. """Visit a ParamSpec node by returning a fresh instance of it."""
  1301. newnode = nodes.ParamSpec(
  1302. lineno=node.lineno,
  1303. col_offset=node.col_offset,
  1304. end_lineno=node.end_lineno,
  1305. end_col_offset=node.end_col_offset,
  1306. parent=parent,
  1307. )
  1308. # Add AssignName node for 'node.name'
  1309. # https://bugs.python.org/issue43994
  1310. newnode.postinit(
  1311. name=self.visit_assignname(node, newnode, node.name),
  1312. default_value=(
  1313. self.visit(node.default_value, newnode) if PY313_PLUS else None
  1314. ),
  1315. )
  1316. return newnode
  1317. def visit_pass(self, node: ast.Pass, parent: nodes.NodeNG) -> nodes.Pass:
  1318. """Visit a Pass node by returning a fresh instance of it."""
  1319. return nodes.Pass(
  1320. lineno=node.lineno,
  1321. col_offset=node.col_offset,
  1322. end_lineno=node.end_lineno,
  1323. end_col_offset=node.end_col_offset,
  1324. parent=parent,
  1325. )
  1326. def visit_raise(self, node: ast.Raise, parent: nodes.NodeNG) -> nodes.Raise:
  1327. """Visit a Raise node by returning a fresh instance of it."""
  1328. newnode = nodes.Raise(
  1329. lineno=node.lineno,
  1330. col_offset=node.col_offset,
  1331. end_lineno=node.end_lineno,
  1332. end_col_offset=node.end_col_offset,
  1333. parent=parent,
  1334. )
  1335. # no traceback; anyway it is not used in Pylint
  1336. newnode.postinit(
  1337. exc=self.visit(node.exc, newnode),
  1338. cause=self.visit(node.cause, newnode),
  1339. )
  1340. return newnode
  1341. def visit_return(self, node: ast.Return, parent: nodes.NodeNG) -> nodes.Return:
  1342. """Visit a Return node by returning a fresh instance of it."""
  1343. newnode = nodes.Return(
  1344. lineno=node.lineno,
  1345. col_offset=node.col_offset,
  1346. end_lineno=node.end_lineno,
  1347. end_col_offset=node.end_col_offset,
  1348. parent=parent,
  1349. )
  1350. newnode.postinit(self.visit(node.value, newnode))
  1351. return newnode
  1352. def visit_set(self, node: ast.Set, parent: nodes.NodeNG) -> nodes.Set:
  1353. """Visit a Set node by returning a fresh instance of it."""
  1354. newnode = nodes.Set(
  1355. lineno=node.lineno,
  1356. col_offset=node.col_offset,
  1357. end_lineno=node.end_lineno,
  1358. end_col_offset=node.end_col_offset,
  1359. parent=parent,
  1360. )
  1361. newnode.postinit([self.visit(child, newnode) for child in node.elts])
  1362. return newnode
  1363. def visit_setcomp(self, node: ast.SetComp, parent: nodes.NodeNG) -> nodes.SetComp:
  1364. """Visit a SetComp node by returning a fresh instance of it."""
  1365. newnode = nodes.SetComp(
  1366. lineno=node.lineno,
  1367. col_offset=node.col_offset,
  1368. end_lineno=node.end_lineno,
  1369. end_col_offset=node.end_col_offset,
  1370. parent=parent,
  1371. )
  1372. newnode.postinit(
  1373. self.visit(node.elt, newnode),
  1374. [self.visit(child, newnode) for child in node.generators],
  1375. )
  1376. return newnode
  1377. def visit_slice(self, node: ast.Slice, parent: nodes.Subscript) -> nodes.Slice:
  1378. """Visit a Slice node by returning a fresh instance of it."""
  1379. newnode = nodes.Slice(
  1380. # position attributes added in 3.9
  1381. lineno=getattr(node, "lineno", None),
  1382. col_offset=getattr(node, "col_offset", None),
  1383. end_lineno=getattr(node, "end_lineno", None),
  1384. end_col_offset=getattr(node, "end_col_offset", None),
  1385. parent=parent,
  1386. )
  1387. newnode.postinit(
  1388. lower=self.visit(node.lower, newnode),
  1389. upper=self.visit(node.upper, newnode),
  1390. step=self.visit(node.step, newnode),
  1391. )
  1392. return newnode
  1393. def visit_subscript(
  1394. self, node: ast.Subscript, parent: nodes.NodeNG
  1395. ) -> nodes.Subscript:
  1396. """Visit a Subscript node by returning a fresh instance of it."""
  1397. context = self._get_context(node)
  1398. newnode = nodes.Subscript(
  1399. ctx=context,
  1400. lineno=node.lineno,
  1401. col_offset=node.col_offset,
  1402. end_lineno=node.end_lineno,
  1403. end_col_offset=node.end_col_offset,
  1404. parent=parent,
  1405. )
  1406. newnode.postinit(
  1407. self.visit(node.value, newnode), self.visit(node.slice, newnode)
  1408. )
  1409. return newnode
  1410. def visit_starred(self, node: ast.Starred, parent: nodes.NodeNG) -> nodes.Starred:
  1411. """Visit a Starred node and return a new instance of it."""
  1412. context = self._get_context(node)
  1413. newnode = nodes.Starred(
  1414. ctx=context,
  1415. lineno=node.lineno,
  1416. col_offset=node.col_offset,
  1417. end_lineno=node.end_lineno,
  1418. end_col_offset=node.end_col_offset,
  1419. parent=parent,
  1420. )
  1421. newnode.postinit(self.visit(node.value, newnode))
  1422. return newnode
  1423. def visit_try(self, node: ast.Try, parent: nodes.NodeNG) -> nodes.Try:
  1424. """Visit a Try node by returning a fresh instance of it"""
  1425. newnode = nodes.Try(
  1426. lineno=node.lineno,
  1427. col_offset=node.col_offset,
  1428. end_lineno=node.end_lineno,
  1429. end_col_offset=node.end_col_offset,
  1430. parent=parent,
  1431. )
  1432. newnode.postinit(
  1433. body=[self.visit(child, newnode) for child in node.body],
  1434. handlers=[self.visit(child, newnode) for child in node.handlers],
  1435. orelse=[self.visit(child, newnode) for child in node.orelse],
  1436. finalbody=[self.visit(child, newnode) for child in node.finalbody],
  1437. )
  1438. return newnode
  1439. def visit_trystar(self, node: ast.TryStar, parent: nodes.NodeNG) -> nodes.TryStar:
  1440. newnode = nodes.TryStar(
  1441. lineno=node.lineno,
  1442. col_offset=node.col_offset,
  1443. end_lineno=node.end_lineno,
  1444. end_col_offset=node.end_col_offset,
  1445. parent=parent,
  1446. )
  1447. newnode.postinit(
  1448. body=[self.visit(n, newnode) for n in node.body],
  1449. handlers=[self.visit(n, newnode) for n in node.handlers],
  1450. orelse=[self.visit(n, newnode) for n in node.orelse],
  1451. finalbody=[self.visit(n, newnode) for n in node.finalbody],
  1452. )
  1453. return newnode
  1454. def visit_tuple(self, node: ast.Tuple, parent: nodes.NodeNG) -> nodes.Tuple:
  1455. """Visit a Tuple node by returning a fresh instance of it."""
  1456. context = self._get_context(node)
  1457. newnode = nodes.Tuple(
  1458. ctx=context,
  1459. lineno=node.lineno,
  1460. col_offset=node.col_offset,
  1461. end_lineno=node.end_lineno,
  1462. end_col_offset=node.end_col_offset,
  1463. parent=parent,
  1464. )
  1465. newnode.postinit([self.visit(child, newnode) for child in node.elts])
  1466. return newnode
  1467. def visit_typealias(
  1468. self, node: ast.TypeAlias, parent: nodes.NodeNG
  1469. ) -> nodes.TypeAlias:
  1470. """Visit a TypeAlias node by returning a fresh instance of it."""
  1471. newnode = nodes.TypeAlias(
  1472. lineno=node.lineno,
  1473. col_offset=node.col_offset,
  1474. end_lineno=node.end_lineno,
  1475. end_col_offset=node.end_col_offset,
  1476. parent=parent,
  1477. )
  1478. newnode.postinit(
  1479. name=self.visit(node.name, newnode),
  1480. type_params=[self.visit(p, newnode) for p in node.type_params],
  1481. value=self.visit(node.value, newnode),
  1482. )
  1483. return newnode
  1484. def visit_typevar(self, node: ast.TypeVar, parent: nodes.NodeNG) -> nodes.TypeVar:
  1485. """Visit a TypeVar node by returning a fresh instance of it."""
  1486. newnode = nodes.TypeVar(
  1487. lineno=node.lineno,
  1488. col_offset=node.col_offset,
  1489. end_lineno=node.end_lineno,
  1490. end_col_offset=node.end_col_offset,
  1491. parent=parent,
  1492. )
  1493. # Add AssignName node for 'node.name'
  1494. # https://bugs.python.org/issue43994
  1495. newnode.postinit(
  1496. name=self.visit_assignname(node, newnode, node.name),
  1497. bound=self.visit(node.bound, newnode),
  1498. default_value=(
  1499. self.visit(node.default_value, newnode) if PY313_PLUS else None
  1500. ),
  1501. )
  1502. return newnode
  1503. def visit_typevartuple(
  1504. self, node: ast.TypeVarTuple, parent: nodes.NodeNG
  1505. ) -> nodes.TypeVarTuple:
  1506. """Visit a TypeVarTuple node by returning a fresh instance of it."""
  1507. newnode = nodes.TypeVarTuple(
  1508. lineno=node.lineno,
  1509. col_offset=node.col_offset,
  1510. end_lineno=node.end_lineno,
  1511. end_col_offset=node.end_col_offset,
  1512. parent=parent,
  1513. )
  1514. # Add AssignName node for 'node.name'
  1515. # https://bugs.python.org/issue43994
  1516. newnode.postinit(
  1517. name=self.visit_assignname(node, newnode, node.name),
  1518. default_value=(
  1519. self.visit(node.default_value, newnode) if PY313_PLUS else None
  1520. ),
  1521. )
  1522. return newnode
  1523. def visit_unaryop(self, node: ast.UnaryOp, parent: nodes.NodeNG) -> nodes.UnaryOp:
  1524. """Visit a UnaryOp node by returning a fresh instance of it."""
  1525. newnode = nodes.UnaryOp(
  1526. op=self._parser_module.unary_op_classes[node.op.__class__],
  1527. lineno=node.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. newnode.postinit(self.visit(node.operand, newnode))
  1534. return newnode
  1535. def visit_while(self, node: ast.While, parent: nodes.NodeNG) -> nodes.While:
  1536. """Visit a While node by returning a fresh instance of it."""
  1537. newnode = nodes.While(
  1538. lineno=node.lineno,
  1539. col_offset=node.col_offset,
  1540. end_lineno=node.end_lineno,
  1541. end_col_offset=node.end_col_offset,
  1542. parent=parent,
  1543. )
  1544. newnode.postinit(
  1545. self.visit(node.test, newnode),
  1546. [self.visit(child, newnode) for child in node.body],
  1547. [self.visit(child, newnode) for child in node.orelse],
  1548. )
  1549. return newnode
  1550. @overload
  1551. def _visit_with(
  1552. self, cls: type[nodes.With], node: ast.With, parent: nodes.NodeNG
  1553. ) -> nodes.With: ...
  1554. @overload
  1555. def _visit_with(
  1556. self, cls: type[nodes.AsyncWith], node: ast.AsyncWith, parent: nodes.NodeNG
  1557. ) -> nodes.AsyncWith: ...
  1558. def _visit_with(
  1559. self,
  1560. cls: type[_WithT],
  1561. node: ast.With | ast.AsyncWith,
  1562. parent: nodes.NodeNG,
  1563. ) -> _WithT:
  1564. newnode = cls(
  1565. lineno=node.lineno,
  1566. col_offset=node.col_offset,
  1567. end_lineno=node.end_lineno,
  1568. end_col_offset=node.end_col_offset,
  1569. parent=parent,
  1570. )
  1571. def visit_child(
  1572. child: ast.withitem,
  1573. ) -> tuple[nodes.NodeNG, nodes.NodeNG | None]:
  1574. expr = self.visit(child.context_expr, newnode)
  1575. var = self.visit(child.optional_vars, newnode)
  1576. return expr, var
  1577. type_annotation = self.check_type_comment(node, parent=newnode)
  1578. newnode.postinit(
  1579. items=[visit_child(child) for child in node.items],
  1580. body=[self.visit(child, newnode) for child in node.body],
  1581. type_annotation=type_annotation,
  1582. )
  1583. return newnode
  1584. def visit_with(self, node: ast.With, parent: nodes.NodeNG) -> nodes.NodeNG:
  1585. return self._visit_with(nodes.With, node, parent)
  1586. def visit_yield(self, node: ast.Yield, parent: nodes.NodeNG) -> nodes.NodeNG:
  1587. """Visit a Yield node by returning a fresh instance of it."""
  1588. newnode = nodes.Yield(
  1589. lineno=node.lineno,
  1590. col_offset=node.col_offset,
  1591. end_lineno=node.end_lineno,
  1592. end_col_offset=node.end_col_offset,
  1593. parent=parent,
  1594. )
  1595. newnode.postinit(self.visit(node.value, newnode))
  1596. return newnode
  1597. def visit_yieldfrom(
  1598. self, node: ast.YieldFrom, parent: nodes.NodeNG
  1599. ) -> nodes.NodeNG:
  1600. newnode = nodes.YieldFrom(
  1601. lineno=node.lineno,
  1602. col_offset=node.col_offset,
  1603. end_lineno=node.end_lineno,
  1604. end_col_offset=node.end_col_offset,
  1605. parent=parent,
  1606. )
  1607. newnode.postinit(self.visit(node.value, newnode))
  1608. return newnode
  1609. def visit_match(self, node: ast.Match, parent: nodes.NodeNG) -> nodes.Match:
  1610. newnode = nodes.Match(
  1611. lineno=node.lineno,
  1612. col_offset=node.col_offset,
  1613. end_lineno=node.end_lineno,
  1614. end_col_offset=node.end_col_offset,
  1615. parent=parent,
  1616. )
  1617. newnode.postinit(
  1618. subject=self.visit(node.subject, newnode),
  1619. cases=[self.visit(case, newnode) for case in node.cases],
  1620. )
  1621. return newnode
  1622. def visit_matchcase(
  1623. self, node: ast.match_case, parent: nodes.NodeNG
  1624. ) -> nodes.MatchCase:
  1625. newnode = nodes.MatchCase(parent=parent)
  1626. newnode.postinit(
  1627. pattern=self.visit(node.pattern, newnode),
  1628. guard=self.visit(node.guard, newnode),
  1629. body=[self.visit(child, newnode) for child in node.body],
  1630. )
  1631. return newnode
  1632. def visit_matchvalue(
  1633. self, node: ast.MatchValue, parent: nodes.NodeNG
  1634. ) -> nodes.MatchValue:
  1635. newnode = nodes.MatchValue(
  1636. lineno=node.lineno,
  1637. col_offset=node.col_offset,
  1638. end_lineno=node.end_lineno,
  1639. end_col_offset=node.end_col_offset,
  1640. parent=parent,
  1641. )
  1642. newnode.postinit(value=self.visit(node.value, newnode))
  1643. return newnode
  1644. def visit_matchsingleton(
  1645. self, node: ast.MatchSingleton, parent: nodes.NodeNG
  1646. ) -> nodes.MatchSingleton:
  1647. return nodes.MatchSingleton(
  1648. value=node.value,
  1649. lineno=node.lineno,
  1650. col_offset=node.col_offset,
  1651. end_lineno=node.end_lineno,
  1652. end_col_offset=node.end_col_offset,
  1653. parent=parent,
  1654. )
  1655. def visit_matchsequence(
  1656. self, node: ast.MatchSequence, parent: nodes.NodeNG
  1657. ) -> nodes.MatchSequence:
  1658. newnode = nodes.MatchSequence(
  1659. lineno=node.lineno,
  1660. col_offset=node.col_offset,
  1661. end_lineno=node.end_lineno,
  1662. end_col_offset=node.end_col_offset,
  1663. parent=parent,
  1664. )
  1665. newnode.postinit(
  1666. patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
  1667. )
  1668. return newnode
  1669. def visit_matchmapping(
  1670. self, node: ast.MatchMapping, parent: nodes.NodeNG
  1671. ) -> nodes.MatchMapping:
  1672. newnode = nodes.MatchMapping(
  1673. lineno=node.lineno,
  1674. col_offset=node.col_offset,
  1675. end_lineno=node.end_lineno,
  1676. end_col_offset=node.end_col_offset,
  1677. parent=parent,
  1678. )
  1679. # Add AssignName node for 'node.name'
  1680. # https://bugs.python.org/issue43994
  1681. newnode.postinit(
  1682. keys=[self.visit(child, newnode) for child in node.keys],
  1683. patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
  1684. rest=self.visit_assignname(node, newnode, node.rest),
  1685. )
  1686. return newnode
  1687. def visit_matchclass(
  1688. self, node: ast.MatchClass, parent: nodes.NodeNG
  1689. ) -> nodes.MatchClass:
  1690. newnode = nodes.MatchClass(
  1691. lineno=node.lineno,
  1692. col_offset=node.col_offset,
  1693. end_lineno=node.end_lineno,
  1694. end_col_offset=node.end_col_offset,
  1695. parent=parent,
  1696. )
  1697. newnode.postinit(
  1698. cls=self.visit(node.cls, newnode),
  1699. patterns=[self.visit(pattern, newnode) for pattern in node.patterns],
  1700. kwd_attrs=node.kwd_attrs,
  1701. kwd_patterns=[
  1702. self.visit(pattern, newnode) for pattern in node.kwd_patterns
  1703. ],
  1704. )
  1705. return newnode
  1706. def visit_matchstar(
  1707. self, node: ast.MatchStar, parent: nodes.NodeNG
  1708. ) -> nodes.MatchStar:
  1709. newnode = nodes.MatchStar(
  1710. lineno=node.lineno,
  1711. col_offset=node.col_offset,
  1712. end_lineno=node.end_lineno,
  1713. end_col_offset=node.end_col_offset,
  1714. parent=parent,
  1715. )
  1716. # Add AssignName node for 'node.name'
  1717. # https://bugs.python.org/issue43994
  1718. newnode.postinit(name=self.visit_assignname(node, newnode, node.name))
  1719. return newnode
  1720. def visit_matchas(self, node: ast.MatchAs, parent: nodes.NodeNG) -> nodes.MatchAs:
  1721. newnode = nodes.MatchAs(
  1722. lineno=node.lineno,
  1723. col_offset=node.col_offset,
  1724. end_lineno=node.end_lineno,
  1725. end_col_offset=node.end_col_offset,
  1726. parent=parent,
  1727. )
  1728. # Add AssignName node for 'node.name'
  1729. # https://bugs.python.org/issue43994
  1730. newnode.postinit(
  1731. pattern=self.visit(node.pattern, newnode),
  1732. name=self.visit_assignname(node, newnode, node.name),
  1733. )
  1734. return newnode
  1735. def visit_matchor(self, node: ast.MatchOr, parent: nodes.NodeNG) -> nodes.MatchOr:
  1736. newnode = nodes.MatchOr(
  1737. lineno=node.lineno,
  1738. col_offset=node.col_offset,
  1739. end_lineno=node.end_lineno,
  1740. end_col_offset=node.end_col_offset,
  1741. parent=parent,
  1742. )
  1743. newnode.postinit(
  1744. patterns=[self.visit(pattern, newnode) for pattern in node.patterns]
  1745. )
  1746. return newnode
  1747. if sys.version_info >= (3, 14):
  1748. def visit_templatestr(
  1749. self, node: ast.TemplateStr, parent: nodes.NodeNG
  1750. ) -> nodes.TemplateStr:
  1751. newnode = nodes.TemplateStr(
  1752. lineno=node.lineno,
  1753. col_offset=node.col_offset,
  1754. end_lineno=node.end_lineno,
  1755. end_col_offset=node.end_col_offset,
  1756. parent=parent,
  1757. )
  1758. newnode.postinit(
  1759. values=[self.visit(value, newnode) for value in node.values]
  1760. )
  1761. return newnode
  1762. def visit_interpolation(
  1763. self, node: ast.Interpolation, parent: nodes.NodeNG
  1764. ) -> nodes.Interpolation:
  1765. newnode = nodes.Interpolation(
  1766. lineno=node.lineno,
  1767. col_offset=node.col_offset,
  1768. end_lineno=node.end_lineno,
  1769. end_col_offset=node.end_col_offset,
  1770. parent=parent,
  1771. )
  1772. newnode.postinit(
  1773. value=self.visit(node.value, parent),
  1774. str=node.str,
  1775. conversion=node.conversion,
  1776. format_spec=self.visit(node.format_spec, parent),
  1777. )
  1778. return newnode