From ace1d09d9d7de0fe7ad323982989d7eba0692637 Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Fri, 9 Dec 2022 03:28:50 -0500 Subject: [PATCH] Add throw/noexcept tests --- cxxheaderparser/parser.py | 2 +- cxxheaderparser/types.py | 5 ++ tests/test_fn.py | 96 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index c5c35ae..67d5a37 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -1653,7 +1653,7 @@ class CxxParser: if self.lex.token_if("throw"): tok = self._next_token_must_be("(") - fn.throw = self._create_value(self._consume_balanced_tokens(tok)) + fn.throw = self._create_value(self._consume_balanced_tokens(tok)[1:-1]) elif self.lex.token_if("noexcept"): toks = [] diff --git a/cxxheaderparser/types.py b/cxxheaderparser/types.py index e13c958..f0bcc5e 100644 --- a/cxxheaderparser/types.py +++ b/cxxheaderparser/types.py @@ -514,7 +514,12 @@ class Function: template: typing.Optional[TemplateDecl] = None + #: Value of any throw specification for this function. The value omits the + #: outer parentheses. throw: typing.Optional[Value] = None + + #: Value of any noexcept specification for this function. The value omits + #: the outer parentheses. noexcept: typing.Optional[Value] = None #: Only set if an MSVC calling convention (__stdcall, etc) is explictly diff --git a/tests/test_fn.py b/tests/test_fn.py index c5688bd..939d862 100644 --- a/tests/test_fn.py +++ b/tests/test_fn.py @@ -1045,3 +1045,99 @@ def test_msvc_conventions() -> None: ], ) ) + + +def test_throw_empty() -> None: + content = """ + void foo() throw() { throw std::runtime_error("foo"); } + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName(segments=[FundamentalSpecifier(name="void")]) + ), + name=PQName(segments=[NameSpecifier(name="foo")]), + parameters=[], + has_body=True, + throw=Value(tokens=[]), + ) + ] + ) + ) + + +def test_throw_dynamic() -> None: + content = """ + void foo() throw(std::exception) { throw std::runtime_error("foo"); } + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName(segments=[FundamentalSpecifier(name="void")]) + ), + name=PQName(segments=[NameSpecifier(name="foo")]), + parameters=[], + has_body=True, + throw=Value( + tokens=[ + Token(value="std"), + Token(value="::"), + Token(value="exception"), + ] + ), + ) + ] + ) + ) + + +def test_noexcept_empty() -> None: + content = """ + void foo() noexcept; + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName(segments=[FundamentalSpecifier(name="void")]) + ), + name=PQName(segments=[NameSpecifier(name="foo")]), + parameters=[], + noexcept=Value(tokens=[]), + ) + ] + ) + ) + + +def test_noexcept_contents() -> None: + content = """ + void foo() noexcept(false); + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + functions=[ + Function( + return_type=Type( + typename=PQName(segments=[FundamentalSpecifier(name="void")]) + ), + name=PQName(segments=[NameSpecifier(name="foo")]), + parameters=[], + noexcept=Value(tokens=[Token(value="false")]), + ) + ] + ) + )