Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 15 additions & 4 deletions cxxheaderparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -901,11 +901,17 @@ def _consume_attribute(self, tok: LexToken) -> None:
raise CxxParseError("internal error")

def _consume_gcc_attribute(
self, tok: LexToken, doxygen: typing.Optional[str] = None
self, tok: typing.Optional[LexToken], doxygen: typing.Optional[str] = None
) -> None:
tok1 = self._next_token_must_be("(")
tok2 = self._next_token_must_be("(")
self._consume_balanced_tokens(tok1, tok2)
while True:
tok1 = self._next_token_must_be("(")
tok2 = self._next_token_must_be("(")
self._consume_balanced_tokens(tok1, tok2)

# Apparently you can have multiple attributes chained together?
tok = self.lex.token_if("__attribute__")
if tok is None:
break

def _consume_declspec(
self, tok: LexToken, doxygen: typing.Optional[str] = None
Expand Down Expand Up @@ -2676,6 +2682,11 @@ def _parse_declarations(
# if it returns True then it handled the end of the statement
break

# Sometimes attributes come after a function
atok = self.lex.token_if("__attribute__")
if atok:
self._consume_gcc_attribute(atok)

# Unset the doxygen, location
doxygen = None

Expand Down
31 changes: 31 additions & 0 deletions tests/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,34 @@ def test_declspec_template() -> None:
]
)
)


def test_multiple_attributes() -> None:
content = """
extern const unsigned short int **__ctype_b_loc (void) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__const__));
"""
data = parse_string(content, cleandoc=True)

assert data == ParsedData(
namespace=NamespaceScope(
functions=[
Function(
return_type=Pointer(
ptr_to=Pointer(
ptr_to=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="unsigned short int")
]
),
const=True,
)
)
),
name=PQName(segments=[NameSpecifier(name="__ctype_b_loc")]),
parameters=[],
extern=True,
)
]
)
)