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,1089 @@
1
+ """The C++ language domain."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from typing import TYPE_CHECKING, Any, ClassVar
7
+
8
+ from docutils import nodes
9
+ from docutils.parsers.rst import directives
10
+
11
+ from sphinx import addnodes
12
+ from sphinx.directives import ObjectDescription
13
+ from sphinx.domains import Domain, ObjType
14
+ from sphinx.domains.cpp._ast import (
15
+ ASTDeclaration,
16
+ ASTIdentifier,
17
+ ASTNamespace,
18
+ ASTNestedName,
19
+ ASTNestedNameElement,
20
+ )
21
+ from sphinx.domains.cpp._ids import _max_id
22
+ from sphinx.domains.cpp._parser import DefinitionParser
23
+ from sphinx.domains.cpp._symbol import Symbol, _DuplicateSymbolError
24
+ from sphinx.errors import NoUri
25
+ from sphinx.locale import _, __
26
+ from sphinx.roles import SphinxRole, XRefRole
27
+ from sphinx.transforms import SphinxTransform
28
+ from sphinx.transforms.post_transforms import ReferencesResolver
29
+ from sphinx.util import logging
30
+ from sphinx.util.cfamily import (
31
+ DefinitionError,
32
+ NoOldIdError,
33
+ anon_identifier_re,
34
+ )
35
+ from sphinx.util.docfields import Field, GroupedField
36
+ from sphinx.util.docutils import SphinxDirective
37
+ from sphinx.util.nodes import make_refnode
38
+
39
+ if TYPE_CHECKING:
40
+ from collections.abc import Iterator
41
+
42
+ from docutils.nodes import Element, Node, TextElement, system_message
43
+
44
+ from sphinx.addnodes import desc_signature, pending_xref
45
+ from sphinx.application import Sphinx
46
+ from sphinx.builders import Builder
47
+ from sphinx.domains.cpp._symbol import LookupKey
48
+ from sphinx.environment import BuildEnvironment
49
+ from sphinx.util.typing import ExtensionMetadata, OptionSpec
50
+
51
+ logger = logging.getLogger(__name__)
52
+
53
+
54
+ def _make_phony_error_name() -> ASTNestedName:
55
+ nne = ASTNestedNameElement(ASTIdentifier("PhonyNameDueToError"), None)
56
+ return ASTNestedName([nne], [False], rooted=False)
57
+
58
+
59
+ class CPPObject(ObjectDescription[ASTDeclaration]):
60
+ """Description of a C++ language object."""
61
+
62
+ doc_field_types: list[Field] = [
63
+ GroupedField('template parameter', label=_('Template Parameters'),
64
+ names=('tparam', 'template parameter'),
65
+ can_collapse=True),
66
+ ]
67
+
68
+ option_spec: ClassVar[OptionSpec] = {
69
+ 'no-index-entry': directives.flag,
70
+ 'no-contents-entry': directives.flag,
71
+ 'no-typesetting': directives.flag,
72
+ 'noindexentry': directives.flag,
73
+ 'nocontentsentry': directives.flag,
74
+ 'tparam-line-spec': directives.flag,
75
+ 'single-line-parameter-list': directives.flag,
76
+ }
77
+
78
+ def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:
79
+ assert ast.objectType == 'enumerator'
80
+ # find the parent, if it exists && is an enum
81
+ # && it's unscoped,
82
+ # then add the name to the parent scope
83
+ symbol = ast.symbol
84
+ assert symbol
85
+ assert symbol.identOrOp is not None
86
+ assert symbol.templateParams is None
87
+ assert symbol.templateArgs is None
88
+ parentSymbol = symbol.parent
89
+ assert parentSymbol
90
+ if parentSymbol.parent is None:
91
+ # TODO: we could warn, but it is somewhat equivalent to unscoped
92
+ # enums, without the enum
93
+ return # no parent
94
+ parentDecl = parentSymbol.declaration
95
+ if parentDecl is None:
96
+ # the parent is not explicitly declared
97
+ # TODO: we could warn, but it could be a style to just assume
98
+ # enumerator parents to be scoped
99
+ return
100
+ if parentDecl.objectType != 'enum':
101
+ # TODO: maybe issue a warning, enumerators in non-enums is weird,
102
+ # but it is somewhat equivalent to unscoped enums, without the enum
103
+ return
104
+ if parentDecl.directiveType != 'enum':
105
+ return
106
+
107
+ targetSymbol = parentSymbol.parent
108
+ s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False, recurseInAnon=True,
109
+ searchInSiblings=False)
110
+ if s is not None:
111
+ # something is already declared with that name
112
+ return
113
+ declClone = symbol.declaration.clone()
114
+ declClone.enumeratorScopedSymbol = symbol
115
+ Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp,
116
+ templateParams=None, templateArgs=None,
117
+ declaration=declClone,
118
+ docname=self.env.docname, line=self.get_source_info()[1])
119
+
120
+ def add_target_and_index(self, ast: ASTDeclaration, sig: str,
121
+ signode: TextElement) -> None:
122
+ # general note: name must be lstrip(':')'ed, to remove "::"
123
+ ids = []
124
+ for i in range(1, _max_id + 1):
125
+ try:
126
+ id = ast.get_id(version=i)
127
+ ids.append(id)
128
+ except NoOldIdError:
129
+ assert i < _max_id
130
+ # let's keep the newest first
131
+ ids.reverse()
132
+ newestId = ids[0]
133
+ assert newestId # shouldn't be None
134
+ if not re.compile(r'^[a-zA-Z0-9_]*$').match(newestId):
135
+ logger.warning('Index id generation for C++ object "%s" failed, please '
136
+ 'report as bug (id=%s).', ast, newestId,
137
+ location=self.get_location())
138
+
139
+ name = ast.symbol.get_full_nested_name().get_display_string().lstrip(':')
140
+ # Add index entry, but not if it's a declaration inside a concept
141
+ isInConcept = False
142
+ s = ast.symbol.parent
143
+ while s is not None:
144
+ decl = s.declaration
145
+ s = s.parent
146
+ if decl is None:
147
+ continue
148
+ if decl.objectType == 'concept':
149
+ isInConcept = True
150
+ break
151
+ if not isInConcept and 'no-index-entry' not in self.options:
152
+ strippedName = name
153
+ for prefix in self.env.config.cpp_index_common_prefix:
154
+ if name.startswith(prefix):
155
+ strippedName = strippedName[len(prefix):]
156
+ break
157
+ indexText = self.get_index_text(strippedName)
158
+ self.indexnode['entries'].append(('single', indexText, newestId, '', None))
159
+
160
+ if newestId not in self.state.document.ids:
161
+ # if the name is not unique, the first one will win
162
+ names = self.env.domaindata['cpp']['names']
163
+ if name not in names:
164
+ names[name] = ast.symbol.docname
165
+ # always add the newest id
166
+ assert newestId
167
+ signode['ids'].append(newestId)
168
+ # only add compatibility ids when there are no conflicts
169
+ for id in ids[1:]:
170
+ if not id: # is None when the element didn't exist in that version
171
+ continue
172
+ if id not in self.state.document.ids:
173
+ signode['ids'].append(id)
174
+ self.state.document.note_explicit_target(signode)
175
+
176
+ @property
177
+ def object_type(self) -> str:
178
+ raise NotImplementedError
179
+
180
+ @property
181
+ def display_object_type(self) -> str:
182
+ return self.object_type
183
+
184
+ def get_index_text(self, name: str) -> str:
185
+ return _('%s (C++ %s)') % (name, self.display_object_type)
186
+
187
+ def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
188
+ return parser.parse_declaration(self.object_type, self.objtype)
189
+
190
+ def describe_signature(self, signode: desc_signature,
191
+ ast: ASTDeclaration, options: dict) -> None:
192
+ ast.describe_signature(signode, 'lastIsName', self.env, options)
193
+
194
+ def run(self) -> list[Node]:
195
+ env = self.state.document.settings.env # from ObjectDescription.run
196
+ if 'cpp:parent_symbol' not in env.temp_data:
197
+ root = env.domaindata['cpp']['root_symbol']
198
+ env.temp_data['cpp:parent_symbol'] = root
199
+ env.ref_context['cpp:parent_key'] = root.get_lookup_key()
200
+
201
+ # The lookup keys assume that no nested scopes exists inside overloaded functions.
202
+ # (see also #5191)
203
+ # Example:
204
+ # .. cpp:function:: void f(int)
205
+ # .. cpp:function:: void f(double)
206
+ #
207
+ # .. cpp:function:: void g()
208
+ #
209
+ # :cpp:any:`boom`
210
+ #
211
+ # So we disallow any signatures inside functions.
212
+ parentSymbol = env.temp_data['cpp:parent_symbol']
213
+ parentDecl = parentSymbol.declaration
214
+ if parentDecl is not None and parentDecl.objectType == 'function':
215
+ msg = ("C++ declarations inside functions are not supported. "
216
+ f"Parent function: {parentSymbol.get_full_nested_name()}\n"
217
+ f"Directive name: {self.name}\nDirective arg: {self.arguments[0]}")
218
+ logger.warning(msg, location=self.get_location())
219
+ name = _make_phony_error_name()
220
+ symbol = parentSymbol.add_name(name)
221
+ env.temp_data['cpp:last_symbol'] = symbol
222
+ return []
223
+ # When multiple declarations are made in the same directive
224
+ # they need to know about each other to provide symbol lookup for function parameters.
225
+ # We use last_symbol to store the latest added declaration in a directive.
226
+ env.temp_data['cpp:last_symbol'] = None
227
+ return super().run()
228
+
229
+ def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
230
+ parentSymbol: Symbol = self.env.temp_data['cpp:parent_symbol']
231
+
232
+ max_len = (self.env.config.cpp_maximum_signature_line_length
233
+ or self.env.config.maximum_signature_line_length
234
+ or 0)
235
+ signode['multi_line_parameter_list'] = (
236
+ 'single-line-parameter-list' not in self.options
237
+ and (len(sig) > max_len > 0)
238
+ )
239
+
240
+ parser = DefinitionParser(sig, location=signode, config=self.env.config)
241
+ try:
242
+ ast = self.parse_definition(parser)
243
+ parser.assert_end()
244
+ except DefinitionError as e:
245
+ logger.warning(e, location=signode)
246
+ # It is easier to assume some phony name than handling the error in
247
+ # the possibly inner declarations.
248
+ name = _make_phony_error_name()
249
+ symbol = parentSymbol.add_name(name)
250
+ self.env.temp_data['cpp:last_symbol'] = symbol
251
+ raise ValueError from e
252
+
253
+ try:
254
+ symbol = parentSymbol.add_declaration(
255
+ ast, docname=self.env.docname, line=self.get_source_info()[1])
256
+ # append the new declaration to the sibling list
257
+ assert symbol.siblingAbove is None
258
+ assert symbol.siblingBelow is None
259
+ symbol.siblingAbove = self.env.temp_data['cpp:last_symbol']
260
+ if symbol.siblingAbove is not None:
261
+ assert symbol.siblingAbove.siblingBelow is None
262
+ symbol.siblingAbove.siblingBelow = symbol
263
+ self.env.temp_data['cpp:last_symbol'] = symbol
264
+ except _DuplicateSymbolError as e:
265
+ # Assume we are actually in the old symbol,
266
+ # instead of the newly created duplicate.
267
+ self.env.temp_data['cpp:last_symbol'] = e.symbol
268
+ msg = __("Duplicate C++ declaration, also defined at %s:%s.\n"
269
+ "Declaration is '.. cpp:%s:: %s'.")
270
+ msg = msg % (e.symbol.docname, e.symbol.line,
271
+ self.display_object_type, sig)
272
+ logger.warning(msg, location=signode)
273
+
274
+ if ast.objectType == 'enumerator':
275
+ self._add_enumerator_to_parent(ast)
276
+
277
+ # note: handle_signature may be called multiple time per directive,
278
+ # if it has multiple signatures, so don't mess with the original options.
279
+ options = dict(self.options)
280
+ options['tparam-line-spec'] = 'tparam-line-spec' in self.options
281
+ self.describe_signature(signode, ast, options)
282
+ return ast
283
+
284
+ def before_content(self) -> None:
285
+ lastSymbol: Symbol = self.env.temp_data['cpp:last_symbol']
286
+ assert lastSymbol
287
+ self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol']
288
+ self.oldParentKey: LookupKey = self.env.ref_context['cpp:parent_key']
289
+ self.env.temp_data['cpp:parent_symbol'] = lastSymbol
290
+ self.env.ref_context['cpp:parent_key'] = lastSymbol.get_lookup_key()
291
+ self.env.temp_data['cpp:domain_name'] = (
292
+ *self.env.temp_data.get('cpp:domain_name', ()),
293
+ lastSymbol.identOrOp._stringify(str),
294
+ )
295
+
296
+ def after_content(self) -> None:
297
+ self.env.temp_data['cpp:parent_symbol'] = self.oldParentSymbol
298
+ self.env.ref_context['cpp:parent_key'] = self.oldParentKey
299
+ self.env.temp_data['cpp:domain_name'] = self.env.temp_data['cpp:domain_name'][:-1]
300
+
301
+ def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]:
302
+ return tuple(s.identOrOp._stringify(str) for s in
303
+ self.env.temp_data['cpp:last_symbol'].get_full_nested_name().names)
304
+
305
+ def _toc_entry_name(self, sig_node: desc_signature) -> str:
306
+ if not sig_node.get('_toc_parts'):
307
+ return ''
308
+
309
+ config = self.env.app.config
310
+ objtype = sig_node.parent.get('objtype')
311
+ if config.add_function_parentheses and objtype in {'function', 'method'}:
312
+ parens = '()'
313
+ else:
314
+ parens = ''
315
+ *parents, name = sig_node['_toc_parts']
316
+ if config.toc_object_entries_show_parents == 'domain':
317
+ return '::'.join((*self.env.temp_data.get('cpp:domain_name', ()), name + parens))
318
+ if config.toc_object_entries_show_parents == 'hide':
319
+ return name + parens
320
+ if config.toc_object_entries_show_parents == 'all':
321
+ return '::'.join([*parents, name + parens])
322
+ return ''
323
+
324
+
325
+ class CPPTypeObject(CPPObject):
326
+ object_type = 'type'
327
+
328
+
329
+ class CPPConceptObject(CPPObject):
330
+ object_type = 'concept'
331
+
332
+
333
+ class CPPMemberObject(CPPObject):
334
+ object_type = 'member'
335
+
336
+
337
+ class CPPFunctionObject(CPPObject):
338
+ object_type = 'function'
339
+
340
+ doc_field_types = [
341
+ *CPPObject.doc_field_types,
342
+ GroupedField(
343
+ "parameter",
344
+ label=_("Parameters"),
345
+ names=("param", "parameter", "arg", "argument"),
346
+ can_collapse=True,
347
+ ),
348
+ GroupedField(
349
+ "exceptions",
350
+ label=_("Throws"),
351
+ rolename="expr",
352
+ names=("throws", "throw", "exception"),
353
+ can_collapse=True,
354
+ ),
355
+ GroupedField(
356
+ "retval",
357
+ label=_("Return values"),
358
+ names=("retvals", "retval"),
359
+ can_collapse=True,
360
+ ),
361
+ Field("returnvalue", label=_("Returns"), has_arg=False, names=("returns", "return")),
362
+ ]
363
+
364
+
365
+ class CPPClassObject(CPPObject):
366
+ object_type = 'class'
367
+
368
+ @property
369
+ def display_object_type(self) -> str:
370
+ # the distinction between class and struct is only cosmetic
371
+ assert self.objtype in ('class', 'struct')
372
+ return self.objtype
373
+
374
+
375
+ class CPPUnionObject(CPPObject):
376
+ object_type = 'union'
377
+
378
+
379
+ class CPPEnumObject(CPPObject):
380
+ object_type = 'enum'
381
+
382
+
383
+ class CPPEnumeratorObject(CPPObject):
384
+ object_type = 'enumerator'
385
+
386
+
387
+ class CPPNamespaceObject(SphinxDirective):
388
+ """
389
+ This directive is just to tell Sphinx that we're documenting stuff in
390
+ namespace foo.
391
+ """
392
+
393
+ has_content = False
394
+ required_arguments = 1
395
+ optional_arguments = 0
396
+ final_argument_whitespace = True
397
+ option_spec: ClassVar[OptionSpec] = {}
398
+
399
+ def run(self) -> list[Node]:
400
+ rootSymbol = self.env.domaindata['cpp']['root_symbol']
401
+ if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
402
+ symbol = rootSymbol
403
+ stack: list[Symbol] = []
404
+ else:
405
+ parser = DefinitionParser(self.arguments[0],
406
+ location=self.get_location(),
407
+ config=self.config)
408
+ try:
409
+ ast = parser.parse_namespace_object()
410
+ parser.assert_end()
411
+ except DefinitionError as e:
412
+ logger.warning(e, location=self.get_location())
413
+ name = _make_phony_error_name()
414
+ ast = ASTNamespace(name, None)
415
+ symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix)
416
+ stack = [symbol]
417
+ self.env.temp_data['cpp:parent_symbol'] = symbol
418
+ self.env.temp_data['cpp:namespace_stack'] = stack
419
+ self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
420
+ return []
421
+
422
+
423
+ class CPPNamespacePushObject(SphinxDirective):
424
+ has_content = False
425
+ required_arguments = 1
426
+ optional_arguments = 0
427
+ final_argument_whitespace = True
428
+ option_spec: ClassVar[OptionSpec] = {}
429
+
430
+ def run(self) -> list[Node]:
431
+ if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
432
+ return []
433
+ parser = DefinitionParser(self.arguments[0],
434
+ location=self.get_location(),
435
+ config=self.config)
436
+ try:
437
+ ast = parser.parse_namespace_object()
438
+ parser.assert_end()
439
+ except DefinitionError as e:
440
+ logger.warning(e, location=self.get_location())
441
+ name = _make_phony_error_name()
442
+ ast = ASTNamespace(name, None)
443
+ oldParent = self.env.temp_data.get('cpp:parent_symbol', None)
444
+ if not oldParent:
445
+ oldParent = self.env.domaindata['cpp']['root_symbol']
446
+ symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix)
447
+ stack = self.env.temp_data.get('cpp:namespace_stack', [])
448
+ stack.append(symbol)
449
+ self.env.temp_data['cpp:parent_symbol'] = symbol
450
+ self.env.temp_data['cpp:namespace_stack'] = stack
451
+ self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
452
+ return []
453
+
454
+
455
+ class CPPNamespacePopObject(SphinxDirective):
456
+ has_content = False
457
+ required_arguments = 0
458
+ optional_arguments = 0
459
+ final_argument_whitespace = True
460
+ option_spec: ClassVar[OptionSpec] = {}
461
+
462
+ def run(self) -> list[Node]:
463
+ stack = self.env.temp_data.get('cpp:namespace_stack', None)
464
+ if not stack or len(stack) == 0:
465
+ logger.warning("C++ namespace pop on empty stack. Defaulting to global scope.",
466
+ location=self.get_location())
467
+ stack = []
468
+ else:
469
+ stack.pop()
470
+ if len(stack) > 0:
471
+ symbol = stack[-1]
472
+ else:
473
+ symbol = self.env.domaindata['cpp']['root_symbol']
474
+ self.env.temp_data['cpp:parent_symbol'] = symbol
475
+ self.env.temp_data['cpp:namespace_stack'] = stack
476
+ self.env.ref_context['cpp:parent_key'] = symbol.get_lookup_key()
477
+ return []
478
+
479
+
480
+ class AliasNode(nodes.Element):
481
+ def __init__(self, sig: str, aliasOptions: dict,
482
+ env: BuildEnvironment | None = None,
483
+ parentKey: LookupKey | None = None) -> None:
484
+ super().__init__()
485
+ self.sig = sig
486
+ self.aliasOptions = aliasOptions
487
+ if env is not None:
488
+ if 'cpp:parent_symbol' not in env.temp_data:
489
+ root = env.domaindata['cpp']['root_symbol']
490
+ env.temp_data['cpp:parent_symbol'] = root
491
+ env.ref_context['cpp:parent_key'] = root.get_lookup_key()
492
+ self.parentKey = env.ref_context['cpp:parent_key']
493
+ else:
494
+ assert parentKey is not None
495
+ self.parentKey = parentKey
496
+
497
+ def copy(self) -> AliasNode:
498
+ return self.__class__(self.sig, self.aliasOptions,
499
+ env=None, parentKey=self.parentKey)
500
+
501
+
502
+ class AliasTransform(SphinxTransform):
503
+ default_priority = ReferencesResolver.default_priority - 1
504
+
505
+ def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
506
+ aliasOptions: dict, renderOptions: dict,
507
+ document: Any) -> list[Node]:
508
+ if maxdepth == 0:
509
+ recurse = True
510
+ elif maxdepth == 1:
511
+ recurse = False
512
+ else:
513
+ maxdepth -= 1
514
+ recurse = True
515
+
516
+ nodes: list[Node] = []
517
+ if not skipThis:
518
+ signode = addnodes.desc_signature('', '')
519
+ nodes.append(signode)
520
+ s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)
521
+
522
+ if recurse:
523
+ if skipThis:
524
+ childContainer: list[Node] | addnodes.desc = nodes
525
+ else:
526
+ content = addnodes.desc_content()
527
+ desc = addnodes.desc()
528
+ content.append(desc)
529
+ desc.document = document
530
+ desc['domain'] = 'cpp'
531
+ # 'desctype' is a backwards compatible attribute
532
+ desc['objtype'] = desc['desctype'] = 'alias'
533
+ desc['no-index'] = True
534
+ childContainer = desc
535
+
536
+ for sChild in s._children:
537
+ if sChild.declaration is None:
538
+ continue
539
+ if sChild.declaration.objectType in ("templateParam", "functionParam"):
540
+ continue
541
+ childNodes = self._render_symbol(
542
+ sChild, maxdepth=maxdepth, skipThis=False,
543
+ aliasOptions=aliasOptions, renderOptions=renderOptions,
544
+ document=document)
545
+ childContainer.extend(childNodes)
546
+
547
+ if not skipThis and len(desc.children) != 0:
548
+ nodes.append(content)
549
+ return nodes
550
+
551
+ def apply(self, **kwargs: Any) -> None:
552
+ for node in self.document.findall(AliasNode):
553
+ sig = node.sig
554
+ parentKey = node.parentKey
555
+ try:
556
+ parser = DefinitionParser(sig, location=node,
557
+ config=self.env.config)
558
+ ast, isShorthand = parser.parse_xref_object()
559
+ parser.assert_end()
560
+ except DefinitionError as e:
561
+ logger.warning(e, location=node)
562
+ ast, isShorthand = None, None
563
+
564
+ if ast is None:
565
+ # could not be parsed, so stop here
566
+ signode = addnodes.desc_signature(sig, '')
567
+ signode.clear()
568
+ signode += addnodes.desc_name(sig, sig)
569
+ node.replace_self(signode)
570
+ continue
571
+
572
+ rootSymbol: Symbol = self.env.domains['cpp'].data['root_symbol']
573
+ parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
574
+ if not parentSymbol:
575
+ logger.debug("Target: %s", sig)
576
+ logger.debug("ParentKey: %s", parentKey)
577
+ logger.debug(rootSymbol.dump(1))
578
+ assert parentSymbol # should be there
579
+
580
+ symbols: list[Symbol] = []
581
+ if isShorthand:
582
+ assert isinstance(ast, ASTNamespace)
583
+ ns = ast
584
+ name = ns.nestedName
585
+ if ns.templatePrefix:
586
+ templateDecls = ns.templatePrefix.templates
587
+ else:
588
+ templateDecls = []
589
+ symbols, failReason = parentSymbol.find_name(
590
+ nestedName=name,
591
+ templateDecls=templateDecls,
592
+ typ='any',
593
+ templateShorthand=True,
594
+ matchSelf=True, recurseInAnon=True,
595
+ searchInSiblings=False)
596
+ if symbols is None:
597
+ symbols = []
598
+ else:
599
+ assert isinstance(ast, ASTDeclaration)
600
+ decl = ast
601
+ name = decl.name
602
+ s = parentSymbol.find_declaration(decl, 'any',
603
+ templateShorthand=True,
604
+ matchSelf=True, recurseInAnon=True)
605
+ if s is not None:
606
+ symbols.append(s)
607
+
608
+ symbols = [s for s in symbols if s.declaration is not None]
609
+
610
+ if len(symbols) == 0:
611
+ signode = addnodes.desc_signature(sig, '')
612
+ node.append(signode)
613
+ signode.clear()
614
+ signode += addnodes.desc_name(sig, sig)
615
+
616
+ logger.warning("Can not find C++ declaration for alias '%s'." % ast,
617
+ location=node)
618
+ node.replace_self(signode)
619
+ else:
620
+ nodes = []
621
+ renderOptions = {
622
+ 'tparam-line-spec': False,
623
+ }
624
+ for s in symbols:
625
+ assert s.declaration is not None
626
+ res = self._render_symbol(
627
+ s, maxdepth=node.aliasOptions['maxdepth'],
628
+ skipThis=node.aliasOptions['noroot'],
629
+ aliasOptions=node.aliasOptions,
630
+ renderOptions=renderOptions,
631
+ document=node.document)
632
+ nodes.extend(res)
633
+ node.replace_self(nodes)
634
+
635
+
636
+ class CPPAliasObject(ObjectDescription):
637
+ option_spec: ClassVar[OptionSpec] = {
638
+ 'maxdepth': directives.nonnegative_int,
639
+ 'noroot': directives.flag,
640
+ }
641
+
642
+ def run(self) -> list[Node]:
643
+ """
644
+ On purpose this doesn't call the ObjectDescription version, but is based on it.
645
+ Each alias signature may expand into multiple real signatures (an overload set).
646
+ The code is therefore based on the ObjectDescription version.
647
+ """
648
+ if ':' in self.name:
649
+ self.domain, self.objtype = self.name.split(':', 1)
650
+ else:
651
+ self.domain, self.objtype = '', self.name
652
+
653
+ node = addnodes.desc()
654
+ node.document = self.state.document
655
+ node['domain'] = self.domain
656
+ # 'desctype' is a backwards compatible attribute
657
+ node['objtype'] = node['desctype'] = self.objtype
658
+
659
+ self.names: list[str] = []
660
+ aliasOptions = {
661
+ 'maxdepth': self.options.get('maxdepth', 1),
662
+ 'noroot': 'noroot' in self.options,
663
+ }
664
+ if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
665
+ logger.warning("Error in C++ alias declaration."
666
+ " Requested 'noroot' but 'maxdepth' 1."
667
+ " When skipping the root declaration,"
668
+ " need 'maxdepth' 0 for infinite or at least 2.",
669
+ location=self.get_location())
670
+ signatures = self.get_signatures()
671
+ for sig in signatures:
672
+ node.append(AliasNode(sig, aliasOptions, env=self.env))
673
+
674
+ contentnode = addnodes.desc_content()
675
+ node.append(contentnode)
676
+ self.before_content()
677
+ self.state.nested_parse(self.content, self.content_offset, contentnode)
678
+ self.env.temp_data['object'] = None
679
+ self.after_content()
680
+ return [node]
681
+
682
+
683
+ class CPPXRefRole(XRefRole):
684
+ def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool,
685
+ title: str, target: str) -> tuple[str, str]:
686
+ refnode.attributes.update(env.ref_context)
687
+
688
+ if not has_explicit_title:
689
+ # major hax: replace anon names via simple string manipulation.
690
+ # Can this actually fail?
691
+ title = anon_identifier_re.sub("[anonymous]", str(title))
692
+
693
+ if refnode['reftype'] == 'any':
694
+ # Assume the removal part of fix_parens for :any: refs.
695
+ # The addition part is done with the reference is resolved.
696
+ if not has_explicit_title and title.endswith('()'):
697
+ title = title[:-2]
698
+ if target.endswith('()'):
699
+ target = target[:-2]
700
+ # TODO: should this really be here?
701
+ if not has_explicit_title:
702
+ target = target.lstrip('~') # only has a meaning for the title
703
+ # if the first character is a tilde, don't display the module/class
704
+ # parts of the contents
705
+ if title[:1] == '~':
706
+ title = title[1:]
707
+ dcolon = title.rfind('::')
708
+ if dcolon != -1:
709
+ title = title[dcolon + 2:]
710
+ return title, target
711
+
712
+
713
+ class CPPExprRole(SphinxRole):
714
+ def __init__(self, asCode: bool) -> None:
715
+ super().__init__()
716
+ if asCode:
717
+ # render the expression as inline code
718
+ self.class_type = 'cpp-expr'
719
+ else:
720
+ # render the expression as inline text
721
+ self.class_type = 'cpp-texpr'
722
+
723
+ def run(self) -> tuple[list[Node], list[system_message]]:
724
+ text = self.text.replace('\n', ' ')
725
+ parser = DefinitionParser(text,
726
+ location=self.get_location(),
727
+ config=self.config)
728
+ # attempt to mimic XRefRole classes, except that...
729
+ try:
730
+ ast = parser.parse_expression()
731
+ except DefinitionError as ex:
732
+ logger.warning('Unparseable C++ expression: %r\n%s', text, ex,
733
+ location=self.get_location())
734
+ # see below
735
+ return [addnodes.desc_inline('cpp', text, text, classes=[self.class_type])], []
736
+ parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None)
737
+ if parentSymbol is None:
738
+ parentSymbol = self.env.domaindata['cpp']['root_symbol']
739
+ # ...most if not all of these classes should really apply to the individual references,
740
+ # not the container node
741
+ signode = addnodes.desc_inline('cpp', classes=[self.class_type])
742
+ ast.describe_signature(signode, 'markType', self.env, parentSymbol)
743
+ return [signode], []
744
+
745
+
746
+ class CPPDomain(Domain):
747
+ """C++ language domain.
748
+
749
+ There are two 'object type' attributes being used::
750
+
751
+ - Each object created from directives gets an assigned .objtype from ObjectDescription.run.
752
+ This is simply the directive name.
753
+ - Each declaration (see the distinction in the directives dict below) has a nested .ast of
754
+ type ASTDeclaration. That object has .objectType which corresponds to the keys in the
755
+ object_types dict below. They are the core different types of declarations in C++ that
756
+ one can document.
757
+ """
758
+
759
+ name = 'cpp'
760
+ label = 'C++'
761
+ object_types = {
762
+ 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'),
763
+ 'union': ObjType(_('union'), 'union', 'identifier', 'type'),
764
+ 'function': ObjType(_('function'), 'func', 'identifier', 'type'),
765
+ 'member': ObjType(_('member'), 'member', 'var', 'identifier'),
766
+ 'type': ObjType(_('type'), 'identifier', 'type'),
767
+ 'concept': ObjType(_('concept'), 'concept', 'identifier'),
768
+ 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'),
769
+ 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'),
770
+ # generated object types
771
+ 'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # NoQA: E501
772
+ 'templateParam': ObjType(_('template parameter'),
773
+ 'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # NoQA: E501
774
+ }
775
+
776
+ directives = {
777
+ # declarations
778
+ 'class': CPPClassObject,
779
+ 'struct': CPPClassObject,
780
+ 'union': CPPUnionObject,
781
+ 'function': CPPFunctionObject,
782
+ 'member': CPPMemberObject,
783
+ 'var': CPPMemberObject,
784
+ 'type': CPPTypeObject,
785
+ 'concept': CPPConceptObject,
786
+ 'enum': CPPEnumObject,
787
+ 'enum-struct': CPPEnumObject,
788
+ 'enum-class': CPPEnumObject,
789
+ 'enumerator': CPPEnumeratorObject,
790
+ # scope control
791
+ 'namespace': CPPNamespaceObject,
792
+ 'namespace-push': CPPNamespacePushObject,
793
+ 'namespace-pop': CPPNamespacePopObject,
794
+ # other
795
+ 'alias': CPPAliasObject,
796
+ }
797
+ roles = {
798
+ 'any': CPPXRefRole(),
799
+ 'class': CPPXRefRole(),
800
+ 'struct': CPPXRefRole(),
801
+ 'union': CPPXRefRole(),
802
+ 'func': CPPXRefRole(fix_parens=True),
803
+ 'member': CPPXRefRole(),
804
+ 'var': CPPXRefRole(),
805
+ 'type': CPPXRefRole(),
806
+ 'concept': CPPXRefRole(),
807
+ 'enum': CPPXRefRole(),
808
+ 'enumerator': CPPXRefRole(),
809
+ 'expr': CPPExprRole(asCode=True),
810
+ 'texpr': CPPExprRole(asCode=False),
811
+ }
812
+ initial_data = {
813
+ 'root_symbol': Symbol(None, None, None, None, None, None, None),
814
+ 'names': {}, # full name for indexing -> docname
815
+ }
816
+
817
+ def clear_doc(self, docname: str) -> None:
818
+ if Symbol.debug_show_tree:
819
+ logger.debug("clear_doc: %s", docname)
820
+ logger.debug("\tbefore:")
821
+ logger.debug(self.data['root_symbol'].dump(1))
822
+ logger.debug("\tbefore end")
823
+
824
+ rootSymbol = self.data['root_symbol']
825
+ rootSymbol.clear_doc(docname)
826
+
827
+ if Symbol.debug_show_tree:
828
+ logger.debug("\tafter:")
829
+ logger.debug(self.data['root_symbol'].dump(1))
830
+ logger.debug("\tafter end")
831
+ logger.debug("clear_doc end: %s", docname)
832
+ for name, nDocname in list(self.data['names'].items()):
833
+ if nDocname == docname:
834
+ del self.data['names'][name]
835
+
836
+ def process_doc(self, env: BuildEnvironment, docname: str,
837
+ document: nodes.document) -> None:
838
+ if Symbol.debug_show_tree:
839
+ logger.debug("process_doc: %s", docname)
840
+ logger.debug(self.data['root_symbol'].dump(0))
841
+ logger.debug("process_doc end: %s", docname)
842
+
843
+ def process_field_xref(self, pnode: pending_xref) -> None:
844
+ pnode.attributes.update(self.env.ref_context)
845
+
846
+ def merge_domaindata(self, docnames: list[str], otherdata: dict[str, Any]) -> None:
847
+ if Symbol.debug_show_tree:
848
+ logger.debug("merge_domaindata:")
849
+ logger.debug("\tself:")
850
+ logger.debug(self.data['root_symbol'].dump(1))
851
+ logger.debug("\tself end")
852
+ logger.debug("\tother:")
853
+ logger.debug(otherdata['root_symbol'].dump(1))
854
+ logger.debug("\tother end")
855
+
856
+ self.data['root_symbol'].merge_with(otherdata['root_symbol'],
857
+ docnames, self.env)
858
+ ourNames = self.data['names']
859
+ for name, docname in otherdata['names'].items():
860
+ if docname in docnames:
861
+ if name not in ourNames:
862
+ ourNames[name] = docname
863
+ # no need to warn on duplicates, the symbol merge already does that
864
+ if Symbol.debug_show_tree:
865
+ logger.debug("\tresult:")
866
+ logger.debug(self.data['root_symbol'].dump(1))
867
+ logger.debug("\tresult end")
868
+ logger.debug("merge_domaindata end")
869
+
870
+ def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
871
+ typ: str, target: str, node: pending_xref,
872
+ contnode: Element) -> tuple[Element | None, str | None]:
873
+ # add parens again for those that could be functions
874
+ if typ in ('any', 'func'):
875
+ target += '()'
876
+ parser = DefinitionParser(target, location=node, config=env.config)
877
+ try:
878
+ ast, isShorthand = parser.parse_xref_object()
879
+ except DefinitionError as e:
880
+ # as arg to stop flake8 from complaining
881
+ def findWarning(e: Exception) -> tuple[str, Exception]:
882
+ if typ != 'any' and typ != 'func':
883
+ return target, e
884
+ # hax on top of the paren hax to try to get correct errors
885
+ parser2 = DefinitionParser(target[:-2],
886
+ location=node,
887
+ config=env.config)
888
+ try:
889
+ parser2.parse_xref_object()
890
+ except DefinitionError as e2:
891
+ return target[:-2], e2
892
+ # strange, that we don't get the error now, use the original
893
+ return target, e
894
+ t, ex = findWarning(e)
895
+ logger.warning('Unparseable C++ cross-reference: %r\n%s', t, ex,
896
+ location=node)
897
+ return None, None
898
+ parentKey: LookupKey = node.get("cpp:parent_key", None)
899
+ rootSymbol = self.data['root_symbol']
900
+ if parentKey:
901
+ parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey)
902
+ if not parentSymbol:
903
+ logger.debug("Target: %s", target)
904
+ logger.debug("ParentKey: %s", parentKey.data)
905
+ logger.debug(rootSymbol.dump(1))
906
+ assert parentSymbol # should be there
907
+ else:
908
+ parentSymbol = rootSymbol
909
+
910
+ if isShorthand:
911
+ assert isinstance(ast, ASTNamespace)
912
+ ns = ast
913
+ name = ns.nestedName
914
+ if ns.templatePrefix:
915
+ templateDecls = ns.templatePrefix.templates
916
+ else:
917
+ templateDecls = []
918
+ # let's be conservative with the sibling lookup for now
919
+ searchInSiblings = (not name.rooted) and len(name.names) == 1
920
+ symbols, failReason = parentSymbol.find_name(
921
+ name, templateDecls, typ,
922
+ templateShorthand=True,
923
+ matchSelf=True, recurseInAnon=True,
924
+ searchInSiblings=searchInSiblings)
925
+ if symbols is None:
926
+ if typ == 'identifier':
927
+ if failReason == 'templateParamInQualified':
928
+ # this is an xref we created as part of a signature,
929
+ # so don't warn for names nested in template parameters
930
+ raise NoUri(str(name), typ)
931
+ s = None
932
+ else:
933
+ # just refer to the arbitrarily first symbol
934
+ s = symbols[0]
935
+ else:
936
+ assert isinstance(ast, ASTDeclaration)
937
+ decl = ast
938
+ name = decl.name
939
+ s = parentSymbol.find_declaration(decl, typ,
940
+ templateShorthand=True,
941
+ matchSelf=True, recurseInAnon=True)
942
+ if s is None or s.declaration is None:
943
+ txtName = str(name)
944
+ if txtName.startswith('std::') or txtName == 'std':
945
+ raise NoUri(txtName, typ)
946
+ return None, None
947
+
948
+ if typ.startswith('cpp:'):
949
+ typ = typ[4:]
950
+ declTyp = s.declaration.objectType
951
+
952
+ def checkType() -> bool:
953
+ if typ == 'any':
954
+ return True
955
+ objtypes = self.objtypes_for_role(typ)
956
+ if objtypes:
957
+ return declTyp in objtypes
958
+ logger.debug(f"Type is {typ}, declaration type is {declTyp}") # NoQA: G004
959
+ raise AssertionError
960
+ if not checkType():
961
+ logger.warning("cpp:%s targets a %s (%s).",
962
+ typ, s.declaration.objectType,
963
+ s.get_full_nested_name(),
964
+ location=node)
965
+
966
+ declaration = s.declaration
967
+ if isShorthand:
968
+ fullNestedName = s.get_full_nested_name()
969
+ displayName = fullNestedName.get_display_string().lstrip(':')
970
+ else:
971
+ displayName = decl.get_display_string()
972
+ docname = s.docname
973
+ assert docname
974
+
975
+ # the non-identifier refs are cross-references, which should be processed:
976
+ # - fix parenthesis due to operator() and add_function_parentheses
977
+ if typ != "identifier":
978
+ title = contnode.pop(0).astext()
979
+ # If it's operator(), we need to add '()' if explicit function parens
980
+ # are requested. Then the Sphinx machinery will add another pair.
981
+ # Also, if it's an 'any' ref that resolves to a function, we need to add
982
+ # parens as well.
983
+ # However, if it's a non-shorthand function ref, for a function that
984
+ # takes no arguments, then we may need to add parens again as well.
985
+ addParen = 0
986
+ if not node.get('refexplicit', False) and declaration.objectType == 'function':
987
+ if isShorthand:
988
+ # this is just the normal haxing for 'any' roles
989
+ if env.config.add_function_parentheses and typ == 'any':
990
+ addParen += 1
991
+ # and now this stuff for operator()
992
+ if (env.config.add_function_parentheses and typ == 'func' and
993
+ title.endswith('operator()')):
994
+ addParen += 1
995
+ if (typ in ('any', 'func') and
996
+ title.endswith('operator') and
997
+ displayName.endswith('operator()')):
998
+ addParen += 1
999
+ else:
1000
+ # our job here is to essentially nullify add_function_parentheses
1001
+ if env.config.add_function_parentheses:
1002
+ if typ == 'any' and displayName.endswith('()'):
1003
+ addParen += 1
1004
+ elif typ == 'func':
1005
+ if title.endswith('()') and not displayName.endswith('()'):
1006
+ title = title[:-2]
1007
+ else:
1008
+ if displayName.endswith('()'):
1009
+ addParen += 1
1010
+ if addParen > 0:
1011
+ title += '()' * addParen
1012
+ # and reconstruct the title again
1013
+ contnode += nodes.Text(title)
1014
+ res = make_refnode(builder, fromdocname, docname,
1015
+ declaration.get_newest_id(), contnode, displayName,
1016
+ ), declaration.objectType
1017
+ return res
1018
+
1019
+ def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
1020
+ typ: str, target: str, node: pending_xref, contnode: Element,
1021
+ ) -> Element | None:
1022
+ return self._resolve_xref_inner(env, fromdocname, builder, typ,
1023
+ target, node, contnode)[0]
1024
+
1025
+ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
1026
+ target: str, node: pending_xref, contnode: Element,
1027
+ ) -> list[tuple[str, Element]]:
1028
+ with logging.suppress_logging():
1029
+ retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder,
1030
+ 'any', target, node, contnode)
1031
+ if retnode:
1032
+ if objtype == 'templateParam':
1033
+ return [('cpp:templateParam', retnode)]
1034
+ else:
1035
+ return [('cpp:' + self.role_for_objtype(objtype), retnode)]
1036
+ return []
1037
+
1038
+ def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]:
1039
+ rootSymbol = self.data['root_symbol']
1040
+ for symbol in rootSymbol.get_all_symbols():
1041
+ if symbol.declaration is None:
1042
+ continue
1043
+ assert symbol.docname
1044
+ fullNestedName = symbol.get_full_nested_name()
1045
+ name = str(fullNestedName).lstrip(':')
1046
+ dispname = fullNestedName.get_display_string().lstrip(':')
1047
+ objectType = symbol.declaration.objectType
1048
+ docname = symbol.docname
1049
+ newestId = symbol.declaration.get_newest_id()
1050
+ yield (name, dispname, objectType, docname, newestId, 1)
1051
+
1052
+ def get_full_qualified_name(self, node: Element) -> str | None:
1053
+ target = node.get('reftarget', None)
1054
+ if target is None:
1055
+ return None
1056
+ parentKey: LookupKey = node.get("cpp:parent_key", None)
1057
+ if parentKey is None or len(parentKey.data) <= 0:
1058
+ return None
1059
+
1060
+ rootSymbol = self.data['root_symbol']
1061
+ parentSymbol = rootSymbol.direct_lookup(parentKey)
1062
+ parentName = parentSymbol.get_full_nested_name()
1063
+ return f'{parentName}::{target}'
1064
+
1065
+
1066
+ def setup(app: Sphinx) -> ExtensionMetadata:
1067
+ app.add_domain(CPPDomain)
1068
+ app.add_config_value("cpp_index_common_prefix", [], 'env')
1069
+ app.add_config_value("cpp_id_attributes", [], 'env')
1070
+ app.add_config_value("cpp_paren_attributes", [], 'env')
1071
+ app.add_config_value("cpp_maximum_signature_line_length", None, 'env', types={int, None})
1072
+ app.add_post_transform(AliasTransform)
1073
+
1074
+ # debug stuff
1075
+ app.add_config_value("cpp_debug_lookup", False, '')
1076
+ app.add_config_value("cpp_debug_show_tree", False, '')
1077
+
1078
+ def initStuff(app: Sphinx) -> None:
1079
+ Symbol.debug_lookup = app.config.cpp_debug_lookup
1080
+ Symbol.debug_show_tree = app.config.cpp_debug_show_tree
1081
+ app.config.cpp_index_common_prefix.sort(reverse=True)
1082
+ app.connect("builder-inited", initStuff)
1083
+
1084
+ return {
1085
+ 'version': 'builtin',
1086
+ 'env_version': 9,
1087
+ 'parallel_read_safe': True,
1088
+ 'parallel_write_safe': True,
1089
+ }