Sphinx 7.2.6__py3-none-any.whl → 7.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Sphinx might be problematic. Click here for more details.

Files changed (388) hide show
  1. sphinx/__init__.py +8 -9
  2. sphinx/addnodes.py +31 -28
  3. sphinx/application.py +9 -15
  4. sphinx/builders/__init__.py +5 -6
  5. sphinx/builders/_epub_base.py +17 -9
  6. sphinx/builders/changes.py +10 -5
  7. sphinx/builders/dirhtml.py +4 -2
  8. sphinx/builders/dummy.py +3 -2
  9. sphinx/builders/epub3.py +5 -3
  10. sphinx/builders/gettext.py +24 -7
  11. sphinx/builders/html/__init__.py +88 -96
  12. sphinx/builders/html/_assets.py +16 -16
  13. sphinx/builders/html/transforms.py +4 -2
  14. sphinx/builders/latex/__init__.py +40 -33
  15. sphinx/builders/latex/nodes.py +6 -2
  16. sphinx/builders/latex/transforms.py +17 -8
  17. sphinx/builders/latex/util.py +1 -1
  18. sphinx/builders/linkcheck.py +86 -27
  19. sphinx/builders/manpage.py +8 -6
  20. sphinx/builders/singlehtml.py +5 -4
  21. sphinx/builders/texinfo.py +18 -14
  22. sphinx/builders/text.py +3 -2
  23. sphinx/builders/xml.py +5 -2
  24. sphinx/cmd/build.py +119 -76
  25. sphinx/cmd/make_mode.py +4 -9
  26. sphinx/cmd/quickstart.py +13 -16
  27. sphinx/config.py +432 -250
  28. sphinx/deprecation.py +23 -13
  29. sphinx/directives/__init__.py +8 -8
  30. sphinx/directives/code.py +7 -7
  31. sphinx/directives/other.py +23 -13
  32. sphinx/directives/patches.py +7 -6
  33. sphinx/domains/__init__.py +2 -2
  34. sphinx/domains/c/__init__.py +796 -0
  35. sphinx/domains/c/_ast.py +1421 -0
  36. sphinx/domains/c/_ids.py +65 -0
  37. sphinx/domains/c/_parser.py +1048 -0
  38. sphinx/domains/c/_symbol.py +700 -0
  39. sphinx/domains/changeset.py +11 -7
  40. sphinx/domains/citation.py +5 -2
  41. sphinx/domains/cpp/__init__.py +1089 -0
  42. sphinx/domains/cpp/_ast.py +3635 -0
  43. sphinx/domains/cpp/_ids.py +537 -0
  44. sphinx/domains/cpp/_parser.py +2117 -0
  45. sphinx/domains/cpp/_symbol.py +1092 -0
  46. sphinx/domains/index.py +6 -4
  47. sphinx/domains/javascript.py +16 -13
  48. sphinx/domains/math.py +9 -4
  49. sphinx/domains/python/__init__.py +890 -0
  50. sphinx/domains/python/_annotations.py +507 -0
  51. sphinx/domains/python/_object.py +426 -0
  52. sphinx/domains/rst.py +12 -7
  53. sphinx/domains/{std.py → std/__init__.py} +19 -16
  54. sphinx/environment/__init__.py +21 -19
  55. sphinx/environment/adapters/indexentries.py +2 -2
  56. sphinx/environment/adapters/toctree.py +10 -9
  57. sphinx/environment/collectors/__init__.py +6 -3
  58. sphinx/environment/collectors/asset.py +4 -3
  59. sphinx/environment/collectors/dependencies.py +3 -2
  60. sphinx/environment/collectors/metadata.py +6 -5
  61. sphinx/environment/collectors/title.py +3 -2
  62. sphinx/environment/collectors/toctree.py +5 -4
  63. sphinx/errors.py +13 -2
  64. sphinx/events.py +14 -9
  65. sphinx/ext/apidoc.py +9 -11
  66. sphinx/ext/autodoc/__init__.py +105 -71
  67. sphinx/ext/autodoc/directive.py +7 -6
  68. sphinx/ext/autodoc/importer.py +102 -36
  69. sphinx/ext/autodoc/mock.py +7 -5
  70. sphinx/ext/autodoc/preserve_defaults.py +4 -3
  71. sphinx/ext/autodoc/type_comment.py +2 -1
  72. sphinx/ext/autodoc/typehints.py +5 -4
  73. sphinx/ext/autosectionlabel.py +3 -2
  74. sphinx/ext/autosummary/__init__.py +21 -17
  75. sphinx/ext/autosummary/generate.py +9 -9
  76. sphinx/ext/coverage.py +26 -20
  77. sphinx/ext/doctest.py +38 -33
  78. sphinx/ext/duration.py +1 -0
  79. sphinx/ext/extlinks.py +4 -3
  80. sphinx/ext/githubpages.py +3 -2
  81. sphinx/ext/graphviz.py +10 -7
  82. sphinx/ext/ifconfig.py +5 -5
  83. sphinx/ext/imgconverter.py +6 -5
  84. sphinx/ext/imgmath.py +9 -8
  85. sphinx/ext/inheritance_diagram.py +31 -31
  86. sphinx/ext/intersphinx.py +140 -23
  87. sphinx/ext/linkcode.py +3 -2
  88. sphinx/ext/mathjax.py +2 -1
  89. sphinx/ext/napoleon/__init__.py +12 -7
  90. sphinx/ext/napoleon/docstring.py +34 -32
  91. sphinx/ext/todo.py +10 -7
  92. sphinx/ext/viewcode.py +12 -11
  93. sphinx/extension.py +18 -8
  94. sphinx/highlighting.py +39 -20
  95. sphinx/io.py +17 -8
  96. sphinx/jinja2glue.py +16 -15
  97. sphinx/locale/__init__.py +30 -23
  98. sphinx/locale/ar/LC_MESSAGES/sphinx.mo +0 -0
  99. sphinx/locale/ar/LC_MESSAGES/sphinx.po +818 -761
  100. sphinx/locale/bg/LC_MESSAGES/sphinx.mo +0 -0
  101. sphinx/locale/bg/LC_MESSAGES/sphinx.po +811 -754
  102. sphinx/locale/bn/LC_MESSAGES/sphinx.mo +0 -0
  103. sphinx/locale/bn/LC_MESSAGES/sphinx.po +835 -778
  104. sphinx/locale/ca/LC_MESSAGES/sphinx.mo +0 -0
  105. sphinx/locale/ca/LC_MESSAGES/sphinx.po +864 -807
  106. sphinx/locale/cak/LC_MESSAGES/sphinx.mo +0 -0
  107. sphinx/locale/cak/LC_MESSAGES/sphinx.po +816 -759
  108. sphinx/locale/cs/LC_MESSAGES/sphinx.mo +0 -0
  109. sphinx/locale/cs/LC_MESSAGES/sphinx.po +837 -780
  110. sphinx/locale/cy/LC_MESSAGES/sphinx.mo +0 -0
  111. sphinx/locale/cy/LC_MESSAGES/sphinx.po +819 -762
  112. sphinx/locale/da/LC_MESSAGES/sphinx.mo +0 -0
  113. sphinx/locale/da/LC_MESSAGES/sphinx.po +838 -781
  114. sphinx/locale/de/LC_MESSAGES/sphinx.mo +0 -0
  115. sphinx/locale/de/LC_MESSAGES/sphinx.po +838 -781
  116. sphinx/locale/de_DE/LC_MESSAGES/sphinx.mo +0 -0
  117. sphinx/locale/de_DE/LC_MESSAGES/sphinx.po +811 -754
  118. sphinx/locale/el/LC_MESSAGES/sphinx.mo +0 -0
  119. sphinx/locale/el/LC_MESSAGES/sphinx.po +853 -796
  120. sphinx/locale/en_DE/LC_MESSAGES/sphinx.mo +0 -0
  121. sphinx/locale/en_DE/LC_MESSAGES/sphinx.po +811 -754
  122. sphinx/locale/en_FR/LC_MESSAGES/sphinx.mo +0 -0
  123. sphinx/locale/en_FR/LC_MESSAGES/sphinx.po +811 -754
  124. sphinx/locale/en_GB/LC_MESSAGES/sphinx.mo +0 -0
  125. sphinx/locale/en_GB/LC_MESSAGES/sphinx.po +856 -799
  126. sphinx/locale/en_HK/LC_MESSAGES/sphinx.mo +0 -0
  127. sphinx/locale/en_HK/LC_MESSAGES/sphinx.po +811 -754
  128. sphinx/locale/eo/LC_MESSAGES/sphinx.mo +0 -0
  129. sphinx/locale/eo/LC_MESSAGES/sphinx.po +820 -763
  130. sphinx/locale/es/LC_MESSAGES/sphinx.mo +0 -0
  131. sphinx/locale/es/LC_MESSAGES/sphinx.po +856 -799
  132. sphinx/locale/es_CO/LC_MESSAGES/sphinx.mo +0 -0
  133. sphinx/locale/es_CO/LC_MESSAGES/sphinx.po +811 -754
  134. sphinx/locale/et/LC_MESSAGES/sphinx.mo +0 -0
  135. sphinx/locale/et/LC_MESSAGES/sphinx.po +845 -788
  136. sphinx/locale/eu/LC_MESSAGES/sphinx.mo +0 -0
  137. sphinx/locale/eu/LC_MESSAGES/sphinx.po +837 -780
  138. sphinx/locale/fa/LC_MESSAGES/sphinx.mo +0 -0
  139. sphinx/locale/fa/LC_MESSAGES/sphinx.po +854 -797
  140. sphinx/locale/fi/LC_MESSAGES/sphinx.mo +0 -0
  141. sphinx/locale/fi/LC_MESSAGES/sphinx.po +816 -759
  142. sphinx/locale/fr/LC_MESSAGES/sphinx.js +1 -1
  143. sphinx/locale/fr/LC_MESSAGES/sphinx.mo +0 -0
  144. sphinx/locale/fr/LC_MESSAGES/sphinx.po +904 -847
  145. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.mo +0 -0
  146. sphinx/locale/fr_FR/LC_MESSAGES/sphinx.po +811 -754
  147. sphinx/locale/gl/LC_MESSAGES/sphinx.js +54 -54
  148. sphinx/locale/gl/LC_MESSAGES/sphinx.mo +0 -0
  149. sphinx/locale/gl/LC_MESSAGES/sphinx.po +1506 -1449
  150. sphinx/locale/he/LC_MESSAGES/sphinx.js +1 -1
  151. sphinx/locale/he/LC_MESSAGES/sphinx.mo +0 -0
  152. sphinx/locale/he/LC_MESSAGES/sphinx.po +823 -766
  153. sphinx/locale/hi/LC_MESSAGES/sphinx.mo +0 -0
  154. sphinx/locale/hi/LC_MESSAGES/sphinx.po +853 -796
  155. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.mo +0 -0
  156. sphinx/locale/hi_IN/LC_MESSAGES/sphinx.po +811 -754
  157. sphinx/locale/hr/LC_MESSAGES/sphinx.mo +0 -0
  158. sphinx/locale/hr/LC_MESSAGES/sphinx.po +844 -787
  159. sphinx/locale/hu/LC_MESSAGES/sphinx.mo +0 -0
  160. sphinx/locale/hu/LC_MESSAGES/sphinx.po +837 -780
  161. sphinx/locale/id/LC_MESSAGES/sphinx.mo +0 -0
  162. sphinx/locale/id/LC_MESSAGES/sphinx.po +854 -797
  163. sphinx/locale/is/LC_MESSAGES/sphinx.mo +0 -0
  164. sphinx/locale/is/LC_MESSAGES/sphinx.po +811 -754
  165. sphinx/locale/it/LC_MESSAGES/sphinx.mo +0 -0
  166. sphinx/locale/it/LC_MESSAGES/sphinx.po +837 -780
  167. sphinx/locale/ja/LC_MESSAGES/sphinx.mo +0 -0
  168. sphinx/locale/ja/LC_MESSAGES/sphinx.po +853 -796
  169. sphinx/locale/ka/LC_MESSAGES/sphinx.mo +0 -0
  170. sphinx/locale/ka/LC_MESSAGES/sphinx.po +848 -791
  171. sphinx/locale/ko/LC_MESSAGES/sphinx.mo +0 -0
  172. sphinx/locale/ko/LC_MESSAGES/sphinx.po +855 -798
  173. sphinx/locale/lt/LC_MESSAGES/sphinx.mo +0 -0
  174. sphinx/locale/lt/LC_MESSAGES/sphinx.po +837 -780
  175. sphinx/locale/lv/LC_MESSAGES/sphinx.mo +0 -0
  176. sphinx/locale/lv/LC_MESSAGES/sphinx.po +837 -780
  177. sphinx/locale/mk/LC_MESSAGES/sphinx.mo +0 -0
  178. sphinx/locale/mk/LC_MESSAGES/sphinx.po +825 -768
  179. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.js +27 -27
  180. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.mo +0 -0
  181. sphinx/locale/nb_NO/LC_MESSAGES/sphinx.po +876 -818
  182. sphinx/locale/ne/LC_MESSAGES/sphinx.mo +0 -0
  183. sphinx/locale/ne/LC_MESSAGES/sphinx.po +837 -780
  184. sphinx/locale/nl/LC_MESSAGES/sphinx.mo +0 -0
  185. sphinx/locale/nl/LC_MESSAGES/sphinx.po +844 -787
  186. sphinx/locale/pl/LC_MESSAGES/sphinx.mo +0 -0
  187. sphinx/locale/pl/LC_MESSAGES/sphinx.po +845 -788
  188. sphinx/locale/pt/LC_MESSAGES/sphinx.mo +0 -0
  189. sphinx/locale/pt/LC_MESSAGES/sphinx.po +811 -754
  190. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.mo +0 -0
  191. sphinx/locale/pt_BR/LC_MESSAGES/sphinx.po +908 -851
  192. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.mo +0 -0
  193. sphinx/locale/pt_PT/LC_MESSAGES/sphinx.po +837 -780
  194. sphinx/locale/ro/LC_MESSAGES/sphinx.mo +0 -0
  195. sphinx/locale/ro/LC_MESSAGES/sphinx.po +837 -780
  196. sphinx/locale/ru/LC_MESSAGES/sphinx.mo +0 -0
  197. sphinx/locale/ru/LC_MESSAGES/sphinx.po +838 -781
  198. sphinx/locale/si/LC_MESSAGES/sphinx.mo +0 -0
  199. sphinx/locale/si/LC_MESSAGES/sphinx.po +823 -766
  200. sphinx/locale/sk/LC_MESSAGES/sphinx.mo +0 -0
  201. sphinx/locale/sk/LC_MESSAGES/sphinx.po +854 -797
  202. sphinx/locale/sl/LC_MESSAGES/sphinx.mo +0 -0
  203. sphinx/locale/sl/LC_MESSAGES/sphinx.po +832 -775
  204. sphinx/locale/sphinx.pot +813 -755
  205. sphinx/locale/sq/LC_MESSAGES/sphinx.js +1 -1
  206. sphinx/locale/sq/LC_MESSAGES/sphinx.mo +0 -0
  207. sphinx/locale/sq/LC_MESSAGES/sphinx.po +865 -808
  208. sphinx/locale/sr/LC_MESSAGES/sphinx.mo +0 -0
  209. sphinx/locale/sr/LC_MESSAGES/sphinx.po +835 -778
  210. sphinx/locale/sr@latin/LC_MESSAGES/sphinx.mo +0 -0
  211. sphinx/locale/sr_RS/LC_MESSAGES/sphinx.mo +0 -0
  212. sphinx/locale/sv/LC_MESSAGES/sphinx.mo +0 -0
  213. sphinx/locale/sv/LC_MESSAGES/sphinx.po +837 -780
  214. sphinx/locale/ta/LC_MESSAGES/sphinx.js +54 -54
  215. sphinx/locale/ta/LC_MESSAGES/sphinx.mo +0 -0
  216. sphinx/locale/ta/LC_MESSAGES/sphinx.po +1530 -1473
  217. sphinx/locale/te/LC_MESSAGES/sphinx.mo +0 -0
  218. sphinx/locale/te/LC_MESSAGES/sphinx.po +811 -754
  219. sphinx/locale/tr/LC_MESSAGES/sphinx.mo +0 -0
  220. sphinx/locale/tr/LC_MESSAGES/sphinx.po +853 -796
  221. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.mo +0 -0
  222. sphinx/locale/uk_UA/LC_MESSAGES/sphinx.po +833 -776
  223. sphinx/locale/ur/LC_MESSAGES/sphinx.mo +0 -0
  224. sphinx/locale/ur/LC_MESSAGES/sphinx.po +811 -754
  225. sphinx/locale/vi/LC_MESSAGES/sphinx.mo +0 -0
  226. sphinx/locale/vi/LC_MESSAGES/sphinx.po +837 -780
  227. sphinx/locale/yue/LC_MESSAGES/sphinx.mo +0 -0
  228. sphinx/locale/yue/LC_MESSAGES/sphinx.po +811 -754
  229. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.mo +0 -0
  230. sphinx/locale/zh_CN/LC_MESSAGES/sphinx.po +855 -798
  231. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.mo +0 -0
  232. sphinx/locale/zh_HK/LC_MESSAGES/sphinx.po +811 -754
  233. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.js +1 -1
  234. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.mo +0 -0
  235. sphinx/locale/zh_TW/LC_MESSAGES/sphinx.po +879 -822
  236. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.mo +0 -0
  237. sphinx/locale/zh_TW.Big5/LC_MESSAGES/sphinx.po +811 -754
  238. sphinx/parsers.py +7 -5
  239. sphinx/project.py +18 -11
  240. sphinx/pycode/__init__.py +6 -5
  241. sphinx/pycode/ast.py +23 -8
  242. sphinx/pycode/parser.py +6 -5
  243. sphinx/registry.py +12 -6
  244. sphinx/roles.py +103 -57
  245. sphinx/search/__init__.py +17 -18
  246. sphinx/search/da.py +2 -2
  247. sphinx/search/de.py +2 -2
  248. sphinx/search/en.py +1 -1
  249. sphinx/search/es.py +2 -2
  250. sphinx/search/fi.py +2 -2
  251. sphinx/search/fr.py +2 -2
  252. sphinx/search/hu.py +2 -2
  253. sphinx/search/it.py +2 -2
  254. sphinx/search/ja.py +13 -22
  255. sphinx/search/nl.py +2 -2
  256. sphinx/search/no.py +2 -2
  257. sphinx/search/pt.py +2 -2
  258. sphinx/search/ro.py +1 -1
  259. sphinx/search/ru.py +2 -2
  260. sphinx/search/sv.py +2 -2
  261. sphinx/search/tr.py +1 -1
  262. sphinx/search/zh.py +2 -3
  263. sphinx/templates/graphviz/graphviz.css +1 -1
  264. sphinx/testing/fixtures.py +41 -24
  265. sphinx/testing/path.py +1 -1
  266. sphinx/testing/util.py +142 -53
  267. sphinx/texinputs/sphinx.xdy +1 -1
  268. sphinx/texinputs/sphinxlatextables.sty +1 -1
  269. sphinx/texinputs/sphinxpackagesubstitutefont.sty +21 -0
  270. sphinx/themes/agogo/layout.html +4 -4
  271. sphinx/themes/agogo/static/agogo.css_t +1 -1
  272. sphinx/themes/agogo/theme.toml +22 -0
  273. sphinx/themes/basic/defindex.html +1 -1
  274. sphinx/themes/basic/domainindex.html +1 -1
  275. sphinx/themes/basic/genindex-single.html +1 -1
  276. sphinx/themes/basic/genindex-split.html +1 -1
  277. sphinx/themes/basic/genindex.html +1 -1
  278. sphinx/themes/basic/globaltoc.html +1 -1
  279. sphinx/themes/basic/layout.html +1 -1
  280. sphinx/themes/basic/localtoc.html +1 -1
  281. sphinx/themes/basic/page.html +1 -1
  282. sphinx/themes/basic/relations.html +1 -1
  283. sphinx/themes/basic/search.html +5 -20
  284. sphinx/themes/basic/searchbox.html +3 -3
  285. sphinx/themes/basic/searchfield.html +3 -3
  286. sphinx/themes/basic/sourcelink.html +1 -1
  287. sphinx/themes/basic/static/basic.css_t +1 -1
  288. sphinx/themes/basic/static/doctools.js +1 -1
  289. sphinx/themes/basic/static/language_data.js_t +2 -2
  290. sphinx/themes/basic/static/searchtools.js +105 -60
  291. sphinx/themes/basic/theme.toml +23 -0
  292. sphinx/themes/bizstyle/layout.html +1 -6
  293. sphinx/themes/bizstyle/static/bizstyle.css_t +1 -1
  294. sphinx/themes/bizstyle/static/bizstyle.js_t +1 -1
  295. sphinx/themes/bizstyle/static/css3-mediaqueries_src.js +3 -3
  296. sphinx/themes/bizstyle/theme.toml +12 -0
  297. sphinx/themes/classic/layout.html +1 -1
  298. sphinx/themes/classic/static/classic.css_t +1 -1
  299. sphinx/themes/classic/static/sidebar.js_t +1 -1
  300. sphinx/themes/classic/theme.toml +34 -0
  301. sphinx/themes/default/theme.toml +2 -0
  302. sphinx/themes/epub/epub-cover.html +1 -1
  303. sphinx/themes/epub/layout.html +1 -1
  304. sphinx/themes/epub/static/epub.css_t +1 -1
  305. sphinx/themes/epub/theme.toml +10 -0
  306. sphinx/themes/haiku/layout.html +3 -3
  307. sphinx/themes/haiku/static/haiku.css_t +2 -2
  308. sphinx/themes/haiku/theme.toml +16 -0
  309. sphinx/themes/nature/static/nature.css_t +1 -1
  310. sphinx/themes/nature/theme.toml +6 -0
  311. sphinx/themes/nonav/layout.html +1 -1
  312. sphinx/themes/nonav/static/nonav.css_t +1 -1
  313. sphinx/themes/nonav/theme.toml +10 -0
  314. sphinx/themes/pyramid/static/epub.css_t +1 -1
  315. sphinx/themes/pyramid/static/pyramid.css_t +1 -1
  316. sphinx/themes/pyramid/theme.toml +6 -0
  317. sphinx/themes/scrolls/artwork/logo.svg +1 -1
  318. sphinx/themes/scrolls/layout.html +2 -2
  319. sphinx/themes/scrolls/static/scrolls.css_t +1 -1
  320. sphinx/themes/scrolls/theme.toml +15 -0
  321. sphinx/themes/sphinxdoc/static/sphinxdoc.css_t +1 -1
  322. sphinx/themes/sphinxdoc/theme.toml +6 -0
  323. sphinx/themes/traditional/static/traditional.css_t +1 -1
  324. sphinx/themes/traditional/theme.toml +9 -0
  325. sphinx/theming.py +427 -131
  326. sphinx/transforms/__init__.py +21 -24
  327. sphinx/transforms/compact_bullet_list.py +5 -5
  328. sphinx/transforms/i18n.py +30 -28
  329. sphinx/transforms/post_transforms/__init__.py +9 -7
  330. sphinx/transforms/post_transforms/code.py +4 -1
  331. sphinx/transforms/post_transforms/images.py +17 -13
  332. sphinx/transforms/references.py +3 -1
  333. sphinx/util/__init__.py +15 -11
  334. sphinx/util/_io.py +34 -0
  335. sphinx/util/_pathlib.py +23 -18
  336. sphinx/util/build_phase.py +1 -0
  337. sphinx/util/cfamily.py +19 -11
  338. sphinx/util/console.py +101 -21
  339. sphinx/util/display.py +3 -2
  340. sphinx/util/docfields.py +12 -8
  341. sphinx/util/docutils.py +21 -35
  342. sphinx/util/exceptions.py +3 -2
  343. sphinx/util/fileutil.py +5 -5
  344. sphinx/util/http_date.py +9 -2
  345. sphinx/util/i18n.py +40 -9
  346. sphinx/util/inspect.py +317 -245
  347. sphinx/util/inventory.py +22 -5
  348. sphinx/util/logging.py +81 -7
  349. sphinx/util/matching.py +2 -1
  350. sphinx/util/math.py +1 -2
  351. sphinx/util/nodes.py +39 -29
  352. sphinx/util/osutil.py +25 -6
  353. sphinx/util/parallel.py +6 -1
  354. sphinx/util/requests.py +8 -5
  355. sphinx/util/rst.py +8 -6
  356. sphinx/util/tags.py +3 -3
  357. sphinx/util/template.py +8 -3
  358. sphinx/util/typing.py +76 -42
  359. sphinx/versioning.py +6 -2
  360. sphinx/writers/html.py +1 -1
  361. sphinx/writers/html5.py +17 -13
  362. sphinx/writers/latex.py +12 -12
  363. sphinx/writers/manpage.py +13 -7
  364. sphinx/writers/texinfo.py +13 -10
  365. sphinx/writers/text.py +13 -23
  366. sphinx/writers/xml.py +1 -1
  367. sphinx-7.2.6.dist-info/LICENSE → sphinx-7.3.1.dist-info/LICENSE.rst +1 -1
  368. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/METADATA +14 -12
  369. sphinx-7.3.1.dist-info/RECORD +581 -0
  370. sphinx/domains/c.py +0 -3906
  371. sphinx/domains/cpp.py +0 -8233
  372. sphinx/domains/python.py +0 -1769
  373. sphinx/themes/agogo/theme.conf +0 -20
  374. sphinx/themes/basic/theme.conf +0 -16
  375. sphinx/themes/bizstyle/theme.conf +0 -10
  376. sphinx/themes/classic/theme.conf +0 -32
  377. sphinx/themes/default/theme.conf +0 -2
  378. sphinx/themes/epub/theme.conf +0 -8
  379. sphinx/themes/haiku/theme.conf +0 -14
  380. sphinx/themes/nature/theme.conf +0 -4
  381. sphinx/themes/nonav/theme.conf +0 -8
  382. sphinx/themes/pyramid/theme.conf +0 -4
  383. sphinx/themes/scrolls/theme.conf +0 -13
  384. sphinx/themes/sphinxdoc/theme.conf +0 -4
  385. sphinx/themes/traditional/theme.conf +0 -7
  386. sphinx-7.2.6.dist-info/RECORD +0 -569
  387. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/WHEEL +0 -0
  388. {sphinx-7.2.6.dist-info → sphinx-7.3.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,1092 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any, Callable, NoReturn
4
+
5
+ from sphinx.domains.cpp._ast import (
6
+ ASTDeclaration,
7
+ ASTIdentifier,
8
+ ASTNestedName,
9
+ ASTNestedNameElement,
10
+ ASTOperator,
11
+ ASTTemplateArgs,
12
+ ASTTemplateDeclarationPrefix,
13
+ ASTTemplateIntroduction,
14
+ ASTTemplateParams,
15
+ )
16
+ from sphinx.locale import __
17
+ from sphinx.util import logging
18
+
19
+ if TYPE_CHECKING:
20
+ from collections.abc import Iterator
21
+
22
+ from sphinx.environment import BuildEnvironment
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class _DuplicateSymbolError(Exception):
28
+ def __init__(self, symbol: Symbol, declaration: ASTDeclaration) -> None:
29
+ assert symbol
30
+ assert declaration
31
+ self.symbol = symbol
32
+ self.declaration = declaration
33
+
34
+ def __str__(self) -> str:
35
+ return "Internal C++ duplicate symbol error:\n%s" % self.symbol.dump(0)
36
+
37
+
38
+ class SymbolLookupResult:
39
+ def __init__(self, symbols: Iterator[Symbol], parentSymbol: Symbol,
40
+ identOrOp: ASTIdentifier | ASTOperator, templateParams: Any,
41
+ templateArgs: ASTTemplateArgs) -> None:
42
+ self.symbols = symbols
43
+ self.parentSymbol = parentSymbol
44
+ self.identOrOp = identOrOp
45
+ self.templateParams = templateParams
46
+ self.templateArgs = templateArgs
47
+
48
+
49
+ class LookupKey:
50
+ def __init__(self, data: list[tuple[ASTNestedNameElement,
51
+ ASTTemplateParams | ASTTemplateIntroduction,
52
+ str]]) -> None:
53
+ self.data = data
54
+
55
+
56
+ def _is_specialization(templateParams: ASTTemplateParams | ASTTemplateIntroduction,
57
+ templateArgs: ASTTemplateArgs) -> bool:
58
+ # Checks if `templateArgs` does not exactly match `templateParams`.
59
+ # the names of the template parameters must be given exactly as args
60
+ # and params that are packs must in the args be the name expanded
61
+ if len(templateParams.params) != len(templateArgs.args):
62
+ return True
63
+ # having no template params and no arguments is also a specialization
64
+ if len(templateParams.params) == 0:
65
+ return True
66
+ for i in range(len(templateParams.params)):
67
+ param = templateParams.params[i]
68
+ arg = templateArgs.args[i]
69
+ # TODO: doing this by string manipulation is probably not the most efficient
70
+ paramName = str(param.name)
71
+ argTxt = str(arg)
72
+ isArgPackExpansion = argTxt.endswith('...')
73
+ if param.isPack != isArgPackExpansion:
74
+ return True
75
+ argName = argTxt[:-3] if isArgPackExpansion else argTxt
76
+ if paramName != argName:
77
+ return True
78
+ return False
79
+
80
+
81
+ class Symbol:
82
+ debug_indent = 0
83
+ debug_indent_string = " "
84
+ debug_lookup = False # overridden by the corresponding config value
85
+ debug_show_tree = False # overridden by the corresponding config value
86
+
87
+ def __copy__(self) -> NoReturn:
88
+ raise AssertionError # shouldn't happen
89
+
90
+ def __deepcopy__(self, memo: Any) -> Symbol:
91
+ if self.parent:
92
+ raise AssertionError # shouldn't happen
93
+ # the domain base class makes a copy of the initial data, which is fine
94
+ return Symbol(None, None, None, None, None, None, None)
95
+
96
+ @staticmethod
97
+ def debug_print(*args: Any) -> None:
98
+ logger.debug(Symbol.debug_indent_string * Symbol.debug_indent, end="")
99
+ logger.debug(*args)
100
+
101
+ def _assert_invariants(self) -> None:
102
+ if not self.parent:
103
+ # parent == None means global scope, so declaration means a parent
104
+ assert not self.identOrOp
105
+ assert not self.templateParams
106
+ assert not self.templateArgs
107
+ assert not self.declaration
108
+ assert not self.docname
109
+ else:
110
+ if self.declaration:
111
+ assert self.docname
112
+
113
+ def __setattr__(self, key: str, value: Any) -> None:
114
+ if key == "children":
115
+ raise AssertionError
116
+ return super().__setattr__(key, value)
117
+
118
+ def __init__(self, parent: Symbol | None,
119
+ identOrOp: ASTIdentifier | ASTOperator | None,
120
+ templateParams: ASTTemplateParams | ASTTemplateIntroduction | None,
121
+ templateArgs: Any, declaration: ASTDeclaration | None,
122
+ docname: str | None, line: int | None) -> None:
123
+ self.parent = parent
124
+ # declarations in a single directive are linked together
125
+ self.siblingAbove: Symbol | None = None
126
+ self.siblingBelow: Symbol | None = None
127
+ self.identOrOp = identOrOp
128
+ # Ensure the same symbol for `A` is created for:
129
+ #
130
+ # .. cpp:class:: template <typename T> class A
131
+ #
132
+ # and
133
+ #
134
+ # .. cpp:function:: template <typename T> int A<T>::foo()
135
+ if (templateArgs is not None and
136
+ not _is_specialization(templateParams, templateArgs)):
137
+ templateArgs = None
138
+ self.templateParams = templateParams # template<templateParams>
139
+ self.templateArgs = templateArgs # identifier<templateArgs>
140
+ self.declaration = declaration
141
+ self.docname = docname
142
+ self.line = line
143
+ self.isRedeclaration = False
144
+ self._assert_invariants()
145
+
146
+ # Remember to modify Symbol.remove if modifications to the parent change.
147
+ self._children: list[Symbol] = []
148
+ self._anonChildren: list[Symbol] = []
149
+ # note: _children includes _anonChildren
150
+ if self.parent:
151
+ self.parent._children.append(self)
152
+ if self.declaration:
153
+ self.declaration.symbol = self
154
+
155
+ # Do symbol addition after self._children has been initialised.
156
+ self._add_template_and_function_params()
157
+
158
+ def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> None:
159
+ self._assert_invariants()
160
+ assert self.declaration is None
161
+ assert self.docname is None
162
+ assert self.line is None
163
+ assert declaration is not None
164
+ assert docname is not None
165
+ assert line is not None
166
+ self.declaration = declaration
167
+ self.declaration.symbol = self
168
+ self.docname = docname
169
+ self.line = line
170
+ self._assert_invariants()
171
+ # and symbol addition should be done as well
172
+ self._add_template_and_function_params()
173
+
174
+ def _add_template_and_function_params(self) -> None:
175
+ if Symbol.debug_lookup:
176
+ Symbol.debug_indent += 1
177
+ Symbol.debug_print("_add_template_and_function_params:")
178
+ # Note: we may be called from _fill_empty, so the symbols we want
179
+ # to add may actually already be present (as empty symbols).
180
+
181
+ # add symbols for the template params
182
+ if self.templateParams:
183
+ for tp in self.templateParams.params:
184
+ if not tp.get_identifier():
185
+ continue
186
+ # only add a declaration if we our self are from a declaration
187
+ if self.declaration:
188
+ decl = ASTDeclaration(objectType='templateParam', declaration=tp)
189
+ else:
190
+ decl = None
191
+ nne = ASTNestedNameElement(tp.get_identifier(), None)
192
+ nn = ASTNestedName([nne], [False], rooted=False)
193
+ self._add_symbols(nn, [], decl, self.docname, self.line)
194
+ # add symbols for function parameters, if any
195
+ if self.declaration is not None and self.declaration.function_params is not None:
196
+ for fp in self.declaration.function_params:
197
+ if fp.arg is None:
198
+ continue
199
+ nn = fp.arg.name
200
+ if nn is None:
201
+ continue
202
+ # (comparing to the template params: we have checked that we are a declaration)
203
+ decl = ASTDeclaration(objectType='functionParam', declaration=fp)
204
+ assert not nn.rooted
205
+ assert len(nn.names) == 1
206
+ self._add_symbols(nn, [], decl, self.docname, self.line)
207
+ if Symbol.debug_lookup:
208
+ Symbol.debug_indent -= 1
209
+
210
+ def remove(self) -> None:
211
+ if self.parent is None:
212
+ return
213
+ assert self in self.parent._children
214
+ self.parent._children.remove(self)
215
+ self.parent = None
216
+
217
+ def clear_doc(self, docname: str) -> None:
218
+ newChildren: list[Symbol] = []
219
+ for sChild in self._children:
220
+ sChild.clear_doc(docname)
221
+ if sChild.declaration and sChild.docname == docname:
222
+ sChild.declaration = None
223
+ sChild.docname = None
224
+ sChild.line = None
225
+ if sChild.siblingAbove is not None:
226
+ sChild.siblingAbove.siblingBelow = sChild.siblingBelow
227
+ if sChild.siblingBelow is not None:
228
+ sChild.siblingBelow.siblingAbove = sChild.siblingAbove
229
+ sChild.siblingAbove = None
230
+ sChild.siblingBelow = None
231
+ newChildren.append(sChild)
232
+ self._children = newChildren
233
+
234
+ def get_all_symbols(self) -> Iterator[Any]:
235
+ yield self
236
+ for sChild in self._children:
237
+ yield from sChild.get_all_symbols()
238
+
239
+ @property
240
+ def children_recurse_anon(self) -> Iterator[Symbol]:
241
+ for c in self._children:
242
+ yield c
243
+ if not c.identOrOp.is_anon():
244
+ continue
245
+
246
+ yield from c.children_recurse_anon
247
+
248
+ def get_lookup_key(self) -> LookupKey:
249
+ # The pickle files for the environment and for each document are distinct.
250
+ # The environment has all the symbols, but the documents has xrefs that
251
+ # must know their scope. A lookup key is essentially a specification of
252
+ # how to find a specific symbol.
253
+ symbols = []
254
+ s = self
255
+ while s.parent:
256
+ symbols.append(s)
257
+ s = s.parent
258
+ symbols.reverse()
259
+ key = []
260
+ for s in symbols:
261
+ nne = ASTNestedNameElement(s.identOrOp, s.templateArgs)
262
+ if s.declaration is not None:
263
+ key.append((nne, s.templateParams, s.declaration.get_newest_id()))
264
+ else:
265
+ key.append((nne, s.templateParams, None))
266
+ return LookupKey(key)
267
+
268
+ def get_full_nested_name(self) -> ASTNestedName:
269
+ symbols = []
270
+ s = self
271
+ while s.parent:
272
+ symbols.append(s)
273
+ s = s.parent
274
+ symbols.reverse()
275
+ names = []
276
+ templates = []
277
+ for s in symbols:
278
+ names.append(ASTNestedNameElement(s.identOrOp, s.templateArgs))
279
+ templates.append(False)
280
+ return ASTNestedName(names, templates, rooted=False)
281
+
282
+ def _find_first_named_symbol(self, identOrOp: ASTIdentifier | ASTOperator,
283
+ templateParams: ASTTemplateParams | ASTTemplateIntroduction,
284
+ templateArgs: ASTTemplateArgs | None,
285
+ templateShorthand: bool, matchSelf: bool,
286
+ recurseInAnon: bool, correctPrimaryTemplateArgs: bool,
287
+ ) -> Symbol | None:
288
+ if Symbol.debug_lookup:
289
+ Symbol.debug_print("_find_first_named_symbol ->")
290
+ res = self._find_named_symbols(identOrOp, templateParams, templateArgs,
291
+ templateShorthand, matchSelf, recurseInAnon,
292
+ correctPrimaryTemplateArgs,
293
+ searchInSiblings=False)
294
+ try:
295
+ return next(res)
296
+ except StopIteration:
297
+ return None
298
+
299
+ def _find_named_symbols(self, identOrOp: ASTIdentifier | ASTOperator,
300
+ templateParams: ASTTemplateParams | ASTTemplateIntroduction,
301
+ templateArgs: ASTTemplateArgs,
302
+ templateShorthand: bool, matchSelf: bool,
303
+ recurseInAnon: bool, correctPrimaryTemplateArgs: bool,
304
+ searchInSiblings: bool) -> Iterator[Symbol]:
305
+ if Symbol.debug_lookup:
306
+ Symbol.debug_indent += 1
307
+ Symbol.debug_print("_find_named_symbols:")
308
+ Symbol.debug_indent += 1
309
+ Symbol.debug_print("self:")
310
+ logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
311
+ Symbol.debug_print("identOrOp: ", identOrOp)
312
+ Symbol.debug_print("templateParams: ", templateParams)
313
+ Symbol.debug_print("templateArgs: ", templateArgs)
314
+ Symbol.debug_print("templateShorthand: ", templateShorthand)
315
+ Symbol.debug_print("matchSelf: ", matchSelf)
316
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
317
+ Symbol.debug_print("correctPrimaryTemplateAargs:", correctPrimaryTemplateArgs)
318
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
319
+
320
+ if correctPrimaryTemplateArgs:
321
+ if templateParams is not None and templateArgs is not None:
322
+ # If both are given, but it's not a specialization, then do lookup as if
323
+ # there is no argument list.
324
+ # For example: template<typename T> int A<T>::var;
325
+ if not _is_specialization(templateParams, templateArgs):
326
+ templateArgs = None
327
+
328
+ def matches(s: Symbol) -> bool:
329
+ if s.identOrOp != identOrOp:
330
+ return False
331
+ if (s.templateParams is None) != (templateParams is None):
332
+ if templateParams is not None:
333
+ # we query with params, they must match params
334
+ return False
335
+ if not templateShorthand:
336
+ # we don't query with params, and we do care about them
337
+ return False
338
+ if templateParams:
339
+ # TODO: do better comparison
340
+ if str(s.templateParams) != str(templateParams):
341
+ return False
342
+ if (s.templateArgs is None) != (templateArgs is None):
343
+ return False
344
+ if s.templateArgs:
345
+ # TODO: do better comparison
346
+ if str(s.templateArgs) != str(templateArgs):
347
+ return False
348
+ return True
349
+
350
+ def candidates() -> Iterator[Symbol]:
351
+ s = self
352
+ if Symbol.debug_lookup:
353
+ Symbol.debug_print("searching in self:")
354
+ logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
355
+ while True:
356
+ if matchSelf:
357
+ yield s
358
+ if recurseInAnon:
359
+ yield from s.children_recurse_anon
360
+ else:
361
+ yield from s._children
362
+
363
+ if s.siblingAbove is None:
364
+ break
365
+ s = s.siblingAbove
366
+ if Symbol.debug_lookup:
367
+ Symbol.debug_print("searching in sibling:")
368
+ logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
369
+
370
+ for s in candidates():
371
+ if Symbol.debug_lookup:
372
+ Symbol.debug_print("candidate:")
373
+ logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
374
+ if matches(s):
375
+ if Symbol.debug_lookup:
376
+ Symbol.debug_indent += 1
377
+ Symbol.debug_print("matches")
378
+ Symbol.debug_indent -= 3
379
+ yield s
380
+ if Symbol.debug_lookup:
381
+ Symbol.debug_indent += 2
382
+ if Symbol.debug_lookup:
383
+ Symbol.debug_indent -= 2
384
+
385
+ def _symbol_lookup(
386
+ self,
387
+ nestedName: ASTNestedName,
388
+ templateDecls: list[Any],
389
+ onMissingQualifiedSymbol: Callable[
390
+ [Symbol, ASTIdentifier | ASTOperator, Any, ASTTemplateArgs], Symbol | None,
391
+ ],
392
+ strictTemplateParamArgLists: bool, ancestorLookupType: str,
393
+ templateShorthand: bool, matchSelf: bool,
394
+ recurseInAnon: bool, correctPrimaryTemplateArgs: bool,
395
+ searchInSiblings: bool,
396
+ ) -> SymbolLookupResult:
397
+ # ancestorLookupType: if not None, specifies the target type of the lookup
398
+ if Symbol.debug_lookup:
399
+ Symbol.debug_indent += 1
400
+ Symbol.debug_print("_symbol_lookup:")
401
+ Symbol.debug_indent += 1
402
+ Symbol.debug_print("self:")
403
+ logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
404
+ Symbol.debug_print("nestedName: ", nestedName)
405
+ Symbol.debug_print("templateDecls: ", ",".join(str(t) for t in templateDecls))
406
+ Symbol.debug_print("strictTemplateParamArgLists:", strictTemplateParamArgLists)
407
+ Symbol.debug_print("ancestorLookupType:", ancestorLookupType)
408
+ Symbol.debug_print("templateShorthand: ", templateShorthand)
409
+ Symbol.debug_print("matchSelf: ", matchSelf)
410
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
411
+ Symbol.debug_print("correctPrimaryTemplateArgs: ", correctPrimaryTemplateArgs)
412
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
413
+
414
+ if strictTemplateParamArgLists:
415
+ # Each template argument list must have a template parameter list.
416
+ # But to declare a template there must be an additional template parameter list.
417
+ assert (nestedName.num_templates() == len(templateDecls) or
418
+ nestedName.num_templates() + 1 == len(templateDecls))
419
+ else:
420
+ assert len(templateDecls) <= nestedName.num_templates() + 1
421
+
422
+ names = nestedName.names
423
+
424
+ # find the right starting point for lookup
425
+ parentSymbol = self
426
+ if nestedName.rooted:
427
+ while parentSymbol.parent:
428
+ parentSymbol = parentSymbol.parent
429
+ if ancestorLookupType is not None:
430
+ # walk up until we find the first identifier
431
+ firstName = names[0]
432
+ if not firstName.is_operator():
433
+ while parentSymbol.parent:
434
+ if parentSymbol.find_identifier(firstName.identOrOp,
435
+ matchSelf=matchSelf,
436
+ recurseInAnon=recurseInAnon,
437
+ searchInSiblings=searchInSiblings):
438
+ # if we are in the scope of a constructor but wants to
439
+ # reference the class we need to walk one extra up
440
+ if (len(names) == 1 and ancestorLookupType == 'class' and matchSelf and
441
+ parentSymbol.parent and
442
+ parentSymbol.parent.identOrOp == firstName.identOrOp):
443
+ pass
444
+ else:
445
+ break
446
+ parentSymbol = parentSymbol.parent
447
+
448
+ if Symbol.debug_lookup:
449
+ Symbol.debug_print("starting point:")
450
+ logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
451
+
452
+ # and now the actual lookup
453
+ iTemplateDecl = 0
454
+ for name in names[:-1]:
455
+ identOrOp = name.identOrOp
456
+ templateArgs = name.templateArgs
457
+ if strictTemplateParamArgLists:
458
+ # there must be a parameter list
459
+ if templateArgs:
460
+ assert iTemplateDecl < len(templateDecls)
461
+ templateParams = templateDecls[iTemplateDecl]
462
+ iTemplateDecl += 1
463
+ else:
464
+ templateParams = None
465
+ else:
466
+ # take the next template parameter list if there is one
467
+ # otherwise it's ok
468
+ if templateArgs and iTemplateDecl < len(templateDecls):
469
+ templateParams = templateDecls[iTemplateDecl]
470
+ iTemplateDecl += 1
471
+ else:
472
+ templateParams = None
473
+
474
+ symbol = parentSymbol._find_first_named_symbol(
475
+ identOrOp,
476
+ templateParams, templateArgs,
477
+ templateShorthand=templateShorthand,
478
+ matchSelf=matchSelf,
479
+ recurseInAnon=recurseInAnon,
480
+ correctPrimaryTemplateArgs=correctPrimaryTemplateArgs)
481
+ if symbol is None:
482
+ symbol = onMissingQualifiedSymbol(parentSymbol, identOrOp,
483
+ templateParams, templateArgs)
484
+ if symbol is None:
485
+ if Symbol.debug_lookup:
486
+ Symbol.debug_indent -= 2
487
+ return None
488
+ # We have now matched part of a nested name, and need to match more
489
+ # so even if we should matchSelf before, we definitely shouldn't
490
+ # even more. (see also issue #2666)
491
+ matchSelf = False
492
+ parentSymbol = symbol
493
+
494
+ if Symbol.debug_lookup:
495
+ Symbol.debug_print("handle last name from:")
496
+ logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
497
+
498
+ # handle the last name
499
+ name = names[-1]
500
+ identOrOp = name.identOrOp
501
+ templateArgs = name.templateArgs
502
+ if iTemplateDecl < len(templateDecls):
503
+ assert iTemplateDecl + 1 == len(templateDecls)
504
+ templateParams = templateDecls[iTemplateDecl]
505
+ else:
506
+ assert iTemplateDecl == len(templateDecls)
507
+ templateParams = None
508
+
509
+ symbols = parentSymbol._find_named_symbols(
510
+ identOrOp, templateParams, templateArgs,
511
+ templateShorthand=templateShorthand, matchSelf=matchSelf,
512
+ recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False,
513
+ searchInSiblings=searchInSiblings)
514
+ if Symbol.debug_lookup:
515
+ symbols = list(symbols) # type: ignore[assignment]
516
+ Symbol.debug_indent -= 2
517
+ return SymbolLookupResult(symbols, parentSymbol,
518
+ identOrOp, templateParams, templateArgs)
519
+
520
+ def _add_symbols(
521
+ self,
522
+ nestedName: ASTNestedName,
523
+ templateDecls: list[Any],
524
+ declaration: ASTDeclaration | None,
525
+ docname: str | None,
526
+ line: int | None,
527
+ ) -> Symbol:
528
+ # Used for adding a whole path of symbols, where the last may or may not
529
+ # be an actual declaration.
530
+
531
+ if Symbol.debug_lookup:
532
+ Symbol.debug_indent += 1
533
+ Symbol.debug_print("_add_symbols:")
534
+ Symbol.debug_indent += 1
535
+ Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls))
536
+ Symbol.debug_print("nn: ", nestedName)
537
+ Symbol.debug_print("decl: ", declaration)
538
+ Symbol.debug_print(f"location: {docname}:{line}")
539
+
540
+ def onMissingQualifiedSymbol(parentSymbol: Symbol,
541
+ identOrOp: ASTIdentifier | ASTOperator,
542
+ templateParams: Any, templateArgs: ASTTemplateArgs,
543
+ ) -> Symbol | None:
544
+ if Symbol.debug_lookup:
545
+ Symbol.debug_indent += 1
546
+ Symbol.debug_print("_add_symbols, onMissingQualifiedSymbol:")
547
+ Symbol.debug_indent += 1
548
+ Symbol.debug_print("templateParams:", templateParams)
549
+ Symbol.debug_print("identOrOp: ", identOrOp)
550
+ Symbol.debug_print("templateARgs: ", templateArgs)
551
+ Symbol.debug_indent -= 2
552
+ return Symbol(parent=parentSymbol, identOrOp=identOrOp,
553
+ templateParams=templateParams,
554
+ templateArgs=templateArgs, declaration=None,
555
+ docname=None, line=None)
556
+
557
+ lookupResult = self._symbol_lookup(nestedName, templateDecls,
558
+ onMissingQualifiedSymbol,
559
+ strictTemplateParamArgLists=True,
560
+ ancestorLookupType=None,
561
+ templateShorthand=False,
562
+ matchSelf=False,
563
+ recurseInAnon=False,
564
+ correctPrimaryTemplateArgs=True,
565
+ searchInSiblings=False)
566
+ assert lookupResult is not None # we create symbols all the way, so that can't happen
567
+ symbols = list(lookupResult.symbols)
568
+ if len(symbols) == 0:
569
+ if Symbol.debug_lookup:
570
+ Symbol.debug_print("_add_symbols, result, no symbol:")
571
+ Symbol.debug_indent += 1
572
+ Symbol.debug_print("templateParams:", lookupResult.templateParams)
573
+ Symbol.debug_print("identOrOp: ", lookupResult.identOrOp)
574
+ Symbol.debug_print("templateArgs: ", lookupResult.templateArgs)
575
+ Symbol.debug_print("declaration: ", declaration)
576
+ Symbol.debug_print(f"location: {docname}:{line}")
577
+ Symbol.debug_indent -= 1
578
+ symbol = Symbol(parent=lookupResult.parentSymbol,
579
+ identOrOp=lookupResult.identOrOp,
580
+ templateParams=lookupResult.templateParams,
581
+ templateArgs=lookupResult.templateArgs,
582
+ declaration=declaration,
583
+ docname=docname, line=line)
584
+ if Symbol.debug_lookup:
585
+ Symbol.debug_indent -= 2
586
+ return symbol
587
+
588
+ if Symbol.debug_lookup:
589
+ Symbol.debug_print("_add_symbols, result, symbols:")
590
+ Symbol.debug_indent += 1
591
+ Symbol.debug_print("number symbols:", len(symbols))
592
+ Symbol.debug_indent -= 1
593
+
594
+ if not declaration:
595
+ if Symbol.debug_lookup:
596
+ Symbol.debug_print("no declaration")
597
+ Symbol.debug_indent -= 2
598
+ # good, just a scope creation
599
+ # TODO: what if we have more than one symbol?
600
+ return symbols[0]
601
+
602
+ noDecl = []
603
+ withDecl = []
604
+ dupDecl = []
605
+ for s in symbols:
606
+ if s.declaration is None:
607
+ noDecl.append(s)
608
+ elif s.isRedeclaration:
609
+ dupDecl.append(s)
610
+ else:
611
+ withDecl.append(s)
612
+ if Symbol.debug_lookup:
613
+ Symbol.debug_print("#noDecl: ", len(noDecl))
614
+ Symbol.debug_print("#withDecl:", len(withDecl))
615
+ Symbol.debug_print("#dupDecl: ", len(dupDecl))
616
+ # With partial builds we may start with a large symbol tree stripped of declarations.
617
+ # Essentially any combination of noDecl, withDecl, and dupDecls seems possible.
618
+ # TODO: make partial builds fully work. What should happen when the primary symbol gets
619
+ # deleted, and other duplicates exist? The full document should probably be rebuild.
620
+
621
+ # First check if one of those with a declaration matches.
622
+ # If it's a function, we need to compare IDs,
623
+ # otherwise there should be only one symbol with a declaration.
624
+ def makeCandSymbol() -> Symbol:
625
+ if Symbol.debug_lookup:
626
+ Symbol.debug_print("begin: creating candidate symbol")
627
+ symbol = Symbol(parent=lookupResult.parentSymbol,
628
+ identOrOp=lookupResult.identOrOp,
629
+ templateParams=lookupResult.templateParams,
630
+ templateArgs=lookupResult.templateArgs,
631
+ declaration=declaration,
632
+ docname=docname, line=line)
633
+ if Symbol.debug_lookup:
634
+ Symbol.debug_print("end: creating candidate symbol")
635
+ return symbol
636
+ if len(withDecl) == 0:
637
+ candSymbol = None
638
+ else:
639
+ candSymbol = makeCandSymbol()
640
+
641
+ def handleDuplicateDeclaration(symbol: Symbol, candSymbol: Symbol) -> None:
642
+ if Symbol.debug_lookup:
643
+ Symbol.debug_indent += 1
644
+ Symbol.debug_print("redeclaration")
645
+ Symbol.debug_indent -= 1
646
+ Symbol.debug_indent -= 2
647
+ # Redeclaration of the same symbol.
648
+ # Let the new one be there, but raise an error to the client
649
+ # so it can use the real symbol as subscope.
650
+ # This will probably result in a duplicate id warning.
651
+ candSymbol.isRedeclaration = True
652
+ raise _DuplicateSymbolError(symbol, declaration)
653
+
654
+ if declaration.objectType != "function":
655
+ assert len(withDecl) <= 1
656
+ handleDuplicateDeclaration(withDecl[0], candSymbol)
657
+ # (not reachable)
658
+
659
+ # a function, so compare IDs
660
+ candId = declaration.get_newest_id()
661
+ if Symbol.debug_lookup:
662
+ Symbol.debug_print("candId:", candId)
663
+ for symbol in withDecl:
664
+ # but all existing must be functions as well,
665
+ # otherwise we declare it to be a duplicate
666
+ if symbol.declaration.objectType != 'function':
667
+ handleDuplicateDeclaration(symbol, candSymbol)
668
+ # (not reachable)
669
+ oldId = symbol.declaration.get_newest_id()
670
+ if Symbol.debug_lookup:
671
+ Symbol.debug_print("oldId: ", oldId)
672
+ if candId == oldId:
673
+ handleDuplicateDeclaration(symbol, candSymbol)
674
+ # (not reachable)
675
+ # no candidate symbol found with matching ID
676
+ # if there is an empty symbol, fill that one
677
+ if len(noDecl) == 0:
678
+ if Symbol.debug_lookup:
679
+ Symbol.debug_print("no match, no empty")
680
+ if candSymbol is not None:
681
+ Symbol.debug_print("result is already created candSymbol")
682
+ else:
683
+ Symbol.debug_print("result is makeCandSymbol()")
684
+ Symbol.debug_indent -= 2
685
+ if candSymbol is not None:
686
+ return candSymbol
687
+ else:
688
+ return makeCandSymbol()
689
+ else:
690
+ if Symbol.debug_lookup:
691
+ Symbol.debug_print(
692
+ "no match, but fill an empty declaration, candSybmol is not None?:",
693
+ candSymbol is not None,
694
+ )
695
+ Symbol.debug_indent -= 2
696
+ if candSymbol is not None:
697
+ candSymbol.remove()
698
+ # assert len(noDecl) == 1
699
+ # TODO: enable assertion when we at some point find out how to do cleanup
700
+ # for now, just take the first one, it should work fine ... right?
701
+ symbol = noDecl[0]
702
+ # If someone first opened the scope, and then later
703
+ # declares it, e.g,
704
+ # .. namespace:: Test
705
+ # .. namespace:: nullptr
706
+ # .. class:: Test
707
+ symbol._fill_empty(declaration, docname, line)
708
+ return symbol
709
+
710
+ def merge_with(self, other: Symbol, docnames: list[str],
711
+ env: BuildEnvironment) -> None:
712
+ if Symbol.debug_lookup:
713
+ Symbol.debug_indent += 1
714
+ Symbol.debug_print("merge_with:")
715
+ assert other is not None
716
+
717
+ def unconditionalAdd(self: Symbol, otherChild: Symbol) -> None:
718
+ # TODO: hmm, should we prune by docnames?
719
+ self._children.append(otherChild)
720
+ otherChild.parent = self
721
+ otherChild._assert_invariants()
722
+
723
+ if Symbol.debug_lookup:
724
+ Symbol.debug_indent += 1
725
+ for otherChild in other._children:
726
+ if Symbol.debug_lookup:
727
+ Symbol.debug_print("otherChild:\n", otherChild.to_string(Symbol.debug_indent))
728
+ Symbol.debug_indent += 1
729
+ if otherChild.isRedeclaration:
730
+ unconditionalAdd(self, otherChild)
731
+ if Symbol.debug_lookup:
732
+ Symbol.debug_print("isRedeclaration")
733
+ Symbol.debug_indent -= 1
734
+ continue
735
+ candiateIter = self._find_named_symbols(
736
+ identOrOp=otherChild.identOrOp,
737
+ templateParams=otherChild.templateParams,
738
+ templateArgs=otherChild.templateArgs,
739
+ templateShorthand=False, matchSelf=False,
740
+ recurseInAnon=False, correctPrimaryTemplateArgs=False,
741
+ searchInSiblings=False)
742
+ candidates = list(candiateIter)
743
+
744
+ if Symbol.debug_lookup:
745
+ Symbol.debug_print("raw candidate symbols:", len(candidates))
746
+ symbols = [s for s in candidates if not s.isRedeclaration]
747
+ if Symbol.debug_lookup:
748
+ Symbol.debug_print("non-duplicate candidate symbols:", len(symbols))
749
+
750
+ if len(symbols) == 0:
751
+ unconditionalAdd(self, otherChild)
752
+ if Symbol.debug_lookup:
753
+ Symbol.debug_indent -= 1
754
+ continue
755
+
756
+ ourChild = None
757
+ if otherChild.declaration is None:
758
+ if Symbol.debug_lookup:
759
+ Symbol.debug_print("no declaration in other child")
760
+ ourChild = symbols[0]
761
+ else:
762
+ queryId = otherChild.declaration.get_newest_id()
763
+ if Symbol.debug_lookup:
764
+ Symbol.debug_print("queryId: ", queryId)
765
+ for symbol in symbols:
766
+ if symbol.declaration is None:
767
+ if Symbol.debug_lookup:
768
+ Symbol.debug_print("empty candidate")
769
+ # if in the end we have non-matching, but have an empty one,
770
+ # then just continue with that
771
+ ourChild = symbol
772
+ continue
773
+ candId = symbol.declaration.get_newest_id()
774
+ if Symbol.debug_lookup:
775
+ Symbol.debug_print("candidate:", candId)
776
+ if candId == queryId:
777
+ ourChild = symbol
778
+ break
779
+ if Symbol.debug_lookup:
780
+ Symbol.debug_indent -= 1
781
+ if ourChild is None:
782
+ unconditionalAdd(self, otherChild)
783
+ continue
784
+ if otherChild.declaration and otherChild.docname in docnames:
785
+ if not ourChild.declaration:
786
+ ourChild._fill_empty(otherChild.declaration,
787
+ otherChild.docname, otherChild.line)
788
+ elif ourChild.docname != otherChild.docname:
789
+ name = str(ourChild.declaration)
790
+ msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
791
+ "Declaration is '.. cpp:%s:: %s'.")
792
+ msg = msg % (ourChild.docname, ourChild.line,
793
+ ourChild.declaration.directiveType, name)
794
+ logger.warning(msg, location=(otherChild.docname, otherChild.line))
795
+ else:
796
+ if (otherChild.declaration.objectType ==
797
+ ourChild.declaration.objectType and
798
+ otherChild.declaration.objectType in
799
+ ('templateParam', 'functionParam') and
800
+ ourChild.parent.declaration == otherChild.parent.declaration):
801
+ # `ourChild` was just created during merging by the call
802
+ # to `_fill_empty` on the parent and can be ignored.
803
+ pass
804
+ else:
805
+ # Both have declarations, and in the same docname.
806
+ # This can apparently happen, it should be safe to
807
+ # just ignore it, right?
808
+ # Hmm, only on duplicate declarations, right?
809
+ msg = "Internal C++ domain error during symbol merging.\n"
810
+ msg += "ourChild:\n" + ourChild.to_string(1)
811
+ msg += "\notherChild:\n" + otherChild.to_string(1)
812
+ logger.warning(msg, location=otherChild.docname)
813
+ ourChild.merge_with(otherChild, docnames, env)
814
+ if Symbol.debug_lookup:
815
+ Symbol.debug_indent -= 2
816
+
817
+ def add_name(self, nestedName: ASTNestedName,
818
+ templatePrefix: ASTTemplateDeclarationPrefix | None = None) -> Symbol:
819
+ if Symbol.debug_lookup:
820
+ Symbol.debug_indent += 1
821
+ Symbol.debug_print("add_name:")
822
+ if templatePrefix:
823
+ templateDecls = templatePrefix.templates
824
+ else:
825
+ templateDecls = []
826
+ res = self._add_symbols(nestedName, templateDecls,
827
+ declaration=None, docname=None, line=None)
828
+ if Symbol.debug_lookup:
829
+ Symbol.debug_indent -= 1
830
+ return res
831
+
832
+ def add_declaration(self, declaration: ASTDeclaration,
833
+ docname: str, line: int) -> Symbol:
834
+ if Symbol.debug_lookup:
835
+ Symbol.debug_indent += 1
836
+ Symbol.debug_print("add_declaration:")
837
+ assert declaration is not None
838
+ assert docname is not None
839
+ assert line is not None
840
+ nestedName = declaration.name
841
+ if declaration.templatePrefix:
842
+ templateDecls = declaration.templatePrefix.templates
843
+ else:
844
+ templateDecls = []
845
+ res = self._add_symbols(nestedName, templateDecls, declaration, docname, line)
846
+ if Symbol.debug_lookup:
847
+ Symbol.debug_indent -= 1
848
+ return res
849
+
850
+ def find_identifier(self, identOrOp: ASTIdentifier | ASTOperator,
851
+ matchSelf: bool, recurseInAnon: bool, searchInSiblings: bool,
852
+ ) -> Symbol | None:
853
+ if Symbol.debug_lookup:
854
+ Symbol.debug_indent += 1
855
+ Symbol.debug_print("find_identifier:")
856
+ Symbol.debug_indent += 1
857
+ Symbol.debug_print("identOrOp: ", identOrOp)
858
+ Symbol.debug_print("matchSelf: ", matchSelf)
859
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
860
+ Symbol.debug_print("searchInSiblings:", searchInSiblings)
861
+ logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
862
+ Symbol.debug_indent -= 2
863
+ current = self
864
+ while current is not None:
865
+ if Symbol.debug_lookup:
866
+ Symbol.debug_indent += 2
867
+ Symbol.debug_print("trying:")
868
+ logger.debug(current.to_string(Symbol.debug_indent + 1), end="")
869
+ Symbol.debug_indent -= 2
870
+ if matchSelf and current.identOrOp == identOrOp:
871
+ return current
872
+ children = current.children_recurse_anon if recurseInAnon else current._children
873
+ for s in children:
874
+ if s.identOrOp == identOrOp:
875
+ return s
876
+ if not searchInSiblings:
877
+ break
878
+ current = current.siblingAbove
879
+ return None
880
+
881
+ def direct_lookup(self, key: LookupKey) -> Symbol:
882
+ if Symbol.debug_lookup:
883
+ Symbol.debug_indent += 1
884
+ Symbol.debug_print("direct_lookup:")
885
+ Symbol.debug_indent += 1
886
+ s = self
887
+ for name, templateParams, id_ in key.data:
888
+ if id_ is not None:
889
+ res = None
890
+ for cand in s._children:
891
+ if cand.declaration is None:
892
+ continue
893
+ if cand.declaration.get_newest_id() == id_:
894
+ res = cand
895
+ break
896
+ s = res
897
+ else:
898
+ identOrOp = name.identOrOp
899
+ templateArgs = name.templateArgs
900
+ s = s._find_first_named_symbol(identOrOp,
901
+ templateParams, templateArgs,
902
+ templateShorthand=False,
903
+ matchSelf=False,
904
+ recurseInAnon=False,
905
+ correctPrimaryTemplateArgs=False)
906
+ if Symbol.debug_lookup:
907
+ Symbol.debug_print("name: ", name)
908
+ Symbol.debug_print("templateParams:", templateParams)
909
+ Symbol.debug_print("id: ", id_)
910
+ if s is not None:
911
+ logger.debug(s.to_string(Symbol.debug_indent + 1), end="")
912
+ else:
913
+ Symbol.debug_print("not found")
914
+ if s is None:
915
+ if Symbol.debug_lookup:
916
+ Symbol.debug_indent -= 2
917
+ return None
918
+ if Symbol.debug_lookup:
919
+ Symbol.debug_indent -= 2
920
+ return s
921
+
922
+ def find_name(
923
+ self,
924
+ nestedName: ASTNestedName,
925
+ templateDecls: list[Any],
926
+ typ: str,
927
+ templateShorthand: bool,
928
+ matchSelf: bool,
929
+ recurseInAnon: bool,
930
+ searchInSiblings: bool,
931
+ ) -> tuple[list[Symbol] | None, str]:
932
+ # templateShorthand: missing template parameter lists for templates is ok
933
+ # If the first component is None,
934
+ # then the second component _may_ be a string explaining why.
935
+ if Symbol.debug_lookup:
936
+ Symbol.debug_indent += 1
937
+ Symbol.debug_print("find_name:")
938
+ Symbol.debug_indent += 1
939
+ Symbol.debug_print("self:")
940
+ logger.debug(self.to_string(Symbol.debug_indent + 1), end="")
941
+ Symbol.debug_print("nestedName: ", nestedName)
942
+ Symbol.debug_print("templateDecls: ", templateDecls)
943
+ Symbol.debug_print("typ: ", typ)
944
+ Symbol.debug_print("templateShorthand:", templateShorthand)
945
+ Symbol.debug_print("matchSelf: ", matchSelf)
946
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
947
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
948
+
949
+ class QualifiedSymbolIsTemplateParam(Exception):
950
+ pass
951
+
952
+ def onMissingQualifiedSymbol(parentSymbol: Symbol,
953
+ identOrOp: ASTIdentifier | ASTOperator,
954
+ templateParams: Any,
955
+ templateArgs: ASTTemplateArgs) -> Symbol | None:
956
+ # TODO: Maybe search without template args?
957
+ # Though, the correctPrimaryTemplateArgs does
958
+ # that for primary templates.
959
+ # Is there another case where it would be good?
960
+ if parentSymbol.declaration is not None:
961
+ if parentSymbol.declaration.objectType == 'templateParam':
962
+ raise QualifiedSymbolIsTemplateParam
963
+ return None
964
+
965
+ try:
966
+ lookupResult = self._symbol_lookup(nestedName, templateDecls,
967
+ onMissingQualifiedSymbol,
968
+ strictTemplateParamArgLists=False,
969
+ ancestorLookupType=typ,
970
+ templateShorthand=templateShorthand,
971
+ matchSelf=matchSelf,
972
+ recurseInAnon=recurseInAnon,
973
+ correctPrimaryTemplateArgs=False,
974
+ searchInSiblings=searchInSiblings)
975
+ except QualifiedSymbolIsTemplateParam:
976
+ return None, "templateParamInQualified"
977
+
978
+ if lookupResult is None:
979
+ # if it was a part of the qualification that could not be found
980
+ if Symbol.debug_lookup:
981
+ Symbol.debug_indent -= 2
982
+ return None, None
983
+
984
+ res = list(lookupResult.symbols)
985
+ if len(res) != 0:
986
+ if Symbol.debug_lookup:
987
+ Symbol.debug_indent -= 2
988
+ return res, None
989
+
990
+ if lookupResult.parentSymbol.declaration is not None:
991
+ if lookupResult.parentSymbol.declaration.objectType == 'templateParam':
992
+ return None, "templateParamInQualified"
993
+
994
+ # try without template params and args
995
+ symbol = lookupResult.parentSymbol._find_first_named_symbol(
996
+ lookupResult.identOrOp, None, None,
997
+ templateShorthand=templateShorthand, matchSelf=matchSelf,
998
+ recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False)
999
+ if Symbol.debug_lookup:
1000
+ Symbol.debug_indent -= 2
1001
+ if symbol is not None:
1002
+ return [symbol], None
1003
+ else:
1004
+ return None, None
1005
+
1006
+ def find_declaration(self, declaration: ASTDeclaration, typ: str, templateShorthand: bool,
1007
+ matchSelf: bool, recurseInAnon: bool) -> Symbol | None:
1008
+ # templateShorthand: missing template parameter lists for templates is ok
1009
+ if Symbol.debug_lookup:
1010
+ Symbol.debug_indent += 1
1011
+ Symbol.debug_print("find_declaration:")
1012
+ nestedName = declaration.name
1013
+ if declaration.templatePrefix:
1014
+ templateDecls = declaration.templatePrefix.templates
1015
+ else:
1016
+ templateDecls = []
1017
+
1018
+ def onMissingQualifiedSymbol(parentSymbol: Symbol,
1019
+ identOrOp: ASTIdentifier | ASTOperator,
1020
+ templateParams: Any,
1021
+ templateArgs: ASTTemplateArgs) -> Symbol | None:
1022
+ return None
1023
+
1024
+ lookupResult = self._symbol_lookup(nestedName, templateDecls,
1025
+ onMissingQualifiedSymbol,
1026
+ strictTemplateParamArgLists=False,
1027
+ ancestorLookupType=typ,
1028
+ templateShorthand=templateShorthand,
1029
+ matchSelf=matchSelf,
1030
+ recurseInAnon=recurseInAnon,
1031
+ correctPrimaryTemplateArgs=False,
1032
+ searchInSiblings=False)
1033
+ if Symbol.debug_lookup:
1034
+ Symbol.debug_indent -= 1
1035
+ if lookupResult is None:
1036
+ return None
1037
+
1038
+ symbols = list(lookupResult.symbols)
1039
+ if len(symbols) == 0:
1040
+ return None
1041
+
1042
+ querySymbol = Symbol(parent=lookupResult.parentSymbol,
1043
+ identOrOp=lookupResult.identOrOp,
1044
+ templateParams=lookupResult.templateParams,
1045
+ templateArgs=lookupResult.templateArgs,
1046
+ declaration=declaration,
1047
+ docname='fakeDocnameForQuery',
1048
+ line=42)
1049
+ queryId = declaration.get_newest_id()
1050
+ for symbol in symbols:
1051
+ if symbol.declaration is None:
1052
+ continue
1053
+ candId = symbol.declaration.get_newest_id()
1054
+ if candId == queryId:
1055
+ querySymbol.remove()
1056
+ return symbol
1057
+ querySymbol.remove()
1058
+ return None
1059
+
1060
+ def to_string(self, indent: int) -> str:
1061
+ res = [Symbol.debug_indent_string * indent]
1062
+ if not self.parent:
1063
+ res.append('::')
1064
+ else:
1065
+ if self.templateParams:
1066
+ res.append(str(self.templateParams))
1067
+ res.append('\n')
1068
+ res.append(Symbol.debug_indent_string * indent)
1069
+ if self.identOrOp:
1070
+ res.append(str(self.identOrOp))
1071
+ else:
1072
+ res.append(str(self.declaration))
1073
+ if self.templateArgs:
1074
+ res.append(str(self.templateArgs))
1075
+ if self.declaration:
1076
+ res.append(": ")
1077
+ if self.isRedeclaration:
1078
+ res.append('!!duplicate!! ')
1079
+ res.append("{" + self.declaration.objectType + "} ")
1080
+ res.append(str(self.declaration))
1081
+ if self.docname:
1082
+ res.append('\t(')
1083
+ res.append(self.docname)
1084
+ res.append(')')
1085
+ res.append('\n')
1086
+ return ''.join(res)
1087
+
1088
+ def dump(self, indent: int) -> str:
1089
+ return ''.join([
1090
+ self.to_string(indent),
1091
+ *(c.dump(indent + 1) for c in self._children),
1092
+ ])