diff --git a/.gitignore b/.gitignore index b72664183..8d33409d5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ .mypy_cache/ .pytest_cache/ .ropeproject/ +.vscode/ TAGS .tags .tox/ diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index e09a56b06..3365bf786 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -10,7 +10,7 @@ import re from typing import ( - Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union + Any, Callable, Dict, Generator, Iterator, List, Tuple, Type, TypeVar, Union, Optional ) from docutils import nodes @@ -1266,7 +1266,7 @@ class ASTNoexceptExpr(ASTExpression): self.expr = expr def _stringify(self, transform: StringifyTransform) -> str: - return "noexcept(" + transform(self.expr) + ")" + return 'noexcept(' + transform(self.expr) + ')' def get_id(self, version: int) -> str: return 'nx' + self.expr.get_id(version) @@ -1812,10 +1812,28 @@ class ASTFunctionParameter(ASTBase): self.arg.describe_signature(signode, mode, env, symbol=symbol) +class ASTNoexceptSpec(ASTBase): + def __init__(self, expr: Optional[ASTExpression]): + self.expr = expr + + def _stringify(self, transform: StringifyTransform) -> str: + if self.expr: + return 'noexcept(' + transform(self.expr) + ')' + return 'noexcept' + + def describe_signature(self, signode: TextElement, mode: str, + env: "BuildEnvironment", symbol: "Symbol") -> None: + signode += addnodes.desc_annotation('noexcept', 'noexcept') + if self.expr: + signode.append(nodes.Text('(')) + self.expr.describe_signature(signode, mode, env, symbol) + signode.append(nodes.Text(')')) + + class ASTParametersQualifiers(ASTBase): - def __init__(self, args: List[ASTFunctionParameter], - volatile: bool, const: bool, refQual: str, - exceptionSpec: str, override: bool, final: bool, initializer: str) -> None: + def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool, + refQual: str, exceptionSpec: ASTNoexceptSpec, override: bool, final: bool, + initializer: str) -> None: self.args = args self.volatile = volatile self.const = const @@ -1874,7 +1892,7 @@ class ASTParametersQualifiers(ASTBase): res.append(self.refQual) if self.exceptionSpec: res.append(' ') - res.append(str(self.exceptionSpec)) + res.append(transform(self.exceptionSpec)) if self.final: res.append(' final') if self.override: @@ -1911,7 +1929,8 @@ class ASTParametersQualifiers(ASTBase): if self.refQual: _add_text(signode, self.refQual) if self.exceptionSpec: - _add_anno(signode, str(self.exceptionSpec)) + signode += nodes.Text(' ') + self.exceptionSpec.describe_signature(signode, mode, env, symbol) if self.final: _add_anno(signode, 'final') if self.override: @@ -5495,11 +5514,14 @@ class DefinitionParser(BaseParser): initializer = None self.skip_ws() if self.skip_string('noexcept'): - exceptionSpec = 'noexcept' - self.skip_ws() - if self.skip_string('('): - self.fail('Parameterised "noexcept" not yet implemented.') - + if self.skip_string_and_ws('('): + expr = self._parse_constant_expression(False) + self.skip_ws() + if not self.skip_string(')'): + self.fail("Expecting ')' to end 'noexcept'.") + exceptionSpec = ASTNoexceptSpec(expr) + else: + exceptionSpec = ASTNoexceptSpec(None) self.skip_ws() override = self.skip_word_and_ws('override') final = self.skip_word_and_ws('final') diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 0b757139a..0180a11d3 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -393,7 +393,7 @@ def test_function_definitions(): x = 'std::vector> &module::test(register int ' \ 'foo, bar, std::string baz = "foobar, blah, bleh") const = 0' check('function', x, {1: "module::test__i.bar.ssC", - 2: "NK6module4testEi3barNSt6stringE"}) + 2: "NK6module4testEi3barNSt6stringE"}) check('function', 'void f(std::pair)', {1: "f__std::pair:A.B:", 2: "1fNSt4pairI1A1BEE"}) check('function', 'explicit module::myclass::foo::foo()', @@ -427,6 +427,10 @@ def test_function_definitions(): {1: "get_valueCE", 2: "9get_valuev"}) check('function', 'int get_value() const noexcept', {1: "get_valueC", 2: "NK9get_valueEv"}) + check('function', 'int get_value() const noexcept(std::is_nothrow_move_constructible::value)', + {1: "get_valueC", 2: "NK9get_valueEv"}) + check('function', 'int get_value() const noexcept("see below")', + {1: "get_valueC", 2: "NK9get_valueEv"}) check('function', 'int get_value() const noexcept = delete', {1: "get_valueC", 2: "NK9get_valueEv"}) check('function', 'int get_value() volatile const', @@ -868,7 +872,7 @@ def test_xref_parsing(): def filter_warnings(warning, file): - lines = warning.getvalue().split("\n"); + lines = warning.getvalue().split("\n") res = [l for l in lines if "domain-cpp" in l and "{}.rst".format(file) in l and "WARNING: document isn't included in any toctree" not in l] print("Filtered warnings for file '{}':".format(file))