C++, fix namespacing of elements and xrefs.

This commit is contained in:
Jakob Lykke Andersen 2014-07-24 11:09:28 +02:00
parent 967ca06545
commit caad958de4
2 changed files with 36 additions and 38 deletions

View File

@ -257,15 +257,7 @@ class ASTBase(UnicodeMixin):
""" """
raise NotImplementedError(repr(self)) raise NotImplementedError(repr(self))
def split_owner(self): def prefix_nested_name(self, prefix):
"""Nodes returned by :meth:`get_name` can split off their
owning parent. This function returns the owner and the
name as a tuple of two items. If a node does not support
it, it returns None as owner and self as name.
"""
raise NotImplementedError(repr(self))
def prefix(self, prefix):
"""Prefix a name node (a node returned by :meth:`get_name`).""" """Prefix a name node (a node returned by :meth:`get_name`)."""
raise NotImplementedError(repr(self)) raise NotImplementedError(repr(self))
@ -276,10 +268,12 @@ class ASTBase(UnicodeMixin):
return '<%s %s>' % (self.__class__.__name__, self) return '<%s %s>' % (self.__class__.__name__, self)
def _verify_parsing_context(context): def _verify_parsing_context(context):
assert context in {'typeObject', 'functionObject', 'memberObject', 'classObject', 'namespaceObject', 'xrefObject', 'abstractDecl', 'functionObjectArgument', 'baseClass'} if not context in {'typeObject', 'functionObject', 'memberObject', 'classObject', 'namespaceObject', 'xrefObject', 'abstractDecl', 'functionObjectArgument', 'baseClass'}:
raise Exception("Parsing context '%s' is invalid." % context)
def _verify_description_mod(mode): def _verify_description_mod(mode):
assert mode in {'lastIsName', 'allIsName', 'noneIsName', 'markType'} if not mode in {'lastIsName', 'allIsName', 'noneIsName', 'markType'}:
raise Exception("Description mode '%s' is invalid." % mode)
class ASTOperatorBuildIn(ASTBase): class ASTOperatorBuildIn(ASTBase):
@ -371,10 +365,11 @@ class ASTNestedName(ASTBase):
def name(self): def name(self):
return self return self
def prefix(self, prefix): def prefix_nested_name(self, prefix):
if self.names[0] == '': if self.names[0] == '':
raise DefinitionError('Can not prefix nested name rooted in outer-most namespace.') return self # it's defined at global namespace, don't tuch it
names = [prefix] assert isinstance(prefix, ASTNestedName)
names = prefix.names[:]
names.extend(self.names) names.extend(self.names)
return ASTNestedName(names) return ASTNestedName(names)
@ -669,10 +664,12 @@ class ASTType(ASTBase):
def get_id(self): def get_id(self):
res = ['___'] res = ['___']
res.append(text_type(self.name)) res.append(text_type(self.prefixedName))
if self.objectType == 'function': if self.objectType == 'function':
res.append('___') res.append('___')
res.append(self.decl.get_param_id()) res.append(self.decl.get_param_id())
elif self.objectType == 'type':
pass
else: else:
print(self.objectType) print(self.objectType)
assert False assert False
@ -711,7 +708,7 @@ class ASTTypeWithInit(ASTBase):
def get_id(self): def get_id(self):
if self.objectType == 'member': if self.objectType == 'member':
return text_type(self.name) return "___" + text_type(self.prefixedName)
else: else:
raise NotImplementedError("Should this happen? %s, %s" % (self.objectType, text_type(self.name))) raise NotImplementedError("Should this happen? %s, %s" % (self.objectType, text_type(self.name)))
@ -1133,12 +1130,12 @@ class DefinitionParser(object):
if context == 'abstractDecl': if context == 'abstractDecl':
declId = None declId = None
elif context == 'functionObjectArgument' \ elif context in {'functionObjectArgument', 'functionObject', 'typeObject'}:
or context == 'functionObject':
# Function arguments don't need to have a name. # Function arguments don't need to have a name.
# Some functions (constructors/destructors) don't ahve return type, # Some functions (constructors/destructors) don't ahve return type,
# so the name has been parsed in the declSpecs. # so the name has been parsed in the declSpecs.
# Also conversion operators (e.g., "A::operator std::string()" will have no declId at this point # Also conversion operators (e.g., "A::operator std::string()" will have no declId at this point
# For types we want to allow the plain declaration that there is a type, i.e., "MyContainer::const_iterator"
pos = self.pos pos = self.pos
try: try:
declId = self._parse_nested_name(context) declId = self._parse_nested_name(context)
@ -1291,23 +1288,12 @@ class CPPObject(ObjectDescription):
self.state.document.note_explicit_target(signode) self.state.document.note_explicit_target(signode)
if not name in objects: if not name in objects:
objects.setdefault(name, (self.env.docname, ast.objectType, theid)) objects.setdefault(name, (self.env.docname, ast.objectType, theid))
self.env.temp_data['cpp:lastname'] = ast.prefixedName
indextext = self.get_index_text(name) indextext = self.get_index_text(name)
if indextext: if indextext:
self.indexnode['entries'].append(('single', indextext, theid, '')) self.indexnode['entries'].append(('single', indextext, theid, ''))
def before_content(self):
lastname = self.names and self.names[-1]
if lastname and not self.env.temp_data.get('cpp:parent'):
self.env.temp_data['cpp:parent'] = lastname.name
self.parentname_set = True
else:
self.parentname_set = False
def after_content(self):
if self.parentname_set:
self.env.temp_data['cpp:parent'] = None
def parse_definition(self, parser): def parse_definition(self, parser):
raise NotImplementedError() raise NotImplementedError()
@ -1325,9 +1311,9 @@ class CPPObject(ObjectDescription):
self.describe_signature(signode, ast) self.describe_signature(signode, ast)
parent = self.env.temp_data.get('cpp:parent') parent = self.env.temp_data.get('cpp:parent')
if parent is not None: if parent and len(parent) > 0:
ast = ast.clone() ast = ast.clone()
ast.prefixedName = ast.name.prefix(parent) ast.prefixedName = ast.name.prefix_nested_name(parent[-1])
else: else:
ast.prefixedName = ast.name ast.prefixedName = ast.name
return ast return ast
@ -1342,7 +1328,7 @@ class CPPTypeObject(CPPObject):
def describe_signature(self, signode, ast): def describe_signature(self, signode, ast):
signode += addnodes.desc_annotation('type ', 'type ') signode += addnodes.desc_annotation('type ', 'type ')
ast.describe_signature(signode, 'typeObject', self.env) ast.describe_signature(signode, 'lastIsName', self.env)
class CPPMemberObject(CPPObject): class CPPMemberObject(CPPObject):
@ -1371,6 +1357,14 @@ class CPPClassObject(CPPObject):
def get_index_text(self, name): def get_index_text(self, name):
return _('%s (C++ class)') % name return _('%s (C++ class)') % name
def before_content(self):
lastname = self.env.temp_data['cpp:lastname']
assert lastname
self.env.temp_data['cpp:parent'].append(lastname)
def after_content(self):
self.env.temp_data['cpp:parent'].pop()
def parse_definition(self, parser): def parse_definition(self, parser):
return parser.parse_class_object() return parser.parse_class_object()
@ -1393,7 +1387,7 @@ class CPPNamespaceObject(Directive):
def run(self): def run(self):
env = self.state.document.settings.env env = self.state.document.settings.env
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'): if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
env.temp_data['cpp:parent'] = None env.temp_data['cpp:parent'] = []
else: else:
parser = DefinitionParser(self.arguments[0]) parser = DefinitionParser(self.arguments[0])
try: try:
@ -1402,13 +1396,15 @@ class CPPNamespaceObject(Directive):
except DefinitionError as e: except DefinitionError as e:
self.state_machine.reporter.warning(e.description,line=self.lineno) self.state_machine.reporter.warning(e.description,line=self.lineno)
else: else:
env.temp_data['cpp:parent'] = prefix env.temp_data['cpp:parent'] = [prefix]
return [] return []
class CPPXRefRole(XRefRole): class CPPXRefRole(XRefRole):
def process_link(self, env, refnode, has_explicit_title, title, target): def process_link(self, env, refnode, has_explicit_title, title, target):
refnode['cpp:parent'] = env.temp_data.get('cpp:parent') parent = env.temp_data.get('cpp:parent')
if parent:
refnode['cpp:parent'] = parent[:]
if not has_explicit_title: if not has_explicit_title:
target = target.lstrip('~') # only has a meaning for the title target = target.lstrip('~') # only has a meaning for the title
# if the first character is a tilde, don't display the module/class # if the first character is a tilde, don't display the module/class
@ -1477,8 +1473,9 @@ class CPPDomain(Domain):
# try qualifying it with the parent # try qualifying it with the parent
parent = node.get('cpp:parent', None) parent = node.get('cpp:parent', None)
if not parent: return None if parent and len(parent) > 0:
else: return _create_refnode(nameAst.prefix(parent)) return _create_refnode(nameAst.prefix_nested_name(parent[-1]))
else: return None
def get_objects(self): def get_objects(self):
for refname, (docname, type, theid) in iteritems(self.data['objects']): for refname, (docname, type, theid) in iteritems(self.data['objects']):

View File

@ -53,6 +53,7 @@ def test_type_definitions():
check("type", "std::function<void()> F") check("type", "std::function<void()> F")
check("type", "std::function<R(A1, A2, A3)> F") check("type", "std::function<R(A1, A2, A3)> F")
check("type", "std::function<R(A1, A2, A3, As...)> F") check("type", "std::function<R(A1, A2, A3, As...)> F")
check("type", "MyContainer::const_iterator")
check('member', ' const std::string & name = 42', 'const std::string &name = 42') check('member', ' const std::string & name = 42', 'const std::string &name = 42')
check('member', ' const std::string & name', 'const std::string &name') check('member', ' const std::string & name', 'const std::string &name')