From dc76328bd5ed469e0a194f9ccf8766a746c540de Mon Sep 17 00:00:00 2001 From: Dustin Spicuzza Date: Fri, 9 Dec 2022 00:20:09 -0500 Subject: [PATCH] Add support for inline namespaces --- cxxheaderparser/parser.py | 4 ++++ cxxheaderparser/simple.py | 4 ++++ tests/test_namespaces.py | 49 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index 0e3dbc5..b240b91 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -284,6 +284,7 @@ class CxxParser: "alignas": self._consume_attribute_specifier_seq, "extern": self._parse_extern, "friend": self._parse_friend_decl, + "inline": self._parse_inline, "namespace": self._parse_namespace, "private": self._process_access_specifier, "protected": self._process_access_specifier, @@ -398,6 +399,9 @@ class CxxParser: tok = self._next_token_must_be("NAME") + if inline and len(names) > 1: + raise CxxParseError("a nested namespace definition cannot be inline") + # TODO: namespace_alias_definition ns = NamespaceDecl(names, inline) diff --git a/cxxheaderparser/simple.py b/cxxheaderparser/simple.py index 35b004d..c4ce156 100644 --- a/cxxheaderparser/simple.py +++ b/cxxheaderparser/simple.py @@ -91,6 +91,7 @@ class NamespaceScope: """ name: str = "" + inline: bool = False classes: typing.List["ClassScope"] = field(default_factory=list) enums: typing.List[EnumDecl] = field(default_factory=list) @@ -248,6 +249,9 @@ class SimpleCxxVisitor: assert ns is not None + # only set inline on inner namespace + ns.inline = state.namespace.inline + self.block = ns self.namespace = ns diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index 74f7f57..7535889 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -1,6 +1,8 @@ # Note: testcases generated via `python -m cxxheaderparser.gentest` +from cxxheaderparser.errors import CxxParseError from cxxheaderparser.types import ( + ForwardDecl, FundamentalSpecifier, NameSpecifier, PQName, @@ -15,6 +17,9 @@ from cxxheaderparser.simple import ( ParsedData, ) +import pytest +import re + def test_dups_in_different_ns() -> None: content = """ @@ -119,3 +124,47 @@ def test_correct_ns() -> None: } ) ) + + +def test_inline_namespace() -> None: + content = """ + namespace Lib { + inline namespace Lib_1 { + class A; + } + } + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + namespaces={ + "Lib": NamespaceScope( + name="Lib", + namespaces={ + "Lib_1": NamespaceScope( + name="Lib_1", + inline=True, + forward_decls=[ + ForwardDecl( + typename=PQName( + segments=[NameSpecifier(name="A")], + classkey="class", + ) + ) + ], + ) + }, + ) + } + ) + ) + + +def test_invalid_inline_namespace() -> None: + content = """ + inline namespace a::b {} + """ + err = ":1: parse error evaluating 'inline': a nested namespace definition cannot be inline" + with pytest.raises(CxxParseError, match=re.escape(err)): + parse_string(content, cleandoc=True)