chiark / gitweb /
doxygen: properly shown includes for relateds in different files.
authorVladimír Vondruš <mosra@centrum.cz>
Sat, 12 Jan 2019 16:11:14 +0000 (17:11 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Sat, 12 Jan 2019 16:16:59 +0000 (17:16 +0100)
doc/doxygen.rst
doxygen/dox2html5.py
doxygen/test/compound_includes/Second.h
doxygen/test/compound_includes/classClass.html
doxygen/test/compound_includes/namespaceSpread.html
doxygen/test/compound_includes_disabled/classClass.html
doxygen/test/compound_includes_disabled/namespaceSpread.html
doxygen/test/compound_includes_undocumented_files/Second.h

index 68ed008925fe3ff68d785ae5c1211897d4c2863c..08a896e7b60b6fec5f43b2d55de0c9fc8ae7fde3 100644 (file)
@@ -211,9 +211,8 @@ If you see something unexpected or not see something expected, check the
 -   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).
-    See `Include files`_ for more information.
+    provided also for namespaces, free and related functions, enums, typedefs
+    and variables. See `Include files`_ for more information.
 
 `Intentionally unsupported features`_
 -------------------------------------
@@ -721,6 +720,9 @@ typedefs, variables and :cpp:`#define`\ s. The rules are:
 -   Files don't show any include information, as it is known implicitly
 -   In case of modules (grouped using ``@defgroup``), the :cpp:`#include` info
     is always shown locally for each member. This includes also :cpp:`#define`\ s.
+-   In case of enums, typedefs, variables, functions and defines ``@related``
+    to some class, these also have the :cpp:`#include` shown in case it's
+    different from the class :cpp:`include`.
 
 This feature is enabled by default, disable :ini:`SHOW_INCLUDE_FILES` to hide
 all :cpp:`#include`-related information:
index 733c212ef1d1d0eeec49c83515a8d008d0586972..2084b14cff475f5064bf698e4220218660f80c9d 100755 (executable)
@@ -466,7 +466,7 @@ def make_include(state: State, file) -> Tuple[str, str]:
         return (html.escape('<{}>'.format(file)), state.compounds[state.includes[file]].url)
     return None
 
-def parse_id_and_include(state: State, element: ET.Element) -> Tuple[str, str, str, Tuple[str, str]]:
+def parse_id_and_include(state: State, element: ET.Element) -> Tuple[str, str, str, Tuple[str, str], bool]:
     # 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
