Merge branch '3.x'

This commit is contained in:
jfbu 2021-02-12 21:27:17 +01:00
commit 62401ef1ec
6 changed files with 190 additions and 40 deletions

View File

@ -157,6 +157,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
----------
@ -229,6 +235,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
--------

View File

@ -207,10 +207,10 @@ You can now use the extension throughout your project. For example:
The recipe contains `tomato` and `cilantro`.
.. recipe:recipe:: TomatoSoup
:contains: tomato cilantro salt pepper
:contains: tomato, cilantro, salt, pepper
This recipe is a tasty tomato soup, combine all ingredients
and cook.
This recipe is a tasty tomato soup, combine all ingredients
and cook.
The important things to note are the use of the ``:recipe:ref:`` role to
cross-reference the recipe actually defined elsewhere (using the

View File

@ -795,6 +795,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::
@ -1219,6 +1226,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
~~~~~~~~~~~~~~~~~~~~~

View File

@ -3435,12 +3435,12 @@ class CNamespacePopObject(SphinxDirective):
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:
@ -3452,19 +3452,16 @@ class AliasNode(nodes.Element):
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:
@ -3472,26 +3469,43 @@ class AliasTransform(SphinxTransform):
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:
@ -3531,17 +3545,40 @@ class AliasTransform(SphinxTransform):
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)
nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
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.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:
@ -3555,10 +3592,19 @@ class CAliasObject(ObjectDescription):
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]

View File

@ -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
@ -3742,6 +3742,7 @@ class ASTDeclaration(ASTBase):
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
@ -7046,10 +7047,12 @@ class CPPNamespacePopObject(SphinxDirective):
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']
@ -7060,14 +7063,62 @@ class AliasNode(nodes.Element):
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:
@ -7131,22 +7182,31 @@ class AliasTransform(SphinxTransform):
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]:
"""
@ -7166,9 +7226,19 @@ class CPPAliasObject(ObjectDescription):
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)

View File

@ -176,7 +176,7 @@
% FIXME: this is unrelated to an option, move this elsewhere
% To allow hyphenation of first word in narrow contexts; no option,
% customization to be done via 'preamble' key
\newcommand*\sphinxAtStartPar{\hskip\z@skip}
\newcommand*\sphinxAtStartPar{\leavevmode\nobreak\hskip\z@skip}
% No need for the \hspace{0pt} trick (\hskip\z@skip) with luatex
\ifdefined\directlua\let\sphinxAtStartPar\@empty\fi
% user interface: options can be changed midway in a document!