diff --git a/doxygen/dox2html5.py b/doxygen/dox2html5.py
index 804d95fa..20917dd8 100755
--- a/doxygen/dox2html5.py
+++ b/doxygen/dox2html5.py
@@ -1839,6 +1839,8 @@ def parse_func(state: State, element: ET.Element):
if func.type.startswith('friend '):
func.type = func.type[7:]
+ def is_identifier(a): return a == '_' or a.isalnum()
+
# Extract function signature to prefix, suffix and various flags. Important
# things affecting caller such as static or const (and rvalue overloads)
# are put into signature prefix/suffix, other things to various is_*
@@ -1882,24 +1884,24 @@ def parse_func(state: State, element: ET.Element):
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]
+ if signature.endswith('final') and not is_identifier(signature[-6]):
+ signature = signature[:-5].rstrip()
func.is_final = True
- if signature.endswith(' override'):
- signature = signature[:-9]
+ if signature.endswith('override') and not is_identifier(signature[-9]):
+ signature = signature[:-8].rstrip()
func.is_override = True
else:
func.is_override = False
# ... and `final override`
- if signature.endswith(' final'):
- signature = signature[:-6]
+ if signature.endswith('final') and not is_identifier(signature[-6]):
+ signature = signature[:-5].rstrip()
func.is_final = True
- if signature.endswith(' noexcept'):
- signature = signature[:-9]
+ if signature.endswith('noexcept') and not is_identifier(signature[-9]):
+ signature = signature[:-8].rstrip()
func.is_noexcept = True
func.is_conditional_noexcept = False
- elif ' noexcept(' in signature:
- signature = signature[:signature.index(' noexcept(')]
+ elif 'noexcept(' in signature and not is_identifier(signature[signature.index('noexcept(') - 1]):
+ signature = signature[:signature.index('noexcept(')].rstrip()
func.is_noexcept = True
func.is_conditional_noexcept = True
else:
diff --git a/doxygen/test/cpp_function_attributes_nospace/Doxyfile b/doxygen/test/cpp_function_attributes_nospace/Doxyfile
new file mode 100644
index 00000000..ee1cb763
--- /dev/null
+++ b/doxygen/test/cpp_function_attributes_nospace/Doxyfile
@@ -0,0 +1,14 @@
+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
diff --git a/doxygen/test/cpp_function_attributes_nospace/input.h b/doxygen/test/cpp_function_attributes_nospace/input.h
new file mode 100644
index 00000000..a3ab3cb1
--- /dev/null
+++ b/doxygen/test/cpp_function_attributes_nospace/input.h
@@ -0,0 +1,21 @@
+/** @brief Base class */
+class Base {
+ virtual void doThing()noexcept;
+ virtual void doAnotherThing();
+ virtual void doYetAnotherThing();
+};
+
+/** @brief Keywords without spaces */
+struct Foo: Base {
+ /** @brief Final w/o override (will cause a compiler warning), w/o a space */
+ void doThing() &&noexcept final;
+
+ /** @brief Do more things, without a space */
+ void doMoreStuff() &&noexcept(false);
+
+ /** @brief Final override, without a space */
+ void doAnotherThing() &&final override;
+
+ /** @brief Override final, without a space */
+ void doYetAnotherThing() &&override final;
+};
diff --git a/doxygen/test/cpp_function_attributes_nospace/structFoo.html b/doxygen/test/cpp_function_attributes_nospace/structFoo.html
new file mode 100644
index 00000000..6d465c05
--- /dev/null
+++ b/doxygen/test/cpp_function_attributes_nospace/structFoo.html
@@ -0,0 +1,73 @@
+
+
+
+
+ Foo struct | My Project
+
+
+
+
+
+
+
+
+
+
+
+ Foo struct
+
+
Keywords without spaces.
+
+
+
+
+ -
+ class Base
+
+ - Base class.
+
+
+
+
+
+ -
+ void doThing() && final noexcept
+
+ - Final w/o override (will cause a compiler warning), w/o a space.
+ -
+ void doMoreStuff() && noexcept(…)
+
+ - Do more things, without a space.
+ -
+ void doAnotherThing() && final
+
+ - Final override, without a space.
+ -
+ void doYetAnotherThing() && final
+
+ - Override final, without a space.
+
+
+
+
+
+
+
+
diff --git a/doxygen/test/test_cpp.py b/doxygen/test/test_cpp.py
index e8bdb5f2..a764dd1e 100644
--- a/doxygen/test/test_cpp.py
+++ b/doxygen/test/test_cpp.py
@@ -101,3 +101,11 @@ def test(self):
self.assertEqual(*self.actual_expected_contents('classBase.html'))
self.assertEqual(*self.actual_expected_contents('classDerived.html'))
self.assertEqual(*self.actual_expected_contents('structFinal.html'))
+
+class FunctionAttributesNospace(IntegrationTestCase):
+ def __init__(self, *args, **kwargs):
+ super().__init__(__file__, 'function_attributes_nospace', *args, **kwargs)
+
+ def test(self):
+ self.run_dox2html5(wildcard='structFoo.xml')
+ self.assertEqual(*self.actual_expected_contents('structFoo.html'))