Allow typedefs of function definitions

- Fixes #13
This commit is contained in:
Dustin Spicuzza 2021-11-26 00:51:39 -05:00
parent e750418d08
commit 3c5174b52f
3 changed files with 128 additions and 8 deletions

View File

@ -1645,6 +1645,7 @@ class CxxParser:
constructor: bool,
destructor: bool,
is_friend: bool,
is_typedef: bool,
) -> bool:
"""
Assumes the caller has already consumed the return type and name, this consumes the
@ -1667,7 +1668,7 @@ class CxxParser:
params, vararg = self._parse_parameters()
if is_class_block:
if is_class_block and not is_typedef:
props.update(dict.fromkeys(mods.meths.keys(), True))
method: Method
@ -1723,9 +1724,39 @@ class CxxParser:
**props,
)
self._parse_fn_end(fn)
self.visitor.on_function(state, fn)
return fn.has_body or fn.has_trailing_return
if is_typedef:
if len(pqname.segments) != 1:
raise CxxParseError(
"typedef name may not be a nested-name-specifier"
)
if fn.constexpr:
raise CxxParseError("typedef function may not be constexpr")
if fn.extern:
raise CxxParseError("typedef function may not be extern")
if fn.static:
raise CxxParseError("typedef function may not be static")
if fn.inline:
raise CxxParseError("typedef function may not be inline")
if fn.has_body:
raise CxxParseError("typedef may not be a function definition")
if fn.template:
raise CxxParseError("typedef function may not have a template")
fntype = FunctionType(
fn.return_type,
fn.parameters,
fn.vararg,
fn.has_trailing_return,
noexcept=fn.noexcept,
)
typedef = Typedef(fntype, pqname.segments[0].name, self._current_access)
self.visitor.on_typedef(state, typedef)
return False
else:
self.visitor.on_function(state, fn)
return fn.has_body or fn.has_trailing_return
#
# Decorated type parsing
@ -1988,9 +2019,6 @@ class CxxParser:
# if ( then it's a function/method
if self.lex.token_if("("):
if is_typedef:
raise self._parse_error(None)
if not pqname:
raise self._parse_error(None)
@ -2005,6 +2033,7 @@ class CxxParser:
constructor,
destructor,
is_friend,
is_typedef,
)
# anything else is a field/variable

View File

@ -236,6 +236,8 @@ class FunctionType:
#: whatever the trailing return type was
has_trailing_return: bool = False
noexcept: typing.Optional[Value] = None
@dataclass
class Type:
@ -550,13 +552,13 @@ class Typedef:
"""
#: The aliased type
#: The aliased type or function type
#:
#: .. code-block:: c++
#:
#: typedef type *pname;
#: ~~~~~~
type: DecoratedType
type: typing.Union[DecoratedType, FunctionType]
#: The alias introduced for the specified type
#:

View File

@ -899,3 +899,92 @@ def test_volatile_typedef():
]
)
)
def test_function_typedef():
content = """
typedef void fn(int);
typedef auto fntype(int) -> int;
struct X {
typedef void fn(int);
};
"""
data = parse_string(content, cleandoc=True)
assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="X")], classkey="struct"
)
),
typedefs=[
Typedef(
type=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[
FundamentalSpecifier(name="int")
]
)
)
)
],
),
name="fn",
access="public",
)
],
)
],
typedefs=[
Typedef(
type=FunctionType(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="void")]
)
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
)
],
),
name="fn",
),
Typedef(
type=FunctionType(
return_type=Type(
typename=PQName(segments=[FundamentalSpecifier(name="int")])
),
parameters=[
Parameter(
type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
)
)
],
has_trailing_return=True,
),
name="fntype",
),
],
)
)