Skip to content

Commit be6391f

Browse files
Merge pull request #8876 from jakobandersen/c_cpp_alias
C and C++, alias fixes and improvements
2 parents 61af7f4 + e46779e commit be6391f

File tree

4 files changed

+186
-36
lines changed

4 files changed

+186
-36
lines changed

CHANGES

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@ Features added
7676
* C++, also hyperlink operator overloads in expressions and alias declarations.
7777
* #8247: Allow production lists to refer to tokens from other production groups
7878
* #8813: Show what extension (or module) caused it on errors on event handler
79+
* #8213: C++: add ``maxdepth`` option to :rst:dir:`cpp:alias` to insert nested
80+
declarations.
81+
* C, add ``noroot`` option to :rst:dir:`c:alias` to render only nested
82+
declarations.
83+
* C++, add ``noroot`` option to :rst:dir:`cpp:alias` to render only nested
84+
declarations.
7985

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

152161
Testing
153162
--------

doc/usage/restructuredtext/domains.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,13 @@ The following directive can be used for this purpose.
755755
756756
.. versionadded:: 3.3
757757
758+
.. rst:directive:option:: noroot
759+
760+
Skip the mentioned declarations and only render nested declarations.
761+
Requires ``maxdepth`` either 0 or at least 2.
762+
763+
.. versionadded:: 3.5
764+
758765
759766
.. c:namespace-pop::
760767
@@ -1179,6 +1186,24 @@ The following directive can be used for this purpose.
11791186
.. versionadded:: 2.0
11801187
11811188
1189+
.. rubric:: Options
1190+
1191+
.. rst:directive:option:: maxdepth: int
1192+
1193+
Insert nested declarations as well, up to the total depth given.
1194+
Use 0 for infinite depth and 1 for just the mentioned declaration.
1195+
Defaults to 1.
1196+
1197+
.. versionadded:: 3.5
1198+
1199+
.. rst:directive:option:: noroot
1200+
1201+
Skip the mentioned declarations and only render nested declarations.
1202+
Requires ``maxdepth`` either 0 or at least 2.
1203+
1204+
.. versionadded:: 3.5
1205+
1206+
11821207
Constrained Templates
11831208
~~~~~~~~~~~~~~~~~~~~~
11841209

sphinx/domains/c.py

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3435,12 +3435,12 @@ def run(self) -> List[Node]:
34353435

34363436

34373437
class AliasNode(nodes.Element):
3438-
def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironment" = None,
3438+
def __init__(self, sig: str, aliasOptions: dict,
3439+
document: Any, env: "BuildEnvironment" = None,
34393440
parentKey: LookupKey = None) -> None:
34403441
super().__init__()
34413442
self.sig = sig
3442-
self.maxdepth = maxdepth
3443-
assert maxdepth >= 0
3443+
self.aliasOptions = aliasOptions
34443444
self.document = document
34453445
if env is not None:
34463446
if 'c:parent_symbol' not in env.temp_data:
@@ -3452,46 +3452,60 @@ def __init__(self, sig: str, maxdepth: int, document: Any, env: "BuildEnvironmen
34523452
self.parentKey = parentKey
34533453

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

34583458

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

3462-
def _render_symbol(self, s: Symbol, maxdepth: int, document: Any) -> List[Node]:
3463-
nodes = [] # type: List[Node]
3464-
options = dict() # type: ignore
3465-
signode = addnodes.desc_signature('', '')
3466-
nodes.append(signode)
3467-
s.declaration.describe_signature(signode, 'markName', self.env, options)
3462+
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
3463+
aliasOptions: dict, renderOptions: dict,
3464+
document: Any) -> List[Node]:
34683465
if maxdepth == 0:
34693466
recurse = True
34703467
elif maxdepth == 1:
34713468
recurse = False
34723469
else:
34733470
maxdepth -= 1
34743471
recurse = True
3472+
3473+
nodes = [] # type: List[Node]
3474+
if not skipThis:
3475+
signode = addnodes.desc_signature('', '')
3476+
nodes.append(signode)
3477+
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)
3478+
34753479
if recurse:
3476-
content = addnodes.desc_content()
3477-
desc = addnodes.desc()
3478-
content.append(desc)
3479-
desc.document = document
3480-
desc['domain'] = 'c'
3481-
# 'desctype' is a backwards compatible attribute
3482-
desc['objtype'] = desc['desctype'] = 'alias'
3483-
desc['noindex'] = True
3480+
if skipThis:
3481+
childContainer = nodes # type: Union[List[Node], addnodes.desc]
3482+
else:
3483+
content = addnodes.desc_content()
3484+
desc = addnodes.desc()
3485+
content.append(desc)
3486+
desc.document = document
3487+
desc['domain'] = 'c'
3488+
# 'desctype' is a backwards compatible attribute
3489+
desc['objtype'] = desc['desctype'] = 'alias'
3490+
desc['noindex'] = True
3491+
childContainer = desc
34843492

