From aa6de409edc8f35cfe9270e7946fa875a2b1b651 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 31 Dec 2018 03:07:34 +0100 Subject: [PATCH] doxygen: show corresponding #include files. This is again a superset of the functionality that stock Doxygen supports (well of course, I'm full-assing things as usual): * Classes (structs, unions) show their corresponding include file right in the header (that's what Doxygen does, too) * Besides that, namespaces that are fully contained in one file show the corresponding include file as well * In case of modules (groups) or when namespace contents are spread over multiple files, each member shows its own specific include file in the detailed docs (because not doing that would be very confusing for users, especially if the mapping to files is not trivial). This means that functions/enums/typedefs/variables/defines that were previously just a brief docs may now get expanded to full docs just to contain the include file information. This also unfortunately hits a bug in Doxygen, where it doesn't properly report the header location for declarations of free (non-member) functions and variables (but uses the definition location, which is in most cases in an (otherwise undocumented) *.cpp file). I need to report and/or PR that, ugh. * Files don't provide the include file information, because there it's known implicitly. * The SHOW_INCLUDE_FILES setting (which defaults to YES and is meant to be for "a list of the files that are included by a file in the documentation of that file" which is just absolutely fucking useless in every way imaginable) is reused to toggle showing of the include information. * To make the rendering a bit more compact, in case the struct or member contains template parameters, the include information is put next to these instead of after the signature. * As with everything else in m.css, if the corresponding header is not documented at all, the include file information is not present. The \headerfile Doxygen command is not supported, because (what a surprise! this is totally shitty as well! who would have thought!): * it works only for classes, you can't override the include name for the file itself! * and forget about doing anything like that for free functions, typedefs or the like! * (minor) it doesn't support #include A_MACRO * it doesn't seem to be exposed in the XML at all (ahahahahah AAAARGH) Co-authored-by: Ryohei Machida --- css/m-dark+doxygen.compiled.css | 19 +- css/m-dark.doxygen.compiled.css | 19 +- css/m-doxygen.css | 22 ++- css/m-light+doxygen.compiled.css | 19 +- css/m-light.doxygen.compiled.css | 19 +- doc/doxygen.rst | 69 ++++++- doxygen/dox2html5.py | 137 +++++++++++++- doxygen/templates/base-class-reference.html | 6 + doxygen/templates/details-define.html | 3 + doxygen/templates/details-enum.html | 7 + doxygen/templates/details-func.html | 6 + doxygen/templates/details-typedef.html | 6 + doxygen/templates/details-var.html | 6 + doxygen/templates/namespace.html | 3 + .../namespaceDeprecatedNamespace.html | 1 + ...catedNamespace_1_1BaseDeprecatedClass.html | 1 + ...eprecatedNamespace_1_1DeprecatedClass.html | 1 + .../test/compound_detailed/namespaceEno.html | 1 + .../test/compound_detailed/namespaceFoo.html | 1 + .../compound_detailed/namespaceNamee.html | 1 + .../test/compound_detailed/namespaceType.html | 1 + .../test/compound_detailed/namespaceVar.html | 1 + .../compound_detailed/namespaceWarning.html | 1 + .../compound_detailed/structTemplate.html | 1 + .../structTemplateWarning.html | 1 + .../structTemplate_3_01void_01_4.html | 1 + doxygen/test/compound_includes/Doxyfile | 13 ++ doxygen/test/compound_includes/First.h | 113 ++++++++++++ doxygen/test/compound_includes/Second.h | 21 +++ .../test/compound_includes/classClass.html | 53 ++++++ .../test/compound_includes/group__group.html | 140 ++++++++++++++ .../compound_includes/namespaceContained.html | 105 +++++++++++ .../compound_includes/namespaceSpread.html | 172 ++++++++++++++++++ .../test/compound_includes_disabled/Doxyfile | 15 ++ .../classClass.html | 52 ++++++ .../group__group.html | 90 +++++++++ .../namespaceContained.html | 104 +++++++++++ .../namespaceSpread.html | 104 +++++++++++ .../test/compound_includes_templated/Doxyfile | 13 ++ .../test/compound_includes_templated/First.h | 26 +++ .../test/compound_includes_templated/Second.h | 10 + .../namespaceSpread.html | 114 ++++++++++++ .../structStruct.html | 34 ++++ .../Doxyfile | 13 ++ .../First.h | 112 ++++++++++++ .../Second.h | 20 ++ ...lassRoot_1_1Directory_1_1Sub_1_1Class.html | 1 + .../namespaceRoot_1_1Directory.html | 1 + .../namespaceNamespace.html | 1 + doxygen/test/cpp_friends/classClass.html | 1 + doxygen/test/cpp_friends/classTemplate.html | 1 + .../test/cpp_signals_slots/classClass.html | 1 + .../cpp_template_alias/structTemplate.html | 1 + doxygen/test/test_compound.py | 54 ++++++ doxygen/test/test_doxyfile.py | 1 + 55 files changed, 1711 insertions(+), 28 deletions(-) create mode 100644 doxygen/test/compound_includes/Doxyfile create mode 100644 doxygen/test/compound_includes/First.h create mode 100644 doxygen/test/compound_includes/Second.h create mode 100644 doxygen/test/compound_includes/classClass.html create mode 100644 doxygen/test/compound_includes/group__group.html create mode 100644 doxygen/test/compound_includes/namespaceContained.html create mode 100644 doxygen/test/compound_includes/namespaceSpread.html create mode 100644 doxygen/test/compound_includes_disabled/Doxyfile create mode 100644 doxygen/test/compound_includes_disabled/classClass.html create mode 100644 doxygen/test/compound_includes_disabled/group__group.html create mode 100644 doxygen/test/compound_includes_disabled/namespaceContained.html create mode 100644 doxygen/test/compound_includes_disabled/namespaceSpread.html create mode 100644 doxygen/test/compound_includes_templated/Doxyfile create mode 100644 doxygen/test/compound_includes_templated/First.h create mode 100644 doxygen/test/compound_includes_templated/Second.h create mode 100644 doxygen/test/compound_includes_templated/namespaceSpread.html create mode 100644 doxygen/test/compound_includes_templated/structStruct.html create mode 100644 doxygen/test/compound_includes_undocumented_files/Doxyfile create mode 100644 doxygen/test/compound_includes_undocumented_files/First.h create mode 100644 doxygen/test/compound_includes_undocumented_files/Second.h diff --git a/css/m-dark+doxygen.compiled.css b/css/m-dark+doxygen.compiled.css index 88dc75d7..6fb8ee8e 100644 --- a/css/m-dark+doxygen.compiled.css +++ b/css/m-dark+doxygen.compiled.css @@ -2503,7 +2503,8 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .w { color: #b2b2b2 } a.m-dox, a.m-dox-self, a.m-dox-external, -ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child { +ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child, +.m-code.m-inverted.m-dox-include > a { text-decoration: none; } a.m-dox, a.m-dox-self { @@ -2581,11 +2582,14 @@ ul.m-dox li.m-dox-expansible > a:first-child:before, ul.m-dox li.m-dox-collapsib } ul.m-dox li.m-dox-expansible > a:first-child:before { content: '⊕'; } ul.m-dox li.m-dox-collapsible > a:first-child:before { content: '⊖'; } -h1 .m-dox-template { +h1 .m-dox-template, h1 .m-dox-include { font-size: 1.3rem; font-weight: normal; } -h3 .m-dox-template { +h1 .m-dox-include:last-child { + margin-bottom: -0.5rem; +} +h3 .m-dox-template, h3 .m-dox-include { font-size: 1rem; font-weight: normal; } @@ -2603,6 +2607,15 @@ dl.m-dox dd a:hover, dl.m-dox dd a:focus, dl.m-dox dd a:active, ul.m-dox li > span.m-dox a:hover, ul.m-dox li > span.m-dox a:focus, ul.m-dox li > span.m-dox a:active { color: #747474; } +.m-code.m-inverted.m-dox-include > a:link, +.m-code.m-inverted.m-dox-include > a:visited { + opacity: 0.6666; +} +.m-code.m-inverted.m-dox-include > a:hover, +.m-code.m-inverted.m-dox-include > a:focus, +.m-code.m-inverted.m-dox-include > a:active { + opacity: 1; +} article section.m-dox-details > div { margin-top: 0; margin-left: 0; diff --git a/css/m-dark.doxygen.compiled.css b/css/m-dark.doxygen.compiled.css index 2760356e..72b4b37e 100644 --- a/css/m-dark.doxygen.compiled.css +++ b/css/m-dark.doxygen.compiled.css @@ -25,7 +25,8 @@ */ a.m-dox, a.m-dox-self, a.m-dox-external, -ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child { +ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child, +.m-code.m-inverted.m-dox-include > a { text-decoration: none; } a.m-dox, a.m-dox-self { @@ -103,11 +104,14 @@ ul.m-dox li.m-dox-expansible > a:first-child:before, ul.m-dox li.m-dox-collapsib } ul.m-dox li.m-dox-expansible > a:first-child:before { content: '⊕'; } ul.m-dox li.m-dox-collapsible > a:first-child:before { content: '⊖'; } -h1 .m-dox-template { +h1 .m-dox-template, h1 .m-dox-include { font-size: 1.3rem; font-weight: normal; } -h3 .m-dox-template { +h1 .m-dox-include:last-child { + margin-bottom: -0.5rem; +} +h3 .m-dox-template, h3 .m-dox-include { font-size: 1rem; font-weight: normal; } @@ -125,6 +129,15 @@ dl.m-dox dd a:hover, dl.m-dox dd a:focus, dl.m-dox dd a:active, ul.m-dox li > span.m-dox a:hover, ul.m-dox li > span.m-dox a:focus, ul.m-dox li > span.m-dox a:active { color: #747474; } +.m-code.m-inverted.m-dox-include > a:link, +.m-code.m-inverted.m-dox-include > a:visited { + opacity: 0.6666; +} +.m-code.m-inverted.m-dox-include > a:hover, +.m-code.m-inverted.m-dox-include > a:focus, +.m-code.m-inverted.m-dox-include > a:active { + opacity: 1; +} article section.m-dox-details > div { margin-top: 0; margin-left: 0; diff --git a/css/m-doxygen.css b/css/m-doxygen.css index 514d38bd..9bea1cd2 100644 --- a/css/m-doxygen.css +++ b/css/m-doxygen.css @@ -23,7 +23,8 @@ */ a.m-dox, a.m-dox-self, a.m-dox-external, -ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child { +ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child, +.m-code.m-inverted.m-dox-include > a { text-decoration: none; } a.m-dox, a.m-dox-self { @@ -103,11 +104,16 @@ ul.m-dox li.m-dox-expansible > a:first-child:before, ul.m-dox li.m-dox-collapsib ul.m-dox li.m-dox-expansible > a:first-child:before { content: '⊕'; } ul.m-dox li.m-dox-collapsible > a:first-child:before { content: '⊖'; } -h1 .m-dox-template { +h1 .m-dox-template, h1 .m-dox-include { font-size: 1.3rem; font-weight: normal; } -h3 .m-dox-template { +/* If there's no template, the include is shown after in a slightly more packed + layout */ +h1 .m-dox-include:last-child { + margin-bottom: -0.5rem; +} +h3 .m-dox-template, h3 .m-dox-include { font-size: 1rem; font-weight: normal; } @@ -125,6 +131,16 @@ dl.m-dox dd a:hover, dl.m-dox dd a:focus, dl.m-dox dd a:active, ul.m-dox li > span.m-dox a:hover, ul.m-dox li > span.m-dox a:focus, ul.m-dox li > span.m-dox a:active { color: var(--dim-link-active-color); } +/* So the link gets highlighted on hover */ +.m-code.m-inverted.m-dox-include > a:link, +.m-code.m-inverted.m-dox-include > a:visited { + opacity: 0.6666; /* Same as .m-code.m-inverted > span */ +} +.m-code.m-inverted.m-dox-include > a:hover, +.m-code.m-inverted.m-dox-include > a:focus, +.m-code.m-inverted.m-dox-include > a:active { + opacity: 1; +} article section.m-dox-details > div { margin-top: 0; diff --git a/css/m-light+doxygen.compiled.css b/css/m-light+doxygen.compiled.css index 9479646e..59a0f71e 100644 --- a/css/m-light+doxygen.compiled.css +++ b/css/m-light+doxygen.compiled.css @@ -2436,7 +2436,8 @@ article:last-child, article section:last-child { margin-bottom: 0; } .m-console .w { color: #b2b2b2 } a.m-dox, a.m-dox-self, a.m-dox-external, -ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child { +ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child, +.m-code.m-inverted.m-dox-include > a { text-decoration: none; } a.m-dox, a.m-dox-self { @@ -2514,11 +2515,14 @@ ul.m-dox li.m-dox-expansible > a:first-child:before, ul.m-dox li.m-dox-collapsib } ul.m-dox li.m-dox-expansible > a:first-child:before { content: '⊕'; } ul.m-dox li.m-dox-collapsible > a:first-child:before { content: '⊖'; } -h1 .m-dox-template { +h1 .m-dox-template, h1 .m-dox-include { font-size: 1.3rem; font-weight: normal; } -h3 .m-dox-template { +h1 .m-dox-include:last-child { + margin-bottom: -0.5rem; +} +h3 .m-dox-template, h3 .m-dox-include { font-size: 1rem; font-weight: normal; } @@ -2536,6 +2540,15 @@ dl.m-dox dd a:hover, dl.m-dox dd a:focus, dl.m-dox dd a:active, ul.m-dox li > span.m-dox a:hover, ul.m-dox li > span.m-dox a:focus, ul.m-dox li > span.m-dox a:active { color: #949494; } +.m-code.m-inverted.m-dox-include > a:link, +.m-code.m-inverted.m-dox-include > a:visited { + opacity: 0.6666; +} +.m-code.m-inverted.m-dox-include > a:hover, +.m-code.m-inverted.m-dox-include > a:focus, +.m-code.m-inverted.m-dox-include > a:active { + opacity: 1; +} article section.m-dox-details > div { margin-top: 0; margin-left: 0; diff --git a/css/m-light.doxygen.compiled.css b/css/m-light.doxygen.compiled.css index e62f1b0c..23832da0 100644 --- a/css/m-light.doxygen.compiled.css +++ b/css/m-light.doxygen.compiled.css @@ -25,7 +25,8 @@ */ a.m-dox, a.m-dox-self, a.m-dox-external, -ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child { +ul.m-dox li.m-dox-expansible > a:first-child, ul.m-dox li.m-dox-collapsible > a:first-child, +.m-code.m-inverted.m-dox-include > a { text-decoration: none; } a.m-dox, a.m-dox-self { @@ -103,11 +104,14 @@ ul.m-dox li.m-dox-expansible > a:first-child:before, ul.m-dox li.m-dox-collapsib } ul.m-dox li.m-dox-expansible > a:first-child:before { content: '⊕'; } ul.m-dox li.m-dox-collapsible > a:first-child:before { content: '⊖'; } -h1 .m-dox-template { +h1 .m-dox-template, h1 .m-dox-include { font-size: 1.3rem; font-weight: normal; } -h3 .m-dox-template { +h1 .m-dox-include:last-child { + margin-bottom: -0.5rem; +} +h3 .m-dox-template, h3 .m-dox-include { font-size: 1rem; font-weight: normal; } @@ -125,6 +129,15 @@ dl.m-dox dd a:hover, dl.m-dox dd a:focus, dl.m-dox dd a:active, ul.m-dox li > span.m-dox a:hover, ul.m-dox li > span.m-dox a:focus, ul.m-dox li > span.m-dox a:active { color: #949494; } +.m-code.m-inverted.m-dox-include > a:link, +.m-code.m-inverted.m-dox-include > a:visited { + opacity: 0.6666; +} +.m-code.m-inverted.m-dox-include > a:hover, +.m-code.m-inverted.m-dox-include > a:focus, +.m-code.m-inverted.m-dox-include > a:active { + opacity: 1; +} article section.m-dox-details > div { margin-top: 0; margin-left: 0; diff --git a/doc/doxygen.rst b/doc/doxygen.rst index ae7e266a..b9203321 100644 --- a/doc/doxygen.rst +++ b/doc/doxygen.rst @@ -209,6 +209,9 @@ If you see something unexpected or not see something expected, check the member detailed docs - Deprecation markers are propagated to member and compound listing pages and search results; :cpp:`delete`\ d functions are marked in search as well +- Information about which file to :cpp:`#include` for given symbol is + provided also for free functions, enums, typedefs and variables (or + namespaces, in case all contents of the namespace are in a single file) `Intentionally unsupported features`_ ------------------------------------- @@ -296,6 +299,15 @@ Variable Description commands. To ensure consistent look with the default m.css themes, set it to ``16``. Doxygen default is ``10``. +:ini:`SHOW_INCLUDE_FILES` Whether to show corresponding :cpp:`#include` + file for classes, namespaces and namespace + members. Originally :ini:`SHOW_INCLUDE_FILES` + is meant to be for "a list of the files that + are included by a file in the documentation of + that file" but that kind of information is + glaringly useless in every imaginable way and + thus the theme is reusing it for something + actually useful. Doxygen default is ``YES``. =============================== =============================================== In addition, the m.css Doxygen theme recognizes the following extra options: @@ -1337,6 +1349,11 @@ Property Description corresponding to output file name :py:`compound.url` Compound URL (or where this file will be saved) +:py:`compound.include` Corresponding :cpp:`#include` statement + to use given compound. Set only for + classes or namespaces that are all + defined in a single file. See + `Include properties`_ for details. :py:`compound.name` Compound name :py:`compound.templates` Template specification. Set only for classes. See `Template properties`_ for @@ -1480,6 +1497,21 @@ of :py:`(url, title)` for a page that's either previous in the defined order, one level up or next. For starting/ending page the :py:`prev`/:py:`next` is :py:`None`. +`Include properties`_ +````````````````````` + +The :py:`compound.include` property is a tuple of :py:`(name, URL)` where +:py:`name` is the include name (together with angle brackets, quotes or a macro +name) and :py:`URL` is a URL pointing to the corresponding header documentation +file. This property is present only if the corresponding header documentation +is present. This property is present for classes; namespaces have it only when +all documented namespace contents are defined in a single file. For modules and +namespaces spread over multiple files this property is presented separately for +each enum, typedef, function, variable or define inside given module or +namespace. Directories, files and file members don't provide this property, +since in that case the mapping to a corresponding :cpp:`#include` file is known +implicitly. + `Module properties`_ ```````````````````` @@ -1590,6 +1622,11 @@ Property Description =============================== =============================================== :py:`enum.base_url` Base URL of file containing detailed description [3]_ +:py:`enum.include` Corresponding :cpp:`#include` to get the enum + definition. Present only for enums inside + modules or inside namespaces that are spread + over multiple files. + See `Include properties`_ for more information. :py:`enum.id` Identifier hash [3]_ :py:`enum.type` Enum type or empty if implicitly typed [6]_ :py:`enum.is_strong` If the enum is strong @@ -1635,6 +1672,12 @@ Property Description =================================== =========================================== :py:`typedef.base_url` Base URL of file containing detailed description [3]_ +:py:`typedef.include` Corresponding :cpp:`#include` to get the + typedef declaration. Present only for + typedefs inside modules or inside + namespaces that are spread over multiple + files. See `Include properties`_ for more + information. :py:`typedef.id` Identifier hash [3]_ :py:`typedef.is_using` Whether it is a :cpp:`typedef` or an :cpp:`using` @@ -1674,6 +1717,11 @@ Property Description =============================== =============================================== :py:`func.base_url` Base URL of file containing detailed description [3]_ +:py:`func.include` Corresponding :cpp:`#include` to get the + function declaration. Present only for + functions inside modules or inside namespaces + that are spread over multiple files. See + `Include properties`_ for more information. :py:`func.id` Identifier hash [3]_ :py:`func.type` Function return type [6]_ :py:`func.name` Function name [4]_ @@ -1765,6 +1813,11 @@ Property Description =============================== =============================================== :py:`var.base_url` Base URL of file containing detailed description [3]_ +:py:`var.include` Corresponding :cpp:`#include` to get the + variable declaration. Present only for + variables inside modules or inside namespaces + that are spread over multiple files. See + `Include properties`_ for more information. :py:`var.id` Identifier hash [3]_ :py:`var.type` Variable type [6]_ :py:`var.name` Variable name [4]_ @@ -1795,6 +1848,12 @@ item has the following properties: =============================== =============================================== Property Description =============================== =============================================== +:py:`define.include` Corresponding :cpp:`#include` to get the + define definition. Present only for defines + inside modules, since otherwise the define is + documented inside a file docs and the + corresponding include is known implicitly. See + `Include properties`_ for more information. :py:`define.id` Identifier hash [3]_ :py:`define.name` Define name :py:`define.params` List of macro parameter names. See below for @@ -1953,11 +2012,11 @@ all directories are before all files. :py:`compound.prefix_wbr` to it to get the fully qualified name. .. [5] :py:`compound.has_*_details` and :py:`i.has_details` are :py:`True` if there is detailed description, function/template/macro parameter - documentation or enum value listing that makes it worth to render the full - description block. If :py:`False`, the member should be included only in - the brief listing on top of the page to avoid unnecessary repetition. If - :py:`i.base_url` is not the same as :py:`compound.url`, its - :py:`i.has_details` is always set to :py:`False`. + documentation, enum value listing or an entry-specific :cpp:`#include` that + makes it worth to render the full description block. If :py:`False`, the + member should be included only in the brief listing on top of the page to + avoid unnecessary repetition. If :py:`i.base_url` is not the same as + :py:`compound.url`, its :py:`i.has_details` is always set to :py:`False`. .. [6] :py:`i.type` and :py:`param.default` is rendered as HTML and usually contains links to related documentation .. [7] :py:`i.is_deprecated` is set to :py:`True` if detailed docs of given diff --git a/doxygen/dox2html5.py b/doxygen/dox2html5.py index bcc27b68..41bf411f 100755 --- a/doxygen/dox2html5.py +++ b/doxygen/dox2html5.py @@ -361,11 +361,21 @@ class State: def __init__(self): self.basedir = '' self.compounds: Dict[str, StateCompound] = {} + self.includes: Dict[str, str] = {} self.search: List[Any] = [] self.examples: List[Any] = [] self.doxyfile: Dict[str, str] = {} self.images: List[str] = [] self.current = '' # current file being processed (for logging) + # Current kind of compound being processed. Affects current_include + # below (i.e., per-entry includes are parsed only for namespaces or + # modules, because for classes they are consistent and don't need to be + # repeated). + self.current_kind = None + # If this is None (or becomes None), it means the compound is spread + # over multiple files and thus every entry needs its own specific + # include definition + self.current_include = None self.current_prefix = [] self.current_compound_url = None self.current_definition_url_base = None @@ -418,13 +428,29 @@ def parse_ref(state: State, element: ET.Element) -> str: return '{}'.format(url, class_, add_wbr(parse_inline_desc(state, element).strip())) -def parse_id(element: ET.Element) -> Tuple[str, str, str]: +def parse_id_and_include(state: State, element: ET.Element) -> Tuple[str, str, str, Tuple[str, str]]: # Returns URL base (usually saved to state.current_definition_url_base and # used by extract_id_hash() later), base URL (with file extension), and the # actual ID id = element.attrib['id'] i = id.rindex('_1') - return id[:i], id[:i] + '.html', id[i+2:] + + # Extract the corresponding include, if the current compound is a namespace + # or a module + include = None + if state.current_kind in ['namespace', 'group']: + file = element.find('location').attrib['file'] + if file in state.includes and state.compounds[state.includes[file]].has_details: + include = (html.escape('<{}>'.format(file)), state.compounds[state.includes[file]].url) + + # If the include differs from current compound include, reset it to signal + # that the compound doesn't have one unique include file. This will get + # later picked up by parse_xml() which either adds has_details to all + # compounds or wipes the compound-specific includes. + if state.current_include and state.current_include != file: + state.current_include = None + + return id[:i], id[:i] + '.html', id[i+2:], include def extract_id_hash(state: State, element: ET.Element) -> str: # Can't use parse_id() here as sections with _1 in it have it verbatim @@ -1593,7 +1619,7 @@ def parse_enum(state: State, element: ET.Element): assert element.tag == 'memberdef' and element.attrib['kind'] == 'enum' enum = Empty() - state.current_definition_url_base, enum.base_url, enum.id = parse_id(element) + state.current_definition_url_base, enum.base_url, enum.id, enum.include = parse_id_and_include(state, element) enum.type = parse_type(state, element.find('type')) enum.name = element.find('name').text if enum.name.startswith('@'): enum.name = '(anonymous)' @@ -1695,7 +1721,7 @@ def parse_typedef(state: State, element: ET.Element): assert element.tag == 'memberdef' and element.attrib['kind'] == 'typedef' typedef = Empty() - state.current_definition_url_base, typedef.base_url, typedef.id = parse_id(element) + state.current_definition_url_base, typedef.base_url, typedef.id, typedef.include = parse_id_and_include(state, element) typedef.is_using = element.findtext('definition', '').startswith('using') typedef.type = parse_type(state, element.find('type')) typedef.args = parse_type(state, element.find('argsstring')) @@ -1723,7 +1749,7 @@ def parse_func(state: State, element: ET.Element): assert element.tag == 'memberdef' and element.attrib['kind'] in ['function', 'friend', 'signal', 'slot'] func = Empty() - state.current_definition_url_base, func.base_url, func.id = parse_id(element) + state.current_definition_url_base, func.base_url, func.id, func.include = parse_id_and_include(state, element) func.type = parse_type(state, element.find('type')) func.name = fix_type_spacing(html.escape(element.find('name').text)) func.brief = parse_desc(state, element.find('briefdescription')) @@ -1838,7 +1864,7 @@ def parse_var(state: State, element: ET.Element): assert element.tag == 'memberdef' and element.attrib['kind'] == 'variable' var = Empty() - state.current_definition_url_base, var.base_url, var.id = parse_id(element) + state.current_definition_url_base, var.base_url, var.id, var.include = parse_id_and_include(state, element) var.type = parse_type(state, element.find('type')) if var.type.startswith('constexpr'): var.type = var.type[10:] @@ -1875,7 +1901,7 @@ def parse_define(state: State, element: ET.Element): # so we don't need to have define.base_url. Can't use extract_id_hash() # here because current_definition_url_base might be stale. See a test in # compound_namespace_members_in_file_scope_define_base_url. - state.current_definition_url_base, _, define.id = parse_id(element) + state.current_definition_url_base, _, define.id, define.include = parse_id_and_include(state, element) define.name = element.find('name').text define.brief = parse_desc(state, element.find('briefdescription')) define.description, params, define.return_value, search_keywords, define.is_deprecated = parse_define_desc(state, element) @@ -2023,6 +2049,29 @@ def postprocess_state(state: State): # Other compounds are not in any index pages or breadcrumb, so leaf # name not needed + # Build reverse header name to ID mapping for #include information, unless + # it's explicitly disabled. Doxygen doesn't provide full path for files so + # we need to combine that ourselves. Ugh. (Yes, I know SHOW_INCLUDE_FILES + # is meant to be for "a list of the files that are included by a file in + # the documentation of that file" but that kind of information is so + # glaringly useless in every imaginable way so I'm reusing it for something + # saner.) + if state.doxyfile['SHOW_INCLUDE_FILES']: + for _, compound in state.compounds.items(): + if not compound.kind == 'file': continue + + # Gather parent compounds + path_reverse = [compound.id] + while path_reverse[-1] in state.compounds and state.compounds[path_reverse[-1]].parent: + path_reverse += [state.compounds[path_reverse[-1]].parent] + + # Fill breadcrumb with leaf names and URLs + include = [] + for i in reversed(path_reverse): + include += [state.compounds[i].leaf_name] + + state.includes['/'.join(include)] = compound.id + # Assign names and URLs to menu items. The link can be either a predefined # keyword from the below list, a Doxygen symbol, or a HTML code. The # template then gets a tuple of (HTML code, title, URL) and either puts @@ -2235,6 +2284,7 @@ def parse_xml(state: State, xml: str): # in file docs and namespace docs, for example) state.current_compound_url = compound.url state.current_definition_url_base = compound.url_base + compound.include = None compound.has_template_details = False compound.templates = None compound.brief = parse_desc(state, compounddef.find('briefdescription')) @@ -2296,6 +2346,25 @@ def parse_xml(state: State, xml: str): else: state.current_prefix = [] + # Decide about the include file for this compound. Classes get it always, + # namespaces only if it we later don't discover that it's spread over + # multiple files; files and dirs don't need it (it's implicit) and it makes + # no sense for pages or modules. + state.current_kind = compound.kind + if compound.kind in ['struct', 'class', 'union', 'namespace']: + include = compounddef.find('location').attrib['file'] + if include in state.includes and state.compounds[state.includes[include]].has_details: + compound.include = (html.escape('<{}>'.format(include)), state.compounds[state.includes[include]].url) + + # Save include for current compound. Every enum/var/function/... parser + # checks against it and resets to None in case the include differs for + # given entry, meaning all entries need to have their own include + # definition instead. That's then finally reflected in has_details of + # each entry. + state.current_include = include + else: + state.current_include = None + if compound.kind == 'page': # Drop TOC for pages, if not requested if compounddef.find('tableofcontents') is None: @@ -2736,7 +2805,7 @@ def parse_xml(state: State, xml: str): 'briefdescription', # handled above 'detaileddescription', # handled above 'innerpage', # doesn't add anything to output - 'location', + 'location', # handled above 'includes', 'includedby', 'incdepgraph', @@ -2814,6 +2883,56 @@ def parse_xml(state: State, xml: str): else: compound.breadcrumb = [(compound.name, compound.id + '.html')] + # Special handling for compounds that might or might not have a common + # #include (for all others the include info is either on a compound itself + # or nowhere at all) + if state.doxyfile['SHOW_INCLUDE_FILES'] and compound.kind in ['namespace', 'group']: + # If we discovered that entries of this compound don't have a common + # #include, flip on has_details of all entries and wipe the compound + # include. Otherwise wipe the include information from everywhere but + # the compound. + if not state.current_include: + compound.include = None + for entry in compound.enums: + if entry.include and not state.current_include: + entry.has_details = True + compound.has_enum_details = True + else: + entry.include = None + for entry in compound.typedefs: + if entry.include and not state.current_include: + entry.has_details = True + compound.has_typedef_details = True + else: + entry.include = None + for entry in compound.funcs: + if entry.include and not state.current_include: + entry.has_details = True + compound.has_func_details = True + else: + entry.include = None + for entry in compound.vars: + if entry.include and not state.current_include: + entry.has_details = True + compound.has_var_details = True + else: + entry.include = None + for entry in compound.defines: + if entry.include and not state.current_include: + entry.has_details = True + compound.has_define_details = True + else: + entry.include = None + # Skipping public_types etc., as that is for classes which have a + # global include anyway + for group in compound.groups: + for kind, entry in group.members: + if entry.include and not state.current_include: + entry.has_details = True + setattr(compound, 'has_{}_details'.format(kind), True) + else: + entry.include = None + # Add the compound to search data, if it's documented # TODO: add example sources there? how? if not state.doxyfile['M_SEARCH_DISABLED'] and not compound.kind == 'example' and (compound.kind == 'group' or compound.brief or compounddef.find('detaileddescription')): @@ -2983,6 +3102,7 @@ def parse_doxyfile(state: State, doxyfile, config = None): 'HTML_EXTRA_FILES': [], 'DOT_FONTNAME': ['Helvetica'], 'DOT_FONTSIZE': ['10'], + 'SHOW_INCLUDE_FILES': ['YES'], 'M_CLASS_TREE_EXPAND_LEVELS': ['1'], 'M_FILE_TREE_EXPAND_LEVELS': ['1'], @@ -3114,6 +3234,7 @@ list using and # Boolean values that we want for i in ['CREATE_SUBDIRS', 'JAVADOC_AUTOBRIEF', + 'SHOW_INCLUDE_FILES', 'M_EXPAND_INNER_TYPES', 'M_SEARCH_DISABLED', 'M_SEARCH_DOWNLOAD_BINARY']: diff --git a/doxygen/templates/base-class-reference.html b/doxygen/templates/base-class-reference.html index 71cf5424..0515dbb0 100644 --- a/doxygen/templates/base-class-reference.html +++ b/doxygen/templates/base-class-reference.html @@ -18,10 +18,16 @@ {% block main %}

