chiark / gitweb /
doxygen: parse override, final and conditional noexcept keywords.
authorVladimír Vondruš <mosra@centrum.cz>
Tue, 1 Jan 2019 18:15:18 +0000 (19:15 +0100)
committerVladimír Vondruš <mosra@centrum.cz>
Wed, 2 Jan 2019 21:07:11 +0000 (22:07 +0100)
 * override and final is now parsed from function signatures, in the
   theme the [virtual] label gets replaced with either [override] or
   [final], since it doesn't make sense to include both [virtual] and
   [override]/[final] label as the former is implicit for the latter.
 * fixed order of parsing function signature keywords so function
   signatures that are both deleted/defaulted and noexcept are parsed
   correctly instead of noexcept being ignored
 * conditional noexcept is now recognized as well, shown in the theme as
   [noexcept(...)]
 * [final] class specifier is now shown in the class header and also in
   the derived class list
 * [virtual] label is now shown for both virtual base class and
   virtually derived classes to make it symmetric

17 files changed:
doc/doxygen.rst
doxygen/dox2html5.py
doxygen/templates/base-class-reference.html
doxygen/templates/details-func.html
doxygen/templates/entry-class.html
doxygen/templates/entry-func.html
doxygen/test/cpp_derived/classNamespace_1_1A.html
doxygen/test/cpp_derived/classNamespace_1_1VirtualBase.html
doxygen/test/cpp_derived/input.h
doxygen/test/cpp_derived/structAnother_1_1Final.html [new file with mode: 0644]
doxygen/test/cpp_function_attributes/Doxyfile [new file with mode: 0644]
doxygen/test/cpp_function_attributes/classBase.html [new file with mode: 0644]
doxygen/test/cpp_function_attributes/classDerived.html [new file with mode: 0644]
doxygen/test/cpp_function_attributes/input.h [new file with mode: 0644]
doxygen/test/cpp_function_attributes/structFinal.html [new file with mode: 0644]
doxygen/test/cpp_function_attributes/structFoo.html [new file with mode: 0644]
doxygen/test/test_cpp.py

index 3ea8d5a7c7cf75a3620b24ac77383db1a71c2d27..b04faee7b1e3496bc70c78093a0890c0ba7b8e6c 100644 (file)
@@ -1396,6 +1396,8 @@ Property                                Description
 :py:`compound.footer_navigation`        Footer navigation of a page. See
                                         `Navigation properties`_ for details.
 :py:`compound.brief`                    Brief description. Can be empty. [1]_
+:py:`compound.is_final`                 Whether the class is :cpp:`final`. Set
+                                        only for classes.
 :py:`compound.is_deprecated`            Whether the compound is deprecated. [7]_
 :py:`compound.description`              Detailed description. Can be empty. [2]_
 :py:`compound.modules`                  List of submodules in this compound.
@@ -1636,8 +1638,11 @@ Property                    Description
 :py:`class.is_deprecated`   Whether the class is deprecated. [7]_
 :py:`class.is_protected`    Whether this is a protected base class. Set only
                             for base classes.
-:py:`class.is_virtual`      Whether this is a virtual base class. Set only for
-                            base classes.
+:py:`class.is_virtual`      Whether this is a virtual base class or a
+                            virtually derived class. Set only for base /
+                            derived classes.
+:py:`class.is_final`        Whether this is a final derived class. Set only for
+                            derived classes.
 =========================== ===================================================
 
 `Enum properties`_
@@ -1743,65 +1748,75 @@ a list of functions, where every item has the following properties:
 
 .. class:: m-table m-fullwidth
 
-=============================== ===============================================
-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]_
-:py:`func.templates`            Template specification. See
-                                `Template properties`_ for details.
-:py:`func.has_template_details` If template parameters have description
-:py:`func.params`               List of function parameters. See below for
-                                details.
-:py:`func.has_param_details`    If function parameters have description
-:py:`func.return_value`         Return value description. Can be empty.
-:py:`func.return_values`        Description of particular return values. See
-                                below for details.
-:py:`func.exceptions`           Description of particular exception types. See
-                                below for details.
-:py:`func.brief`                Brief description. Can be empty. [1]_
-:py:`func.description`          Detailed description. Can be empty. [2]_
-:py:`func.has_details`          If there is enough content for the full
-                                description block [5]_
-:py:`func.prefix`               Function signature prefix, containing keywords
-                                such as :cpp:`static`. Information about
-                                :cpp:`constexpr`\ ness, :cpp:`explicit`\ ness
-                                and :cpp:`virtual`\ ity is removed from the
-                                prefix and available via other properties.
-:py:`func.suffix`               Function signature suffix, containing keywords
-                                such as :cpp:`const` and r-value overloads.
-                                Information about :cpp:`noexcept`, pure
-                                :cpp:`virtual`\ ity and :cpp:`delete`\ d /
-                                :cpp:`default`\ ed functions is removed from
-                                the suffix and available via other properties.
-:py:`func.is_deprecated`        Whether the function is deprecated. [7]_
-:py:`func.is_protected`         If the function is :cpp:`protected`. Set only
-                                for member functions.
-:py:`func.is_private`           If the function is :cpp:`private`. Set only for
-                                member functions.
-:py:`func.is_explicit`          If the function is :cpp:`explicit`. Set only
-                                for member functions.
-:py:`func.is_virtual`           If the function is :cpp:`virtual`. Set only for
-                                member functions.
-:py:`func.is_pure_virtual`      If the function is pure :cpp:`virtual`. Set
-                                only for member functions.
-:py:`func.is_noexcept`          If the function is :cpp:`noexcept`
-:py:`func.is_constexpr`         If the function is :cpp:`constexpr`
-:py:`func.is_defaulted`         If the function is :cpp:`default`\ ed
-:py:`func.is_deleted`           If the function is :cpp:`delete`\ d
-:py:`func.is_signal`            If the function is a Qt signal. Set only for
-                                member functions.
-:py:`func.is_slot`              If the function is a Qt slot. Set only for
-                                member functions.
-=============================== ===============================================
+=================================== ===========================================
+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]_
+:py:`func.templates`                Template specification. See
+                                    `Template properties`_ for details.
+:py:`func.has_template_details`     If template parameters have description
+:py:`func.params`                   List of function parameters. See below for
+                                    details.
+:py:`func.has_param_details`        If function parameters have description
+:py:`func.return_value`             Return value description. Can be empty.
+:py:`func.return_values`            Description of particular return values.
+                                    See below for details.
+:py:`func.exceptions`               Description of particular exception types.
+                                    See below for details.
+:py:`func.brief`                    Brief description. Can be empty. [1]_
+:py:`func.description`              Detailed description. Can be empty. [2]_
+:py:`func.has_details`              If there is enough content for the full
+                                    description block [5]_
+:py:`func.prefix`                   Function signature prefix, containing
+                                    keywords such as :cpp:`static`. Information
+                                    about :cpp:`constexpr`\ ness,
+                                    :cpp:`explicit`\ ness and
+                                    :cpp:`virtual`\ ity is removed from the
+                                    prefix and available via other properties.
+:py:`func.suffix`                   Function signature suffix, containing
+                                    keywords such as :cpp:`const` and r-value
+                                    overloads. Information about
+                                    :cpp:`noexcept`, pure :cpp:`virtual`\ ity
+                                    and :cpp:`delete`\ d / :cpp:`default`\ ed
+                                    functions is removed from the suffix and
+                                    available via other properties.
+:py:`func.is_deprecated`            Whether the function is deprecated. [7]_
+:py:`func.is_protected`             If the function is :cpp:`protected`. Set
+                                    only for member functions.
+:py:`func.is_private`               If the function is :cpp:`private`. Set only
+                                    for member functions.
+:py:`func.is_explicit`              If the function is :cpp:`explicit`. Set
+                                    only for member functions.
+:py:`func.is_virtual`               If the function is :cpp:`virtual` (or pure
+                                    virtual). Set only for member functions.
+:py:`func.is_pure_virtual`          If the function is pure :cpp:`virtual`. Set
+                                    only for member functions.
+:py:`func.is_override`              If the function is an :cpp:`override`. Set
+                                    only for member functions.
+:py:`func.is_final`                 If the function is a :cpp:`final override`.
+                                    Set only for member functions.
+:py:`func.is_noexcept`              If the function is :cpp:`noexcept` (even
+                                    conditionally)
+:py:`func.is_conditional_noexcept`  If the function is conditionally
+                                    :cpp:`noexcept`.
+:py:`func.is_constexpr`             If the function is :cpp:`constexpr`
+:py:`func.is_defaulted`             If the function is :cpp:`default`\ ed
+:py:`func.is_deleted`               If the function is :cpp:`delete`\ d
+:py:`func.is_signal`                If the function is a Qt signal. Set only
+                                    for member functions.
+:py:`func.is_slot`                  If the function is a Qt slot. Set only for
+                                    member functions.
+=================================== ===========================================
 
 The :py:`func.params` is a list of function parameters and their description.
 Each item has the following properties:
index 9a17afa1e38229c395786c5527a718753214fc0a..7f6460c8c6024580a6c1167304aee07fc96a48b3 100755 (executable)
@@ -354,6 +354,8 @@ class StateCompound:
         self.url: str
         self.brief: str
         self.has_details: bool
