Skip to content

Commit

Permalink
Merge pull request #8876 from jakobandersen/c_cpp_alias
Browse files Browse the repository at this point in the history
C and C++, alias fixes and improvements
  • Loading branch information
jakobandersen committed Feb 12, 2021
2 parents 61af7f4 + e46779e commit be6391f
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 36 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Features added
* C++, also hyperlink operator overloads in expressions and alias declarations.
* #8247: Allow production lists to refer to tokens from other production groups
* #8813: Show what extension (or module) caused it on errors on event handler
* #8213: C++: add ``maxdepth`` option to :rst:dir:`cpp:alias` to insert nested
declarations.
* C, add ``noroot`` option to :rst:dir:`c:alias` to render only nested
declarations.
* C++, add ``noroot`` option to :rst:dir:`cpp:alias` to render only nested
declarations.

Bugs fixed
----------
Expand Down Expand Up @@ -148,6 +154,9 @@ Bugs fixed
builds
* #8865: LaTeX: Restructure the index nodes inside title nodes only on LaTeX
builds
* C, :rst:dir:`c:alias` skip symbols without explicit declarations
instead of crashing.
* C, :rst:dir:`c:alias` give a warning when the root symbol is not declared.

Testing
--------
Expand Down
25 changes: 25 additions & 0 deletions doc/usage/restructuredtext/domains.rst
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,13 @@ The following directive can be used for this purpose.
.. versionadded:: 3.3
.. rst:directive:option:: noroot
Skip the mentioned declarations and only render nested declarations.
Requires ``maxdepth`` either 0 or at least 2.
.. versionadded:: 3.5
.. c:namespace-pop::
Expand Down Expand Up @@ -1179,6 +1186,24 @@ The following directive can be used for this purpose.
.. versionadded:: 2.0
.. rubric:: Options
.. rst:directive:option:: maxdepth: int
Insert nested declarations as well, up to the total depth given.
Use 0 for infinite depth and 1 for just the mentioned declaration.
Defaults to 1.
.. versionadded:: 3.5
.. rst:directive:option:: noroot
Skip the mentioned declarations and only render nested declarations.
Requires ``maxdepth`` either 0 or at least 2.
.. versionadded:: 3.5
Constrained Templates
~~~~~~~~~~~~~~~~~~~~~
Expand Down
96 changes: 71 additions & 25 deletions sphinx/domains/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -3435,12 +3435,12 @@ def run(self) -> List[Node]:


class AliasNode(nodes.Element):
def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None,
def __init__(self, sig: str, aliasOptions: dict,
document: Any, env: "BuildEnvironment" = None,
parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
self.maxdepth = maxdepth
assert maxdepth >= 0
self.aliasOptions = aliasOptions
self.document = document
if env is not None:
if 'c:parent_symbol' not in env.temp_data:
Expand All @@ -3452,46 +3452,60 @@ def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironmen
self.parentKey = parentKey

def copy(self) -> 'AliasNode':
return self.__class__(self.sig, self.maxdepth, self.document,
return self.__class__(self.sig, self.aliasOptions, self.document,
env=None, parentKey=self.parentKey)


class AliasTransform(SphinxTransform):
default_priority = ReferencesResolver.default_priority - 1

def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]:
nodes = [] # type: List[Node]
options = dict() # type: ignore
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, options)
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
aliasOptions: dict, renderOptions: dict,
document: Any) -> List[Node]:
if maxdepth == 0:
recurse = True
elif maxdepth == 1:
recurse = False
else:
maxdepth -= 1
recurse = True

nodes = [] # type: List[Node]
if not skipThis:
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)

if recurse:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'c'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
if skipThis:
childContainer = nodes # type: Union[List[Node], addnodes.desc]
else:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'c'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
childContainer = desc

for sChild in s.children:
childNodes = self._render_symbol(sChild, maxdepth, document)
desc.extend(childNodes)
if sChild.declaration is None:
continue
childNodes = self._render_symbol(
sChild, maxdepth=maxdepth, skipThis=False,
aliasOptions=aliasOptions, renderOptions=renderOptions,
document=document)
childContainer.extend(childNodes)

if len(desc.children) != 0:
if not skipThis and len(desc.children) != 0:
nodes.append(content)
return nodes

def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
node = cast(AliasNode, node)
sig = node.sig
parentKey = node.parentKey
try:
Expand Down Expand Up @@ -3531,17 +3545,40 @@ def apply(self, **kwargs: Any) -> None:
location=node)
node.replace_self(signode)
continue
# Declarations like .. var:: int Missing::var
# may introduce symbols without declarations.
# But if we skip the root then it is ok to start recursion from it.
if not node.aliasOptions['noroot'] and s.declaration is None:
signode = addnodes.desc_signature(sig, '')
node.append(signode)
signode.clear()
signode += addnodes.desc_name(sig, sig)

logger.warning(
"Can not render C declaration for alias '%s'. No such declaration." % name,
location=node)
node.replace_self(signode)
continue

nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
nodes = self._render_symbol(s, maxdepth=node.aliasOptions['maxdepth'],
skipThis=node.aliasOptions['noroot'],
aliasOptions=node.aliasOptions,
renderOptions=dict(), document=node.document)
node.replace_self(nodes)


class CAliasObject(ObjectDescription):
option_spec = {
'maxdepth': directives.nonnegative_int
'maxdepth': directives.nonnegative_int,
'noroot': directives.flag,
} # type: Dict

