From 670e8b149fa3349f08619f4d44617c0df9b84f8a Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Thu, 10 Mar 2022 22:03:42 -0800 Subject: [PATCH 01/12] [C++] Support attributes on class and union and improve formatting --- sphinx/domains/cpp.py | 61 ++++++++++++++++++++++++++++++++++------ sphinx/util/cfamily.py | 6 ++-- tests/test_domain_cpp.py | 9 ++++++ 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4f336a4bfb4..819299fca36 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -267,7 +267,8 @@ class_object: goal: a class declaration, but with specification of a base class grammar: - nested-name "final"[opt] (":" base-specifier-list)[opt] + attribute-specifier-seq[opt] + nested-name "final"[opt] (":" base-specifier-list)[opt] base-specifier-list -> base-specifier "..."[opt] | base-specifier-list, base-specifier "..."[opt] @@ -281,7 +282,8 @@ goal: an unscoped enum or a scoped enum, optionally with the underlying type specified grammar: - ("class" | "struct")[opt] visibility[opt] nested-name (":" type)[opt] + ("class" | "struct")[opt] visibility[opt] + attribute-specifier-seq[opt] nested-name (":" type)[opt] enumerator_object: goal: an element in a scoped or unscoped enum. The name should be injected according to the scopedness. @@ -3318,16 +3320,20 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTClass(ASTBase): - def __init__(self, name: ASTNestedName, final: bool, bases: List[ASTBaseClass]) -> None: + def __init__(self, name: ASTNestedName, final: bool, bases: List[ASTBaseClass], + attrs: Optional[List[ASTAttribute]] = None) -> None: self.name = name self.final = final self.bases = bases + self.attrs = attrs or [] def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: return symbol.get_full_nested_name().get_id(version) def _stringify(self, transform: StringifyTransform) -> str: res = [] + for attr in self.attrs: + res.append(transform(attr) + ' ') res.append(transform(self.name)) if self.final: res.append(' final') @@ -3344,6 +3350,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) + for attr in self.attrs: + attr.describe_signature(signode) + signode += addnodes.desc_sig_space() self.name.describe_signature(signode, mode, env, symbol=symbol) if self.final: signode += addnodes.desc_sig_space() @@ -3361,8 +3370,10 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTUnion(ASTBase): - def __init__(self, name: ASTNestedName) -> None: + def __init__(self, name: ASTNestedName, + attrs: Optional[List[ASTAttribute]] = None) -> None: self.name = name + self.attrs = attrs or [] def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: if version == 1: @@ -3370,20 +3381,29 @@ def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: return symbol.get_full_nested_name().get_id(version) def _stringify(self, transform: StringifyTransform) -> str: - return transform(self.name) + res = [] + for attr in self.attrs: + res.append(transform(attr) + ' ') + res.append(transform(self.name)) + return ''.join(res) def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) + for attr in self.attrs: + attr.describe_signature(signode) + signode += addnodes.desc_sig_space() self.name.describe_signature(signode, mode, env, symbol=symbol) class ASTEnum(ASTBase): def __init__(self, name: ASTNestedName, scoped: str, - underlyingType: ASTType) -> None: + underlyingType: ASTType, + attrs: Optional[List[ASTAttribute]] = None) -> None: self.name = name self.scoped = scoped self.underlyingType = underlyingType + self.attrs = attrs or [] def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: if version == 1: @@ -3395,6 +3415,8 @@ def _stringify(self, transform: StringifyTransform) -> str: if self.scoped: res.append(self.scoped) res.append(' ') + for attr in self.attrs: + res.append(transform(attr) + ' ') res.append(transform(self.name)) if self.underlyingType: res.append(' : ') @@ -3405,6 +3427,9 @@ def describe_signature(self, signode: TextElement, mode: str, env: "BuildEnvironment", symbol: "Symbol") -> None: verify_description_mode(mode) # self.scoped has been done by the CPPEnumObject + for attr in self.attrs: + attr.describe_signature(signode) + signode += addnodes.desc_sig_space() self.name.describe_signature(signode, mode, env, symbol=symbol) if self.underlyingType: signode += addnodes.desc_sig_space() @@ -6567,6 +6592,12 @@ def _parse_concept(self) -> ASTConcept: return ASTConcept(nestedName, initializer) def _parse_class(self) -> ASTClass: + attrs = [] + while 1: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) name = self._parse_nested_name() self.skip_ws() final = self.skip_word_and_ws('final') @@ -6594,21 +6625,33 @@ def _parse_class(self) -> ASTClass: continue else: break - return ASTClass(name, final, bases) + return ASTClass(name, final, bases, attrs) def _parse_union(self) -> ASTUnion: + attrs = [] + while 1: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) name = self._parse_nested_name() - return ASTUnion(name) + return ASTUnion(name, attrs) def _parse_enum(self) -> ASTEnum: scoped = None # is set by CPPEnumObject + attrs = [] + while 1: + attr = self._parse_attribute() + if attr is None: + break + attrs.append(attr) self.skip_ws() name = self._parse_nested_name() self.skip_ws() underlyingType = None if self.skip_string(':'): underlyingType = self._parse_type(named=False) - return ASTEnum(name, scoped, underlyingType) + return ASTEnum(name, scoped, underlyingType, attrs) def _parse_enumerator(self) -> ASTEnumerator: name = self._parse_nested_name() diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index a86cb6f4b56..a69b9d7dacd 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -15,6 +15,7 @@ from docutils import nodes from docutils.nodes import TextElement +import sphinx.addnodes from sphinx.config import Config from sphinx.util import logging @@ -134,8 +135,9 @@ def _stringify(self, transform: StringifyTransform) -> str: return "[[" + self.arg + "]]" def describe_signature(self, signode: TextElement) -> None: - txt = str(self) - signode.append(nodes.Text(txt, txt)) + signode.append(sphinx.addnodes.desc_sig_punctuation('[[', '[[')) + signode.append(sphinx.addnodes.desc_sig_keyword(self.arg, self.arg)) + signode.append(sphinx.addnodes.desc_sig_punctuation(']]', ']]')) class ASTGnuAttribute(ASTBaseBase): diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 8fc974f4949..f5b54949f00 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -996,6 +996,15 @@ def test_domain_cpp_ast_attributes(): # position: parameters and qualifiers check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'}) + # position: class + check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo', 3: '3Foo', 4: '3Foo'}, + key='class') + check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, + key='union') + # position: enum + check('enum', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, + key='enum') + def test_domain_cpp_ast_xref_parsing(): def check(target): From 1dd0220f51b3438b9c2c4202d4b1ab82c684828c Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:12 -0800 Subject: [PATCH 02/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 819299fca36..ef1ed3eda54 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3321,7 +3321,7 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTClass(ASTBase): def __init__(self, name: ASTNestedName, final: bool, bases: List[ASTBaseClass], - attrs: Optional[List[ASTAttribute]] = None) -> None: + attrs: List[ASTAttribute]) -> None: self.name = name self.final = final self.bases = bases From 619d817e364f69572d027297272155295c94b9aa Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:18 -0800 Subject: [PATCH 03/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index ef1ed3eda54..4fd7eae7a5b 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3325,7 +3325,7 @@ def __init__(self, name: ASTNestedName, final: bool, bases: List[ASTBaseClass], self.name = name self.final = final self.bases = bases - self.attrs = attrs or [] + self.attrs = attrs def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: return symbol.get_full_nested_name().get_id(version) From 6073b320938f856f55974ca3658c9323ec593d3b Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:23 -0800 Subject: [PATCH 04/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 4fd7eae7a5b..a2fd39fefef 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3371,7 +3371,7 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTUnion(ASTBase): def __init__(self, name: ASTNestedName, - attrs: Optional[List[ASTAttribute]] = None) -> None: + attrs: List[ASTAttribute]) -> None: self.name = name self.attrs = attrs or [] From 0cb021b65c2ec9ef4d7979aabe90ae77d634538c Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:28 -0800 Subject: [PATCH 05/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index a2fd39fefef..7a0c5b64df6 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3373,7 +3373,7 @@ class ASTUnion(ASTBase): def __init__(self, name: ASTNestedName, attrs: List[ASTAttribute]) -> None: self.name = name - self.attrs = attrs or [] + self.attrs = attrs def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: if version == 1: From 8aa785fe5da0f6d810efbf043188c03b4b19868c Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:34 -0800 Subject: [PATCH 06/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 7a0c5b64df6..604730287ea 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3399,7 +3399,7 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTEnum(ASTBase): def __init__(self, name: ASTNestedName, scoped: str, underlyingType: ASTType, - attrs: Optional[List[ASTAttribute]] = None) -> None: + attrs: List[ASTAttribute]) -> None: self.name = name self.scoped = scoped self.underlyingType = underlyingType From f3277570b72460290cf8649296385579bf61c44f Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:41 -0800 Subject: [PATCH 07/12] Update sphinx/util/cfamily.py Co-authored-by: Jakob Lykke Andersen --- sphinx/util/cfamily.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index a69b9d7dacd..87c2d67b3e2 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -15,7 +15,7 @@ from docutils import nodes from docutils.nodes import TextElement -import sphinx.addnodes +from sphinx import addnodes from sphinx.config import Config from sphinx.util import logging From 2307e9f171cef9195114a2a02f1e4496bf38c294 Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:48 -0800 Subject: [PATCH 08/12] Update sphinx/util/cfamily.py Co-authored-by: Jakob Lykke Andersen --- sphinx/util/cfamily.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py index 87c2d67b3e2..dd2bde03274 100644 --- a/sphinx/util/cfamily.py +++ b/sphinx/util/cfamily.py @@ -135,9 +135,9 @@ def _stringify(self, transform: StringifyTransform) -> str: return "[[" + self.arg + "]]" def describe_signature(self, signode: TextElement) -> None: - signode.append(sphinx.addnodes.desc_sig_punctuation('[[', '[[')) - signode.append(sphinx.addnodes.desc_sig_keyword(self.arg, self.arg)) - signode.append(sphinx.addnodes.desc_sig_punctuation(']]', ']]')) + signode.append(addnodes.desc_sig_punctuation('[[', '[[')) + signode.append(nodes.Text(self.arg, self.arg)) + signode.append(addnodes.desc_sig_punctuation(']]', ']]')) class ASTGnuAttribute(ASTBaseBase): From ce82f9ee9ce1e3bcedd5786c155f5594a48f4068 Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:54 -0800 Subject: [PATCH 09/12] Update tests/test_domain_cpp.py Co-authored-by: Jakob Lykke Andersen --- tests/test_domain_cpp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index f5b54949f00..e3dba78ba89 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -997,8 +997,7 @@ def test_domain_cpp_ast_attributes(): check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'}) # position: class - check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo', 3: '3Foo', 4: '3Foo'}, - key='class') + check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo'}, key='class') check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, key='union') # position: enum From 2c1e4c437e7aa397624b293017d02dde7dd41070 Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:02:59 -0800 Subject: [PATCH 10/12] Update tests/test_domain_cpp.py Co-authored-by: Jakob Lykke Andersen --- tests/test_domain_cpp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index e3dba78ba89..96f03d61191 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -998,8 +998,7 @@ def test_domain_cpp_ast_attributes(): # position: class check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo'}, key='class') - check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, - key='union') + check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo'}, key='union') # position: enum check('enum', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, key='enum') From a9a5cec681a02815b51b977857cc9d3835dcf47f Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 05:03:05 -0800 Subject: [PATCH 11/12] Update tests/test_domain_cpp.py Co-authored-by: Jakob Lykke Andersen --- tests/test_domain_cpp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py index 96f03d61191..e811af335ae 100644 --- a/tests/test_domain_cpp.py +++ b/tests/test_domain_cpp.py @@ -1000,8 +1000,7 @@ def test_domain_cpp_ast_attributes(): check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo'}, key='class') check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo'}, key='union') # position: enum - check('enum', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo', 3: '3Foo', 4: '3Foo'}, - key='enum') + check('enum', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo'}, key='enum') def test_domain_cpp_ast_xref_parsing(): From 926fab0a01ee0c22275edc45e35c794fca7f4023 Mon Sep 17 00:00:00 2001 From: Jeremy Maitin-Shepard Date: Fri, 11 Mar 2022 06:53:42 -0800 Subject: [PATCH 12/12] Update sphinx/domains/cpp.py Co-authored-by: Jakob Lykke Andersen --- sphinx/domains/cpp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 604730287ea..f5c54ed635d 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3403,7 +3403,7 @@ def __init__(self, name: ASTNestedName, scoped: str, self.name = name self.scoped = scoped self.underlyingType = underlyingType - self.attrs = attrs or [] + self.attrs = attrs def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str: if version == 1: