From 2e2b57fc3a655cc86db8773058e40ef8a827637b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 1 Jan 2019 19:15:18 +0100 Subject: [PATCH] doxygen: parse override, final and conditional noexcept keywords. * 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 --- doc/doxygen.rst | 137 ++++++++++-------- doxygen/dox2html5.py | 52 ++++++- doxygen/templates/base-class-reference.html | 4 +- doxygen/templates/details-func.html | 2 +- doxygen/templates/entry-class.html | 2 +- doxygen/templates/entry-func.html | 2 +- .../test/cpp_derived/classNamespace_1_1A.html | 4 + .../classNamespace_1_1VirtualBase.html | 2 +- doxygen/test/cpp_derived/input.h | 3 + .../cpp_derived/structAnother_1_1Final.html | 40 +++++ doxygen/test/cpp_function_attributes/Doxyfile | 18 +++ .../cpp_function_attributes/classBase.html | 89 ++++++++++++ .../cpp_function_attributes/classDerived.html | 81 +++++++++++ doxygen/test/cpp_function_attributes/input.h | 98 +++++++++++++ .../cpp_function_attributes/structFinal.html | 93 ++++++++++++ .../cpp_function_attributes/structFoo.html | 100 +++++++++++++ doxygen/test/test_cpp.py | 12 ++ 17 files changed, 667 insertions(+), 72 deletions(-) create mode 100644 doxygen/test/cpp_derived/structAnother_1_1Final.html create mode 100644 doxygen/test/cpp_function_attributes/Doxyfile create mode 100644 doxygen/test/cpp_function_attributes/classBase.html create mode 100644 doxygen/test/cpp_function_attributes/classDerived.html create mode 100644 doxygen/test/cpp_function_attributes/input.h create mode 100644 doxygen/test/cpp_function_attributes/structFinal.html create mode 100644 doxygen/test/cpp_function_attributes/structFoo.html diff --git a/doc/doxygen.rst b/doc/doxygen.rst index 3ea8d5a7..b04faee7 100644 --- a/doc/doxygen.rst +++ b/doc/doxygen.rst @@ -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: diff --git a/doxygen/dox2html5.py b/doxygen/dox2html5.py index 9a17afa1..7f6460c8 100755 --- a/doxygen/dox2html5.py +++ b/doxygen/dox2html5.py @@ -354,6 +354,8 @@ def __init__(self): 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_] diff --git a/doxygen/templates/base-class-reference.html b/doxygen/templates/base-class-reference.html index 0515dbb0..67f6aefb 100644 --- a/doxygen/templates/base-class-reference.html +++ b/doxygen/templates/base-class-reference.html @@ -24,7 +24,9 @@

