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
43 changes: 35 additions & 8 deletions cxxheaderparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -608,11 +608,19 @@ def _parse_template_decl(self) -> TemplateDecl:
param = self._parse_template_type_parameter(tok, None)
else:
param, _ = self._parse_parameter(
ptok, TemplateNonTypeParam, False, ">"
ptok,
TemplateNonTypeParam,
concept_ok=False,
deduce_this_ok=False,
end=">",
)
else:
param, _ = self._parse_parameter(
tok, TemplateNonTypeParam, concept_ok=False, end=">"
tok,
TemplateNonTypeParam,
concept_ok=False,
deduce_this_ok=False,
end=">",
)

params.append(param)
Expand Down Expand Up @@ -1761,6 +1769,7 @@ def _parse_parameter(
tok: typing.Optional[LexToken],
cls: typing.Type[PT],
concept_ok: bool,
deduce_this_ok: bool,
end: str = ")",
) -> typing.Tuple[PT, typing.Optional[Type]]:
"""
Expand All @@ -1775,6 +1784,10 @@ def _parse_parameter(
param_pack = False
parsed_type: typing.Optional[Type]
at_type: typing.Optional[Type] = None
extras: typing.Dict[str, typing.Any] = {}

if deduce_this_ok and self.lex.token_if("this"):
extras["deduces_this"] = True

if not tok:
tok = self.lex.token()
Expand Down Expand Up @@ -1825,12 +1838,18 @@ def _parse_parameter(
if at_type and self.lex.token_if("ELLIPSIS"):
param_pack = True

param = cls(type=dtype, name=param_name, default=default, param_pack=param_pack)
param = cls(
type=dtype,
name=param_name,
default=default,
param_pack=param_pack,
**extras,
)
self.debug_print("parameter: %s", param)
return param, at_type

def _parse_parameters(
self, concept_ok: bool
self, concept_ok: bool, deduce_this_ok: bool
) -> typing.Tuple[typing.List[Parameter], bool, typing.List[TemplateParam]]:
"""
Consumes function parameters and returns them, and vararg if found, and
Expand All @@ -1854,7 +1873,13 @@ def _parse_parameters(
self._next_token_must_be(")")
break

param, at_type = self._parse_parameter(None, Parameter, concept_ok)
# Deduce-this only applicable for first function parameter
param, at_type = self._parse_parameter(
None,
Parameter,
concept_ok,
deduce_this_ok=deduce_this_ok and len(params) == 0,
)
params.append(param)
if at_type:
at_params.append(
Expand Down Expand Up @@ -2047,7 +2072,9 @@ def _parse_function(
state.location = location
is_class_block = isinstance(state, ClassBlockState)

params, vararg, at_params = self._parse_parameters(True)
params, vararg, at_params = self._parse_parameters(
True, deduce_this_ok=is_class_block
)

# Promote abbreviated template parameters
if at_params:
Expand Down Expand Up @@ -2243,7 +2270,7 @@ def _parse_cv_ptr_or_fn(
toks = self._consume_balanced_tokens(gtok)
self.lex.return_tokens(toks[1:-1])

fn_params, vararg, _ = self._parse_parameters(False)
fn_params, vararg, _ = self._parse_parameters(False, False)

assert not isinstance(dtype, FunctionType)
dtype = dtype_fn = FunctionType(dtype, fn_params, vararg)
Expand Down Expand Up @@ -2273,7 +2300,7 @@ def _parse_cv_ptr_or_fn(
assert not isinstance(dtype, FunctionType)
dtype = self._parse_array_type(aptok, dtype)
elif aptok.type == "(":
fn_params, vararg, _ = self._parse_parameters(False)
fn_params, vararg, _ = self._parse_parameters(False, False)
# the type we already have is the return type of the function pointer

assert not isinstance(dtype, FunctionType)
Expand Down
3 changes: 3 additions & 0 deletions cxxheaderparser/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,9 @@ class Parameter:
default: typing.Optional[Value] = None
param_pack: bool = False

#: Indicates that this parameter is the parameter used for cxx23 deducing-this
deduces_this: bool = False

def format(self) -> str:
default = f" = {self.default.format()}" if self.default else ""
pp = "... " if self.param_pack else ""
Expand Down
54 changes: 54 additions & 0 deletions tests/test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,60 @@ class StoneClass {
)


def test_class_fn_deduce_this() -> None:
content = """
class StoneClass {
template<typename Self>
int doSelf(this Self&& self);
};
"""
data = parse_string(content, cleandoc=True)

assert data == ParsedData(
namespace=NamespaceScope(
classes=[
ClassScope(
class_decl=ClassDecl(
typename=PQName(
segments=[NameSpecifier(name="StoneClass")],
classkey="class",
)
),
methods=[
Method(
return_type=Type(
typename=PQName(
segments=[FundamentalSpecifier(name="int")]
)
),
name=PQName(segments=[NameSpecifier(name="doSelf")]),
parameters=[
Parameter(
type=MoveReference(
moveref_to=Type(
typename=PQName(
segments=[NameSpecifier(name="Self")]
)
)
),
name="self",
deduces_this=True,
)
],
template=TemplateDecl(
params=[
TemplateTypeParam(typekey="typename", name="Self")
]
),
access="private",
),
],
)
]
)
)


def test_class_fn_return_global_ns() -> None:
content = """
struct Avacado {
Expand Down