{% if compound.templates != None %} + {% if compound.include %} + + {% endif %} {% set j = joiner(', ') %}
template<{% for t in compound.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}>
{% endif %} {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} {{ compound.kind }} + {% if compound.include and compound.templates == None %} + + {% endif %}

{% if compound.brief %}

{{ compound.brief }}

diff --git a/doxygen/templates/details-define.html b/doxygen/templates/details-define.html index 2fd66b4a..132ea4eb 100644 --- a/doxygen/templates/details-define.html +++ b/doxygen/templates/details-define.html @@ -2,6 +2,9 @@

{% set j = joiner(',\n ') %} #define {{ define.name }}{% if define.params != None %}({% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %} + {% if define.include %} + + {% endif %}

{% if define.brief %}

{{ define.brief }}

diff --git a/doxygen/templates/details-enum.html b/doxygen/templates/details-enum.html index 504bee53..e95b5590 100644 --- a/doxygen/templates/details-enum.html +++ b/doxygen/templates/details-enum.html @@ -9,6 +9,13 @@ enum {% if enum.is_strong %}class {% endif %}{{ prefix }}{{ enum.name }}{% if enum.type %}: {{ enum.type }}{% endif %}{% if enum.is_protected %} protected{% endif %} {# not sure why there needs to be this space #} + {% if enum.include %} + {# Template info can be only present if the enum is inside a + templated class, but in that case we have global include + information, so no need to handle case where + `enum.include and compound.templates != None` #} + + {% endif %} {% if enum.brief %}{# brief can be omitted for anonymous enums #}

{{ enum.brief }}

diff --git a/doxygen/templates/details-func.html b/doxygen/templates/details-func.html index 2c394c7b..43e11f3d 100644 --- a/doxygen/templates/details-func.html +++ b/doxygen/templates/details-func.html @@ -1,6 +1,9 @@

{% if compound.templates != None or func.templates != None %} + {% if func.include %} + + {% endif %}
{% if compound.templates != None %} {% set j = joiner(', ') %} @@ -14,6 +17,9 @@ {% endif %} {% set j = joiner(',\n ') %} {{ func.prefix }}{{ func.type }} {{ prefix }}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} explicit {% endif %}{% if func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_noexcept %} noexcept{% endif %} + {% if func.include and compound.templates == None and func.templates == None %} + + {% endif %}

