summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Lykke Andersen <jakob@caput.dk>2014-07-24 11:09:28 +0200
committerJakob Lykke Andersen <jakob@caput.dk>2014-07-24 11:09:28 +0200
commitcaad958de49df5f8ab6adb629e69ee93dc45efc8 (patch)
tree1d3ac71b2d77c2e038d71c7b26c37cfc3fbdc095
parent967ca06545b4432c6ec3e6a13aed9ea03d3874cc (diff)
downloadsphinx-git-caad958de49df5f8ab6adb629e69ee93dc45efc8.tar.gz
C++, fix namespacing of elements and xrefs.
-rw-r--r--sphinx/domains/cpp.py73
-rw-r--r--tests/test_cpp_domain.py1
2 files changed, 36 insertions, 38 deletions
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 02ba872f7..4ff2a0ab7 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -257,15 +257,7 @@ class ASTBase(UnicodeMixin):
"""
raise NotImplementedError(repr(self))
- def split_owner(self):
- """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):
+ def prefix_nested_name(self, prefix):
"""Prefix a name node (a node returned by :meth:`get_name`)."""
raise NotImplementedError(repr(self))
@@ -276,10 +268,12 @@ class ASTBase(UnicodeMixin):
return '<%s %s>' % (self.__class__.__name__, self)
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):
- 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):
@@ -371,10 +365,11 @@ class ASTNestedName(ASTBase):
def name(self):
return self
- def prefix(self, prefix):
+ def prefix_nested_name(self, prefix):
if self.names[0] == '':
- raise DefinitionError('Can not prefix nested name rooted in outer-most namespace.')
- names = [prefix]
+ return self # it's defined at global namespace, don't tuch it
+ assert isinstance(prefix, ASTNestedName)
+ names = prefix.names[:]
names.extend(self.names)
return ASTNestedName(names)
@@ -669,10 +664,12 @@ class ASTType(ASTBase):
def get_id(self):
res = ['___']
- res.append(text_type(self.name))
+ res.append(text_type(self.prefixedName))
if self.objectType == 'function':
res.append('___')
res.append(self.decl.get_param_id())
+ elif self.objectType == 'type':
+ pass
else:
print(self.objectType)
assert False
@@ -711,7 +708,7 @@ class ASTTypeWithInit(ASTBase):
def get_id(self):
if self.objectType == 'member':
- return text_type(self.name)
+ return "___" + text_type(self.prefixedName)
else:
raise NotImplementedError("Should this happen? %s, %s" % (self.objectType, text_type(self.name)))
@@ -1133,12 +1130,12 @@ class DefinitionParser(object):
if context == 'abstractDecl':
declId = None
- elif context == 'functionObjectArgument' \
- or context == 'functionObject':
+ elif context in {'functionObjectArgument', 'functionObject', 'typeObject'}:
# Function arguments don't need to have a name.
# Some functions (constructors/destructors) don't ahve return type,
# 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
+ # For types we want to allow the plain declaration that there is a type, i.e., "MyContainer::const_iterator"
pos = self.pos
try:
declId = self._parse_nested_name(context)
@@ -1291,23 +1288,12 @@ class CPPObject(ObjectDescription):
self.state.document.note_explicit_target(signode)
if not name in objects:
objects.setdefault(name, (self.env.docname, ast.objectType, theid))
+ self.env.temp_data['cpp:lastname'] = ast.prefixedName
indextext = self.get_index_text(name)
if indextext:
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):
raise NotImplementedError()
@@ -1325,9 +1311,9 @@ class CPPObject(ObjectDescription):
self.describe_signature(signode, ast)
parent = self.env.temp_data.get('cpp:parent')
- if parent is not None:
+ if parent and len(parent) > 0:
ast = ast.clone()
- ast.prefixedName = ast.name.prefix(parent)
+ ast.prefixedName = ast.name.prefix_nested_name(parent[-1])
else:
ast.prefixedName = ast.name
return ast
@@ -1342,7 +1328,7 @@ class CPPTypeObject(CPPObject):
def describe_signature(self, signode, ast):
signode += addnodes.desc_annotation('type ', 'type ')
- ast.describe_signature(signode, 'typeObject', self.env)
+ ast.describe_signature(signode, 'lastIsName', self.env)
class CPPMemberObject(CPPObject):
@@ -1371,6 +1357,14 @@ class CPPClassObject(CPPObject):
def get_index_text(self, 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):
return parser.parse_class_object()
@@ -1393,7 +1387,7 @@ class CPPNamespaceObject(Directive):
def run(self):
env = self.state.document.settings.env
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
- env.temp_data['cpp:parent'] = None
+ env.temp_data['cpp:parent'] = []
else:
parser = DefinitionParser(self.arguments[0])
try:
@@ -1402,13 +1396,15 @@ class CPPNamespaceObject(Directive):
except DefinitionError as e:
self.state_machine.reporter.warning(e.description,line=self.lineno)
else:
- env.temp_data['cpp:parent'] = prefix
+ env.temp_data['cpp:parent'] = [prefix]
return []
class CPPXRefRole(XRefRole):
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:
target = target.lstrip('~') # only has a meaning for the title
# 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
parent = node.get('cpp:parent', None)
- if not parent: return None
- else: return _create_refnode(nameAst.prefix(parent))
+ if parent and len(parent) > 0:
+ return _create_refnode(nameAst.prefix_nested_name(parent[-1]))
+ else: return None
def get_objects(self):
for refname, (docname, type, theid) in iteritems(self.data['objects']):
diff --git a/tests/test_cpp_domain.py b/tests/test_cpp_domain.py
index 20160da9e..b3df490f9 100644
--- a/tests/test_cpp_domain.py
+++ b/tests/test_cpp_domain.py
@@ -53,6 +53,7 @@ def test_type_definitions():
check("type", "std::function<void()> F")
check("type", "std::function<R(A1, A2, A3)> 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', 'const std::string &name')