@@ -476,6 +476,7 @@ def parse_id_and_include(state: State, element: ET.Element) -> Tuple[str, str, s
     # Extract the corresponding include, if the current compound is a namespace
     # or a module
     include = None
+    has_details = False
     if state.current_kind in ['namespace', 'group']:
         location_attribs = element.find('location').attrib
         file = location_attribs['declfile'] if 'declfile' in location_attribs else location_attribs['file']
@@ -498,7 +499,18 @@ def parse_id_and_include(state: State, element: ET.Element) -> Tuple[str, str, s
         elif state.current_include and state.current_include != file:
             state.current_include = None
 
-    return id[:i], id[:i] + '.html', id[i+2:], include
+    # Extract corresponding include also for class/struct/union "relateds", if
+    # it's different from what the class has. This also forcibly enables
+    # has_details (unlike the case above, where has_details will be enabled
+    # only if all members don't have the same include)
+    if state.current_kind in ['class', 'struct', 'union']:
+        location_attribs = element.find('location').attrib
+        file = location_attribs['declfile'] if 'declfile' in location_attribs else location_attribs['file']
+        if state.current_include != file:
+            include = make_include(state, file)
+            has_details = True
+
+    return id[:i], id[:i] + '.html', id[i+2:], include, has_details
 
 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
@@ -1667,7 +1679,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, enum.include = parse_id_and_include(state, element)
+    state.current_definition_url_base, enum.base_url, enum.id, enum.include, enum.has_details = 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)'
@@ -1705,7 +1717,8 @@ def parse_enum(state: State, element: ET.Element):
                 state.search += [result]
         enum.values += [value]
 
-    enum.has_details = enum.base_url == state.current_compound_url and (enum.description or enum.has_value_details)
+    if enum.base_url == state.current_compound_url and (enum.description or enum.has_value_details):
+        enum.has_details = True # has_details might already be True from above
     if enum.brief or enum.has_details or enum.has_value_details:
         if enum.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
@@ -1769,7 +1782,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, typedef.include = parse_id_and_include(state, element)
+    state.current_definition_url_base, typedef.base_url, typedef.id, typedef.include, typedef.has_details = 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'))
@@ -1779,7 +1792,8 @@ def parse_typedef(state: State, element: ET.Element):
     typedef.is_protected = element.attrib['prot'] == 'protected'
     typedef.has_template_details, typedef.templates = parse_template_params(state, element.find('templateparamlist'), templates)
 
-    typedef.has_details = typedef.base_url == state.current_compound_url and (typedef.description or typedef.has_template_details)
+    if typedef.base_url == state.current_compound_url and (typedef.description or typedef.has_template_details):
+        typedef.has_details = True # has_details might already be True from above
     if typedef.brief or typedef.has_details:
         # Avoid duplicates in search
         if typedef.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']:
@@ -1797,7 +1811,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, func.include = parse_id_and_include(state, element)
+    state.current_definition_url_base, func.base_url, func.id, func.include, func.has_details = 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'))
@@ -1915,7 +1929,8 @@ def parse_func(state: State, element: ET.Element):
     # Some param description got unused
     if params: logging.warning("{}: function parameter description doesn't match parameter names: {}".format(state.current, repr(params)))
 
-    func.has_details = func.base_url == state.current_compound_url and (func.description or func.has_template_details or func.has_param_details or func.return_value or func.return_values or func.exceptions)
+    if func.base_url == state.current_compound_url and (func.description or func.has_template_details or func.has_param_details or func.return_value or func.return_values or func.exceptions):
+        func.has_details = True # has_details might already be True from above
     if func.brief or func.has_details:
         # Avoid duplicates in search
         if func.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']:
@@ -1935,7 +1950,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, var.include = parse_id_and_include(state, element)
+    state.current_definition_url_base, var.base_url, var.id, var.include, var.has_details = parse_id_and_include(state, element)
     var.type = parse_type(state, element.find('type'))
     if var.type.startswith('constexpr'):
         var.type = var.type[10:]
@@ -1950,7 +1965,8 @@ def parse_var(state: State, element: ET.Element):
     var.description, templates, search_keywords, var.is_deprecated = parse_var_desc(state, element)
     var.has_template_details, var.templates = parse_template_params(state, element.find('templateparamlist'), templates)
 
-    var.has_details = var.base_url == state.current_compound_url and (var.description or var.has_template_details)
+    if var.base_url == state.current_compound_url and (var.description or var.has_template_details):
+        var.has_details = True # has_details might already be True from above
     if var.brief or var.has_details:
         # Avoid duplicates in search
         if var.base_url == state.current_compound_url and not state.doxyfile['M_SEARCH_DISABLED']:
@@ -1972,7 +1988,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, define.include = parse_id_and_include(state, element)
+    state.current_definition_url_base, _, define.id, define.include, define.has_details = 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)
@@ -1993,7 +2009,8 @@ def parse_define(state: State, element: ET.Element):
     # Some param description got unused
     if params: logging.warning("{}: define parameter description doesn't match parameter names: {}".format(state.current, repr(params)))
 
-    define.has_details = define.description or define.return_value
+    if define.description or define.return_value:
+        define.has_details = True # has_details might already be True from above
     if define.brief or define.has_details:
         if not state.doxyfile['M_SEARCH_DISABLED']:
             result = Empty()
index 5f36640685fd9bed8306c02f2f7d860b701fd0ad..c833d45fb5cfb13bdd0bbfde808954f090e70a3c 100644 (file)
@@ -18,4 +18,29 @@ enum Flag {};
 
 /*@}*/
 
+/** @related Class
+ * @brief A related enum in a different file. Shouldn't be shown in namespace docs but it is :(
+ */
+enum RelatedEnum {};
+
+/** @related Class
+ * @brief A related typedef in a different file
+ */
+typedef int RelatedInt;
+
+/** @related Class
+ * @brief A related variable in a different file
+ */
+constexpr const int RelatedVar = 3;
+
+/** @related Class
+ * @brief A related function in a different file
+ */
+void relatedFunc();
+
+/** @related Class
+ * @brief A related define in a different file
+ */
+#define RELATED_DEFINE
+
 }
