chiark / gitweb /
doxygen: show corresponding #include files.
authorVladimír Vondruš <mosra@centrum.cz>
Mon, 31 Dec 2018 02:07:34 +0000 (03:07 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Mon, 31 Dec 2018 02:47:33 +0000 (03:47 +0100)
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 <machida_mn@complex.ist.hokudai.ac.jp>
55 files changed:
css/m-dark+doxygen.compiled.css
css/m-dark.doxygen.compiled.css
css/m-doxygen.css
css/m-light+doxygen.compiled.css
css/m-light.doxygen.compiled.css
doc/doxygen.rst
doxygen/dox2html5.py
doxygen/templates/base-class-reference.html
doxygen/templates/details-define.html
doxygen/templates/details-enum.html
doxygen/templates/details-func.html
doxygen/templates/details-typedef.html
doxygen/templates/details-var.html
doxygen/templates/namespace.html
doxygen/test/compound_deprecated/namespaceDeprecatedNamespace.html
doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1BaseDeprecatedClass.html
doxygen/test/compound_deprecated/structDeprecatedNamespace_1_1DeprecatedClass.html
doxygen/test/compound_detailed/namespaceEno.html
doxygen/test/compound_detailed/namespaceFoo.html
doxygen/test/compound_detailed/namespaceNamee.html
doxygen/test/compound_detailed/namespaceType.html
doxygen/test/compound_detailed/namespaceVar.html
doxygen/test/compound_detailed/namespaceWarning.html
doxygen/test/compound_detailed/structTemplate.html
doxygen/test/compound_detailed/structTemplateWarning.html
doxygen/test/compound_detailed/structTemplate_3_01void_01_4.html
doxygen/test/compound_includes/Doxyfile [new file with mode: 0644]
doxygen/test/compound_includes/First.h [new file with mode: 0644]
doxygen/test/compound_includes/Second.h [new file with mode: 0644]
doxygen/test/compound_includes/classClass.html [new file with mode: 0644]
doxygen/test/compound_includes/group__group.html [new file with mode: 0644]
doxygen/test/compound_includes/namespaceContained.html [new file with mode: 0644]
doxygen/test/compound_includes/namespaceSpread.html [new file with mode: 0644]
doxygen/test/compound_includes_disabled/Doxyfile [new file with mode: 0644]
doxygen/test/compound_includes_disabled/classClass.html [new file with mode: 0644]
doxygen/test/compound_includes_disabled/group__group.html [new file with mode: 0644]
doxygen/test/compound_includes_disabled/namespaceContained.html [new file with mode: 0644]
doxygen/test/compound_includes_disabled/namespaceSpread.html [new file with mode: 0644]
doxygen/test/compound_includes_templated/Doxyfile [new file with mode: 0644]
doxygen/test/compound_includes_templated/First.h [new file with mode: 0644]
doxygen/test/compound_includes_templated/Second.h [new file with mode: 0644]
doxygen/test/compound_includes_templated/namespaceSpread.html [new file with mode: 0644]
doxygen/test/compound_includes_templated/structStruct.html [new file with mode: 0644]
doxygen/test/compound_includes_undocumented_files/Doxyfile [new file with mode: 0644]
doxygen/test/compound_includes_undocumented_files/First.h [new file with mode: 0644]
doxygen/test/compound_includes_undocumented_files/Second.h [new file with mode: 0644]
doxygen/test/compound_listing/classRoot_1_1Directory_1_1Sub_1_1Class.html
doxygen/test/compound_listing/namespaceRoot_1_1Directory.html
doxygen/test/compound_namespace_members_in_file_scope/namespaceNamespace.html
doxygen/test/cpp_friends/classClass.html
doxygen/test/cpp_friends/classTemplate.html
doxygen/test/cpp_signals_slots/classClass.html
doxygen/test/cpp_template_alias/structTemplate.html
doxygen/test/test_compound.py
doxygen/test/test_doxyfile.py

index 88dc75d72c8d0445124b83a22225a65ced0748ee..6fb8ee8eb094d30765408083081e296c399d7bc0 100644 (file)
@@ -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;
index 2760356e008a39344df6979891330586c0f951c3..72b4b37ec12a48fb12a8ad8fa0eafae1e8c83d5d 100644 (file)
@@ -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;
index 514d38bd9c8b45f6c48cdf3e2775c213b8be65f8..9bea1cd20aa749ca603643213b13548d9dfa962c 100644 (file)
@@ -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;
index 9479646ef908339c14b22fa7ad76ec68728b5eec..59a0f71e32ca0225540eb1785ed6e535601f349b 100644 (file)
@@ -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;
index e62f1b0c2e0ea496d5a019f9e052e4e6c7493fb6..23832da055eb0232545107a4982f8f6c1d69d6fb 100644 (file)
@@ -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;
index ae7e266a89e8cf99e6d9ba59363213bb1f35a64c..b920332169aace6810266bcef1ee5b73eac91e5b 100644 (file)
@@ -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
index bcc27b68773ee0d0e1f9d310dfb01748bb47d613..41bf411f7589955b9b3b944c611e19e98d6b35e9 100755 (executable)
@@ -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 '<a href="{}" class="{}">{}</a>'.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 <span class="m-label m-dim">&darr;</span> 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']:
index 71cf5424b779f27f54b2a4e8b1fbdf530fd9ce47..0515dbb0ef09d03559a3073903dbc3c1161989eb 100644 (file)
 {% block main %}
         <h1>
           {% if compound.templates != None %}
+          {% if compound.include %}
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ compound.include[1] }}">{{ compound.include[0] }}</a></div>
+          {% endif %}
           {% set j = joiner(', ') %}
           <div class="m-dox-template">template&lt;{% for t in compound.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}&gt;</div>
           {% endif %}
           {%+ for name, target in compound.breadcrumb[:-1] %}<span class="m-breadcrumb"><a href="{{ target }}">{{ name }}</a>::<wbr/></span>{% endfor %}{{ compound.breadcrumb[-1][0] }} <span class="m-thin">{{ compound.kind }}</span>