def run(self) -> List[Node]:
"""
On purpose this doesn't call the ObjectDescription version, but is based on it.
Each alias signature may expand into multiple real signatures if 'noroot'.
The code is therefore based on the ObjectDescription version.
"""
if ':' in self.name:
self.domain, self.objtype = self.name.split(':', 1)
else:
Expand All @@ -3555,10 +3592,19 @@ def run(self) -> List[Node]:
node['noindex'] = True

self.names = [] # type: List[str]
maxdepth = self.options.get('maxdepth', 1)
aliasOptions = {
'maxdepth': self.options.get('maxdepth', 1),
'noroot': 'noroot' in self.options,
}
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
logger.warning("Error in C alias declaration."
" Requested 'noroot' but 'maxdepth' 1."
" When skipping the root declaration,"
" need 'maxdepth' 0 for infinite or at least 2.",
location=self.get_source_info())
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env))
node.append(AliasNode(sig, aliasOptions, self.state.document, env=self.env))
return [node]


Expand Down
92 changes: 81 additions & 11 deletions sphinx/domains/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import re
from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type,
TypeVar, Union)
TypeVar, Union, cast)

from docutils import nodes
from docutils.nodes import Element, Node, TextElement, system_message
Expand Down Expand Up @@ -3742,6 +3742,7 @@ def describe_signature(self, signode: desc_signature, mode: str,
elif self.objectType == 'enumerator':
mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ')
else:
print(self.objectType)
assert False
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
lastDeclNode = mainDeclNode
Expand Down Expand Up @@ -7046,10 +7047,12 @@ def run(self) -> List[Node]:


class AliasNode(nodes.Element):
def __init__(self, sig: str, env: "BuildEnvironment" = None,
def __init__(self, sig: str, aliasOptions: dict,
env: "BuildEnvironment" = None,
parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
self.aliasOptions = aliasOptions
if env is not None:
if 'cpp:parent_symbol' not in env.temp_data:
root = env.domaindata['cpp']['root_symbol']
Expand All @@ -7060,14 +7063,62 @@ def __init__(self, sig: str, env: "BuildEnvironment" = None,
self.parentKey = parentKey

def copy(self) -> 'AliasNode':
return self.__class__(self.sig, env=None, parentKey=self.parentKey)
return self.__class__(self.sig, self.aliasOptions,
env=None, parentKey=self.parentKey)


class AliasTransform(SphinxTransform):
default_priority = ReferencesResolver.default_priority - 1

def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
aliasOptions: dict, renderOptions: dict,
document: Any) -> List[Node]:
if maxdepth == 0:
recurse = True
elif maxdepth == 1:
recurse = False
else:
maxdepth -= 1
recurse = True

nodes = [] # type: List[Node]
if not skipThis:
signode = addnodes.desc_signature('', '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)

if recurse:
if skipThis:
childContainer = nodes # type: Union[List[Node], addnodes.desc]
else:
content = addnodes.desc_content()
desc = addnodes.desc()
content.append(desc)
desc.document = document
desc['domain'] = 'cpp'
# 'desctype' is a backwards compatible attribute
desc['objtype'] = desc['desctype'] = 'alias'
desc['noindex'] = True
childContainer = desc

for sChild in s._children:
if sChild.declaration is None:
continue
if sChild.declaration.objectType in ("templateParam", "functionParam"):
continue
childNodes = self._render_symbol(
sChild, maxdepth=maxdepth, skipThis=False,
aliasOptions=aliasOptions, renderOptions=renderOptions,
document=document)
childContainer.extend(childNodes)

if not skipThis and len(desc.children) != 0:
nodes.append(content)
return nodes

def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
node = cast(AliasNode, node)
sig = node.sig
parentKey = node.parentKey
try:
Expand Down Expand Up @@ -7131,22 +7182,31 @@ def apply(self, **kwargs: Any) -> None:
signode.clear()
signode += addnodes.desc_name(sig, sig)

logger.warning("Could not find C++ declaration for alias '%s'." % ast,
logger.warning("Can not find C++ declaration for alias '%s'." % ast,
location=node)
node.replace_self(signode)
else:
nodes = []
options = dict()
options['tparam-line-spec'] = False
renderOptions = {
'tparam-line-spec': False,
}
for s in symbols:
signode = addnodes.desc_signature(sig, '')
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, options)
assert s.declaration is not None
res = self._render_symbol(
s, maxdepth=node.aliasOptions['maxdepth'],
skipThis=node.aliasOptions['noroot'],
aliasOptions=node.aliasOptions,
renderOptions=renderOptions,
document=node.document)
nodes.extend(res)
node.replace_self(nodes)


class CPPAliasObject(ObjectDescription):
option_spec = {} # type: Dict
option_spec = {
'maxdepth': directives.nonnegative_int,
'noroot': directives.flag,
} # type: Dict

def run(self) -> List[Node]:
"""
Expand All @@ -7166,9 +7226,19 @@ def run(self) -> List[Node]:
node['objtype'] = node['desctype'] = self.objtype

self.names = [] # type: List[str]
aliasOptions = {
'maxdepth': self.options.get('maxdepth', 1),
'noroot': 'noroot' in self.options,
}
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
logger.warning("Error in C++ alias declaration."
" Requested 'noroot' but 'maxdepth' 1."
" When skipping the root declaration,"
" need 'maxdepth' 0 for infinite or at least 2.",
location=self.get_source_info())
signatures = self.get_signatures()
for i, sig in enumerate(signatures):
node.append(AliasNode(sig, env=self.env))
node.append(AliasNode(sig, aliasOptions, env=self.env))

contentnode = addnodes.desc_content()
node.append(contentnode)
Expand Down

0 comments on commit be6391f

Please sign in to comment.