commit
a5277d951a
@ -1758,16 +1758,15 @@ class CxxParser:
|
|||||||
|
|
||||||
params, vararg = self._parse_parameters()
|
params, vararg = self._parse_parameters()
|
||||||
|
|
||||||
if is_class_block and not is_typedef:
|
# A method outside of a class has multiple name segments
|
||||||
assert isinstance(state, ClassBlockState)
|
multiple_name_segments = len(pqname.segments) > 1
|
||||||
|
|
||||||
|
if (is_class_block or multiple_name_segments) and not is_typedef:
|
||||||
|
|
||||||
props.update(dict.fromkeys(mods.meths.keys(), True))
|
props.update(dict.fromkeys(mods.meths.keys(), True))
|
||||||
|
|
||||||
method: Method
|
method: Method
|
||||||
|
|
||||||
current_access = self._current_access
|
|
||||||
assert current_access is not None
|
|
||||||
|
|
||||||
if op:
|
if op:
|
||||||
method = Operator(
|
method = Operator(
|
||||||
return_type,
|
return_type,
|
||||||
@ -1777,7 +1776,7 @@ class CxxParser:
|
|||||||
doxygen=doxygen,
|
doxygen=doxygen,
|
||||||
operator=op,
|
operator=op,
|
||||||
template=template,
|
template=template,
|
||||||
access=current_access,
|
access=self._current_access,
|
||||||
**props, # type: ignore
|
**props, # type: ignore
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -1790,12 +1789,14 @@ class CxxParser:
|
|||||||
constructor=constructor,
|
constructor=constructor,
|
||||||
destructor=destructor,
|
destructor=destructor,
|
||||||
template=template,
|
template=template,
|
||||||
access=current_access,
|
access=self._current_access,
|
||||||
**props, # type: ignore
|
**props, # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
self._parse_method_end(method)
|
self._parse_method_end(method)
|
||||||
|
|
||||||
|
if is_class_block:
|
||||||
|
assert isinstance(state, ClassBlockState)
|
||||||
if is_friend:
|
if is_friend:
|
||||||
friend = FriendDecl(fn=method)
|
friend = FriendDecl(fn=method)
|
||||||
self.visitor.on_class_friend(state, friend)
|
self.visitor.on_class_friend(state, friend)
|
||||||
@ -1806,6 +1807,10 @@ class CxxParser:
|
|||||||
raise self._parse_error(None)
|
raise self._parse_error(None)
|
||||||
|
|
||||||
self.visitor.on_class_method(state, method)
|
self.visitor.on_class_method(state, method)
|
||||||
|
else:
|
||||||
|
if not method.has_body:
|
||||||
|
raise self._parse_error(None, expected="Method body")
|
||||||
|
self.visitor.on_method_impl(state, method)
|
||||||
|
|
||||||
return method.has_body or method.has_trailing_return
|
return method.has_body or method.has_trailing_return
|
||||||
|
|
||||||
@ -2126,12 +2131,22 @@ class CxxParser:
|
|||||||
tok = self.lex.token_if("(")
|
tok = self.lex.token_if("(")
|
||||||
if tok:
|
if tok:
|
||||||
|
|
||||||
# Check to see if this is a constructor/destructor
|
dsegments: typing.List[PQNameSegment] = []
|
||||||
if isinstance(state, ClassBlockState) and isinstance(dtype, Type):
|
if isinstance(dtype, Type):
|
||||||
|
|
||||||
dsegments = dtype.typename.segments
|
dsegments = dtype.typename.segments
|
||||||
|
|
||||||
if not is_friend:
|
# Check to see if this is a constructor/destructor by matching
|
||||||
|
# the method name to the class name
|
||||||
|
is_class_block = isinstance(state, ClassBlockState)
|
||||||
|
if (is_class_block or len(dsegments) > 1) and isinstance(dtype, Type):
|
||||||
|
|
||||||
|
if not is_class_block:
|
||||||
|
# must be an instance of a class
|
||||||
|
cls_name = getattr(dsegments[-2], "name", None)
|
||||||
|
|
||||||
|
elif not is_friend:
|
||||||
|
assert isinstance(state, ClassBlockState)
|
||||||
|
|
||||||
# class name to match against is this class
|
# class name to match against is this class
|
||||||
cls_name = getattr(
|
cls_name = getattr(
|
||||||
state.class_decl.typename.segments[-1], "name", None
|
state.class_decl.typename.segments[-1], "name", None
|
||||||
|
@ -94,7 +94,13 @@ class NamespaceScope:
|
|||||||
|
|
||||||
classes: typing.List["ClassScope"] = field(default_factory=list)
|
classes: typing.List["ClassScope"] = field(default_factory=list)
|
||||||
enums: typing.List[EnumDecl] = field(default_factory=list)
|
enums: typing.List[EnumDecl] = field(default_factory=list)
|
||||||
|
|
||||||
|
#: Function declarations (with or without body)
|
||||||
functions: typing.List[Function] = field(default_factory=list)
|
functions: typing.List[Function] = field(default_factory=list)
|
||||||
|
|
||||||
|
#: Method implementations outside of a class (must have a body)
|
||||||
|
method_impls: typing.List[Method] = field(default_factory=list)
|
||||||
|
|
||||||
typedefs: typing.List[Typedef] = field(default_factory=list)
|
typedefs: typing.List[Typedef] = field(default_factory=list)
|
||||||
variables: typing.List[Variable] = field(default_factory=list)
|
variables: typing.List[Variable] = field(default_factory=list)
|
||||||
|
|
||||||
@ -264,6 +270,10 @@ class SimpleCxxVisitor:
|
|||||||
assert isinstance(self.block, NamespaceScope)
|
assert isinstance(self.block, NamespaceScope)
|
||||||
self.block.functions.append(fn)
|
self.block.functions.append(fn)
|
||||||
|
|
||||||
|
def on_method_impl(self, state: State, method: Method) -> None:
|
||||||
|
assert isinstance(self.block, NamespaceScope)
|
||||||
|
self.block.method_impls.append(method)
|
||||||
|
|
||||||
def on_typedef(self, state: State, typedef: Typedef) -> None:
|
def on_typedef(self, state: State, typedef: Typedef) -> None:
|
||||||
self.block.typedefs.append(typedef)
|
self.block.typedefs.append(typedef)
|
||||||
|
|
||||||
|
@ -529,7 +529,8 @@ class Method(Function):
|
|||||||
A method declaration, potentially with the method body
|
A method declaration, potentially with the method body
|
||||||
"""
|
"""
|
||||||
|
|
||||||
access: str = ""
|
#: If parsed within a class, the access level for this method
|
||||||
|
access: typing.Optional[str] = None
|
||||||
|
|
||||||
const: bool = False
|
const: bool = False
|
||||||
volatile: bool = False
|
volatile: bool = False
|
||||||
|
@ -106,6 +106,22 @@ class CxxVisitor(Protocol):
|
|||||||
def on_function(self, state: State, fn: Function) -> None:
|
def on_function(self, state: State, fn: Function) -> None:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def on_method_impl(self, state: State, method: Method) -> None:
|
||||||
|
"""
|
||||||
|
Called when a method implementation is encountered outside of a class
|
||||||
|
declaration. For example:
|
||||||
|
|
||||||
|
.. code-block:: c++
|
||||||
|
|
||||||
|
void MyClass::fn() {
|
||||||
|
// does something
|
||||||
|
}
|
||||||
|
|
||||||
|
.. note:: The above implementation is ambiguous, as it technically could
|
||||||
|
be a function in a namespace. We emit this instead as it's
|
||||||
|
more likely to be the case in common code.
|
||||||
|
"""
|
||||||
|
|
||||||
def on_typedef(self, state: State, typedef: Typedef) -> None:
|
def on_typedef(self, state: State, typedef: Typedef) -> None:
|
||||||
"""
|
"""
|
||||||
Called for each typedef instance encountered. For example:
|
Called for each typedef instance encountered. For example:
|
||||||
@ -184,7 +200,7 @@ class CxxVisitor(Protocol):
|
|||||||
|
|
||||||
def on_class_method(self, state: ClassBlockState, method: Method) -> None:
|
def on_class_method(self, state: ClassBlockState, method: Method) -> None:
|
||||||
"""
|
"""
|
||||||
Called when a method of a class is encountered
|
Called when a method of a class is encountered inside of a class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def on_class_end(self, state: ClassBlockState) -> None:
|
def on_class_end(self, state: ClassBlockState) -> None:
|
||||||
|
@ -1909,8 +1909,8 @@ def test_class_fn_inline_impl() -> None:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
functions=[
|
method_impls=[
|
||||||
Function(
|
Method(
|
||||||
return_type=Type(
|
return_type=Type(
|
||||||
typename=PQName(segments=[FundamentalSpecifier(name="void")])
|
typename=PQName(segments=[FundamentalSpecifier(name="void")])
|
||||||
),
|
),
|
||||||
@ -2109,8 +2109,8 @@ def test_class_fn_return_class() -> None:
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
functions=[
|
method_impls=[
|
||||||
Function(
|
Method(
|
||||||
return_type=Pointer(
|
return_type=Pointer(
|
||||||
ptr_to=Type(
|
ptr_to=Type(
|
||||||
typename=PQName(
|
typename=PQName(
|
||||||
@ -2198,8 +2198,8 @@ def test_class_fn_template_impl() -> None:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
functions=[
|
method_impls=[
|
||||||
Function(
|
Method(
|
||||||
return_type=Pointer(
|
return_type=Pointer(
|
||||||
ptr_to=Type(
|
ptr_to=Type(
|
||||||
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
@ -2265,8 +2265,8 @@ def test_class_fn_inline_template_impl() -> None:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
functions=[
|
method_impls=[
|
||||||
Function(
|
Method(
|
||||||
return_type=Type(
|
return_type=Type(
|
||||||
typename=PQName(segments=[NameSpecifier(name="T")])
|
typename=PQName(segments=[NameSpecifier(name="T")])
|
||||||
),
|
),
|
||||||
@ -3212,3 +3212,51 @@ def test_class_ref_qualifiers() -> None:
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_method_outside_class() -> None:
|
||||||
|
content = """
|
||||||
|
int foo::bar() { return 1; }
|
||||||
|
"""
|
||||||
|
data = parse_string(content, cleandoc=True)
|
||||||
|
|
||||||
|
assert data == ParsedData(
|
||||||
|
namespace=NamespaceScope(
|
||||||
|
method_impls=[
|
||||||
|
Method(
|
||||||
|
return_type=Type(
|
||||||
|
typename=PQName(segments=[FundamentalSpecifier(name="int")])
|
||||||
|
),
|
||||||
|
name=PQName(
|
||||||
|
segments=[NameSpecifier(name="foo"), NameSpecifier(name="bar")]
|
||||||
|
),
|
||||||
|
parameters=[],
|
||||||
|
has_body=True,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_constructor_outside_class() -> None:
|
||||||
|
content = """
|
||||||
|
inline foo::foo() {}
|
||||||
|
"""
|
||||||
|
data = parse_string(content, cleandoc=True)
|
||||||
|
|
||||||
|
assert data == ParsedData(
|
||||||
|
namespace=NamespaceScope(
|
||||||
|
method_impls=[
|
||||||
|
Method(
|
||||||
|
return_type=None,
|
||||||
|
name=PQName(
|
||||||
|
segments=[NameSpecifier(name="foo"), NameSpecifier(name="foo")]
|
||||||
|
),
|
||||||
|
parameters=[],
|
||||||
|
inline=True,
|
||||||
|
has_body=True,
|
||||||
|
constructor=True,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user