Merge pull request #40 from robotpy/method-fixes

Method fixes
This commit is contained in:
Dustin Spicuzza 2022-12-08 09:58:55 -05:00 committed by GitHub
commit a5277d951a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 30 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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,
)
]
)
)