+        self.is_deprecated: bool
+        self.is_final: bool = None
         self.children: List[str]
         self.parent: str = None
 
@@ -1790,12 +1792,9 @@ def parse_func(state: State, element: ET.Element):
     func.is_virtual = element.attrib['virt'] != 'non-virtual'
     if element.attrib['static'] == 'yes':
         func.prefix += 'static '
-    signature = element.find('argsstring').text
-    if signature.endswith(' noexcept'):
-        signature = signature[:-9]
-        func.is_noexcept = True
-    else:
-        func.is_noexcept = False
+    # Extract additional C++11 stuff from the signature. Order matters, going
+    # from the keywords that can be rightmost to the leftmost.
+    signature: str = element.find('argsstring').text
     if signature.endswith('=default'):
         signature = signature[:-8]
         func.is_defaulted = True
@@ -1811,6 +1810,32 @@ def parse_func(state: State, element: ET.Element):
         func.is_pure_virtual = True
     else:
         func.is_pure_virtual = False
+    # Final tested twice because it can be both `override final`
+    func.is_final = False
+    if signature.endswith(' final'):
+        signature = signature[:-6]
+        func.is_final = True
+    if signature.endswith(' override'):
+        signature = signature[:-9]
+        func.is_override = True
+    else:
+        func.is_override = False
+    # ... and `final override`
+    if signature.endswith(' final'):
+        signature = signature[:-6]
+        func.is_final = True
+    if signature.endswith(' noexcept'):
+        signature = signature[:-9]
+        func.is_noexcept = True
+        func.is_conditional_noexcept = False
+    elif ' noexcept(' in signature:
+        signature = signature[:signature.index(' noexcept(')]
+        func.is_noexcept = True
+        func.is_conditional_noexcept = True
+    else:
+        func.is_noexcept = False
+        func.is_conditional_noexcept = False
+    # Put the rest (const, volatile, ...) into a suffix
     func.suffix = html.escape(signature[signature.rindex(')') + 1:].strip())
     if func.suffix: func.suffix = ' ' + func.suffix
     # Protected / private makes no sense for friend functions
@@ -1995,6 +2020,7 @@ def extract_metadata(state: State, xml):
     compound.has_details = compound.kind in ['group', 'page'] or compound.brief or compounddef.find('detaileddescription')
     compound.children = []
 
+    # Deprecation status
     compound.is_deprecated = False
     for i in compounddef.find('detaileddescription').findall('.//xrefsect'):
         id = i.attrib['id']
@@ -2004,6 +2030,12 @@ def extract_metadata(state: State, xml):
             compound.is_deprecated = True
             break
 
+    # Final classes
+    if compound.kind in ['struct', 'class', 'union'] and compounddef.attrib.get('final') == 'yes':
+        compound.is_final = True
+    else:
+        compound.is_final = False
+
     if compound.kind in ['class', 'struct', 'union']:
         # Fix type spacing
         compound.name = fix_type_spacing(compound.name)
@@ -2360,6 +2392,12 @@ def parse_xml(state: State, xml: str):
     else:
         state.current_prefix = []
 
+    # Final classes
+    if compound.kind in ['struct', 'class', 'union'] and compounddef.attrib.get('final') == 'yes':
+        compound.is_final = True
+    else:
+        compound.is_final = False
+
     # Decide about the include file for this compound. Classes get it always,
     # namespaces without any members too.
     state.current_kind = compound.kind
@@ -2537,6 +2575,8 @@ def parse_xml(state: State, xml: str):
                     class_.brief = symbol.brief
                     class_.templates = symbol.templates
                     class_.is_deprecated = symbol.is_deprecated
+                    class_.is_virtual = compounddef_child.attrib['virt'] == 'virtual'
+                    class_.is_final = symbol.is_final
 
                     compound.derived_classes += [class_]
 