34853493
for sChild in s.children:
3486-
childNodes = self._render_symbol(sChild, maxdepth, document)
3487-
desc.extend(childNodes)
3494+
if sChild.declaration is None:
3495+
continue
3496+
childNodes = self._render_symbol(
3497+
sChild, maxdepth=maxdepth, skipThis=False,
3498+
aliasOptions=aliasOptions, renderOptions=renderOptions,
3499+
document=document)
3500+
childContainer.extend(childNodes)
34883501

3489-
if len(desc.children) != 0:
3502+
if not skipThis and len(desc.children) != 0:
34903503
nodes.append(content)
34913504
return nodes
34923505

34933506
def apply(self, **kwargs: Any) -> None:
34943507
for node in self.document.traverse(AliasNode):
3508+
node = cast(AliasNode, node)
34953509
sig = node.sig
34963510
parentKey = node.parentKey
34973511
try:
@@ -3531,17 +3545,40 @@ def apply(self, **kwargs: Any) -> None:
35313545
location=node)
35323546
node.replace_self(signode)
35333547
continue
3548+
# Declarations like .. var:: int Missing::var
3549+
# may introduce symbols without declarations.
3550+
# But if we skip the root then it is ok to start recursion from it.
3551+
if not node.aliasOptions['noroot'] and s.declaration is None:
3552+
signode = addnodes.desc_signature(sig, '')
3553+
node.append(signode)
3554+
signode.clear()
3555+
signode += addnodes.desc_name(sig, sig)
3556+
3557+
logger.warning(
3558+
"Can not render C declaration for alias '%s'. No such declaration." % name,
3559+
location=node)
3560+
node.replace_self(signode)
3561+
continue
35343562

3535-
nodes = self._render_symbol(s, maxdepth=node.maxdepth, document=node.document)
3563+
nodes = self._render_symbol(s, maxdepth=node.aliasOptions['maxdepth'],
3564+
skipThis=node.aliasOptions['noroot'],
3565+
aliasOptions=node.aliasOptions,
3566+
renderOptions=dict(), document=node.document)
35363567
node.replace_self(nodes)
35373568

35383569

35393570
class CAliasObject(ObjectDescription):
35403571
option_spec = {
3541-
'maxdepth': directives.nonnegative_int
3572+
'maxdepth': directives.nonnegative_int,
3573+
'noroot': directives.flag,
35423574
} # type: Dict
35433575

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

35573594
self.names = [] # type: List[str]
3558-
maxdepth = self.options.get('maxdepth', 1)
3595+
aliasOptions = {
3596+
'maxdepth': self.options.get('maxdepth', 1),
3597+
'noroot': 'noroot' in self.options,
3598+
}
3599+
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
3600+
logger.warning("Error in C alias declaration."
3601+
" Requested 'noroot' but 'maxdepth' 1."
3602+
" When skipping the root declaration,"
3603+
" need 'maxdepth' 0 for infinite or at least 2.",
3604+
location=self.get_source_info())
35593605
signatures = self.get_signatures()
35603606
for i, sig in enumerate(signatures):
3561-
node.append(AliasNode(sig, maxdepth, self.state.document, env=self.env))
3607+
node.append(AliasNode(sig, aliasOptions, self.state.document, env=self.env))
35623608
return [node]
35633609

35643610

sphinx/domains/cpp.py

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import re
1212
from typing import (Any, Callable, Dict, Generator, Iterator, List, Optional, Tuple, Type,
13-
TypeVar, Union)
13+
TypeVar, Union, cast)
1414