+          {% if compound.include and compound.templates == None %}
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ compound.include[1] }}">{{ compound.include[0] }}</a></div>
+          {% endif %}
         </h1>
         {% if compound.brief %}
         <p>{{ compound.brief }}</p>
index 2fd66b4a6a36dabf8a535e97012a179a51b47769..132ea4eb7dc8927e3b25bdabc2ed208739773bda 100644 (file)
@@ -2,6 +2,9 @@
             <h3>
               {% set j = joiner(',\n              ') %}
               <span class="m-dox-wrap-bumper">#define <a href="#{{ define.id }}" class="m-dox-self">{{ define.name }}</a>{% if define.params != None %}(</span><span class="m-dox-wrap">{% for param in define.params %}{{ j() }}{{ param[0] }}{% endfor %}){% endif %}</span>
+              {% if define.include %}
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ define.include[1] }}">{{ define.include[0] }}</a></div>
+              {% endif %}
             </h3>
             {% if define.brief %}
             <p>{{ define.brief }}</p>
index 504bee5335b9e9687fdc9ae4e9706b033fee708e..e95b5590721d5140709cb561610187878ab37fa5 100644 (file)
@@ -9,6 +9,13 @@
               enum {% if enum.is_strong %}class {% endif %}{{ prefix }}<a href="#{{ enum.id }}" class="m-dox-self">{{ enum.name }}</a>{% if enum.type %}: {{ enum.type }}{% endif %}{% if enum.is_protected %} <span class="m-label m-warning">protected</span>{% 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` #}
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ enum.include[1] }}">{{ enum.include[0] }}</a></div>
+              {% endif %}
             </h3>
             {% if enum.brief %}{# brief can be omitted for anonymous enums #}
             <p>{{ enum.brief }}</p>
index 2c394c7b92ab873e9b23934d5b32ad12255664c0..43e11f3dfadd5aa6bc52f4ddc90c051e5f7dfe75 100644 (file)
@@ -1,6 +1,9 @@
           <section class="m-dox-details" id="{{ func.id }}"><div>
             <h3>
               {% if compound.templates != None or func.templates != None %}
+              {% if func.include %}
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ func.include[1] }}">{{ func.include[0] }}</a></div>
+              {% endif %}
               <div class="m-dox-template">
                 {% if compound.templates != None %}
                 {% set j = joiner(', ') %}
@@ -14,6 +17,9 @@
               {% endif %}
               {% set j = joiner(',\n              ') %}
               <span class="m-dox-wrap-bumper">{{ func.prefix }}{{ func.type }} {{ prefix }}</span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#{{ func.id }}" class="m-dox-self">{{ func.name }}</a>(</span><span class="m-dox-wrap">{% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} <span class="m-label m-info">explicit</span> {% endif %}{% if func.is_pure_virtual %} <span class="m-label m-warning">pure virtual</span>{% elif func.is_virtual %} <span class="m-label m-warning">virtual</span>{% endif %}{% if func.is_protected %} <span class="m-label m-warning">protected{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_private %} <span class="m-label m-danger">private{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_signal %} <span class="m-label m-success">signal</span>{% elif func.is_slot %} <span class="m-label m-success">public slot</span>{% endif %}{% if func.is_defaulted %} <span class="m-label m-info">defaulted</span>{% endif %}{% if func.is_deleted %} <span class="m-label m-danger">deleted</span>{% endif %}{% if func.is_constexpr %} <span class="m-label m-primary">constexpr</span>{% endif %}{% if func.is_noexcept %} <span class="m-label m-success">noexcept</span>{% endif %}</span></span>
+              {% if func.include and compound.templates == None and func.templates == None %}
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ func.include[1] }}">{{ func.include[0] }}</a></div>
+              {% endif %}
             </h3>
             {% if func.brief %}
             <p>{{ func.brief }}</p>
index bec5a0f465ec42c45988a78052e0d066821f5084..8e994a15e26b2d44185df7c6b583840b1e0e041e 100644 (file)
@@ -1,6 +1,9 @@
           <section class="m-dox-details" id="{{ typedef.id }}"><div>
             <h3>
               {% if compound.templates != None or typedef.templates != None %}
+              {% if typedef.include %}
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ typedef.include[1] }}">{{ typedef.include[0] }}</a></div>
+              {% endif %}
               <div class="m-dox-template">
                 {% 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 %}
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ typedef.include[1] }}">{{ typedef.include[0] }}</a></div>
+              {% endif %}
             </h3>
             {% if typedef.brief %}
             <p>{{ typedef.brief }}</p>
index 2dbea7a40813a8a53d67873d18b9e3af04feb629..ca8c0c96e94f47cbe15fc22fdf0cf158c5fbd5ef 100644 (file)
@@ -1,6 +1,9 @@
           <section class="m-dox-details" id="{{ var.id }}"><div>
             <h3>
               {% if compound.templates != None or var.templates != None  %}
+              {% if var.include %}
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ var.include[1] }}">{{ var.include[0] }}</a></div>
+              {% endif %}
               <div class="m-dox-template">
                 {% if compound.templates != None %}
                 {% set j = joiner(', ') %}
@@ -15,6 +18,9 @@
               {%+ if var.is_static %}static {% endif %}{{ var.type }} {{ prefix }}<a href="#{{ var.id }}" class="m-dox-self">{{ var.name }}</a>{% if var.is_protected %} <span class="m-label m-warning">protected</span>{% endif %}{% if var.is_constexpr %} <span class="m-label m-primary">constexpr</span>{% 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 %}
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ var.include[1] }}">{{ var.include[0] }}</a></div>
+              {% endif %}
             </h3>
             {% if var.brief %}
             <p>{{ var.brief }}</p>
index 302a95463f0233ae8df92d2a29d4f2d55d3f0b25..e32a1f7049a3dd5cf101442d784eacc4f4ce27fb 100644 (file)
@@ -5,5 +5,8 @@
 {% block header %}
         <h1>
           {%+ for name, target in compound.breadcrumb[:-1] %}<span class="m-breadcrumb"><a href="{{ target }}">{{ name }}</a>::<wbr/></span>{% endfor %}{{ compound.breadcrumb[-1][0] }} <span class="m-thin">namespace</span>
+          {% if compound.include %}
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="{{ compound.include[1] }}">{{ compound.include[0] }}</a></div>
+          {% endif %}
         </h1>
 {% endblock %}
index 96369bb9abc5f16d074781df7c429f313302d097..ede92b56b7c78279d93d1007cf9672f5b932dea4 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           DeprecatedNamespace <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="DeprecatedFile_8h.html">&lt;Dir/DeprecatedFile.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index 3792d2f973cd88d59f2ca45edc9fdda2b6be9bd3..71ab801e96cf89c428a34a288a9df7f6d4d2e0d5 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           <span class="m-breadcrumb"><a href="namespaceDeprecatedNamespace.html">DeprecatedNamespace</a>::<wbr/></span>BaseDeprecatedClass <span class="m-thin">struct</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="DeprecatedFile_8h.html">&lt;Dir/DeprecatedFile.h&gt;</a></div>
         </h1>
         <p>A base class.</p>
 <aside class="m-note m-danger"><h4><a href="deprecated.html#_deprecated000005" class="m-dox">Deprecated</a></h4><p>This class is deprecated.</p></aside>
index a9bd6dde3599fc0a33ec9f8457647bf3c45415a4..5dbf702fb3d5a8811af0780618b9b8f942141392 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           <span class="m-breadcrumb"><a href="namespaceDeprecatedNamespace.html">DeprecatedNamespace</a>::<wbr/></span>DeprecatedClass <span class="m-thin">struct</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="DeprecatedFile_8h.html">&lt;Dir/DeprecatedFile.h&gt;</a></div>
         </h1>
         <p>A class.</p>
 <aside class="m-note m-danger"><h4><a href="deprecated.html#_deprecated000006" class="m-dox">Deprecated</a></h4><p>This class is deprecated.</p></aside>
index 98eb5510a23db5c17ff361e977a89321ff174a1e..31d2cbc8c953a1cf77ae82873ab88538ee7e5ee3 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Eno <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <section id="enum-members">
index 8bf583494831d9f9092c0ad8de46877f9456441a..2cbe43c0bae8359dd041cc613878ceb0c5f20de1 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Foo <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index c048ab8c3dec435d446078d9e5d60f9d5bf8fde7..210b0f718fc78bd868ed3b3ddf5010e81bc17f88 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Namee <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>Namespace docs.</p>
 <p>And we have some detailed docs as well.</p>
index e60d09b3dd27452fa07f8f59de6c8683251fac76..a9b231bd7dba31340c98667bdc87ff6ea468efe5 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Type <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index 44b53fbf1969b1bf5489e4914b0f270cd255316f..e0ca116539238ff478027375e3074452dbf01486 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Var <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index 869febf59b3aaae32e2ca3820763fb917235f2db..7f43df7d237ad5e3fc29631a453b7d23d539cf66 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Warning <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index 0dd5cb712b33f3a351095c90d4255bf4999b2fba..a07a97db49185d0c41958fbd04eac9f8bfb682ea 100644 (file)
@@ -20,6 +20,7 @@
     <div class="m-row">
       <div class="m-col-l-10 m-push-l-1">
         <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
           <div class="m-dox-template">template&lt;class T, class U = void, class = int&gt;</div>
           Template <span class="m-thin">struct</span>
         </h1>
index 146cb2d5afbbcfe8798c64aec05fb1e19674be0e..fae824a14491fd28ccef0900c48c6b2684349662 100644 (file)
@@ -20,6 +20,7 @@
     <div class="m-row">
       <div class="m-col-l-10 m-push-l-1">
         <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
           <div class="m-dox-template">template&lt;class T&gt;</div>
           TemplateWarning <span class="m-thin">struct</span>
         </h1>
index 7cee82fe0c71198a113d5a68d8e0130511fec0ae..f524b08445e5fb549b0e0ea6135753ec4c44f3e2 100644 (file)
@@ -20,6 +20,7 @@
     <div class="m-row">
       <div class="m-col-l-10 m-push-l-1">
         <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
           <div class="m-dox-template">template&lt;&gt;</div>
           Template&lt;void&gt; <span class="m-thin">struct</span>
         </h1>
diff --git a/doxygen/test/compound_includes/Doxyfile b/doxygen/test/compound_includes/Doxyfile
new file mode 100644 (file)
index 0000000..ce05b2e
--- /dev/null
@@ -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 (file)
index 0000000..e43deb1
--- /dev/null
@@ -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 (file)
index 0000000..5f36640
--- /dev/null
@@ -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 (file)
index 0000000..6df71c7
--- /dev/null
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Class class | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Class <span class="m-thin">class</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+        </h1>
+        <p>A class.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#pub-methods">Public functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>Global include information for this one. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="pub-methods">
+          <h2><a href="#pub-methods">Public functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a7b841d4b5f36c46ee3625e15c77f2f65" class="m-dox-self" name="a7b841d4b5f36c46ee3625e15c77f2f65">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>No include information for this one (and thus no details)</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes/group__group.html b/doxygen/test/compound_includes/group__group.html
new file mode 100644 (file)
index 0000000..7f20d7a
--- /dev/null
@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>A group module | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          A group <span class="m-thin">module</span></h1>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#defines">Defines</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#ga8150b7776c2a1749101acf22e868d091" class="m-dox">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#ga7cc214a236ad3bb6ad435bdcf5262a3f" class="m-dox">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#gac07863d69ae41a4e395b31f73b35fbcd" class="m-dox">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#ga7708bd7aaec399e771a2b30db52e4d22" class="m-dox">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="define-members">
+          <h2><a href="#define-members">Defines</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">#define <a href="#ga144a2a84c08d05de76f6a4a245584810" class="m-dox">A_DEFINE</a></span>
+            </dt>
+            <dd>A define.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Enum documentation</h2>
+          <section class="m-dox-details" id="ga8150b7776c2a1749101acf22e868d091"><div>
+            <h3>
+              enum <a href="#ga8150b7776c2a1749101acf22e868d091" class="m-dox-self">Enum</a>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>An enum.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Typedef documentation</h2>
+          <section class="m-dox-details" id="ga7cc214a236ad3bb6ad435bdcf5262a3f"><div>
+            <h3>
+              typedef int <a href="#ga7cc214a236ad3bb6ad435bdcf5262a3f" class="m-dox-self">Int</a>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A typedef.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="gac07863d69ae41a4e395b31f73b35fbcd"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void </span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#gac07863d69ae41a4e395b31f73b35fbcd" class="m-dox-self">foo</a>(</span><span class="m-dox-wrap">)</span></span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A function.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Variable documentation</h2>
+          <section class="m-dox-details" id="ga7708bd7aaec399e771a2b30db52e4d22"><div>
+            <h3>
+              const int <a href="#ga7708bd7aaec399e771a2b30db52e4d22" class="m-dox-self">Var</a> <span class="m-label m-primary">constexpr</span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A variable.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Define documentation</h2>
+          <section class="m-dox-details" id="ga144a2a84c08d05de76f6a4a245584810"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">#define <a href="#ga144a2a84c08d05de76f6a4a245584810" class="m-dox-self">A_DEFINE</a></span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A define.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes/namespaceContained.html b/doxygen/test/compound_includes/namespaceContained.html
new file mode 100644 (file)
index 0000000..0c6b5b3
--- /dev/null
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Contained namespace | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Contained <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+        </h1>
+        <p>This namespace is contained in a single file.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#a-group">A group</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>So it has only the global include and no per-entry includes, thus also no detailed sections because there&#x27;s only brief. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a1e198a456efa4fe54dfc7f1f60e0b5d7" class="m-dox-self" name="a1e198a456efa4fe54dfc7f1f60e0b5d7">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#ad01b62dead0717cef791ff24ed1371cd" class="m-dox-self" name="ad01b62dead0717cef791ff24ed1371cd">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a805f49495092c6f2bb1347f50bf2453e" class="m-dox-self" name="a805f49495092c6f2bb1347f50bf2453e">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#a91e894fe69f4a6c73074f7862ede5503" class="m-dox-self" name="a91e894fe69f4a6c73074f7862ede5503">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="a-group">
+          <h2><a href="#a-group">A group</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a11d588fad4de0640556b055558c5fa1d" class="m-dox-self" name="a11d588fad4de0640556b055558c5fa1d">Flag</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>Flag in a group.</dd>
+            <dt>
+              using <a href="#a0b67fd41e23a38858d471e30a817d591" class="m-dox-self" name="a0b67fd41e23a38858d471e30a817d591">Main</a> = void
+            </dt>
+            <dd>Alias in a group.</dd>
+            <dt>
+              void* <a href="#ac65f93520b7abe37daa15a999faa4323" class="m-dox-self" name="ac65f93520b7abe37daa15a999faa4323">variable</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>Variable in a group.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#abcad26bce92bd85654aaf9b7effc043b" class="m-dox-self" name="abcad26bce92bd85654aaf9b7effc043b">bar</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>Function in a group.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes/namespaceSpread.html b/doxygen/test/compound_includes/namespaceSpread.html
new file mode 100644 (file)
index 0000000..9952561
--- /dev/null
@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Spread namespace | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Spread <span class="m-thin">namespace</span>
+        </h1>
+        <p>This namespace is spread over two files.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#a-group">A group</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>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.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a527869a2c002fb30f314deaff11e0fc6" class="m-dox">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#a9fc9fdc7cf8b70815d959519730179e3" class="m-dox">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a811e0028cbcd17f7895e36f63ace4e41" class="m-dox">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#a25b13ca7d2a86255c5e75a436ade62cf" class="m-dox">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="a-group">
+          <h2><a href="#a-group">A group</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#aa29ea9c4e31c7d0408e7c5abddb50cd3" class="m-dox">Flag</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>Flag in a group.</dd>
+            <dt>
+              using <a href="#a0dbfc6770d1bfbd85f3c3fc4772937a3" class="m-dox">Main</a> = void
+            </dt>
+            <dd>Alias in a group.</dd>
+            <dt>
+              void* <a href="#aa0bc03c4dea294a892d53860b4f0377e" class="m-dox">variable</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>Variable in a group.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#ad0126ebd4b7c6ba90561fa98ebbe9a94" class="m-dox">bar</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>Function in a group.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Enum documentation</h2>
+          <section class="m-dox-details" id="a527869a2c002fb30f314deaff11e0fc6"><div>
+            <h3>
+              enum Spread::<wbr /><a href="#a527869a2c002fb30f314deaff11e0fc6" class="m-dox-self">Enum</a>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>An enum.</p>
+          </div></section>
+          <section class="m-dox-details" id="aa29ea9c4e31c7d0408e7c5abddb50cd3"><div>
+            <h3>
+              enum Spread::<wbr /><a href="#aa29ea9c4e31c7d0408e7c5abddb50cd3" class="m-dox-self">Flag</a>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="Second_8h.html">&lt;Second.h&gt;</a></div>
+            </h3>
+            <p>Flag in a group.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Typedef documentation</h2>
+          <section class="m-dox-details" id="a9fc9fdc7cf8b70815d959519730179e3"><div>
+            <h3>
+              typedef int Spread::<wbr /><a href="#a9fc9fdc7cf8b70815d959519730179e3" class="m-dox-self">Int</a>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A typedef.</p>
+          </div></section>
+          <section class="m-dox-details" id="a0dbfc6770d1bfbd85f3c3fc4772937a3"><div>
+            <h3>
+              using Spread::<wbr /><a href="#a0dbfc6770d1bfbd85f3c3fc4772937a3" class="m-dox-self">Main</a> = void
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>Alias in a group.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="a811e0028cbcd17f7895e36f63ace4e41"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Spread::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a811e0028cbcd17f7895e36f63ace4e41" class="m-dox-self">foo</a>(</span><span class="m-dox-wrap">)</span></span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="Second_8h.html">&lt;Second.h&gt;</a></div>
+            </h3>
+            <p>A function.</p>
+          </div></section>
+          <section class="m-dox-details" id="ad0126ebd4b7c6ba90561fa98ebbe9a94"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Spread::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#ad0126ebd4b7c6ba90561fa98ebbe9a94" class="m-dox-self">bar</a>(</span><span class="m-dox-wrap">)</span></span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>Function in a group.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Variable documentation</h2>
+          <section class="m-dox-details" id="a25b13ca7d2a86255c5e75a436ade62cf"><div>
+            <h3>
+              const int Spread::<wbr /><a href="#a25b13ca7d2a86255c5e75a436ade62cf" class="m-dox-self">Var</a> <span class="m-label m-primary">constexpr</span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>A variable.</p>
+          </div></section>
+          <section class="m-dox-details" id="aa0bc03c4dea294a892d53860b4f0377e"><div>
+            <h3>
+              void* Spread::<wbr /><a href="#aa0bc03c4dea294a892d53860b4f0377e" class="m-dox-self">variable</a> <span class="m-label m-primary">constexpr</span>
+              <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+            </h3>
+            <p>Variable in a group.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_disabled/Doxyfile b/doxygen/test/compound_includes_disabled/Doxyfile
new file mode 100644 (file)
index 0000000..02218d3
--- /dev/null
@@ -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 (file)
index 0000000..ff36bbb
--- /dev/null
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Class class | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Class <span class="m-thin">class</span>
+        </h1>
+        <p>A class.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#pub-methods">Public functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>Global include information for this one. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="pub-methods">
+          <h2><a href="#pub-methods">Public functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a7b841d4b5f36c46ee3625e15c77f2f65" class="m-dox-self" name="a7b841d4b5f36c46ee3625e15c77f2f65">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>No include information for this one (and thus no details)</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_disabled/group__group.html b/doxygen/test/compound_includes_disabled/group__group.html
new file mode 100644 (file)
index 0000000..af48cf1
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>A group module | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          A group <span class="m-thin">module</span></h1>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#defines">Defines</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>All entries inside should have include information. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#ga8150b7776c2a1749101acf22e868d091" class="m-dox-self" name="ga8150b7776c2a1749101acf22e868d091">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#ga7cc214a236ad3bb6ad435bdcf5262a3f" class="m-dox-self" name="ga7cc214a236ad3bb6ad435bdcf5262a3f">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#gac07863d69ae41a4e395b31f73b35fbcd" class="m-dox-self" name="gac07863d69ae41a4e395b31f73b35fbcd">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#ga7708bd7aaec399e771a2b30db52e4d22" class="m-dox-self" name="ga7708bd7aaec399e771a2b30db52e4d22">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="define-members">
+          <h2><a href="#define-members">Defines</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">#define <a href="#ga144a2a84c08d05de76f6a4a245584810" class="m-dox-self" name="ga144a2a84c08d05de76f6a4a245584810">A_DEFINE</a></span>
+            </dt>
+            <dd>A define.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_disabled/namespaceContained.html b/doxygen/test/compound_includes_disabled/namespaceContained.html
new file mode 100644 (file)
index 0000000..b897e09
--- /dev/null
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Contained namespace | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Contained <span class="m-thin">namespace</span>
+        </h1>
+        <p>This namespace is contained in a single file.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#a-group">A group</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>So it has only the global include and no per-entry includes, thus also no detailed sections because there&#x27;s only brief. (Unless the includes are disabled globally or the file is not documented.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a1e198a456efa4fe54dfc7f1f60e0b5d7" class="m-dox-self" name="a1e198a456efa4fe54dfc7f1f60e0b5d7">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#ad01b62dead0717cef791ff24ed1371cd" class="m-dox-self" name="ad01b62dead0717cef791ff24ed1371cd">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a805f49495092c6f2bb1347f50bf2453e" class="m-dox-self" name="a805f49495092c6f2bb1347f50bf2453e">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#a91e894fe69f4a6c73074f7862ede5503" class="m-dox-self" name="a91e894fe69f4a6c73074f7862ede5503">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="a-group">
+          <h2><a href="#a-group">A group</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a11d588fad4de0640556b055558c5fa1d" class="m-dox-self" name="a11d588fad4de0640556b055558c5fa1d">Flag</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>Flag in a group.</dd>
+            <dt>
+              using <a href="#a0b67fd41e23a38858d471e30a817d591" class="m-dox-self" name="a0b67fd41e23a38858d471e30a817d591">Main</a> = void
+            </dt>
+            <dd>Alias in a group.</dd>
+            <dt>
+              void* <a href="#ac65f93520b7abe37daa15a999faa4323" class="m-dox-self" name="ac65f93520b7abe37daa15a999faa4323">variable</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>Variable in a group.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#abcad26bce92bd85654aaf9b7effc043b" class="m-dox-self" name="abcad26bce92bd85654aaf9b7effc043b">bar</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>Function in a group.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_disabled/namespaceSpread.html b/doxygen/test/compound_includes_disabled/namespaceSpread.html
new file mode 100644 (file)
index 0000000..5201662
--- /dev/null
@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Spread namespace | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Spread <span class="m-thin">namespace</span>
+        </h1>
+        <p>This namespace is spread over two files.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#enum-members">Enums</a></li>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+                <li><a href="#a-group">A group</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>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.)</p>
+        <section id="enum-members">
+          <h2><a href="#enum-members">Enums</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#a527869a2c002fb30f314deaff11e0fc6" class="m-dox-self" name="a527869a2c002fb30f314deaff11e0fc6">Enum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>An enum.</dd>
+          </dl>
+        </section>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              using <a href="#a9fc9fdc7cf8b70815d959519730179e3" class="m-dox-self" name="a9fc9fdc7cf8b70815d959519730179e3">Int</a> = int
+            </dt>
+            <dd>A typedef.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a811e0028cbcd17f7895e36f63ace4e41" class="m-dox-self" name="a811e0028cbcd17f7895e36f63ace4e41">foo</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              const int <a href="#a25b13ca7d2a86255c5e75a436ade62cf" class="m-dox-self" name="a25b13ca7d2a86255c5e75a436ade62cf">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A variable.</dd>
+          </dl>
+        </section>
+        <section id="a-group">
+          <h2><a href="#a-group">A group</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#aa29ea9c4e31c7d0408e7c5abddb50cd3" class="m-dox-self" name="aa29ea9c4e31c7d0408e7c5abddb50cd3">Flag</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>Flag in a group.</dd>
+            <dt>
+              using <a href="#a0dbfc6770d1bfbd85f3c3fc4772937a3" class="m-dox-self" name="a0dbfc6770d1bfbd85f3c3fc4772937a3">Main</a> = void
+            </dt>
+            <dd>Alias in a group.</dd>
+            <dt>
+              void* <a href="#aa0bc03c4dea294a892d53860b4f0377e" class="m-dox-self" name="aa0bc03c4dea294a892d53860b4f0377e">variable</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>Variable in a group.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#ad0126ebd4b7c6ba90561fa98ebbe9a94" class="m-dox-self" name="ad0126ebd4b7c6ba90561fa98ebbe9a94">bar</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>Function in a group.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_templated/Doxyfile b/doxygen/test/compound_includes_templated/Doxyfile
new file mode 100644 (file)
index 0000000..ce05b2e
--- /dev/null
@@ -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 (file)
index 0000000..d982ad6
--- /dev/null
@@ -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<class T> using Alias = T;
+
+/** @brief A templated function */
+template<class T> void bar();
+
+}
+
+/**
+@brief A templated struct
+
+Has global include info next to the template info.
+*/
+template<class T> struct Struct {};
diff --git a/doxygen/test/compound_includes_templated/Second.h b/doxygen/test/compound_includes_templated/Second.h
new file mode 100644 (file)
index 0000000..b012b49
--- /dev/null
@@ -0,0 +1,10 @@
+/** @file
+ * @brief Second file
+ */
+
+namespace Spread {
+
+/** @brief A templated variable */
+template<class T> 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 (file)
index 0000000..4a0c1de
--- /dev/null
@@ -0,0 +1,114 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Spread namespace | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          Spread <span class="m-thin">namespace</span>
+        </h1>
+        <p>This namespace is spread over two files.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#typedef-members">Typedefs</a></li>
+                <li><a href="#func-members">Functions</a></li>
+                <li><a href="#var-members">Variables</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+<p>So it has per-entry includes next to template info, properly expanding the brief-only docs into detailed ones.</p>
+        <section id="typedef-members">
+          <h2><a href="#typedef-members">Typedefs</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <div class="m-dox-template">template&lt;class T&gt;</div>
+              using <a href="#a0a3b8ac7e2c32367f8ce7e291412ca8f" class="m-dox">Alias</a> = T
+            </dt>
+            <dd>A template alias.</dd>
+          </dl>
+        </section>
+        <section id="func-members">
+          <h2><a href="#func-members">Functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <div class="m-dox-template">template&lt;class T&gt;</div>
+              <span class="m-dox-wrap-bumper">void <a href="#adab32b19ce66dfa18991e8dc0ce97098" class="m-dox">bar</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A templated function.</dd>
+          </dl>
+        </section>
+        <section id="var-members">
+          <h2><a href="#var-members">Variables</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <div class="m-dox-template">template&lt;class T&gt;</div>
+              const T* <a href="#aba28a7edc2b0785dd1f9241eef0e8041" class="m-dox">Var</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A templated variable.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Typedef documentation</h2>
+          <section class="m-dox-details" id="a0a3b8ac7e2c32367f8ce7e291412ca8f"><div>
+            <h3>
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+              <div class="m-dox-template">
+                template&lt;class T&gt;
+              </div>
+              using Spread::<wbr /><a href="#a0a3b8ac7e2c32367f8ce7e291412ca8f" class="m-dox-self">Alias</a> = T
+            </h3>
+            <p>A template alias.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="adab32b19ce66dfa18991e8dc0ce97098"><div>
+            <h3>
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+              <div class="m-dox-template">
+                template&lt;class T&gt;
+              </div>
+              <span class="m-dox-wrap-bumper">void Spread::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#adab32b19ce66dfa18991e8dc0ce97098" class="m-dox-self">bar</a>(</span><span class="m-dox-wrap">)</span></span>
+            </h3>
+            <p>A templated function.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Variable documentation</h2>
+          <section class="m-dox-details" id="aba28a7edc2b0785dd1f9241eef0e8041"><div>
+            <h3>
+              <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="Second_8h.html">&lt;Second.h&gt;</a></div>
+              <div class="m-dox-template">
+                template&lt;class T&gt;
+              </div>
+              const T* Spread::<wbr /><a href="#aba28a7edc2b0785dd1f9241eef0e8041" class="m-dox-self">Var</a> <span class="m-label m-primary">constexpr</span>
+            </h3>
+            <p>A templated variable.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_templated/structStruct.html b/doxygen/test/compound_includes_templated/structStruct.html
new file mode 100644 (file)
index 0000000..7ca6df2
--- /dev/null
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Struct struct | My Project</title>
+  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+  <link rel="stylesheet" href="m-dark+doxygen.compiled.css" />
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+  <div class="m-container">
+    <div class="m-row">
+      <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Project</a>
+    </div>
+  </div>
+</nav></header>
+<main><article>
+  <div class="m-container m-container-inflatable">
+    <div class="m-row">
+      <div class="m-col-l-10 m-push-l-1">
+        <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="First_8h.html">&lt;First.h&gt;</a></div>
+          <div class="m-dox-template">template&lt;class T&gt;</div>
+          Struct <span class="m-thin">struct</span>
+        </h1>
+        <p>A templated struct.</p>
+<p>Has global include info next to the template info.</p>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/compound_includes_undocumented_files/Doxyfile b/doxygen/test/compound_includes_undocumented_files/Doxyfile
new file mode 100644 (file)
index 0000000..ce05b2e
--- /dev/null
@@ -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 (file)
index 0000000..5a18d9a
--- /dev/null
@@ -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 (file)
index 0000000..58738cd
--- /dev/null
@@ -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 {};
+
+/*@}*/
+
+}
index 3a48bde09f419d916e751e78be8728de9b4d0857..ff6d6991be8e5f6e4e49bc03721b03f87acaa60a 100644 (file)
@@ -37,6 +37,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           <span class="m-breadcrumb"><a href="namespaceRoot.html">Root</a>::<wbr/></span><span class="m-breadcrumb"><a href="namespaceRoot_1_1Directory.html">Directory</a>::<wbr/></span><span class="m-breadcrumb"><a href="namespaceRoot_1_1Directory_1_1Sub.html">Sub</a>::<wbr/></span>Class <span class="m-thin">class</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="Class_8h.html">&lt;Directory/Sub/Class.h&gt;</a></div>
         </h1>
         <p>A class.</p>
         <div class="m-block m-default">
index 9ec430f69a5092b2caec4961530ad5028a14356e..7a3c42c7e875f7e7c5354f5620f5bf26bb93c899 100644 (file)
@@ -37,6 +37,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           <span class="m-breadcrumb"><a href="namespaceRoot.html">Root</a>::<wbr/></span>Directory <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;Directory/File.h&gt;</a></div>
         </h1>
         <p>Namespace in directory.</p>
         <div class="m-block m-default">
index 392539182ee57f0c5c4e99aa81ae9f9dfb6d8e71..d4c2f9514ed603d50a113e4cf764927946d961d6 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Namespace <span class="m-thin">namespace</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A namespace.</p>
         <div class="m-block m-default">
index 86211ef3477e3fdfcd8e66803e387f66d14036d0..67ff11ea3dd387087ca0eab176d281db87fe0b23 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Class <span class="m-thin">class</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A class.</p>
         <div class="m-block m-default">
index 596cbb7ecf86dab9d66afbdb9badf19d4d94cab6..b8a326ec33de698e4a8d0f13f95599a8927d3586 100644 (file)
@@ -20,6 +20,7 @@
     <div class="m-row">
       <div class="m-col-l-10 m-push-l-1">
         <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
           <div class="m-dox-template">template&lt;class T, class U = void, class = int&gt;</div>
           Template <span class="m-thin">class</span>
         </h1>
index 08cb0eeb422bee3b5a221350df9593dfe35a9fd1..b1d75e2af567bdcf65fff41bbdf275df77da7221 100644 (file)
@@ -21,6 +21,7 @@
       <div class="m-col-l-10 m-push-l-1">
         <h1>
           Class <span class="m-thin">class</span>
+          <div class="m-dox-include m-code m-inverted m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
         </h1>
         <p>A class.</p>
         <div class="m-block m-default">
index ceaaf827c622269e9bbb1d3f3520aa9710ce24a4..f38065c38719d4ddac2bb3960ce2e5f0c528e207 100644 (file)
@@ -20,6 +20,7 @@
     <div class="m-row">
       <div class="m-col-l-10 m-push-l-1">
         <h1>
+          <div class="m-dox-include m-code m-inverted m-right-m m-text-right"><span class="cp">#include</span> <a class="cpf" href="File_8h.html">&lt;File.h&gt;</a></div>
           <div class="m-dox-template">template&lt;class T, class U = void, class = int&gt;</div>
           Template <span class="m-thin">struct</span>
         </h1>
index a2478f5f057905a6d257f1804cc105270a5549fc..6597ee3801599a62f1cec5eb619511c70fbe90a1 100644 (file)
@@ -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'))
index 36c33eb1d4ec2bba7520c8d8d820998654e10c2d..57825aff01246269a7f0cb1f99925327f51d64b7 100644 (file)
@@ -70,6 +70,7 @@ list using <span class="m-label m-dim">&darr;</span> and
             'OUTPUT_DIRECTORY': '',
             'PROJECT_BRIEF': 'is cool',
             'PROJECT_NAME': 'My Pet Project',
+            'SHOW_INCLUDE_FILES': True,
             'XML_OUTPUT': 'xml'
         })