index 0515dbb0ef09d03559a3073903dbc3c1161989eb..67f6aefba2f1baf4cb77bc1c87c847da50643d1b 100644 (file)
@@ -24,7 +24,9 @@
           {% 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>
+          {%+ 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.is_final %} <span class="m-label m-flat m-warning">final</span>{% endif %}
+          {# need an explicit space here otherwise the newline gets removed #}
+
           {% 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 %}
index 43e11f3dfadd5aa6bc52f4ddc90c051e5f7dfe75..3e633f594b4c0123cc4d7a578a28bcbcd9c0d0b3 100644 (file)
@@ -16,7 +16,7 @@
               </div>
               {% 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>
+              <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_final %} <span class="m-label m-warning">final</span>{% elif func.is_override %} <span class="m-label m-warning">override</span>{% elif 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_conditional_noexcept %} <span class="m-label m-success">noexcept(…)</span>{% elif 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 %}
index 0cb8dee07e0ab10333c6eec25ed0617e6d023144..5b4daed5c8ededd30c87b9884079577a03ec53b8 100644 (file)
@@ -3,7 +3,7 @@
               {% set j = joiner(', ') %}
               <div class="m-dox-template">template&lt;{% for t in class.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}&gt;</div>
               {% endif %}
-              {{ class.kind }} <a href="{{ class.url }}" class="m-dox">{{ class.name }}</a>{% if class.is_deprecated %} <span class="m-label m-danger">deprecated</span>{% endif %}{% if class.is_protected %} <span class="m-label m-flat m-warning">protected</span>{% endif %}{% if class.is_virtual %} <span class="m-label m-flat m-warning">virtual</span>{% endif %}
+              {{ class.kind }} <a href="{{ class.url }}" class="m-dox">{{ class.name }}</a>{% if class.is_deprecated %} <span class="m-label m-danger">deprecated</span>{% endif %}{% if class.is_protected %} <span class="m-label m-flat m-warning">protected</span>{% endif %}{% if class.is_final %} <span class="m-label m-flat m-warning">final</span>{% elif class.is_virtual %} <span class="m-label m-flat m-warning">virtual</span>{% endif %}
 
               {# the empty line is above to fix spacing #}
             </dt>
index 66e03b7f1c31300d1049f716956d03c2be13570b..b2d6fceef3189e8072bbc2855a278398a04edc73 100644 (file)
@@ -4,6 +4,6 @@
               <div class="m-dox-template">template&lt;{% for t in func.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}&gt;</div>
               {% endif %}
               {% set j = joiner(',\n              ') %}
-              <span class="m-dox-wrap-bumper">{{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}<a href="{% if func.base_url != compound.url %}{{ func.base_url }}{% endif %}#{{ func.id }}" {% if func.has_details or func.base_url != compound.url %}class="m-dox"{% else %}class="m-dox-self" name="{{ func.id }}"{% endif %}>{{ 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.type and func.type != 'void' %} -&gt; {{ func.type }}{% endif %}{% if func.is_deprecated %} <span class="m-label m-danger">deprecated</span>{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} <span class="m-label m-flat m-warning">protected{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_private %} <span class="m-label m-flat m-danger">private{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_signal %} <span class="m-label m-flat m-success">signal</span>{% elif func.is_slot %} <span class="m-label m-flat m-success">public slot</span>{% endif %}{% endif %}{% if func.is_defaulted %} <span class="m-label m-flat m-info">defaulted</span>{% endif %}{% if func.is_deleted %} <span class="m-label m-flat m-danger">deleted</span>{% endif %}{% if func.is_explicit %} <span class="m-label m-flat m-info">explicit</span> {% endif %}{% if func.is_pure_virtual %} <span class="m-label m-flat m-warning">pure virtual</span>{% elif func.is_virtual %} <span class="m-label m-flat m-warning">virtual</span>{% endif %}{% if func.is_constexpr %} <span class="m-label m-flat m-primary">constexpr</span>{% endif %}{% if func.is_noexcept %} <span class="m-label m-flat m-success">noexcept</span>{% endif %}</span>
+              <span class="m-dox-wrap-bumper">{{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}<a href="{% if func.base_url != compound.url %}{{ func.base_url }}{% endif %}#{{ func.id }}" {% if func.has_details or func.base_url != compound.url %}class="m-dox"{% else %}class="m-dox-self" name="{{ func.id }}"{% endif %}>{{ 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.type and func.type != 'void' %} -&gt; {{ func.type }}{% endif %}{% if func.is_deprecated %} <span class="m-label m-danger">deprecated</span>{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} <span class="m-label m-flat m-warning">protected{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_private %} <span class="m-label m-flat m-danger">private{% if func.is_slot %} slot{% endif %}</span>{% elif func.is_signal %} <span class="m-label m-flat m-success">signal</span>{% elif func.is_slot %} <span class="m-label m-flat m-success">public slot</span>{% endif %}{% endif %}{% if func.is_defaulted %} <span class="m-label m-flat m-info">defaulted</span>{% endif %}{% if func.is_deleted %} <span class="m-label m-flat m-danger">deleted</span>{% endif %}{% if func.is_explicit %} <span class="m-label m-flat m-info">explicit</span> {% endif %}{% if func.is_final %} <span class="m-label m-flat m-warning">final</span>{% elif func.is_override %} <span class="m-label m-flat m-warning">override</span>{% elif func.is_pure_virtual %} <span class="m-label m-flat m-warning">pure virtual</span>{% elif func.is_virtual %} <span class="m-label m-flat m-warning">virtual</span>{% endif %}{% if func.is_constexpr %} <span class="m-label m-flat m-primary">constexpr</span>{% endif %}{% if func.is_conditional_noexcept %} <span class="m-label m-flat m-success">noexcept(…)</span>{% elif func.is_noexcept %} <span class="m-label m-flat m-success">noexcept</span>{% endif %}</span>
             </dt>
             <dd>{{ func.brief }}</dd>
index a8cc7a500073ae58143cf223ebea538105b09f1a..916c42a82a4c03fa8e4e98e422a8215fa89fdb79 100644 (file)
               class <a href="classAnother_1_1Derived.html" class="m-dox">Another::Derived</a>
             </dt>
             <dd>A derived class.</dd>
+            <dt>
+              struct <a href="structAnother_1_1Final.html" class="m-dox">Another::Final</a> <span class="m-label m-flat m-warning">final</span>
+            </dt>
+            <dd>A final derived class.</dd>
           </dl>
         </section>
       </div>
index ab7333c08f079d291304fa6b838f1a91d1eb826d..b729787d38430c370cdc334b6f8296f297bcd4d4 100644 (file)
@@ -27,7 +27,7 @@
           <h2><a href="#derived-classes">Derived classes</a></h2>
           <dl class="m-dox">
             <dt>
-              class <a href="classNamespace_1_1A.html" class="m-dox">A</a>
+              class <a href="classNamespace_1_1A.html" class="m-dox">A</a> <span class="m-label m-flat m-warning">virtual</span>
             </dt>
             <dd>A class.</dd>
           </dl>
index 2800095bb5e3d4ef39cb77b6b705f9b3a1dcb09b..66795a20981484b223111cdcb4a9aded94d0cef6 100644 (file)
@@ -34,6 +34,9 @@ namespace Another {
 /** @brief A derived class */
 class Derived: public Namespace::A {};
 
+/** @brief A final derived class */
+struct Final final: Namespace::A {};
+
 }
 
 namespace Namespace {
diff --git a/doxygen/test/cpp_derived/structAnother_1_1Final.html b/doxygen/test/cpp_derived/structAnother_1_1Final.html
new file mode 100644 (file)
index 0000000..ccf4319
--- /dev/null
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Another::Final 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>
+          <span class="m-breadcrumb"><a href="namespaceAnother.html">Another</a>::<wbr/></span>Final <span class="m-thin">struct</span> <span class="m-label m-flat m-warning">final</span>
+        </h1>
+        <p>A final derived class.</p>
+        <section id="base-classes">
+          <h2><a href="#base-classes">Base classes</a></h2>
+          <dl class="m-dox">
+            <dt>
+              class <a href="classNamespace_1_1A.html" class="m-dox">Namespace::A</a>
+            </dt>
+            <dd>A class.</dd>
+          </dl>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/cpp_function_attributes/Doxyfile b/doxygen/test/cpp_function_attributes/Doxyfile
new file mode 100644 (file)
index 0000000..2186bfc
--- /dev/null
@@ -0,0 +1,18 @@
+INPUT                   = input.h
+AUTOLINK_SUPPORT        = NO
+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
+
+# EXTRACT_PRIVATE         = YES
+INHERIT_DOCS           = NO
+EXTRACT_PRIVATE_VIRTUAL = YES
diff --git a/doxygen/test/cpp_function_attributes/classBase.html b/doxygen/test/cpp_function_attributes/classBase.html
new file mode 100644 (file)
index 0000000..d5ed8a9
--- /dev/null
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Base 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>
+          Base <span class="m-thin">class</span>
+        </h1>
+        <p>Base class.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#derived-classes">Derived classes</a></li>
+                <li><a href="#pub-methods">Public functions</a></li>
+                <li><a href="#pri-methods">Private functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="derived-classes">
+          <h2><a href="#derived-classes">Derived classes</a></h2>
+          <dl class="m-dox">
+            <dt>
+              class <a href="classDerived.html" class="m-dox">Derived</a>
+            </dt>
+            <dd>A derived class.</dd>
+            <dt>
+              struct <a href="structFinal.html" class="m-dox">Final</a> <span class="m-label m-flat m-warning">final</span>
+            </dt>
+            <dd>Various uses of final keywords.</dd>
+          </dl>
+        </section>
+        <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="#a72db7eaef78cfaff4fa4e93ebc53cb91" class="m-dox-self" name="a72db7eaef78cfaff4fa4e93ebc53cb91">doThing</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-flat m-warning">virtual</span> <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Do a thing with crazy attribs.</dd>
+          </dl>
+        </section>
+        <section id="pri-methods">
+          <h2><a href="#pri-methods">Private functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a116c39e85dca0cccea0c3ee107fb05c8" class="m-dox-self" name="a116c39e85dca0cccea0c3ee107fb05c8">doAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-flat m-warning">virtual</span></span>
+            </dt>
+            <dd>Do another thing, privately.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a29dff0e36707edf152f50836c52be808" class="m-dox">doYetAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-flat m-warning">virtual</span></span>
+            </dt>
+            <dd>Do yet another thing, privately.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="a29dff0e36707edf152f50836c52be808"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Base::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a29dff0e36707edf152f50836c52be808" class="m-dox-self">doYetAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-warning">virtual</span> <span class="m-label m-danger">private</span></span></span>
+            </h3>
+            <p>Do yet another thing, privately.</p>
+<p>The override will get hidden because <code>INHERIT_DOCS</code> is disabled.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/cpp_function_attributes/classDerived.html b/doxygen/test/cpp_function_attributes/classDerived.html
new file mode 100644 (file)
index 0000000..f8332b6
--- /dev/null
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Derived 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>
+          Derived <span class="m-thin">class</span>
+        </h1>
+        <p>A derived class.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#base-classes">Base classes</a></li>
+                <li><a href="#pro-methods">Protected functions</a></li>
+                <li><a href="#pri-methods">Private functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="base-classes">
+          <h2><a href="#base-classes">Base classes</a></h2>
+          <dl class="m-dox">
+            <dt>
+              class <a href="classBase.html" class="m-dox">Base</a>
+            </dt>
+            <dd>Base class.</dd>
+          </dl>
+        </section>
+        <section id="pro-methods">
+          <h2><a href="#pro-methods">Protected functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a0b1e72ba2c219253091525588d75fdd4" class="m-dox-self" name="a0b1e72ba2c219253091525588d75fdd4">doThing</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-flat m-warning">override</span> <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Do a thing, overriden, now protected.</dd>
+          </dl>
+        </section>
+        <section id="pri-methods">
+          <h2><a href="#pri-methods">Private functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a24c3acc5291d5f82f2a4432c88a730f8" class="m-dox">doAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-flat m-warning">override</span></span>
+            </dt>
+            <dd>Do another thing, privately, with different docs.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="a24c3acc5291d5f82f2a4432c88a730f8"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Derived::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a24c3acc5291d5f82f2a4432c88a730f8" class="m-dox-self">doAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-warning">override</span> <span class="m-label m-danger">private</span></span></span>
+            </h3>
+            <p>Do another thing, privately, with different docs.</p>
+<p>Documented, so not hidden.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/cpp_function_attributes/input.h b/doxygen/test/cpp_function_attributes/input.h
new file mode 100644 (file)
index 0000000..2d97756
--- /dev/null
@@ -0,0 +1,98 @@
+#include <type_traits>
+
+/** @brief Pathological cases of noexcept */
+struct Foo {
+    /**
+     * @brief Combined default and noexcept
+     *
+     * Details.
+     */
+    Foo(Foo&&) noexcept = default;
+
+    /**
+     * @brief Conditional noexcept
+     *
+     * Details.
+     */
+    Foo(const Foo&) noexcept(std::is_nothrow_copy_constructible<Foo>::value);
+
+    /**
+     * @brief Combined conditional noexcept and delete
+     *
+     * Details.
+     */
+    Foo& operator=(const Foo&) noexcept(std::is_nothrow_copy_constructible<Foo>::value) = delete;
+
+    /**
+     * @brief Const, conditional noexcept and a pure virtual
+     *
+     * Details.
+     */
+    virtual void foo() const noexcept(false) = 0;
+};
+
+/** @brief Base class */
+class Base {
+    public:
+        /** @brief Do a thing with crazy attribs */
+        virtual void doThing() const noexcept(false);
+
+    private:
+        /** @brief Do another thing, privately */
+        virtual void doAnotherThing();
+
+        /**
+         * @brief Do yet another thing, privately
+         *
+         * The override will get hidden because `INHERIT_DOCS` is disabled.
+         */
+        virtual void doYetAnotherThing();
+
+        /* Not documented, should be hidden */
+        virtual void doUndocumentedThing();
+};
+
+/** @brief A derived class */
+class Derived: public Base {
+    protected:
+        /** @brief Do a thing, overriden, now protected */
+        void doThing() const noexcept(false) override;
+
+    private:
+        /**
+         * @brief Do another thing, privately, with different docs
+         *
+         * Documented, so not hidden.
+         */
+        void doAnotherThing() override;
+
+        /* Hidden because there's no doc block */
+        void doYetAnotherThing() override;
+
+        /* Hidden as well because even the parent was undocumented */
+        void doUndocumentedThing() override;
+};
+
+/** @brief Various uses of final keywords */
+struct Final final: protected Base {
+    /**
+     * @brief Final w/o override (will cause a compiler warning)
+     *
+     * Details.
+     */
+    void doThing() const noexcept(false) final;
+
+    /**
+     * @brief Final override
+     *
+     * Details.
+     */
+    void doAnotherThing() final override;
+
+    /**
+     * @brief Override final
+     *
+     * Details.
+     */
+    void doYetAnotherThing() override final;
+};
diff --git a/doxygen/test/cpp_function_attributes/structFinal.html b/doxygen/test/cpp_function_attributes/structFinal.html
new file mode 100644 (file)
index 0000000..fdbe881
--- /dev/null
@@ -0,0 +1,93 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Final 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>
+          Final <span class="m-thin">struct</span> <span class="m-label m-flat m-warning">final</span>
+        </h1>
+        <p>Various uses of final keywords.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#base-classes">Base classes</a></li>
+                <li><a href="#pub-methods">Public functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="base-classes">
+          <h2><a href="#base-classes">Base classes</a></h2>
+          <dl class="m-dox">
+            <dt>
+              class <a href="classBase.html" class="m-dox">Base</a> <span class="m-label m-flat m-warning">protected</span>
+            </dt>
+            <dd>Base class.</dd>
+          </dl>
+        </section>
+        <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="#af4c21109738e0cb65462052a56cda155" class="m-dox">doThing</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-flat m-warning">final</span> <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Final w/o override (will cause a compiler warning)</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a44dd4b2453ab771b32e1d7c4ef8cfd2d" class="m-dox">doAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-flat m-warning">final</span></span>
+            </dt>
+            <dd>Final override.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a59a34b268e0ff383f090753d6562ad4d" class="m-dox">doYetAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-flat m-warning">final</span></span>
+            </dt>
+            <dd>Override final.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="af4c21109738e0cb65462052a56cda155"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Final::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#af4c21109738e0cb65462052a56cda155" class="m-dox-self">doThing</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-warning">final</span> <span class="m-label m-success">noexcept(…)</span></span></span>
+            </h3>
+            <p>Final w/o override (will cause a compiler warning)</p>
+<p>Details.</p>
+          </div></section>
+          <section class="m-dox-details" id="a44dd4b2453ab771b32e1d7c4ef8cfd2d"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Final::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a44dd4b2453ab771b32e1d7c4ef8cfd2d" class="m-dox-self">doAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-warning">final</span></span></span>
+            </h3>
+            <p>Final override.</p>
+<p>Details.</p>
+          </div></section>
+          <section class="m-dox-details" id="a59a34b268e0ff383f090753d6562ad4d"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Final::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a59a34b268e0ff383f090753d6562ad4d" class="m-dox-self">doYetAnotherThing</a>(</span><span class="m-dox-wrap">) <span class="m-label m-warning">final</span></span></span>
+            </h3>
+            <p>Override final.</p>
+<p>Details.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
diff --git a/doxygen/test/cpp_function_attributes/structFoo.html b/doxygen/test/cpp_function_attributes/structFoo.html
new file mode 100644 (file)
index 0000000..3012f95
--- /dev/null
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8" />
+  <title>Foo 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>
+          Foo <span class="m-thin">struct</span>
+        </h1>
+        <p>Pathological cases of noexcept.</p>
+        <div class="m-block m-default">
+          <h3>Contents</h3>
+          <ul>
+            <li>
+              Reference
+              <ul>
+                <li><a href="#typeless-methods">Constructors, destructors, conversion operators</a></li>
+                <li><a href="#pub-methods">Public functions</a></li>
+              </ul>
+            </li>
+          </ul>
+        </div>
+        <section id="typeless-methods">
+          <h2><a href="#typeless-methods">Constructors, destructors, conversion operators</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper"><a href="#ad5953d17211071264b501747c67e6fdc" class="m-dox">Foo</a>(</span><span class="m-dox-wrap"><a href="structFoo.html" class="m-dox">Foo</a>&amp;&amp;) <span class="m-label m-flat m-info">defaulted</span> <span class="m-label m-flat m-success">noexcept</span></span>
+            </dt>
+            <dd>Combined default and noexcept.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper"><a href="#aa5e6af28b3d9578c4c1653ef8a7eb8d5" class="m-dox">Foo</a>(</span><span class="m-dox-wrap">const <a href="structFoo.html" class="m-dox">Foo</a>&amp;) <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Conditional noexcept.</dd>
+          </dl>
+        </section>
+        <section id="pub-methods">
+          <h2><a href="#pub-methods">Public functions</a></h2>
+          <dl class="m-dox">
+            <dt>
+              <span class="m-dox-wrap-bumper">auto <a href="#ad9331e22010cb345be1d123831ecc8a0" class="m-dox">operator=</a>(</span><span class="m-dox-wrap">const <a href="structFoo.html" class="m-dox">Foo</a>&amp;) -&gt; <a href="structFoo.html" class="m-dox">Foo</a>&amp; <span class="m-label m-flat m-danger">deleted</span> <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Combined conditional noexcept and delete.</dd>
+            <dt>
+              <span class="m-dox-wrap-bumper">void <a href="#a67e9f6865d19c8e7734b182143d5e9b3" class="m-dox">foo</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-flat m-warning">pure virtual</span> <span class="m-label m-flat m-success">noexcept(…)</span></span>
+            </dt>
+            <dd>Const, conditional noexcept and a pure virtual.</dd>
+          </dl>
+        </section>
+        <section>
+          <h2>Function documentation</h2>
+          <section class="m-dox-details" id="ad5953d17211071264b501747c67e6fdc"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper"> Foo::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#ad5953d17211071264b501747c67e6fdc" class="m-dox-self">Foo</a>(</span><span class="m-dox-wrap"><a href="structFoo.html" class="m-dox">Foo</a>&amp;&amp;) <span class="m-label m-info">defaulted</span> <span class="m-label m-success">noexcept</span></span></span>
+            </h3>
+            <p>Combined default and noexcept.</p>
+<p>Details.</p>
+          </div></section>
+          <section class="m-dox-details" id="aa5e6af28b3d9578c4c1653ef8a7eb8d5"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper"> Foo::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#aa5e6af28b3d9578c4c1653ef8a7eb8d5" class="m-dox-self">Foo</a>(</span><span class="m-dox-wrap">const <a href="structFoo.html" class="m-dox">Foo</a>&amp;) <span class="m-label m-success">noexcept(…)</span></span></span>
+            </h3>
+            <p>Conditional noexcept.</p>
+<p>Details.</p>
+          </div></section>
+          <section class="m-dox-details" id="ad9331e22010cb345be1d123831ecc8a0"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper"><a href="structFoo.html" class="m-dox">Foo</a>&amp; Foo::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#ad9331e22010cb345be1d123831ecc8a0" class="m-dox-self">operator=</a>(</span><span class="m-dox-wrap">const <a href="structFoo.html" class="m-dox">Foo</a>&amp;) <span class="m-label m-danger">deleted</span> <span class="m-label m-success">noexcept(…)</span></span></span>
+            </h3>
+            <p>Combined conditional noexcept and delete.</p>
+<p>Details.</p>
+          </div></section>
+          <section class="m-dox-details" id="a67e9f6865d19c8e7734b182143d5e9b3"><div>
+            <h3>
+              <span class="m-dox-wrap-bumper">void Foo::<wbr /></span><span class="m-dox-wrap"><span class="m-dox-wrap-bumper"><a href="#a67e9f6865d19c8e7734b182143d5e9b3" class="m-dox-self">foo</a>(</span><span class="m-dox-wrap">) const <span class="m-label m-warning">pure virtual</span> <span class="m-label m-success">noexcept(…)</span></span></span>
+            </h3>
+            <p>Const, conditional noexcept and a pure virtual.</p>
+<p>Details.</p>
+          </div></section>
+        </section>
+      </div>
+    </div>
+  </div>
+</article></main>
+</body>
+</html>
index 054abdda9d801c3dcdb782fa3fe7555c7b34aec3..e8bdb5f218c3255e91dc9405a561f315c6fa5004 100644 (file)
@@ -61,6 +61,7 @@ class Derived(IntegrationTestCase):
         self.assertEqual(*self.actual_expected_contents('classNamespace_1_1VirtualBase.html'))
         self.assertEqual(*self.actual_expected_contents('classBaseOutsideANamespace.html'))
         self.assertEqual(*self.actual_expected_contents('classDerivedOutsideANamespace.html'))
+        self.assertEqual(*self.actual_expected_contents('structAnother_1_1Final.html'))
 
 class Friends(IntegrationTestCase):
     def __init__(self, *args, **kwargs):
@@ -89,3 +90,14 @@ class VariableTemplate(IntegrationTestCase):
         self.run_dox2html5(wildcard='*.xml')
         self.assertEqual(*self.actual_expected_contents('structFoo.html'))
         self.assertEqual(*self.actual_expected_contents('structBar.html'))
+
+class FunctionAttributes(IntegrationTestCase):
+    def __init__(self, *args, **kwargs):
+        super().__init__(__file__, 'function_attributes', *args, **kwargs)
+
+    def test(self):
+        self.run_dox2html5(wildcard='*.xml')
+        self.assertEqual(*self.actual_expected_contents('structFoo.html'))
+        self.assertEqual(*self.actual_expected_contents('classBase.html'))
+        self.assertEqual(*self.actual_expected_contents('classDerived.html'))
+        self.assertEqual(*self.actual_expected_contents('structFinal.html'))