index 6df71c72ab0475fa752bda7a05c9856736108f81..16de8ae1f8bcf38335fe3f0e2ee3294b97fd03ba 100644 (file)
@@ -31,6 +31,7 @@
               Reference
               <ul>
                 <li><a href="#pub-methods">Public functions</a></li>
+                <li><a href="#related">Related</a></li>
               </ul>
             </li>
           </ul>
             <dd>No include information for this one (and thus no details)</dd>
           </dl>
         </section>
+        <section id="related">
+          <h2><a href="#related">Related</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#ab66c81fc768958c4185a517d488a89c7" class="m-dox">RelatedEnum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</dd>
+            <dt>
+              using <a href="#aca8f196c01494bf1dab261745f3693c8" class="m-dox">RelatedInt</a> = int
+            </dt>
+            <dd>A related typedef in a different file.</dd>
+            <dt>
+              const int <a href="#a15e320413819ae46dffcbccbbb542b8c" class="m-dox">RelatedVar</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A related variable in a different file.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a8b69414d6ef13f920d3a855bd22362fb" class="m-dox">relatedFunc</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A related function in a different file.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">#define <a href="#a8887c0b6a87e2438ea90ffe476680da1" class="m-dox">RELATED_DEFINE</a></span>
+            </dt>
+            <dd>A related define in a different file.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Enum documentation</h2>
+          <section class="m-dox-details" id="ab66c81fc768958c4185a517d488a89c7"><div>
+            <h3>
+              enum <a href="#ab66c81fc768958c4185a517d488a89c7" class="m-dox-self">RelatedEnum</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>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Typedef documentation</h2>
+          <section class="m-dox-details" id="aca8f196c01494bf1dab261745f3693c8"><div>
+            <h3>
+              typedef int <a href="#aca8f196c01494bf1dab261745f3693c8" class="m-dox-self">RelatedInt</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>A related typedef in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="a8b69414d6ef13f920d3a855bd22362fb"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void </span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a8b69414d6ef13f920d3a855bd22362fb" class="m-dox-self">relatedFunc</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 related function in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Variable documentation</h2>
+          <section class="m-dox-details" id="a15e320413819ae46dffcbccbbb542b8c"><div>
+            <h3>
+              const int <a href="#a15e320413819ae46dffcbccbbb542b8c" class="m-dox-self">RelatedVar</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="Second_8h.html">&lt;Second.h&gt;</a></div>
+            </h3>
+            <p>A related variable in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Define documentation</h2>
+          <section class="m-dox-details" id="a8887c0b6a87e2438ea90ffe476680da1"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">#define <a href="#a8887c0b6a87e2438ea90ffe476680da1" class="m-dox-self">RELATED_DEFINE</a></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 related define in a different file.</p>
+          </div></section>
+        </section>
       </div>
     </div>
   </div>
index 9952561a74615d186cd38637cd43ac3ed75b32bc..5ff098c5875f4619f5e93f31820bafcb3135a677 100644 (file)
               <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>
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="classClass.html#ab66c81fc768958c4185a517d488a89c7" class="m-dox">RelatedEnum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</dd>
           </dl>
         </section>
         <section id="typedef-members">
             </h3>
             <p>An enum.</p>
           </div></section>
+          <section class="m-dox-details" id="ab66c81fc768958c4185a517d488a89c7"><div>
+            <h3>
+              enum Spread::<wbr /><a href="#ab66c81fc768958c4185a517d488a89c7" class="m-dox-self">RelatedEnum</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>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</p>
+          </div></section>
           <section class="m-dox-details" id="aa29ea9c4e31c7d0408e7c5abddb50cd3"><div>
             <h3>
               enum Spread::<wbr /><a href="#aa29ea9c4e31c7d0408e7c5abddb50cd3" class="m-dox-self">Flag</a>
index ff36bbb6df3aad469e57085f7b2cad24ea64ef81..9c1c9374ef4e57bafb3a2a23d6a0bfcf11be4bd7 100644 (file)
@@ -30,6 +30,7 @@
               Reference
               <ul>
                 <li><a href="#pub-methods">Public functions</a></li>
+                <li><a href="#related">Related</a></li>
               </ul>
             </li>
           </ul>
             <dd>No include information for this one (and thus no details)</dd>
           </dl>
         </section>
