Merge pull request #30 from robotpy/fix-12

Support __declspec (and other attributes) when parsing a name
This commit is contained in:
Dustin Spicuzza 2021-11-26 10:09:11 -05:00 committed by GitHub
commit bcc57c72c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 78 additions and 11 deletions

View File

@ -614,6 +614,23 @@ class CxxParser:
# Attributes # Attributes
# #
_attribute_specifier_seq_start_types = {"DBL_LBRACKET", "alignas"}
_attribute_start_tokens = {
"__attribute__",
"__declspec",
}
_attribute_start_tokens |= _attribute_specifier_seq_start_types
def _consume_attribute(self, tok: LexToken) -> None:
if tok.type == "__attribute__":
self._consume_gcc_attribute(tok)
elif tok.type == "__declspec":
self._consume_declspec(tok)
elif tok.type in self._attribute_specifier_seq_start_types:
self._consume_attribute_specifier_seq(tok)
else:
raise CxxParseError("internal error")
def _consume_gcc_attribute( def _consume_gcc_attribute(
self, tok: LexToken, doxygen: typing.Optional[str] = None self, tok: LexToken, doxygen: typing.Optional[str] = None
) -> None: ) -> None:
@ -627,8 +644,6 @@ class CxxParser:
tok = self._next_token_must_be("(") tok = self._next_token_must_be("(")
self._consume_balanced_tokens(tok) self._consume_balanced_tokens(tok)
_attribute_specifier_seq_start_types = ("DBL_LBRACKET", "alignas")
def _consume_attribute_specifier_seq( def _consume_attribute_specifier_seq(
self, tok: LexToken, doxygen: typing.Optional[str] = None self, tok: LexToken, doxygen: typing.Optional[str] = None
) -> None: ) -> None:
@ -1361,16 +1376,10 @@ class CxxParser:
if tok: if tok:
classkey = f"{classkey} {tok.value}" classkey = f"{classkey} {tok.value}"
tok = self.lex.token_if( # Sometimes there's an embedded attribute
"alignas", "__attribute__", "__declspec", "DBL_LBRACKET" tok = self.lex.token_if(*self._attribute_start_tokens)
)
if tok: if tok:
if tok.type == "__attribute__": self._consume_attribute(tok)
self._consume_gcc_attribute(tok)
elif tok.type == "__declspec":
self._consume_declspec(tok)
else:
self._consume_attribute_specifier_seq(tok)
tok = self.lex.token_if("NAME", "DBL_COLON") tok = self.lex.token_if("NAME", "DBL_COLON")
if not tok: if not tok:
@ -1898,6 +1907,7 @@ class CxxParser:
pqname: typing.Optional[PQName] = None pqname: typing.Optional[PQName] = None
_pqname_start_tokens = self._pqname_start_tokens _pqname_start_tokens = self._pqname_start_tokens
_attribute_start = self._attribute_start_tokens
# This loop parses until it finds two pqname or ptr/ref # This loop parses until it finds two pqname or ptr/ref
while True: while True:
@ -1926,6 +1936,8 @@ class CxxParser:
vars["mutable"] = tok vars["mutable"] = tok
elif tok_type == "volatile": elif tok_type == "volatile":
volatile = True volatile = True
elif tok_type in _attribute_start:
self._consume_attribute(tok)
else: else:
break break

View File

@ -5,8 +5,10 @@ from cxxheaderparser.types import (
EnumDecl, EnumDecl,
Enumerator, Enumerator,
Field, Field,
FriendDecl,
Function, Function,
FundamentalSpecifier, FundamentalSpecifier,
Method,
NameSpecifier, NameSpecifier,
PQName, PQName,
Pointer, Pointer,
@ -146,3 +148,56 @@ def test_attributes_gcc_enum_packed():
] ]
) )
) )
def test_friendly_declspec():
content = """
struct D {
friend __declspec(dllexport) void my_friend();
static __declspec(dllexport) void static_declspec();
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="D")], classkey="struct"
)
),
friends=[
FriendDecl(
fn=Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(segments=[NameSpecifier(name="my_friend")]),
parameters=[],
access="public",
)
)
],
methods=[
Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
name=PQName(
segments=[NameSpecifier(name="static_declspec")]
),
parameters=[],
static=True,
access="public",
)
],
)
]
)
)