mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
C++, fixes to id generation.
New ids are prefixed with "_CPPv1". Replacing the prefix with "_Z" should yield a valid mangled name following the Itanium C++ ABI, except for expressions, which are currently not handled.
This commit is contained in:
parent
f4cf30b95e
commit
fb3a524a90
@ -189,7 +189,6 @@ _operator_re = re.compile(r'''(?x)
|
||||
# Id v1 constants
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
_id_prefix_v1 = '_CPP'
|
||||
_id_fundamental_v1 = {
|
||||
'char': 'c',
|
||||
'signed char': 'c',
|
||||
@ -264,7 +263,7 @@ _id_operator_v1 = {
|
||||
# Id v2 constants
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
_id_prefix_v2 = '_CPP'
|
||||
_id_prefix_v2 = '_CPPv2'
|
||||
_id_fundamental_v2 = {
|
||||
# not all of these are actually parsed as fundamental types, TODO: do that
|
||||
'void': 'v',
|
||||
@ -517,6 +516,9 @@ class ASTNestedNameElement(ASTBase):
|
||||
res = []
|
||||
if self.identifier == "std":
|
||||
res.append(u'St')
|
||||
elif self.identifier[0] == "~":
|
||||
# a destructor, just use an arbitrary version of dtors
|
||||
res.append("D0")
|
||||
else:
|
||||
res.append(text_type(len(self.identifier)))
|
||||
res.append(self.identifier)
|
||||
@ -591,13 +593,14 @@ class ASTNestedName(ASTBase):
|
||||
res.append(n.get_id_v1())
|
||||
return u'::'.join(res)
|
||||
|
||||
def get_id_v2(self):
|
||||
def get_id_v2(self, modifiers=""):
|
||||
res = []
|
||||
if len(self.names) > 1:
|
||||
if len(self.names) > 1 or len(modifiers) > 0:
|
||||
res.append('N')
|
||||
res.append(modifiers)
|
||||
for n in self.names:
|
||||
res.append(n.get_id_v2())
|
||||
if len(self.names) > 1:
|
||||
if len(self.names) > 1 or len(modifiers) > 0:
|
||||
res.append('E')
|
||||
return u''.join(res)
|
||||
|
||||
@ -867,6 +870,17 @@ class ASTDeclSpecsSimple(ASTBase):
|
||||
self.volatile = volatile
|
||||
self.const = const
|
||||
|
||||
def mergeWith(self, other):
|
||||
if not other:
|
||||
return self
|
||||
return ASTDeclSpecsSimple(self.storage or other.storage,
|
||||
self.inline or other.inline,
|
||||
self.virtual or other.virtual,
|
||||
self.explicit or other.explicit,
|
||||
self.constexpr or other.constexpr,
|
||||
self.volatile or other.volatile,
|
||||
self.const or other.const)
|
||||
|
||||
def __unicode__(self):
|
||||
res = []
|
||||
if self.storage:
|
||||
@ -905,12 +919,16 @@ class ASTDeclSpecsSimple(ASTBase):
|
||||
if self.const:
|
||||
_add(modifiers, 'const')
|
||||
|
||||
|
||||
class ASTDeclSpecs(ASTBase):
|
||||
def __init__(self, outer, visibility, leftSpecs, rightSpecs, trailing):
|
||||
# leftSpecs and rightSpecs are used for output
|
||||
# allSpecs are used for id generation
|
||||
self.outer = outer
|
||||
self.visibility = visibility
|
||||
self.leftSpecs = leftSpecs
|
||||
self.rightSpecs = rightSpecs
|
||||
self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
|
||||
self.trailingTypeSpec = trailing
|
||||
|
||||
@property
|
||||
@ -920,9 +938,9 @@ class ASTDeclSpecs(ASTBase):
|
||||
def get_id_v1(self):
|
||||
res = []
|
||||
res.append(self.trailingTypeSpec.get_id_v1())
|
||||
if self.leftSpecs.volatile or self.rightSpecs.volatile:
|
||||
if self.allSpecs.volatile:
|
||||
res.append('V')
|
||||
if self.leftSpecs.const or self.rightSpecs.const:
|
||||
if self.allSpecs.const:
|
||||
res.append('C')
|
||||
return u''.join(res)
|
||||
|
||||
@ -986,6 +1004,7 @@ class ASTDeclSpecs(ASTBase):
|
||||
for m in modifiers:
|
||||
signode += m
|
||||
|
||||
|
||||
class ASTPtrOpPtr(ASTBase):
|
||||
def __init__(self, volatile, const):
|
||||
self.volatile = volatile
|
||||
@ -1194,8 +1213,8 @@ class ASTType(ASTBase):
|
||||
if self.objectType: # needs the name
|
||||
res.append(_id_prefix_v2)
|
||||
if self.objectType == 'function': # also modifiers
|
||||
res.append(self.decl.get_modifiers_id_v2())
|
||||
res.append(self.prefixedName.get_id_v2())
|
||||
modifiers = self.decl.get_modifiers_id_v2()
|
||||
res.append(self.prefixedName.get_id_v2(modifiers))
|
||||
res.append(self.decl.get_param_id_v2())
|
||||
elif self.objectType == 'type': # just the name
|
||||
res.append(self.prefixedName.get_id_v2())
|
||||
@ -1225,6 +1244,7 @@ class ASTType(ASTBase):
|
||||
signode += nodes.Text(' ')
|
||||
self.decl.describe_signature(signode, mode, env)
|
||||
|
||||
|
||||
class ASTTypeWithInit(ASTBase):
|
||||
def __init__(self, type, init):
|
||||
self.objectType = None
|
||||
@ -1939,7 +1959,7 @@ class CPPObject(ObjectDescription):
|
||||
ast.get_id_v2(),
|
||||
ast.get_id_v1()
|
||||
]
|
||||
theid = ids[1] # TODO: change to [0] before final version
|
||||
theid = ids[0]
|
||||
name = text_type(ast.prefixedName)
|
||||
if theid not in self.state.document.ids:
|
||||
# if the name is not unique, the first one will win
|
||||
|
@ -15,6 +15,8 @@ from util import raises
|
||||
|
||||
from sphinx.domains.cpp import DefinitionParser, DefinitionError
|
||||
|
||||
ids = []
|
||||
|
||||
def parse(name, string):
|
||||
parser = DefinitionParser(string)
|
||||
res = getattr(parser, "parse_" + name + "_object")()
|
||||
@ -37,10 +39,12 @@ def check(name, input, output=None):
|
||||
print("Expected: ", output)
|
||||
raise DefinitionError("")
|
||||
ast.describe_signature([], 'lastIsName', None)
|
||||
ast.prefixedName = ast.name # otherwise the get_id fails, it would be set
|
||||
# in handle_signarue
|
||||
# Artificially set the prefixedName, otherwise the get_id fails.
|
||||
# It would usually have been set in handle_signarue.
|
||||
ast.prefixedName = ast.name
|
||||
ast.get_id_v1()
|
||||
ast.get_id_v2()
|
||||
ids.append(ast.get_id_v2())
|
||||
#print ".. %s:: %s" % (name, input)
|
||||
|
||||
def test_type_definitions():
|
||||
@ -79,6 +83,9 @@ def test_type_definitions():
|
||||
check('member', 'module::myclass foo[n]')
|
||||
|
||||
check('function', 'operator bool() const')
|
||||
check('function', 'A::operator bool() const')
|
||||
check('function', 'A::operator bool() volatile const &')
|
||||
check('function', 'A::operator bool() volatile const &&')
|
||||
check('function', 'bool namespaced::theclass::method(arg1, arg2)')
|
||||
x = 'std::vector<std::pair<std::string, int>> &module::test(register ' \
|
||||
'foo, bar, std::string baz = "foobar, blah, bleh") const = 0'
|
||||
@ -99,6 +106,7 @@ def test_type_definitions():
|
||||
check('function', 'static constexpr int get_value()')
|
||||
check('function', 'int get_value() const noexcept')
|
||||
check('function', 'int get_value() const noexcept = delete')
|
||||
check('function', 'int get_value() volatile const')
|
||||
check('function', 'MyClass::MyClass(MyClass::MyClass&&) = default')
|
||||
check('function', 'virtual MyClass::a_virtual_function() const override')
|
||||
check('function', 'A B() override')
|
||||
@ -142,3 +150,9 @@ def test_operators():
|
||||
check('function', 'void operator bool() const', 'void operator bool() const')
|
||||
for op in '*-+=/%!':
|
||||
check('function', 'void operator %s ()' % op, 'void operator%s()' % op)
|
||||
|
||||
#def test_print():
|
||||
# # used for getting all the ids out for checking
|
||||
# for a in ids:
|
||||
# print(a)
|
||||
# raise DefinitionError("")
|
Loading…
Reference in New Issue
Block a user