{% if func.brief %}

{{ func.brief }}

diff --git a/doxygen/templates/details-typedef.html b/doxygen/templates/details-typedef.html index bec5a0f4..8e994a15 100644 --- a/doxygen/templates/details-typedef.html +++ b/doxygen/templates/details-typedef.html @@ -1,6 +1,9 @@

{% if compound.templates != None or typedef.templates != None %} + {% if typedef.include %} + + {% endif %}
{% if compound.templates != None %} {% set j = joiner(', ') %} @@ -19,6 +22,9 @@ {% endif %} {# the empty line has to be here to prevent the lines from merging #} + {% if typedef.include and compound.templates == None and typedef.templates == None %} + + {% endif %}

{% if typedef.brief %}

{{ typedef.brief }}

diff --git a/doxygen/templates/details-var.html b/doxygen/templates/details-var.html index 2dbea7a4..ca8c0c96 100644 --- a/doxygen/templates/details-var.html +++ b/doxygen/templates/details-var.html @@ -1,6 +1,9 @@

{% if compound.templates != None or var.templates != None %} + {% if var.include %} + + {% endif %}
{% if compound.templates != None %} {% set j = joiner(', ') %} @@ -15,6 +18,9 @@ {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ prefix }}{{ var.name }}{% if var.is_protected %} protected{% endif %}{% if var.is_constexpr %} constexpr{% endif %} {# the empty line needs to be here to prevent the lines from merging #} + {% if var.include and compound.templates == None and var.templates == None %} + + {% endif %}

{% if var.brief %}

{{ var.brief }}

diff --git a/doxygen/templates/namespace.html b/doxygen/templates/namespace.html index 302a9546..e32a1f70 100644 --- a/doxygen/templates/namespace.html +++ b/doxygen/templates/namespace.html @@ -5,5 +5,8 @@ {% block header %}

{%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} namespace + {% if compound.include %} + + {% endif %}

{% endblock %} diff --git a/doxygen/test/compound_deprecated/namespaceDeprecatedNamespace.html b/doxygen/test/compound_deprecated/namespaceDeprecatedNamespace.html index 96369bb9..ede92b56 100644 --- a/doxygen/test/compound_deprecated/namespaceDeprecatedNamespace.html +++ b/doxygen/test/compound_deprecated/namespaceDeprecatedNamespace.html @@ -21,6 +21,7 @@

DeprecatedNamespace namespace +

A namespace.

diff --git a/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1BaseDeprecatedClass.html b/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1BaseDeprecatedClass.html index 3792d2f9..71ab801e 100644 --- a/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1BaseDeprecatedClass.html +++ b/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1BaseDeprecatedClass.html @@ -21,6 +21,7 @@

DeprecatedNamespace::BaseDeprecatedClass struct +

A base class.

diff --git a/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1DeprecatedClass.html b/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1DeprecatedClass.html index a9bd6dde..5dbf702f 100644 --- a/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1DeprecatedClass.html +++ b/doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1DeprecatedClass.html @@ -21,6 +21,7 @@

DeprecatedNamespace::DeprecatedClass struct +

A class.

diff --git a/doxygen/test/compound_detailed/namespaceEno.html b/doxygen/test/compound_detailed/namespaceEno.html index 98eb5510..31d2cbc8 100644 --- a/doxygen/test/compound_detailed/namespaceEno.html +++ b/doxygen/test/compound_detailed/namespaceEno.html @@ -21,6 +21,7 @@

Eno namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/compound_detailed/namespaceFoo.html b/doxygen/test/compound_detailed/namespaceFoo.html index 8bf58349..2cbe43c0 100644 --- a/doxygen/test/compound_detailed/namespaceFoo.html +++ b/doxygen/test/compound_detailed/namespaceFoo.html @@ -21,6 +21,7 @@

Foo namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/compound_detailed/namespaceNamee.html b/doxygen/test/compound_detailed/namespaceNamee.html index c048ab8c..210b0f71 100644 --- a/doxygen/test/compound_detailed/namespaceNamee.html +++ b/doxygen/test/compound_detailed/namespaceNamee.html @@ -21,6 +21,7 @@

Namee namespace +
#include <File.h>

Namespace docs.

And we have some detailed docs as well.

diff --git a/doxygen/test/compound_detailed/namespaceType.html b/doxygen/test/compound_detailed/namespaceType.html index e60d09b3..a9b231bd 100644 --- a/doxygen/test/compound_detailed/namespaceType.html +++ b/doxygen/test/compound_detailed/namespaceType.html @@ -21,6 +21,7 @@

Type namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/compound_detailed/namespaceVar.html b/doxygen/test/compound_detailed/namespaceVar.html index 44b53fbf..e0ca1165 100644 --- a/doxygen/test/compound_detailed/namespaceVar.html +++ b/doxygen/test/compound_detailed/namespaceVar.html @@ -21,6 +21,7 @@

Var namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/compound_detailed/namespaceWarning.html b/doxygen/test/compound_detailed/namespaceWarning.html index 869febf5..7f43df7d 100644 --- a/doxygen/test/compound_detailed/namespaceWarning.html +++ b/doxygen/test/compound_detailed/namespaceWarning.html @@ -21,6 +21,7 @@

Warning namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/compound_detailed/structTemplate.html b/doxygen/test/compound_detailed/structTemplate.html index 0dd5cb71..a07a97db 100644 --- a/doxygen/test/compound_detailed/structTemplate.html +++ b/doxygen/test/compound_detailed/structTemplate.html @@ -20,6 +20,7 @@

+
#include <File.h>
template<class T, class U = void, class = int>
Template struct

diff --git a/doxygen/test/compound_detailed/structTemplateWarning.html b/doxygen/test/compound_detailed/structTemplateWarning.html index 146cb2d5..fae824a1 100644 --- a/doxygen/test/compound_detailed/structTemplateWarning.html +++ b/doxygen/test/compound_detailed/structTemplateWarning.html @@ -20,6 +20,7 @@

+
#include <File.h>
template<class T>
TemplateWarning struct

diff --git a/doxygen/test/compound_detailed/structTemplate_3_01void_01_4.html b/doxygen/test/compound_detailed/structTemplate_3_01void_01_4.html index 7cee82fe..f524b084 100644 --- a/doxygen/test/compound_detailed/structTemplate_3_01void_01_4.html +++ b/doxygen/test/compound_detailed/structTemplate_3_01void_01_4.html @@ -20,6 +20,7 @@

+
#include <File.h>
template<>
Template<void> struct

diff --git a/doxygen/test/compound_includes/Doxyfile b/doxygen/test/compound_includes/Doxyfile new file mode 100644 index 00000000..ce05b2e1 --- /dev/null +++ b/doxygen/test/compound_includes/Doxyfile @@ -0,0 +1,13 @@ +INPUT = First.h Second.h +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = +##! M_LINKS_NAVBAR2 = +##! M_SEARCH_DISABLED = YES diff --git a/doxygen/test/compound_includes/First.h b/doxygen/test/compound_includes/First.h new file mode 100644 index 00000000..e43deb10 --- /dev/null +++ b/doxygen/test/compound_includes/First.h @@ -0,0 +1,113 @@ +/** @file + * @brief First file + */ + +/* This file needs to be kept the same as + compound_includes_undocumented_files/First.h except for the above @file + block. */ + +/** +@brief This namespace is contained in a single file + +So it has only the global include and no per-entry includes, thus also no +detailed sections because there's only brief. (Unless the includes are disabled +globally or the file is not documented.) +*/ +namespace Contained { + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @brief A function */ +void foo(); + +/** @{ @name A group */ + +/** @brief Flag in a group */ +enum Flag {}; + +/** @brief Alias in a group */ +using Main = void; + +/** @brief Function in a group */ +void bar(); + +/** @brief Variable in a group */ +constexpr void* variable = nullptr; + +/*@}*/ + +} + +/** +@brief This namespace is spread over two files + +So it has no global include but per-entry includes, properly expanding the +brief-only docs into detailed ones. (Unless the includes are disabled globally +or the files are not documented.) +*/ +namespace Spread { + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @{ @name A group */ + +/** @brief Alias in a group */ +using Main = void; + +/** @brief Function in a group */ +void bar(); + +/** @brief Variable in a group */ +constexpr void* variable = nullptr; + +/*@}*/ + +} + +/** +@brief A class + +Global include information for this one. (Unless the includes are disabled +globally or the file is not documented.) +*/ +class Class { + public: + /** @brief No include information for this one (and thus no details) */ + void foo(); +}; + +/** @defgroup group A group + +All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.) +@{ */ + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @brief A function */ +void foo(); + +/** @brief A define */ +#define A_DEFINE + +/*@}*/ diff --git a/doxygen/test/compound_includes/Second.h b/doxygen/test/compound_includes/Second.h new file mode 100644 index 00000000..5f366406 --- /dev/null +++ b/doxygen/test/compound_includes/Second.h @@ -0,0 +1,21 @@ +/** @file + * @brief Second file + */ + +/* This file needs to be kept the same as + compound_includes_undocumented_files/Second.h except for the above @file + block. */ + +namespace Spread { + +/** @brief A function */ +void foo(); + +/** @{ @name A group */ + +/** @brief Flag in a group */ +enum Flag {}; + +/*@}*/ + +} diff --git a/doxygen/test/compound_includes/classClass.html b/doxygen/test/compound_includes/classClass.html new file mode 100644 index 00000000..6df71c72 --- /dev/null +++ b/doxygen/test/compound_includes/classClass.html @@ -0,0 +1,53 @@ + + + + + Class class | My Project + + + + + +
+
+
+
+
+

+ Class class +
#include <First.h>
+

+

A class.

+
+

Contents

+ +
+

Global include information for this one. (Unless the includes are disabled globally or the file is not documented.)

+
+

Public functions

+
+
+ void foo() +
+
No include information for this one (and thus no details)
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes/group__group.html b/doxygen/test/compound_includes/group__group.html new file mode 100644 index 00000000..7f20d7a5 --- /dev/null +++ b/doxygen/test/compound_includes/group__group.html @@ -0,0 +1,140 @@ + + + + + A group module | My Project + + + + + +
+
+
+
+
+

+ A group module

+
+

Contents

+ +
+

All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

Defines

+
+
+ #define A_DEFINE +
+
A define.
+
+
+
+

Enum documentation

+
+

+ enum Enum +
#include <First.h>
+

+

An enum.

+
+
+
+

Typedef documentation

+
+

+ typedef int Int +
#include <First.h>
+

+

A typedef.

+
+
+
+

Function documentation

+
+

+ void foo() +
#include <First.h>
+

+

A function.

+
+
+
+

Variable documentation

+
+

+ const int Var constexpr +
#include <First.h>
+

+

A variable.

+
+
+
+

Define documentation

+
+

+ #define A_DEFINE +
#include <First.h>
+

+

A define.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes/namespaceContained.html b/doxygen/test/compound_includes/namespaceContained.html new file mode 100644 index 00000000..0c6b5b3e --- /dev/null +++ b/doxygen/test/compound_includes/namespaceContained.html @@ -0,0 +1,105 @@ + + + + + Contained namespace | My Project + + + + + +
+
+
+
+
+

+ Contained namespace +
#include <First.h>
+

+

This namespace is contained in a single file.

+
+

Contents

+ +
+

So it has only the global include and no per-entry includes, thus also no detailed sections because there's only brief. (Unless the includes are disabled globally or the file is not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

A group

+
+
+ enum Flag { } +
+
Flag in a group.
+
+ using Main = void +
+
Alias in a group.
+
+ void* variable constexpr +
+
Variable in a group.
+
+ void bar() +
+
Function in a group.
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes/namespaceSpread.html b/doxygen/test/compound_includes/namespaceSpread.html new file mode 100644 index 00000000..9952561a --- /dev/null +++ b/doxygen/test/compound_includes/namespaceSpread.html @@ -0,0 +1,172 @@ + + + + + Spread namespace | My Project + + + + + +
+
+
+
+
+

+ Spread namespace +

+

This namespace is spread over two files.

+
+

Contents

+ +
+

So it has no global include but per-entry includes, properly expanding the brief-only docs into detailed ones. (Unless the includes are disabled globally or the files are not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

A group

+
+
+ enum Flag { } +
+
Flag in a group.
+
+ using Main = void +
+
Alias in a group.
+
+ void* variable constexpr +
+
Variable in a group.
+
+ void bar() +
+
Function in a group.
+
+
+
+

Enum documentation

+
+

+ enum Spread::Enum +
#include <First.h>
+

+

An enum.

+
+
+

+ enum Spread::Flag +
#include <Second.h>
+

+

Flag in a group.

+
+
+
+

Typedef documentation

+
+

+ typedef int Spread::Int +
#include <First.h>
+

+

A typedef.

+
+
+

+ using Spread::Main = void +
#include <First.h>
+

+

Alias in a group.

+
+
+
+

Function documentation

+
+

+ void Spread::foo() +
#include <Second.h>
+

+

A function.

+
+
+

+ void Spread::bar() +
#include <First.h>
+

+

Function in a group.

+
+
+
+

Variable documentation

+
+

+ const int Spread::Var constexpr +
#include <First.h>
+

+

A variable.

+
+
+

+ void* Spread::variable constexpr +
#include <First.h>
+

+

Variable in a group.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_disabled/Doxyfile b/doxygen/test/compound_includes_disabled/Doxyfile new file mode 100644 index 00000000..02218d35 --- /dev/null +++ b/doxygen/test/compound_includes_disabled/Doxyfile @@ -0,0 +1,15 @@ +INPUT = ../compound_includes/First.h ../compound_includes/Second.h +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = +##! M_LINKS_NAVBAR2 = +##! M_SEARCH_DISABLED = YES + +SHOW_INCLUDE_FILES = NO # explicitly disabled diff --git a/doxygen/test/compound_includes_disabled/classClass.html b/doxygen/test/compound_includes_disabled/classClass.html new file mode 100644 index 00000000..ff36bbb6 --- /dev/null +++ b/doxygen/test/compound_includes_disabled/classClass.html @@ -0,0 +1,52 @@ + + + + + Class class | My Project + + + + + +
+
+
+
+
+

+ Class class +

+

A class.

+
+

Contents

+ +
+

Global include information for this one. (Unless the includes are disabled globally or the file is not documented.)

+
+

Public functions

+
+
+ void foo() +
+
No include information for this one (and thus no details)
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_disabled/group__group.html b/doxygen/test/compound_includes_disabled/group__group.html new file mode 100644 index 00000000..af48cf18 --- /dev/null +++ b/doxygen/test/compound_includes_disabled/group__group.html @@ -0,0 +1,90 @@ + + + + + A group module | My Project + + + + + +
+
+
+
+
+

+ A group module

+
+

Contents

+ +
+

All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

Defines

+
+
+ #define A_DEFINE +
+
A define.
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_disabled/namespaceContained.html b/doxygen/test/compound_includes_disabled/namespaceContained.html new file mode 100644 index 00000000..b897e09e --- /dev/null +++ b/doxygen/test/compound_includes_disabled/namespaceContained.html @@ -0,0 +1,104 @@ + + + + + Contained namespace | My Project + + + + + +
+
+
+
+
+

+ Contained namespace +

+

This namespace is contained in a single file.

+
+

Contents

+ +
+

So it has only the global include and no per-entry includes, thus also no detailed sections because there's only brief. (Unless the includes are disabled globally or the file is not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

A group

+
+
+ enum Flag { } +
+
Flag in a group.
+
+ using Main = void +
+
Alias in a group.
+
+ void* variable constexpr +
+
Variable in a group.
+
+ void bar() +
+
Function in a group.
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_disabled/namespaceSpread.html b/doxygen/test/compound_includes_disabled/namespaceSpread.html new file mode 100644 index 00000000..52016621 --- /dev/null +++ b/doxygen/test/compound_includes_disabled/namespaceSpread.html @@ -0,0 +1,104 @@ + + + + + Spread namespace | My Project + + + + + +
+
+
+
+
+

+ Spread namespace +

+

This namespace is spread over two files.

+
+

Contents

+ +
+

So it has no global include but per-entry includes, properly expanding the brief-only docs into detailed ones. (Unless the includes are disabled globally or the files are not documented.)

+
+

Enums

+
+
+ enum Enum { } +
+
An enum.
+
+
+
+

Typedefs

+
+
+ using Int = int +
+
A typedef.
+
+
+
+

Functions

+
+
+ void foo() +
+
A function.
+
+
+
+

Variables

+
+
+ const int Var constexpr +
+
A variable.
+
+
+
+

A group

+
+
+ enum Flag { } +
+
Flag in a group.
+
+ using Main = void +
+
Alias in a group.
+
+ void* variable constexpr +
+
Variable in a group.
+
+ void bar() +
+
Function in a group.
+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_templated/Doxyfile b/doxygen/test/compound_includes_templated/Doxyfile new file mode 100644 index 00000000..ce05b2e1 --- /dev/null +++ b/doxygen/test/compound_includes_templated/Doxyfile @@ -0,0 +1,13 @@ +INPUT = First.h Second.h +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = +##! M_LINKS_NAVBAR2 = +##! M_SEARCH_DISABLED = YES diff --git a/doxygen/test/compound_includes_templated/First.h b/doxygen/test/compound_includes_templated/First.h new file mode 100644 index 00000000..d982ad6a --- /dev/null +++ b/doxygen/test/compound_includes_templated/First.h @@ -0,0 +1,26 @@ +/** @file + * @brief First file + */ + +/** +@brief This namespace is spread over two files + +So it has per-entry includes next to template info, properly expanding the +brief-only docs into detailed ones. +*/ +namespace Spread { + +/** @brief A template alias */ +template using Alias = T; + +/** @brief A templated function */ +template void bar(); + +} + +/** +@brief A templated struct + +Has global include info next to the template info. +*/ +template struct Struct {}; diff --git a/doxygen/test/compound_includes_templated/Second.h b/doxygen/test/compound_includes_templated/Second.h new file mode 100644 index 00000000..b012b497 --- /dev/null +++ b/doxygen/test/compound_includes_templated/Second.h @@ -0,0 +1,10 @@ +/** @file + * @brief Second file + */ + +namespace Spread { + +/** @brief A templated variable */ +template constexpr const T* Var = nullptr; + +} diff --git a/doxygen/test/compound_includes_templated/namespaceSpread.html b/doxygen/test/compound_includes_templated/namespaceSpread.html new file mode 100644 index 00000000..4a0c1de0 --- /dev/null +++ b/doxygen/test/compound_includes_templated/namespaceSpread.html @@ -0,0 +1,114 @@ + + + + + Spread namespace | My Project + + + + + +
+
+
+
+
+

+ Spread namespace +

+

This namespace is spread over two files.

+
+

Contents

+ +
+

So it has per-entry includes next to template info, properly expanding the brief-only docs into detailed ones.

+
+

Typedefs

+
+
+
template<class T>
+ using Alias = T +
+
A template alias.
+
+
+
+

Functions

+
+
+
template<class T>
+ void bar() +
+
A templated function.
+
+
+
+

Variables

+
+
+
template<class T>
+ const T* Var constexpr +
+
A templated variable.
+
+
+
+

Typedef documentation

+
+

+
#include <First.h>
+
+ template<class T> +
+ using Spread::Alias = T +

+

A template alias.

+
+
+
+

Function documentation

+
+

+
#include <First.h>
+
+ template<class T> +
+ void Spread::bar() +

+

A templated function.

+
+
+
+

Variable documentation

+
+

+
#include <Second.h>
+
+ template<class T> +
+ const T* Spread::Var constexpr +

+

A templated variable.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_templated/structStruct.html b/doxygen/test/compound_includes_templated/structStruct.html new file mode 100644 index 00000000..7ca6df2b --- /dev/null +++ b/doxygen/test/compound_includes_templated/structStruct.html @@ -0,0 +1,34 @@ + + + + + Struct struct | My Project + + + + + +
+
+
+
+
+

+
#include <First.h>
+
template<class T>
+ Struct struct +

+

A templated struct.

+

Has global include info next to the template info.

+
+
+
+
+ + diff --git a/doxygen/test/compound_includes_undocumented_files/Doxyfile b/doxygen/test/compound_includes_undocumented_files/Doxyfile new file mode 100644 index 00000000..ce05b2e1 --- /dev/null +++ b/doxygen/test/compound_includes_undocumented_files/Doxyfile @@ -0,0 +1,13 @@ +INPUT = First.h Second.h +QUIET = YES +GENERATE_HTML = NO +GENERATE_LATEX = NO +GENERATE_XML = YES +XML_PROGRAMLISTING = NO + +##! M_PAGE_FINE_PRINT = +##! M_THEME_COLOR = +##! M_FAVICON = +##! M_LINKS_NAVBAR1 = +##! M_LINKS_NAVBAR2 = +##! M_SEARCH_DISABLED = YES diff --git a/doxygen/test/compound_includes_undocumented_files/First.h b/doxygen/test/compound_includes_undocumented_files/First.h new file mode 100644 index 00000000..5a18d9ac --- /dev/null +++ b/doxygen/test/compound_includes_undocumented_files/First.h @@ -0,0 +1,112 @@ +/* @file + * @brief Turn this into a Doxygen comment to enable include info + */ + +/* This file needs to be kept the same as compound_includes/First.h except for + the above @file block. */ + +/** +@brief This namespace is contained in a single file + +So it has only the global include and no per-entry includes, thus also no +detailed sections because there's only brief. (Unless the includes are disabled +globally or the file is not documented.) +*/ +namespace Contained { + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @brief A function */ +void foo(); + +/** @{ @name A group */ + +/** @brief Flag in a group */ +enum Flag {}; + +/** @brief Alias in a group */ +using Main = void; + +/** @brief Function in a group */ +void bar(); + +/** @brief Variable in a group */ +constexpr void* variable = nullptr; + +/*@}*/ + +} + +/** +@brief This namespace is spread over two files + +So it has no global include but per-entry includes, properly expanding the +brief-only docs into detailed ones. (Unless the includes are disabled globally +or the files are not documented.) +*/ +namespace Spread { + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @{ @name A group */ + +/** @brief Alias in a group */ +using Main = void; + +/** @brief Function in a group */ +void bar(); + +/** @brief Variable in a group */ +constexpr void* variable = nullptr; + +/*@}*/ + +} + +/** +@brief A class + +Global include information for this one. (Unless the includes are disabled +globally or the file is not documented.) +*/ +class Class { + public: + /** @brief No include information for this one (and thus no details) */ + void foo(); +}; + +/** @defgroup group A group + +All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.) +@{ */ + +/** @brief An enum */ +enum Enum {}; + +/** @brief A typedef */ +typedef int Int; + +/** @brief A variable */ +constexpr const int Var = 3; + +/** @brief A function */ +void foo(); + +/** @brief A define */ +#define A_DEFINE + +/*@}*/ diff --git a/doxygen/test/compound_includes_undocumented_files/Second.h b/doxygen/test/compound_includes_undocumented_files/Second.h new file mode 100644 index 00000000..58738cdb --- /dev/null +++ b/doxygen/test/compound_includes_undocumented_files/Second.h @@ -0,0 +1,20 @@ +/* @file + * @brief Turn this into a Doxygen comment to enable include info + */ + +/* This file needs to be kept the same as compound_includes/Second.h except for + the above @file block. */ + +namespace Spread { + +/** @brief A function */ +void foo(); + +/** @{ @name A group */ + +/** @brief Flag in a group */ +enum Flag {}; + +/*@}*/ + +} diff --git a/doxygen/test/compound_listing/classRoot_1_1Directory_1_1Sub_1_1Class.html b/doxygen/test/compound_listing/classRoot_1_1Directory_1_1Sub_1_1Class.html index 3a48bde0..ff6d6991 100644 --- a/doxygen/test/compound_listing/classRoot_1_1Directory_1_1Sub_1_1Class.html +++ b/doxygen/test/compound_listing/classRoot_1_1Directory_1_1Sub_1_1Class.html @@ -37,6 +37,7 @@

Root::Directory::Sub::Class class +

A class.

diff --git a/doxygen/test/compound_listing/namespaceRoot_1_1Directory.html b/doxygen/test/compound_listing/namespaceRoot_1_1Directory.html index 9ec430f6..7a3c42c7 100644 --- a/doxygen/test/compound_listing/namespaceRoot_1_1Directory.html +++ b/doxygen/test/compound_listing/namespaceRoot_1_1Directory.html @@ -37,6 +37,7 @@

Root::Directory namespace +

Namespace in directory.

diff --git a/doxygen/test/compound_namespace_members_in_file_scope/namespaceNamespace.html b/doxygen/test/compound_namespace_members_in_file_scope/namespaceNamespace.html index 39253918..d4c2f951 100644 --- a/doxygen/test/compound_namespace_members_in_file_scope/namespaceNamespace.html +++ b/doxygen/test/compound_namespace_members_in_file_scope/namespaceNamespace.html @@ -21,6 +21,7 @@

Namespace namespace +
#include <File.h>

A namespace.

diff --git a/doxygen/test/cpp_friends/classClass.html b/doxygen/test/cpp_friends/classClass.html index 86211ef3..67ff11ea 100644 --- a/doxygen/test/cpp_friends/classClass.html +++ b/doxygen/test/cpp_friends/classClass.html @@ -21,6 +21,7 @@

Class class +
#include <File.h>

A class.

diff --git a/doxygen/test/cpp_friends/classTemplate.html b/doxygen/test/cpp_friends/classTemplate.html index 596cbb7e..b8a326ec 100644 --- a/doxygen/test/cpp_friends/classTemplate.html +++ b/doxygen/test/cpp_friends/classTemplate.html @@ -20,6 +20,7 @@

+
#include <File.h>
template<class T, class U = void, class = int>
Template class

diff --git a/doxygen/test/cpp_signals_slots/classClass.html b/doxygen/test/cpp_signals_slots/classClass.html index 08cb0eeb..b1d75e2a 100644 --- a/doxygen/test/cpp_signals_slots/classClass.html +++ b/doxygen/test/cpp_signals_slots/classClass.html @@ -21,6 +21,7 @@

Class class +
#include <File.h>

A class.

diff --git a/doxygen/test/cpp_template_alias/structTemplate.html b/doxygen/test/cpp_template_alias/structTemplate.html index ceaaf827..f38065c3 100644 --- a/doxygen/test/cpp_template_alias/structTemplate.html +++ b/doxygen/test/cpp_template_alias/structTemplate.html @@ -20,6 +20,7 @@

+
#include <File.h>
template<class T, class U = void, class = int>
Template struct

diff --git a/doxygen/test/test_compound.py b/doxygen/test/test_compound.py index a2478f5f..6597ee38 100644 --- a/doxygen/test/test_compound.py +++ b/doxygen/test/test_compound.py @@ -245,3 +245,57 @@ class CrazyTemplateParams(IntegrationTestCase): # The file should have the whole template argument as a type self.assertEqual(*self.actual_expected_contents('File_8h.html')) + +class Includes(IntegrationTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, 'includes', *args, **kwargs) + + def test(self): + self.run_dox2html5(wildcard='*.xml') + + # The Contained namespace should have just the global include, the + # Spread just the local includes, the class a global include and the + # group, even though in a single file, should have local includes + self.assertEqual(*self.actual_expected_contents('namespaceContained.html')) + self.assertEqual(*self.actual_expected_contents('namespaceSpread.html')) + self.assertEqual(*self.actual_expected_contents('classClass.html')) + self.assertEqual(*self.actual_expected_contents('group__group.html')) + +class IncludesDisabled(IntegrationTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, 'includes_disabled', *args, **kwargs) + + def test(self): + self.run_dox2html5(wildcard='*.xml') + + # No include information as SHOW_INCLUDE_FILES is disabled globally + self.assertEqual(*self.actual_expected_contents('namespaceContained.html')) + self.assertEqual(*self.actual_expected_contents('namespaceSpread.html')) + self.assertEqual(*self.actual_expected_contents('classClass.html')) + self.assertEqual(*self.actual_expected_contents('group__group.html')) + +class IncludesUndocumentedFiles(IntegrationTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, 'includes_undocumented_files', *args, **kwargs) + + def test(self): + self.run_dox2html5(wildcard='*.xml') + + # The files are not documented, so there should be no include + # information -- practically the same output as when SHOW_INCLUDE_FILES + # is disabled globally + self.assertEqual(*self.actual_expected_contents('namespaceContained.html', '../compound_includes_disabled/namespaceContained.html')) + self.assertEqual(*self.actual_expected_contents('namespaceSpread.html', '../compound_includes_disabled/namespaceSpread.html')) + self.assertEqual(*self.actual_expected_contents('classClass.html', '../compound_includes_disabled/classClass.html')) + self.assertEqual(*self.actual_expected_contents('group__group.html', '../compound_includes_disabled/group__group.html')) + +class IncludesTemplated(IntegrationTestCase): + def __init__(self, *args, **kwargs): + super().__init__(__file__, 'includes_templated', *args, **kwargs) + + def test(self): + self.run_dox2html5(wildcard='*.xml') + + # All entries should have the includes next to the template + self.assertEqual(*self.actual_expected_contents('namespaceSpread.html')) + self.assertEqual(*self.actual_expected_contents('structStruct.html')) diff --git a/doxygen/test/test_doxyfile.py b/doxygen/test/test_doxyfile.py index 36c33eb1..57825aff 100644 --- a/doxygen/test/test_doxyfile.py +++ b/doxygen/test/test_doxyfile.py @@ -70,6 +70,7 @@ list using and 'OUTPUT_DIRECTORY': '', 'PROJECT_BRIEF': 'is cool', 'PROJECT_NAME': 'My Pet Project', + 'SHOW_INCLUDE_FILES': True, 'XML_OUTPUT': 'xml' }) -- 2.30.2