+        <section id="related">
+          <h2><a href="#related">Related</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="#ab66c81fc768958c4185a517d488a89c7" class="m-dox">RelatedEnum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</dd>
+            <dt>
+              using <a href="#aca8f196c01494bf1dab261745f3693c8" class="m-dox">RelatedInt</a> = int
+            </dt>
+            <dd>A related typedef in a different file.</dd>
+            <dt>
+              const int <a href="#a15e320413819ae46dffcbccbbb542b8c" class="m-dox">RelatedVar</a> <span class="m-label m-flat m-primary">constexpr</span>
+            </dt>
+            <dd>A related variable in a different file.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a8b69414d6ef13f920d3a855bd22362fb" class="m-dox">relatedFunc</a>(</span><span class="m-dox-wrap">)</span>
+            </dt>
+            <dd>A related function in a different file.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">#define <a href="#a8887c0b6a87e2438ea90ffe476680da1" class="m-dox">RELATED_DEFINE</a></span>
+            </dt>
+            <dd>A related define in a different file.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Enum documentation</h2>
+          <section class="m-dox-details" id="ab66c81fc768958c4185a517d488a89c7"><div>
+            <h3>
+              enum <a href="#ab66c81fc768958c4185a517d488a89c7" class="m-dox-self">RelatedEnum</a>
+            </h3>
+            <p>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Typedef documentation</h2>
+          <section class="m-dox-details" id="aca8f196c01494bf1dab261745f3693c8"><div>
+            <h3>
+              typedef int <a href="#aca8f196c01494bf1dab261745f3693c8" class="m-dox-self">RelatedInt</a>
+            </h3>
+            <p>A related typedef in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="a8b69414d6ef13f920d3a855bd22362fb"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void </span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a8b69414d6ef13f920d3a855bd22362fb" class="m-dox-self">relatedFunc</a>(</span><span class="m-dox-wrap">)</span></span>
+            </h3>
+            <p>A related function in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Variable documentation</h2>
+          <section class="m-dox-details" id="a15e320413819ae46dffcbccbbb542b8c"><div>
+            <h3>
+              const int <a href="#a15e320413819ae46dffcbccbbb542b8c" class="m-dox-self">RelatedVar</a> <span class="m-label m-primary">constexpr</span>
+            </h3>
+            <p>A related variable in a different file.</p>
+          </div></section>
+        </section>
+        <section>
+          <h2>Define documentation</h2>
+          <section class="m-dox-details" id="a8887c0b6a87e2438ea90ffe476680da1"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">#define <a href="#a8887c0b6a87e2438ea90ffe476680da1" class="m-dox-self">RELATED_DEFINE</a></span>
+            </h3>
+            <p>A related define in a different file.</p>
+          </div></section>
+        </section>
       </div>
     </div>
   </div>
index 5201662159fde4c144ed142db17e2720310dcd7f..4099b5fad7342e5444f6b18a8dc776154021041e 100644 (file)
               <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>
+            <dt>
+              <span class="m-dox-wrap-bumper">enum <a href="classClass.html#ab66c81fc768958c4185a517d488a89c7" class="m-dox">RelatedEnum</a> { </span><span class="m-dox-wrap"> }</span>
+            </dt>
+            <dd>A related enum in a different file. Shouldn&#x27;t be shown in namespace docs but it is :(.</dd>
           </dl>
         </section>
         <section id="typedef-members">
index 58738cdba2a272864078ddc44eb2da74edd63f28..3b54153893dbab0f821108390867149f67d0353f 100644 (file)
@@ -17,4 +17,29 @@ enum Flag {};
 
 /*@}*/
 
+/** @related Class
+ * @brief A related enum in a different file. Shouldn't be shown in namespace docs but it is :(
+ */
+enum RelatedEnum {};
+
+/** @related Class
+ * @brief A related typedef in a different file
+ */
+typedef int RelatedInt;
+
+/** @related Class
+ * @brief A related variable in a different file
+ */
+constexpr const int RelatedVar = 3;
+
+/** @related Class
+ * @brief A related function in a different file
+ */
+void relatedFunc();
+
+/** @related Class
+ * @brief A related define in a different file
+ */
+#define RELATED_DEFINE
+
 }