mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
C++, add support for pointers to member (function)
See sphinx-doc/sphinx#2146
This commit is contained in:
parent
e800fef3d1
commit
0e28d366bc
1
CHANGES
1
CHANGES
@ -18,6 +18,7 @@ Features added
|
||||
* Intersphinx: Added support for fetching Intersphinx inventories with URLs
|
||||
using HTTP basic auth
|
||||
* C++, added support for template parameter in function info field lists.
|
||||
* C++, added support for pointers to member (function).
|
||||
|
||||
Bugs fixed
|
||||
----------
|
||||
|
@ -151,7 +151,7 @@ from sphinx.util.docfields import Field, GroupedField
|
||||
| "& attribute-specifier-seq[opt]
|
||||
| "&&" attribute-specifier-seq[opt]
|
||||
| "::"[opt] nested-name-specifier "*" attribute-specifier-seq[opt]
|
||||
cv-qualifier-seq[opt] # TOOD: not implemented
|
||||
cv-qualifier-seq[opt]
|
||||
# function_object must use a parameters-and-qualifiers, the others may
|
||||
# use it (e.g., function poitners)
|
||||
parameters-and-qualifiers ->
|
||||
@ -1402,9 +1402,14 @@ class ASTDeclaratorPtr(ASTBase):
|
||||
def __unicode__(self):
|
||||
res = ['*']
|
||||
if self.volatile:
|
||||
res.append('volatile ')
|
||||
res.append('volatile')
|
||||
if self.const:
|
||||
res.append('const ')
|
||||
if self.volatile:
|
||||
res.append(' ')
|
||||
res.append('const')
|
||||
if self.const or self.volatile:
|
||||
if self.next.require_space_after_declSpecs:
|
||||
res.append(' ')
|
||||
res.append(text_type(self.next))
|
||||
return u''.join(res)
|
||||
|
||||
@ -1459,6 +1464,18 @@ class ASTDeclaratorPtr(ASTBase):
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
_verify_description_mode(mode)
|
||||
signode += nodes.Text("*")
|
||||
|
||||
def _add_anno(signode, text):
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
if self.volatile:
|
||||
_add_anno(signode, 'volatile')
|
||||
if self.const:
|
||||
if self.volatile:
|
||||
signode += nodes.Text(' ')
|
||||
_add_anno(signode, 'const')
|
||||
if self.const or self.volatile:
|
||||
if self.next.require_space_after_declSpecs:
|
||||
signode += nodes.Text(' ')
|
||||
self.next.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
@ -1571,6 +1588,94 @@ class ASTDeclaratorParamPack(ASTBase):
|
||||
self.next.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
class ASTDeclaratorMemPtr(ASTBase):
|
||||
def __init__(self, className, const, volatile, next):
|
||||
assert className
|
||||
assert next
|
||||
self.className = className
|
||||
self.const = const
|
||||
self.volatile = volatile
|
||||
self.next = next
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.next.name
|
||||
|
||||
def require_space_after_declSpecs(self):
|
||||
return True
|
||||
|
||||
def __unicode__(self):
|
||||
res = []
|
||||
res.append(text_type(self.className))
|
||||
res.append('::*')
|
||||
if self.volatile:
|
||||
res.append(' volatile')
|
||||
if self.const:
|
||||
res.append(' const')
|
||||
if self.next.require_space_after_declSpecs():
|
||||
res.append(' ')
|
||||
res.append(text_type(self.next))
|
||||
return ''.join(res)
|
||||
|
||||
# Id v1 ------------------------------------------------------------------
|
||||
|
||||
def get_modifiers_id_v1(self):
|
||||
raise NoOldIdError()
|
||||
|
||||
def get_param_id_v1(self): # only the parameters (if any)
|
||||
raise NoOldIdError()
|
||||
|
||||
def get_ptr_suffix_id_v1(self):
|
||||
raise NoOldIdError()
|
||||
|
||||
# Id v2 ------------------------------------------------------------------
|
||||
|
||||
def get_modifiers_id_v2(self):
|
||||
return self.next.get_modifiers_id_v2()
|
||||
|
||||
def get_param_id_v2(self): # only the parameters (if any)
|
||||
return self.next.get_param_id_v2()
|
||||
|
||||
def get_ptr_suffix_id_v2(self):
|
||||
raise NotImplementedError()
|
||||
return self.next.get_ptr_suffix_id_v2() + u'Dp'
|
||||
|
||||
def get_type_id_v2(self, returnTypeId):
|
||||
# ReturnType name::* next, so we are part of the return type of next
|
||||
nextReturnTypeId = ''
|
||||
if self.volatile:
|
||||
nextReturnTypeId += 'V'
|
||||
if self.const:
|
||||
nextReturnTypeId += 'K'
|
||||
nextReturnTypeId += 'M'
|
||||
nextReturnTypeId += self.className.get_id_v2()
|
||||
nextReturnTypeId += returnTypeId
|
||||
return self.next.get_type_id_v2(nextReturnTypeId)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
|
||||
def is_function_type(self):
|
||||
return self.next.is_function_type()
|
||||
|
||||
def describe_signature(self, signode, mode, env, symbol):
|
||||
_verify_description_mode(mode)
|
||||
self.className.describe_signature(signode, mode, env, symbol)
|
||||
signode += nodes.Text('::*')
|
||||
|
||||
def _add_anno(signode, text):
|
||||
signode += addnodes.desc_annotation(text, text)
|
||||
if self.volatile:
|
||||
_add_anno(signode, 'volatile')
|
||||
if self.const:
|
||||
if self.volatile:
|
||||
signode += nodes.Text(' ')
|
||||
_add_anno(signode, 'const')
|
||||
if self.next.require_space_after_declSpecs():
|
||||
if self.volatile or self.const:
|
||||
signode += nodes.Text(' ')
|
||||
self.next.describe_signature(signode, mode, env, symbol)
|
||||
|
||||
|
||||
class ASTDeclaratorParen(ASTBase):
|
||||
def __init__(self, inner, next):
|
||||
assert inner
|
||||
@ -2541,6 +2646,30 @@ class DefinitionParser(object):
|
||||
|
||||
self.warnEnv = warnEnv
|
||||
|
||||
def _make_multi_error(self, errors, header):
|
||||
if len(errors) == 1:
|
||||
return DefinitionError(header + '\n' + errors[0][0].description)
|
||||
result = [header, '\n']
|
||||
for e in errors:
|
||||
if len(e[1]) > 0:
|
||||
ident = ' '
|
||||
result.append(e[1])
|
||||
result.append(':\n')
|
||||
for line in e[0].description.split('\n'):
|
||||
if len(line) == 0:
|
||||
continue
|
||||
result.append(ident)
|
||||
result.append(line)
|
||||
result.append('\n')
|
||||
else:
|
||||
result.append(e[0].description)
|
||||
return DefinitionError(''.join(result))
|
||||
|
||||
def status(self, msg):
|
||||
# for debugging
|
||||
indicator = '-' * self.pos + '^'
|
||||
print("%s\n%s\n%s" % (msg, self.definition, indicator))
|
||||
|
||||
def fail(self, msg):
|
||||
indicator = '-' * self.pos + '^'
|
||||
raise DefinitionError(
|
||||
@ -2672,6 +2801,7 @@ class DefinitionParser(object):
|
||||
self.skip_ws()
|
||||
if not self.skip_string('<'):
|
||||
return None
|
||||
prevErrors = []
|
||||
templateArgs = []
|
||||
while 1:
|
||||
pos = self.pos
|
||||
@ -2688,7 +2818,7 @@ class DefinitionParser(object):
|
||||
self.fail('Expected ">" or "," in template argument list.')
|
||||
templateArgs.append(type)
|
||||
except DefinitionError as e:
|
||||
errorType = e.description
|
||||
prevErrors.append((e, "If type argument"))
|
||||
self.pos = pos
|
||||
try:
|
||||
value = self._parse_expression(end=[',', '>'])
|
||||
@ -2701,18 +2831,16 @@ class DefinitionParser(object):
|
||||
self.fail('Expected ">" or "," in template argument list.')
|
||||
templateArgs.append(ASTTemplateArgConstant(value))
|
||||
except DefinitionError as e:
|
||||
errorExpr = e.description
|
||||
msg = "Error in parsing template argument list. " \
|
||||
"Error if type argument:\n%s\n" \
|
||||
"Error if non-type argument:\n%s" \
|
||||
% (errorType, errorExpr)
|
||||
self.fail(msg)
|
||||
self.pos = pos
|
||||
prevErrors.append((e, "If non-type argument"))
|
||||
header = "Error in parsing template argument list."
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
if parsedEnd:
|
||||
assert not parsedComma
|
||||
break
|
||||
return ASTTemplateArgs(templateArgs)
|
||||
|
||||
def _parse_nested_name(self):
|
||||
def _parse_nested_name(self, memberPointer=False):
|
||||
names = []
|
||||
|
||||
self.skip_ws()
|
||||
@ -2728,6 +2856,8 @@ class DefinitionParser(object):
|
||||
names.append(op)
|
||||
else:
|
||||
if not self.match(_identifier_re):
|
||||
if memberPointer and len(names) > 0:
|
||||
break
|
||||
self.fail("Expected identifier in nested name.")
|
||||
identifier = self.matched_text
|
||||
# make sure there isn't a keyword
|
||||
@ -2740,6 +2870,8 @@ class DefinitionParser(object):
|
||||
|
||||
self.skip_ws()
|
||||
if not self.skip_string('::'):
|
||||
if memberPointer:
|
||||
self.fail("Expected '::' in pointer to member (function).")
|
||||
break
|
||||
return ASTNestedName(names, rooted)
|
||||
|
||||
@ -2808,7 +2940,7 @@ class DefinitionParser(object):
|
||||
'parameters_and_qualifiers.')
|
||||
break
|
||||
if paramMode == 'function':
|
||||
arg = self._parse_type_with_init(outer=None, named='maybe')
|
||||
arg = self._parse_type_with_init(outer=None, named='single')
|
||||
else:
|
||||
arg = self._parse_type(named=False)
|
||||
# TODO: parse default parameters # TODO: didn't we just do that?
|
||||
@ -2824,7 +2956,10 @@ class DefinitionParser(object):
|
||||
'Expecting "," or ")" in parameters_and_qualifiers, '
|
||||
'got "%s".' % self.current_char)
|
||||
|
||||
if paramMode != 'function':
|
||||
# TODO: why did we have this bail-out?
|
||||
# does it hurt to parse the extra stuff?
|
||||
# it's needed for pointer to member functions
|
||||
if paramMode != 'function' and False:
|
||||
return ASTParametersQualifiers(
|
||||
args, None, None, None, None, None, None, None)
|
||||
|
||||
@ -2965,26 +3100,27 @@ class DefinitionParser(object):
|
||||
def _parse_declarator_name_param_qual(self, named, paramMode, typed):
|
||||
# now we should parse the name, and then suffixes
|
||||
if named == 'maybe':
|
||||
pos = self.pos
|
||||
try:
|
||||
declId = self._parse_nested_name()
|
||||
except DefinitionError:
|
||||
self.pos = pos
|
||||
declId = None
|
||||
elif named == 'single':
|
||||
if self.match(_identifier_re):
|
||||
identifier = ASTIdentifier(self.matched_text)
|
||||
nne = ASTNestedNameElement(identifier, None)
|
||||
declId = ASTNestedName([nne], rooted=False)
|
||||
# if it's a member pointer, we may have '::', which should be an error
|
||||
self.skip_ws()
|
||||
if self.current_char == ':':
|
||||
self.fail("Unexpected ':' after identifier.")
|
||||
else:
|
||||
declId = None
|
||||
elif named:
|
||||
declId = self._parse_nested_name()
|
||||
else:
|
||||
declId = None
|
||||
self.skip_ws()
|
||||
if typed and declId:
|
||||
if self.skip_string("*"):
|
||||
self.fail("Member pointers not implemented.")
|
||||
|
||||
arrayOps = []
|
||||
while 1:
|
||||
self.skip_ws()
|
||||
@ -3005,6 +3141,7 @@ class DefinitionParser(object):
|
||||
if paramMode not in ('type', 'function', 'operatorCast'):
|
||||
raise Exception(
|
||||
"Internal error, unknown paramMode '%s'." % paramMode)
|
||||
prevErrors = []
|
||||
self.skip_ws()
|
||||
if typed and self.skip_string('*'):
|
||||
self.skip_ws()
|
||||
@ -3023,13 +3160,39 @@ class DefinitionParser(object):
|
||||
next = self._parse_declerator(named, paramMode, typed)
|
||||
return ASTDeclaratorPtr(next=next, volatile=volatile, const=const)
|
||||
# TODO: shouldn't we parse an R-value ref here first?
|
||||
elif typed and self.skip_string("&"):
|
||||
if typed and self.skip_string("&"):
|
||||
next = self._parse_declerator(named, paramMode, typed)
|
||||
return ASTDeclaratorRef(next=next)
|
||||
elif typed and self.skip_string("..."):
|
||||
if typed and self.skip_string("..."):
|
||||
next = self._parse_declerator(named, paramMode, False)
|
||||
return ASTDeclaratorParamPack(next=next)
|
||||
elif typed and self.current_char == '(': # note: peeking, not skipping
|
||||
if typed: # pointer to member
|
||||
pos = self.pos
|
||||
try:
|
||||
name = self._parse_nested_name(memberPointer=True)
|
||||
self.skip_ws()
|
||||
if not self.skip_string('*'):
|
||||
self.fail("Expected '*' in pointer to member declarator.")
|
||||
self.skip_ws()
|
||||
except DefinitionError as e:
|
||||
self.pos = pos
|
||||
prevErrors.append((e, "If pointer to member declarator"))
|
||||
else:
|
||||
volatile = False
|
||||
const = False
|
||||
while 1:
|
||||
if not volatile:
|
||||
volatile = self.skip_word_and_ws('volatile')
|
||||
if volatile:
|
||||
continue
|
||||
if not const:
|
||||
const = self.skip_word_and_ws('const')
|
||||
if const:
|
||||
continue
|
||||
break
|
||||
next = self._parse_declerator(named, paramMode, typed)
|
||||
return ASTDeclaratorMemPtr(name, const, volatile, next=next)
|
||||
if typed and self.current_char == '(': # note: peeking, not skipping
|
||||
if paramMode == "operatorCast":
|
||||
# TODO: we should be able to parse cast operators which return
|
||||
# function pointers. For now, just hax it and ignore.
|
||||
@ -3037,14 +3200,15 @@ class DefinitionParser(object):
|
||||
paramQual=None)
|
||||
# maybe this is the beginning of params and quals,try that first,
|
||||
# otherwise assume it's noptr->declarator > ( ptr-declarator )
|
||||
startPos = self.pos
|
||||
pos = self.pos
|
||||
try:
|
||||
# assume this is params and quals
|
||||
res = self._parse_declarator_name_param_qual(named, paramMode,
|
||||
typed)
|
||||
return res
|
||||
except DefinitionError as exParamQual:
|
||||
self.pos = startPos
|
||||
prevErrors.append((exParamQual, "If declId, parameters, and qualifiers"))
|
||||
self.pos = pos
|
||||
try:
|
||||
assert self.current_char == '('
|
||||
self.skip_string('(')
|
||||
@ -3059,13 +3223,18 @@ class DefinitionParser(object):
|
||||
typed=typed)
|
||||
return ASTDeclaratorParen(inner=inner, next=next)
|
||||
except DefinitionError as exNoPtrParen:
|
||||
raise DefinitionError(
|
||||
"If declId, parameters, and qualifiers {\n%s\n"
|
||||
"} else If parenthesis in noptr-declarator {\n%s\n}"
|
||||
% (exParamQual, exNoPtrParen))
|
||||
else:
|
||||
return self._parse_declarator_name_param_qual(named, paramMode,
|
||||
typed)
|
||||
self.pos = pos
|
||||
prevErrors.append((exNoPtrParen, "If parenthesis in noptr-declarator"))
|
||||
header = "Error in declarator"
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
pos = self.pos
|
||||
try:
|
||||
return self._parse_declarator_name_param_qual(named, paramMode, typed)
|
||||
except DefinitionError as e:
|
||||
self.pos = pos
|
||||
prevErrors.append((e, "If declarator-id"))
|
||||
header = "Error in declarator or parameters and qualifiers"
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
|
||||
def _parse_initializer(self, outer=None):
|
||||
self.skip_ws()
|
||||
@ -3102,6 +3271,7 @@ class DefinitionParser(object):
|
||||
# We allow type objects to just be a name.
|
||||
# Some functions don't have normal return types: constructors,
|
||||
# destrutors, cast operators
|
||||
prevErrors = []
|
||||
startPos = self.pos
|
||||
# first try without the type
|
||||
try:
|
||||
@ -3110,37 +3280,49 @@ class DefinitionParser(object):
|
||||
typed=False)
|
||||
self.assert_end()
|
||||
except DefinitionError as exUntyped:
|
||||
if outer == 'type':
|
||||
desc = "If just a name"
|
||||
elif outer == 'function':
|
||||
desc = "If the function has no return type"
|
||||
else:
|
||||
assert False
|
||||
prevErrors.append((exUntyped, desc))
|
||||
self.pos = startPos
|
||||
try:
|
||||
declSpecs = self._parse_decl_specs(outer=outer)
|
||||
decl = self._parse_declerator(named=True, paramMode=outer)
|
||||
except DefinitionError as exTyped:
|
||||
self.pos = startPos
|
||||
if outer == 'type':
|
||||
desc = "If typedef-like declaration"
|
||||
elif outer == 'function':
|
||||
desc = "If the function has a return type"
|
||||
else:
|
||||
assert False
|
||||
prevErrors.append((exTyped, desc))
|
||||
# Retain the else branch for easier debugging.
|
||||
# TODO: it would be nice to save the previous stacktrace
|
||||
# and output it here.
|
||||
if True:
|
||||
if outer == 'type':
|
||||
desc = ('Type must be either just a name or a '
|
||||
'typedef-like declaration.\n'
|
||||
'Just a name error: %s\n'
|
||||
'Typedef-like expression error: %s')
|
||||
header = "Type must be either just a name or a "
|
||||
header += "typedef-like declaration."
|
||||
elif outer == 'function':
|
||||
desc = ('Error when parsing function declaration:\n'
|
||||
'If no return type {\n%s\n'
|
||||
'} else if return type {\n%s\n}')
|
||||
header = "Error when parsing function declaration."
|
||||
else:
|
||||
assert False
|
||||
raise DefinitionError(
|
||||
desc % (exUntyped.description, exTyped.description))
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
else:
|
||||
# For testing purposes.
|
||||
# do it again to get the proper traceback (how do you
|
||||
# relieable save a traceback when an exception is
|
||||
# constructed?)
|
||||
pass
|
||||
self.pos = startPos
|
||||
declSpecs = self._parse_decl_specs(outer=outer, typed=False)
|
||||
typed = True
|
||||
declSpecs = self._parse_decl_specs(outer=outer, typed=typed)
|
||||
decl = self._parse_declerator(named=True, paramMode=outer,
|
||||
typed=False)
|
||||
typed=typed)
|
||||
else:
|
||||
paramMode = 'type'
|
||||
if outer == 'member': # i.e., member
|
||||
@ -3226,7 +3408,7 @@ class DefinitionParser(object):
|
||||
if not self.skip_string("<"):
|
||||
self.fail("Expected '<' after 'template'")
|
||||
while 1:
|
||||
extraError = ''
|
||||
prevErrors = []
|
||||
self.skip_ws()
|
||||
if self.skip_word('template'):
|
||||
# declare a tenplate template parameter
|
||||
@ -3272,19 +3454,20 @@ class DefinitionParser(object):
|
||||
param = self._parse_type_with_init('maybe', 'templateParam')
|
||||
templateParams.append(ASTTemplateParamNonType(param))
|
||||
except DefinitionError as e:
|
||||
prevErrors.append((e, "If non-type template parameter"))
|
||||
self.pos = pos
|
||||
extraError = "Error if non-type template parameter: %s"
|
||||
extraError = extraError % e.description
|
||||
self.skip_ws()
|
||||
if self.skip_string('>'):
|
||||
return ASTTemplateParams(templateParams)
|
||||
elif self.skip_string(','):
|
||||
continue
|
||||
else:
|
||||
msg = 'Expected "=", ",", or ">" in template parameter list.'
|
||||
if len(extraError) > 0:
|
||||
msg += '\n%s' % extraError
|
||||
self.fail(msg)
|
||||
header = "Error in template parameter list."
|
||||
try:
|
||||
self.fail('Expected "=", ",", or ">".')
|
||||
except DefinitionError as e:
|
||||
prevErrors.append((e, ""))
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
|
||||
def _parse_template_declaration_prefix(self):
|
||||
templates = []
|
||||
@ -3347,25 +3530,23 @@ class DefinitionParser(object):
|
||||
templatePrefix = self._parse_template_declaration_prefix()
|
||||
|
||||
if objectType == 'type':
|
||||
error = None
|
||||
prevErrors = []
|
||||
pos = self.pos
|
||||
try:
|
||||
if not templatePrefix:
|
||||
declaration = self._parse_type(named=True, outer='type')
|
||||
except DefinitionError as e:
|
||||
error = e.description
|
||||
prevErrors.append((e, "If typedef-like declaration"))
|
||||
self.pos = pos
|
||||
pos = self.pos
|
||||
try:
|
||||
if not declaration:
|
||||
declaration = self._parse_type_using()
|
||||
except DefinitionError as e:
|
||||
if error:
|
||||
msg = "Error if typedef:\n%s\n" \
|
||||
"Error if type alias or template alias:\n%s" \
|
||||
% (error, e.description)
|
||||
raise DefinitionError(msg)
|
||||
else:
|
||||
raise e
|
||||
self.pos = pos
|
||||
prevErrors.append((e, "If type alias or template alias"))
|
||||
header = "Error in type declaration."
|
||||
raise self._make_multi_error(prevErrors, header)
|
||||
elif objectType == 'member':
|
||||
declaration = self._parse_type_with_init(named=True, outer='member')
|
||||
elif objectType == 'function':
|
||||
|
@ -78,6 +78,27 @@ def check(name, input, idv1output=None, idv2output=None, output=None):
|
||||
#print ".. %s:: %s" % (name, input)
|
||||
|
||||
|
||||
def test_fundamental_types():
|
||||
# see http://en.cppreference.com/w/cpp/language/types
|
||||
for t, id_v2 in cppDomain._id_fundamental_v2.items():
|
||||
if t == "decltype(auto)":
|
||||
continue
|
||||
|
||||
def makeIdV1():
|
||||
id = t.replace(" ", "-").replace("long", "l").replace("int", "i")
|
||||
id = id.replace("bool", "b").replace("char", "c")
|
||||
id = id.replace("wc_t", "wchar_t").replace("c16_t", "char16_t")
|
||||
id = id.replace("c32_t", "char32_t")
|
||||
return "f__%s" % id
|
||||
|
||||
def makeIdV2():
|
||||
id = id_v2
|
||||
if t == "std::nullptr_t":
|
||||
id = "NSt9nullptr_tE"
|
||||
return "1f%s" % id
|
||||
check("function", "void f(%s arg)" % t, makeIdV1(), makeIdV2())
|
||||
|
||||
|
||||
def test_type_definitions():
|
||||
check("type", "public bool b", "b", "1b", "bool b")
|
||||
check("type", "bool A::b", "A::b", "N1A1bE")
|
||||
@ -107,6 +128,10 @@ def test_type_definitions():
|
||||
# test name in global scope
|
||||
check("type", "bool ::B::b", "B::b", "N1B1bE")
|
||||
|
||||
check('type', 'A = B', None, '1A')
|
||||
|
||||
|
||||
def test_member_definitions():
|
||||
check('member', ' const std::string & name = 42',
|
||||
"name__ssCR", "4name", output='const std::string &name = 42')
|
||||
check('member', ' const std::string & name', "name__ssCR", "4name",
|
||||
@ -117,7 +142,10 @@ def test_type_definitions():
|
||||
"name__std::vector:unsigned-i.l:CR",
|
||||
"4name", output='const std::vector<unsigned int, long> &name')
|
||||
check('member', 'module::myclass foo[n]', "foo__module::myclassA", "3foo")
|
||||
check('member', 'int *const p', 'p__iPC', '1p')
|
||||
|
||||
|
||||
def test_function_definitions():
|
||||
check('function', 'operator bool() const', "castto-b-operatorC", "NKcvbEv")
|
||||
check('function', 'A::operator bool() const',
|
||||
"A::castto-b-operatorC", "NK1AcvbEv")
|
||||
@ -223,6 +251,8 @@ def test_type_definitions():
|
||||
"A::f__doubleC", "NK1A1fEd")
|
||||
check("function", "void f(std::shared_ptr<int(double)> ptr)",
|
||||
None, "1fNSt10shared_ptrIFidEEE")
|
||||
check("function", "void f(int *const p)", "f__iPC", "1fPCi")
|
||||
check("function", "void f(int *volatile const p)", "f__iPVC", "1fPVCi")
|
||||
|
||||
# TODO: make tests for functions in a template, e.g., Test<int&&()>
|
||||
# such that the id generation for function type types is correct.
|
||||
@ -237,9 +267,72 @@ def test_type_definitions():
|
||||
check('function', 'void f(enum E e)', 'f__E', '1f1E')
|
||||
check('function', 'void f(union E e)', 'f__E', '1f1E')
|
||||
|
||||
# pointer to member (function)
|
||||
check('function', 'void f(int C::*)', None, '1fM1Ci')
|
||||
check('function', 'void f(int C::* p)', None, '1fM1Ci')
|
||||
check('function', 'void f(int ::C::* p)', None, '1fM1Ci')
|
||||
check('function', 'void f(int C::* const)', None, '1fKM1Ci')
|
||||
check('function', 'void f(int C::* const&)', None, '1fRKM1Ci')
|
||||
check('function', 'void f(int C::* volatile)', None, '1fVM1Ci')
|
||||
check('function', 'void f(int C::* const volatile)', None, '1fVKM1Ci',
|
||||
output='void f(int C::* volatile const)')
|
||||
check('function', 'void f(int C::* volatile const)', None, '1fVKM1Ci')
|
||||
check('function', 'void f(int (C::*)(float, double))', None, '1fM1CFifdE')
|
||||
check('function', 'void f(int (C::* p)(float, double))', None, '1fM1CFifdE')
|
||||
check('function', 'void f(int (::C::* p)(float, double))', None, '1fM1CFifdE')
|
||||
check('function', 'void f(void (C::*)() const &)', None, '1fM1CKRFvvE')
|
||||
check('function', 'int C::* f(int, double)', None, '1fid')
|
||||
check('function', 'void f(int C::* *)', None, '1fPM1Ci')
|
||||
|
||||
|
||||
def test_operators():
|
||||
check('function', 'void operator new [ ] ()',
|
||||
"new-array-operator", "nav", output='void operator new[]()')
|
||||
check('function', 'void operator delete ()',
|
||||
"delete-operator", "dlv", output='void operator delete()')
|
||||
check('function', 'operator bool() const',
|
||||
"castto-b-operatorC", "NKcvbEv", output='operator bool() const')
|
||||
|
||||
check('function', 'void operator * ()',
|
||||
"mul-operator", "mlv", output='void operator*()')
|
||||
check('function', 'void operator - ()',
|
||||
"sub-operator", "miv", output='void operator-()')
|
||||
check('function', 'void operator + ()',
|
||||
"add-operator", "plv", output='void operator+()')
|
||||
check('function', 'void operator = ()',
|
||||
"assign-operator", "aSv", output='void operator=()')
|
||||
check('function', 'void operator / ()',
|
||||
"div-operator", "dvv", output='void operator/()')
|
||||
check('function', 'void operator % ()',
|
||||
"mod-operator", "rmv", output='void operator%()')
|
||||
check('function', 'void operator ! ()',
|
||||
"not-operator", "ntv", output='void operator!()')
|
||||
|
||||
check('function', 'void operator "" _udl()',
|
||||
None, 'li4_udlv', output='void operator""_udl()')
|
||||
|
||||
|
||||
def test_class_definitions():
|
||||
check('class', 'public A', "A", "1A", output='A')
|
||||
check('class', 'private A', "A", "1A")
|
||||
check('class', 'A final', 'A', '1A')
|
||||
|
||||
# test bases
|
||||
check('class', 'A', "A", "1A")
|
||||
check('class', 'A::B::C', "A::B::C", "N1A1B1CE")
|
||||
check('class', 'A : B', "A", "1A")
|
||||
check('class', 'A : private B', "A", "1A", output='A : B')
|
||||
check('class', 'A : public B', "A", "1A")
|
||||
check('class', 'A : B, C', "A", "1A")
|
||||
check('class', 'A : B, protected C, D', "A", "1A")
|
||||
check('class', 'A : virtual private B', 'A', '1A', output='A : virtual B')
|
||||
check('class', 'A : B, virtual C', 'A', '1A')
|
||||
check('class', 'A : public virtual B', 'A', '1A')
|
||||
check('class', 'A : B, C...', 'A', '1A')
|
||||
check('class', 'A : B..., C', 'A', '1A')
|
||||
|
||||
|
||||
def test_enum_definitions():
|
||||
check('enum', 'A', None, "1A")
|
||||
check('enum', 'A : std::underlying_type<B>::type', None, "1A")
|
||||
check('enum', 'A : unsigned int', None, "1A")
|
||||
@ -250,29 +343,6 @@ def test_type_definitions():
|
||||
check('enumerator', 'A = std::numeric_limits<unsigned long>::max()',
|
||||
None, "1A")
|
||||
|
||||
check('type', 'A = B', None, '1A')
|
||||
|
||||
|
||||
def test_fundamental_types():
|
||||
# see http://en.cppreference.com/w/cpp/language/types
|
||||
for t, id_v2 in cppDomain._id_fundamental_v2.items():
|
||||
if t == "decltype(auto)":
|
||||
continue
|
||||
|
||||
def makeIdV1():
|
||||
id = t.replace(" ", "-").replace("long", "l").replace("int", "i")
|
||||
id = id.replace("bool", "b").replace("char", "c")
|
||||
id = id.replace("wc_t", "wchar_t").replace("c16_t", "char16_t")
|
||||
id = id.replace("c32_t", "char32_t")
|
||||
return "f__%s" % id
|
||||
|
||||
def makeIdV2():
|
||||
id = id_v2
|
||||
if t == "std::nullptr_t":
|
||||
id = "NSt9nullptr_tE"
|
||||
return "1f%s" % id
|
||||
check("function", "void f(%s arg)" % t, makeIdV1(), makeIdV2())
|
||||
|
||||
|
||||
def test_templates():
|
||||
check('class', "A<T>", None, "IE1AI1TE", output="template<> A<T>")
|
||||
@ -318,51 +388,6 @@ def test_templates():
|
||||
"RK18c_string_view_baseIK4Char6TraitsE")
|
||||
|
||||
|
||||
def test_class():
|
||||
check('class', 'A final', 'A', '1A')
|
||||
|
||||
|
||||
def test_bases():
|
||||
check('class', 'A', "A", "1A")
|
||||
check('class', 'A::B::C', "A::B::C", "N1A1B1CE")
|
||||
check('class', 'A : B', "A", "1A")
|
||||
check('class', 'A : private B', "A", "1A", output='A : B')
|
||||
check('class', 'A : public B', "A", "1A")
|
||||
check('class', 'A : B, C', "A", "1A")
|
||||
check('class', 'A : B, protected C, D', "A", "1A")
|
||||
check('class', 'A : virtual private B', 'A', '1A', output='A : virtual B')
|
||||
check('class', 'A : B, virtual C', 'A', '1A')
|
||||
check('class', 'A : public virtual B', 'A', '1A')
|
||||
check('class', 'A : B, C...', 'A', '1A')
|
||||
check('class', 'A : B..., C', 'A', '1A')
|
||||
|
||||
|
||||
def test_operators():
|
||||
check('function', 'void operator new [ ] ()',
|
||||
"new-array-operator", "nav", output='void operator new[]()')
|
||||
check('function', 'void operator delete ()',
|
||||
"delete-operator", "dlv", output='void operator delete()')
|
||||
check('function', 'operator bool() const',
|
||||
"castto-b-operatorC", "NKcvbEv", output='operator bool() const')
|
||||
|
||||
check('function', 'void operator * ()',
|
||||
"mul-operator", "mlv", output='void operator*()')
|
||||
check('function', 'void operator - ()',
|
||||
"sub-operator", "miv", output='void operator-()')
|
||||
check('function', 'void operator + ()',
|
||||
"add-operator", "plv", output='void operator+()')
|
||||
check('function', 'void operator = ()',
|
||||
"assign-operator", "aSv", output='void operator=()')
|
||||
check('function', 'void operator / ()',
|
||||
"div-operator", "dvv", output='void operator/()')
|
||||
check('function', 'void operator % ()',
|
||||
"mod-operator", "rmv", output='void operator%()')
|
||||
check('function', 'void operator ! ()',
|
||||
"not-operator", "ntv", output='void operator!()')
|
||||
|
||||
check('function', 'void operator "" _udl()',
|
||||
None, 'li4_udlv', output='void operator""_udl()')
|
||||
|
||||
#def test_print():
|
||||
# # used for getting all the ids out for checking
|
||||
# for a in ids:
|
||||
|
Loading…
Reference in New Issue
Block a user