1515
from docutils import nodes
1616
from docutils.nodes import Element, Node, TextElement, system_message
@@ -3742,6 +3742,7 @@ def describe_signature(self, signode: desc_signature, mode: str,
37423742
elif self.objectType == 'enumerator':
37433743
mainDeclNode += addnodes.desc_annotation('enumerator ', 'enumerator ')
37443744
else:
3745+
print(self.objectType)
37453746
assert False
37463747
self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
37473748
lastDeclNode = mainDeclNode
@@ -7046,10 +7047,12 @@ def run(self) -> List[Node]:
70467047

70477048

70487049
class AliasNode(nodes.Element):
7049-
def __init__(self, sig: str, env: "BuildEnvironment" = None,
7050+
def __init__(self, sig: str, aliasOptions: dict,
7051+
env: "BuildEnvironment" = None,
70507052
parentKey: LookupKey = None) -> None:
70517053
super().__init__()
70527054
self.sig = sig
7055+
self.aliasOptions = aliasOptions
70537056
if env is not None:
70547057
if 'cpp:parent_symbol' not in env.temp_data:
70557058
root = env.domaindata['cpp']['root_symbol']
@@ -7060,14 +7063,62 @@ def __init__(self, sig: str, env: "BuildEnvironment" = None,
70607063
self.parentKey = parentKey
70617064

70627065
def copy(self) -> 'AliasNode':
7063-
return self.__class__(self.sig, env=None, parentKey=self.parentKey)
7066+
return self.__class__(self.sig, self.aliasOptions,
7067+
env=None, parentKey=self.parentKey)
70647068

70657069

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

7073+
def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool,
7074+
aliasOptions: dict, renderOptions: dict,
7075+
document: Any) -> List[Node]:
7076+
if maxdepth == 0:
7077+
recurse = True
7078+
elif maxdepth == 1:
7079+
recurse = False
7080+
else:
7081+
maxdepth -= 1
7082+
recurse = True
7083+
7084+
nodes = [] # type: List[Node]
7085+
if not skipThis:
7086+
signode = addnodes.desc_signature('', '')
7087+
nodes.append(signode)
7088+
s.declaration.describe_signature(signode, 'markName', self.env, renderOptions)
7089+
7090+
if recurse:
7091+
if skipThis:
7092+
childContainer = nodes # type: Union[List[Node], addnodes.desc]
7093+
else:
7094+
content = addnodes.desc_content()
7095+
desc = addnodes.desc()
7096+
content.append(desc)
7097+
desc.document = document
7098+
desc['domain'] = 'cpp'
7099+
# 'desctype' is a backwards compatible attribute
7100+
desc['objtype'] = desc['desctype'] = 'alias'
7101+
desc['noindex'] = True
7102+
childContainer = desc
7103+
7104+
for sChild in s._children:
7105+
if sChild.declaration is None:
7106+
continue
7107+
if sChild.declaration.objectType in ("templateParam", "functionParam"):
7108+
continue
7109+
childNodes = self._render_symbol(
7110+
sChild, maxdepth=maxdepth, skipThis=False,
7111+
aliasOptions=aliasOptions, renderOptions=renderOptions,
7112+
document=document)
7113+
childContainer.extend(childNodes)
7114+
7115+
if not skipThis and len(desc.children) != 0:
7116+
nodes.append(content)
7117+
return nodes
7118+
70697119
def apply(self, **kwargs: Any) -> None:
70707120
for node in self.document.traverse(AliasNode):
7121+
node = cast(AliasNode, node)
70717122
sig = node.sig
70727123
parentKey = node.parentKey
70737124
try:
@@ -7131,22 +7182,31 @@ def apply(self, **kwargs: Any) -> None:
71317182
signode.clear()
71327183
signode += addnodes.desc_name(sig, sig)
71337184

7134-
logger.warning("Could not find C++ declaration for alias '%s'." % ast,
7185+
logger.warning("Can not find C++ declaration for alias '%s'." % ast,
71357186
location=node)
71367187
node.replace_self(signode)
71377188
else:
71387189
nodes = []
7139-
options = dict()
7140-
options['tparam-line-spec'] = False
7190+
renderOptions = {
7191+
'tparam-line-spec': False,
7192+
}
71417193
for s in symbols:
7142-
signode = addnodes.desc_signature(sig, '')
7143-
nodes.append(signode)
7144-
s.declaration.describe_signature(signode, 'markName', self.env, options)
7194+
assert s.declaration is not None
7195+
res = self._render_symbol(
7196+
s, maxdepth=node.aliasOptions['maxdepth'],
7197+
skipThis=node.aliasOptions['noroot'],
7198+
aliasOptions=node.aliasOptions,
7199+
renderOptions=renderOptions,
7200+
document=node.document)
7201+
nodes.extend(res)
71457202
node.replace_self(nodes)
71467203

71477204

71487205
class CPPAliasObject(ObjectDescription):
7149-
option_spec = {} # type: Dict
7206+
option_spec = {
7207+
'maxdepth': directives.nonnegative_int,
7208+
'noroot': directives.flag,
7209+
} # type: Dict
71507210

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

71687228
self.names = [] # type: List[str]
7229+
aliasOptions = {
7230+
'maxdepth': self.options.get('maxdepth', 1),
7231+
'noroot': 'noroot' in self.options,
7232+
}
7233+
if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1:
7234+
logger.warning("Error in C++ alias declaration."
7235+
" Requested 'noroot' but 'maxdepth' 1."
7236+
" When skipping the root declaration,"
7237+
" need 'maxdepth' 0 for infinite or at least 2.",
7238+
location=self.get_source_info())
71697239
signatures = self.get_signatures()
71707240
for i, sig in enumerate(signatures):
7171-
node.append(AliasNode(sig, env=self.env))
7241+
node.append(AliasNode(sig, aliasOptions, env=self.env))
71727242

71737243
contentnode = addnodes.desc_content()
71747244
node.append(contentnode)

0 commit comments

Comments
 (0)