{% set j = joiner(', ') %}
template<{% for t in compound.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif%}{% endfor %}>
{% endif %} - {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} {{ compound.kind }} + {%+ for name, target in compound.breadcrumb[:-1] %}{{ name }}::{% endfor %}{{ compound.breadcrumb[-1][0] }} {{ compound.kind }}{% if compound.is_final %} final{% endif %} + {# need an explicit space here otherwise the newline gets removed #} + {% if compound.include and compound.templates == None %} {% endif %} diff --git a/doxygen/templates/details-func.html b/doxygen/templates/details-func.html index 43e11f3d..3e633f59 100644 --- a/doxygen/templates/details-func.html +++ b/doxygen/templates/details-func.html @@ -16,7 +16,7 @@

{% endif %} {% set j = joiner(',\n ') %} - {{ func.prefix }}{{ func.type }} {{ prefix }}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} explicit {% endif %}{% if func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_noexcept %} noexcept{% endif %} + {{ func.prefix }}{{ func.type }} {{ prefix }}{{ func.name }}({% for param in func.params %}{{ j() }}{{ param.type_name }}{% if param.default %} = {{ param.default }}{% endif %}{% endfor %}){{ func.suffix }}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %} {% if func.include and compound.templates == None and func.templates == None %} {% endif %} diff --git a/doxygen/templates/entry-class.html b/doxygen/templates/entry-class.html index 0cb8dee0..5b4daed5 100644 --- a/doxygen/templates/entry-class.html +++ b/doxygen/templates/entry-class.html @@ -3,7 +3,7 @@ {% set j = joiner(', ') %}
template<{% for t in class.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}>
{% endif %} - {{ class.kind }} {{ class.name }}{% if class.is_deprecated %} deprecated{% endif %}{% if class.is_protected %} protected{% endif %}{% if class.is_virtual %} virtual{% endif %} + {{ class.kind }} {{ class.name }}{% if class.is_deprecated %} deprecated{% endif %}{% if class.is_protected %} protected{% endif %}{% if class.is_final %} final{% elif class.is_virtual %} virtual{% endif %} {# the empty line is above to fix spacing #} diff --git a/doxygen/templates/entry-func.html b/doxygen/templates/entry-func.html index 66e03b7f..b2d6fcee 100644 --- a/doxygen/templates/entry-func.html +++ b/doxygen/templates/entry-func.html @@ -4,6 +4,6 @@
template<{% for t in func.templates %}{{ j() }}{{ t.type }}{% if t.name %} {{ t.name }}{% endif %}{% if t.default %} = {{ t.default }}{% endif %}{% endfor %}>
{% endif %} {% set j = joiner(',\n ') %} - {{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}{{ func.name }}({% 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' %} -> {{ func.type }}{% endif %}{% if func.is_deprecated %} deprecated{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_explicit %} explicit {% endif %}{% if func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_noexcept %} noexcept{% endif %} + {{ func.prefix }}{% if func.type == 'void' %}void {% elif func.type %}auto {% endif %}{{ func.name }}({% 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' %} -> {{ func.type }}{% endif %}{% if func.is_deprecated %} deprecated{% endif %}{% if not func.type or mark_nonpublic %}{% if func.is_protected %} protected{% if func.is_slot %} slot{% endif %}{% elif func.is_private %} private{% if func.is_slot %} slot{% endif %}{% elif func.is_signal %} signal{% elif func.is_slot %} public slot{% endif %}{% endif %}{% if func.is_defaulted %} defaulted{% endif %}{% if func.is_deleted %} deleted{% endif %}{% if func.is_explicit %} explicit {% endif %}{% if func.is_final %} final{% elif func.is_override %} override{% elif func.is_pure_virtual %} pure virtual{% elif func.is_virtual %} virtual{% endif %}{% if func.is_constexpr %} constexpr{% endif %}{% if func.is_conditional_noexcept %} noexcept(…){% elif func.is_noexcept %} noexcept{% endif %}
{{ func.brief }}
diff --git a/doxygen/test/cpp_derived/classNamespace_1_1A.html b/doxygen/test/cpp_derived/classNamespace_1_1A.html index a8cc7a50..916c42a8 100644 --- a/doxygen/test/cpp_derived/classNamespace_1_1A.html +++ b/doxygen/test/cpp_derived/classNamespace_1_1A.html @@ -44,6 +44,10 @@

Derived classes

class Another::Derived
A derived class.
+
+ struct Another::Final final +
+
A final derived class.
diff --git a/doxygen/test/cpp_derived/classNamespace_1_1VirtualBase.html b/doxygen/test/cpp_derived/classNamespace_1_1VirtualBase.html index ab7333c0..b729787d 100644 --- a/doxygen/test/cpp_derived/classNamespace_1_1VirtualBase.html +++ b/doxygen/test/cpp_derived/classNamespace_1_1VirtualBase.html @@ -27,7 +27,7 @@

Derived classes

- class A + class A virtual
A class.
diff --git a/doxygen/test/cpp_derived/input.h b/doxygen/test/cpp_derived/input.h index 2800095b..66795a20 100644 --- a/doxygen/test/cpp_derived/input.h +++ b/doxygen/test/cpp_derived/input.h @@ -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 index 00000000..ccf4319b --- /dev/null +++ b/doxygen/test/cpp_derived/structAnother_1_1Final.html @@ -0,0 +1,40 @@ + + + + + Another::Final struct | My Project + + + + + +
+
+ + diff --git a/doxygen/test/cpp_function_attributes/Doxyfile b/doxygen/test/cpp_function_attributes/Doxyfile new file mode 100644 index 00000000..2186bfc2 --- /dev/null +++ b/doxygen/test/cpp_function_attributes/Doxyfile @@ -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 index 00000000..d5ed8a90 --- /dev/null +++ b/doxygen/test/cpp_function_attributes/classBase.html @@ -0,0 +1,89 @@ + + + + + Base class | My Project + + + + + +
+
+
+
+
+

+ Base class +

+

Base class.

+
+

Contents

+ +
+
+

Derived classes

+
+
+ class Derived +
+
A derived class.
+
+ struct Final final +
+
Various uses of final keywords.
+
+
+
+

Public functions

+
+
+ void doThing() const virtual noexcept(…) +
+
Do a thing with crazy attribs.
+
+
+
+

Private functions

+
+
+ void doAnotherThing() virtual +
+
Do another thing, privately.
+
+ void doYetAnotherThing() virtual +
+
Do yet another thing, privately.
+
+
+
+

Function documentation

+
+

+ void Base::doYetAnotherThing() virtual private +

+

Do yet another thing, privately.

+

The override will get hidden because INHERIT_DOCS is disabled.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/cpp_function_attributes/classDerived.html b/doxygen/test/cpp_function_attributes/classDerived.html new file mode 100644 index 00000000..f8332b66 --- /dev/null +++ b/doxygen/test/cpp_function_attributes/classDerived.html @@ -0,0 +1,81 @@ + + + + + Derived class | My Project + + + + + +
+
+
+
+
+

+ Derived class +

+

A derived class.

+
+

Contents

+ +
+
+

Base classes

+
+
+ class Base +
+
Base class.
+
+
+
+

Protected functions

+
+
+ void doThing() const override noexcept(…) +
+
Do a thing, overriden, now protected.
+
+
+
+

Private functions

+
+
+ void doAnotherThing() override +
+
Do another thing, privately, with different docs.
+
+
+
+

Function documentation

+
+

+ void Derived::doAnotherThing() override private +

+

Do another thing, privately, with different docs.

+

Documented, so not hidden.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/cpp_function_attributes/input.h b/doxygen/test/cpp_function_attributes/input.h new file mode 100644 index 00000000..2d97756e --- /dev/null +++ b/doxygen/test/cpp_function_attributes/input.h @@ -0,0 +1,98 @@ +#include + +/** @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::value); + + /** + * @brief Combined conditional noexcept and delete + * + * Details. + */ + Foo& operator=(const Foo&) noexcept(std::is_nothrow_copy_constructible::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 index 00000000..fdbe881a --- /dev/null +++ b/doxygen/test/cpp_function_attributes/structFinal.html @@ -0,0 +1,93 @@ + + + + + Final struct | My Project + + + + + +
+
+
+
+
+

+ Final struct final +

+

Various uses of final keywords.

+
+

Contents

+ +
+
+

Base classes

+
+
+ class Base protected +
+
Base class.
+
+
+
+

Public functions

+
+
+ void doThing() const final noexcept(…) +
+
Final w/o override (will cause a compiler warning)
+
+ void doAnotherThing() final +
+
Final override.
+
+ void doYetAnotherThing() final +
+
Override final.
+
+
+
+

Function documentation

+
+

+ void Final::doThing() const final noexcept(…) +

+

Final w/o override (will cause a compiler warning)

+

Details.

+
+
+

+ void Final::doAnotherThing() final +

+

Final override.

+

Details.

+
+
+

+ void Final::doYetAnotherThing() final +

+

Override final.

+

Details.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/cpp_function_attributes/structFoo.html b/doxygen/test/cpp_function_attributes/structFoo.html new file mode 100644 index 00000000..3012f95d --- /dev/null +++ b/doxygen/test/cpp_function_attributes/structFoo.html @@ -0,0 +1,100 @@ + + + + + Foo struct | My Project + + + + + +
+
+
+
+
+

+ Foo struct +

+

Pathological cases of noexcept.

+
+

Contents

+ +
+
+

Constructors, destructors, conversion operators

+
+
+ Foo(Foo&&) defaulted noexcept +
+
Combined default and noexcept.
+
+ Foo(const Foo&) noexcept(…) +
+
Conditional noexcept.
+
+
+
+

Public functions

+
+
+ auto operator=(const Foo&) -> Foo& deleted noexcept(…) +
+
Combined conditional noexcept and delete.
+
+ void foo() const pure virtual noexcept(…) +
+
Const, conditional noexcept and a pure virtual.
+
+
+
+

Function documentation

+
+

+ Foo::Foo(Foo&&) defaulted noexcept +

+

Combined default and noexcept.

+

Details.

+
+
+

+ Foo::Foo(const Foo&) noexcept(…) +

+

Conditional noexcept.

+

Details.

+
+
+

+ Foo& Foo::operator=(const Foo&) deleted noexcept(…) +

+

Combined conditional noexcept and delete.

+

Details.

+
+
+

+ void Foo::foo() const pure virtual noexcept(…) +

+

Const, conditional noexcept and a pure virtual.

+

Details.

+
+
+
+
+
+
+ + diff --git a/doxygen/test/test_cpp.py b/doxygen/test/test_cpp.py index 054abdda..e8bdb5f2 100644 --- a/doxygen/test/test_cpp.py +++ b/doxygen/test/test_cpp.py @@ -61,6 +61,7 @@ def test(self): 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 @@ def test(self): 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'))