parent
a67c9c4afe
commit
92f8e72779
@ -359,6 +359,15 @@ class CxxParser:
|
||||
# Various
|
||||
#
|
||||
|
||||
_msvc_conventions = {
|
||||
"__cdecl",
|
||||
"__clrcall",
|
||||
"__stdcall",
|
||||
"__fastcall",
|
||||
"__thiscall",
|
||||
"__vectorcall",
|
||||
}
|
||||
|
||||
def _parse_namespace(
|
||||
self, tok: LexToken, doxygen: typing.Optional[str], inline: bool = False
|
||||
) -> None:
|
||||
@ -1655,6 +1664,7 @@ class CxxParser:
|
||||
destructor: bool,
|
||||
is_friend: bool,
|
||||
is_typedef: bool,
|
||||
msvc_convention: typing.Optional[LexToken],
|
||||
) -> bool:
|
||||
"""
|
||||
Assumes the caller has already consumed the return type and name, this consumes the
|
||||
@ -1670,6 +1680,8 @@ class CxxParser:
|
||||
raise self._parse_error(None)
|
||||
|
||||
props = dict.fromkeys(mods.both.keys(), True)
|
||||
if msvc_convention:
|
||||
props["msvc_convention"] = msvc_convention.value
|
||||
|
||||
state = self.state
|
||||
state.location = location
|
||||
@ -1758,6 +1770,7 @@ class CxxParser:
|
||||
fn.vararg,
|
||||
fn.has_trailing_return,
|
||||
noexcept=fn.noexcept,
|
||||
msvc_convention=fn.msvc_convention,
|
||||
)
|
||||
|
||||
typedef = Typedef(fntype, pqname.segments[0].name, self._current_access)
|
||||
@ -1823,6 +1836,10 @@ class CxxParser:
|
||||
self._parse_trailing_return_type(dtype)
|
||||
|
||||
else:
|
||||
msvc_convention = self.lex.token_if_val(*self._msvc_conventions)
|
||||
if msvc_convention:
|
||||
msvc_convention = msvc_convention.value
|
||||
|
||||
# Check to see if this is a grouping paren or something else
|
||||
if not self.lex.token_peek_if("*", "&"):
|
||||
self.lex.return_token(tok)
|
||||
@ -1840,7 +1857,9 @@ class CxxParser:
|
||||
fn_params, vararg = self._parse_parameters()
|
||||
# the type we already have is the return type of the function pointer
|
||||
|
||||
dtype = FunctionType(dtype, fn_params, vararg)
|
||||
dtype = FunctionType(
|
||||
dtype, fn_params, vararg, msvc_convention=msvc_convention
|
||||
)
|
||||
|
||||
# the inner tokens must either be a * or a pqname that ends
|
||||
# with ::* (member function pointer)
|
||||
@ -1975,6 +1994,7 @@ class CxxParser:
|
||||
constructor = False
|
||||
destructor = False
|
||||
op = None
|
||||
msvc_convention = None
|
||||
|
||||
# If we have a leading (, that's either an obnoxious grouping
|
||||
# paren or it's a constructor
|
||||
@ -2021,6 +2041,8 @@ class CxxParser:
|
||||
self.lex.return_tokens(toks[1:-1])
|
||||
|
||||
if dtype:
|
||||
msvc_convention = self.lex.token_if_val(*self._msvc_conventions)
|
||||
|
||||
tok = self.lex.token_if_in_set(self._pqname_start_tokens)
|
||||
if tok:
|
||||
pqname, op = self._parse_pqname(tok, fn_ok=True)
|
||||
@ -2046,7 +2068,10 @@ class CxxParser:
|
||||
destructor,
|
||||
is_friend,
|
||||
is_typedef,
|
||||
msvc_convention,
|
||||
)
|
||||
elif msvc_convention:
|
||||
raise self._parse_error(msvc_convention)
|
||||
|
||||
# anything else is a field/variable
|
||||
if is_friend:
|
||||
|
@ -238,6 +238,14 @@ class FunctionType:
|
||||
|
||||
noexcept: typing.Optional[Value] = None
|
||||
|
||||
#: Only set if an MSVC calling convention (__stdcall, etc) is explictly
|
||||
#: specified.
|
||||
#:
|
||||
#: .. note:: If your code contains things like WINAPI, you will need to
|
||||
#: use a preprocessor to transform it to the appropriate
|
||||
#: calling convention
|
||||
msvc_convention: typing.Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Type:
|
||||
@ -487,6 +495,14 @@ class Function:
|
||||
throw: typing.Optional[Value] = None
|
||||
noexcept: typing.Optional[Value] = None
|
||||
|
||||
#: Only set if an MSVC calling convention (__stdcall, etc) is explictly
|
||||
#: specified.
|
||||
#:
|
||||
#: .. note:: If your code contains things like WINAPI, you will need to
|
||||
#: use a preprocessor to transform it to the appropriate
|
||||
#: calling convention
|
||||
msvc_convention: typing.Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class Method(Function):
|
||||
|
@ -20,6 +20,7 @@ from cxxheaderparser.types import (
|
||||
TemplateTypeParam,
|
||||
Token,
|
||||
Type,
|
||||
Typedef,
|
||||
Value,
|
||||
)
|
||||
from cxxheaderparser.simple import (
|
||||
@ -993,3 +994,54 @@ def test_fn_w_mvreference():
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def test_msvc_conventions():
|
||||
content = """
|
||||
void __cdecl fn();
|
||||
typedef const char* (__stdcall *wglGetExtensionsStringARB_t)(HDC theDeviceContext);
|
||||
"""
|
||||
data = parse_string(content, cleandoc=True)
|
||||
|
||||
assert data == ParsedData(
|
||||
namespace=NamespaceScope(
|
||||
functions=[
|
||||
Function(
|
||||
return_type=Type(
|
||||
typename=PQName(segments=[FundamentalSpecifier(name="void")])
|
||||
),
|
||||
name=PQName(segments=[NameSpecifier(name="fn")]),
|
||||
parameters=[],
|
||||
msvc_convention="__cdecl",
|
||||
)
|
||||
],
|
||||
typedefs=[
|
||||
Typedef(
|
||||
type=Pointer(
|
||||
ptr_to=FunctionType(
|
||||
return_type=Pointer(
|
||||
ptr_to=Type(
|
||||
typename=PQName(
|
||||
segments=[FundamentalSpecifier(name="char")]
|
||||
),
|
||||
const=True,
|
||||
)
|
||||
),
|
||||
parameters=[
|
||||
Parameter(
|
||||
type=Type(
|
||||
typename=PQName(
|
||||
segments=[NameSpecifier(name="HDC")]
|
||||
)
|
||||
),
|
||||
name="theDeviceContext",
|
||||
)
|
||||
],
|
||||
msvc_convention="__stdcall",
|
||||
)
|
||||
),
|
||||
name="wglGetExtensionsStringARB_t",
|
||||
)
|
||||
],
|
||||
)
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user