summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Lykke Andersen <Jakob@caput.dk>2022-04-17 17:17:19 +0200
committerJakob Lykke Andersen <Jakob@caput.dk>2022-04-17 17:17:19 +0200
commit991fe26fa5683bb76a925389024d375c6bb11dba (patch)
treece60b5bc9d132660e599b03b9f8a65bb7a4d233e
parentd951e55bc3419dbda809ed0aca17addeed8e9e30 (diff)
downloadsphinx-git-991fe26fa5683bb76a925389024d375c6bb11dba.tar.gz
C and C++, refactor attribute lists
-rw-r--r--sphinx/domains/c.py54
-rw-r--r--sphinx/domains/cpp.py127
-rw-r--r--sphinx/util/cfamily.py33
-rw-r--r--tests/test_domain_c.py8
-rw-r--r--tests/test_domain_cpp.py16
5 files changed, 118 insertions, 120 deletions
diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py
index 532eebe52..22280dfd5 100644
--- a/sphinx/domains/c.py
+++ b/sphinx/domains/c.py
@@ -21,8 +21,8 @@ from sphinx.roles import SphinxRole, XRefRole
from sphinx.transforms import SphinxTransform
from sphinx.transforms.post_transforms import ReferencesResolver
from sphinx.util import logging
-from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser,
- DefinitionError, NoOldIdError, StringifyTransform,
+from sphinx.util.cfamily import (ASTAttributeList, ASTBaseBase, ASTBaseParenExprList,
+ BaseParser, DefinitionError, NoOldIdError, StringifyTransform,
UnsupportedMultiCharacterCharLiteral, anon_identifier_re,
binary_literal_re, char_literal_re, float_literal_re,
float_literal_suffix_re, hex_literal_re, identifier_re,
@@ -687,7 +687,7 @@ class ASTFunctionParameter(ASTBase):
class ASTParameters(ASTBase):
- def __init__(self, args: List[ASTFunctionParameter], attrs: List[ASTAttribute]) -> None:
+ def __init__(self, args: List[ASTFunctionParameter], attrs: ASTAttributeList) -> None:
self.args = args
self.attrs = attrs
@@ -705,9 +705,9 @@ class ASTParameters(ASTBase):
first = False
res.append(str(a))
res.append(')')
- for attr in self.attrs:
+ if len(self.attrs) != 0:
res.append(' ')
- res.append(transform(attr))
+ res.append(transform(self.attrs))
return ''.join(res)
def describe_signature(self, signode: TextElement, mode: str,
@@ -732,14 +732,14 @@ class ASTParameters(ASTBase):
arg.describe_signature(signode, 'markType', env, symbol=symbol)
signode += addnodes.desc_sig_punctuation(')', ')')
- for attr in self.attrs:
+ if len(self.attrs) != 0:
signode += addnodes.desc_sig_space()
- attr.describe_signature(signode)
+ self.attrs.describe_signature(signode)
class ASTDeclSpecsSimple(ASTBaseBase):
def __init__(self, storage: str, threadLocal: str, inline: bool,
- restrict: bool, volatile: bool, const: bool, attrs: List[Any]) -> None:
+ restrict: bool, volatile: bool, const: bool, attrs: ASTAttributeList) -> None:
self.storage = storage
self.threadLocal = threadLocal
self.inline = inline
@@ -761,7 +761,8 @@ class ASTDeclSpecsSimple(ASTBaseBase):
def _stringify(self, transform: StringifyTransform) -> str:
res: List[str] = []
- res.extend(transform(attr) for attr in self.attrs)
+ if len(self.attrs) != 0:
+ res.append(transform(self.attrs))
if self.storage:
res.append(self.storage)
if self.threadLocal:
@@ -778,14 +779,15 @@ class ASTDeclSpecsSimple(ASTBaseBase):
def describe_signature(self, modifiers: List[Node]) -> None:
def _add(modifiers: List[Node], text: str) -> None:
- if len(modifiers) > 0:
+ if len(modifiers) != 0:
modifiers.append(addnodes.desc_sig_space())
modifiers.append(addnodes.desc_sig_keyword(text, text))
- for attr in self.attrs:
- if len(modifiers) > 0:
- modifiers.append(addnodes.desc_sig_space())
- modifiers.append(attr.describe_signature(modifiers))
+ if len(modifiers) != 0 and len(self.attrs) != 0:
+ modifiers.append(addnodes.desc_sig_space())
+ tempNode = nodes.TextElement()
+ self.attrs.describe_signature(tempNode)
+ modifiers.extend(tempNode.children)
if self.storage:
_add(modifiers, self.storage)
if self.threadLocal:
@@ -1002,7 +1004,7 @@ class ASTDeclaratorNameBitField(ASTDeclarator):
class ASTDeclaratorPtr(ASTDeclarator):
def __init__(self, next: ASTDeclarator, restrict: bool, volatile: bool, const: bool,
- attrs: Any) -> None:
+ attrs: ASTAttributeList) -> None:
assert next
self.next = next
self.restrict = restrict
@@ -1025,9 +1027,8 @@ class ASTDeclaratorPtr(ASTDeclarator):
def _stringify(self, transform: StringifyTransform) -> str:
res = ['*']
- for a in self.attrs:
- res.append(transform(a))
- if len(self.attrs) > 0 and (self.restrict or self.volatile or self.const):
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
res.append(' ')
if self.restrict:
res.append('restrict')
@@ -1049,9 +1050,8 @@ class ASTDeclaratorPtr(ASTDeclarator):
env: "BuildEnvironment", symbol: "Symbol") -> None:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('*', '*')
- for a in self.attrs:
- a.describe_signature(signode)
- if len(self.attrs) > 0 and (self.restrict or self.volatile or self.const):
+ self.attrs.describe_signature(signode)
+ if len(self.attrs) != 0 and (self.restrict or self.volatile or self.const):
signode += addnodes.desc_sig_space()
def _add_anno(signode: TextElement, text: str) -> None:
@@ -2641,13 +2641,7 @@ class DefinitionParser(BaseParser):
'Expecting "," or ")" in parameters, '
'got "%s".' % self.current_char)
- attrs = []
- while True:
- attr = self._parse_attribute()
- if attr is None:
- break
- attrs.append(attr)
-
+ attrs = self._parse_attribute_list()
return ASTParameters(args, attrs)
def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple:
@@ -2706,7 +2700,7 @@ class DefinitionParser(BaseParser):
continue
break
return ASTDeclSpecsSimple(storage, threadLocal, inline,
- restrict, volatile, const, attrs)
+ restrict, volatile, const, ASTAttributeList(attrs))
def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs:
if outer:
@@ -2838,7 +2832,7 @@ class DefinitionParser(BaseParser):
next = self._parse_declarator(named, paramMode, typed)
return ASTDeclaratorPtr(next=next,
restrict=restrict, volatile=volatile, const=const,
- attrs=attrs)
+ attrs=ASTAttributeList(attrs))
if typed and self.current_char == '(': # note: peeking, not skipping
# maybe this is the beginning of params, try that first,
# otherwise assume it's noptr->declarator > ( ptr-declarator )
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index f62a8d06a..26a2f2cd2 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -21,8 +21,8 @@ from sphinx.roles import SphinxRole, XRefRole
from sphinx.transforms import SphinxTransform
from sphinx.transforms.post_transforms import ReferencesResolver
from sphinx.util import logging
-from sphinx.util.cfamily import (ASTAttribute, ASTBaseBase, ASTBaseParenExprList, BaseParser,
- DefinitionError, NoOldIdError, StringifyTransform,
+from sphinx.util.cfamily import (ASTAttributeList, ASTBaseBase, ASTBaseParenExprList,
+ BaseParser, DefinitionError, NoOldIdError, StringifyTransform,
UnsupportedMultiCharacterCharLiteral, anon_identifier_re,
binary_literal_re, char_literal_re, float_literal_re,
float_literal_suffix_re, hex_literal_re, identifier_re,
@@ -2048,7 +2048,7 @@ class ASTParametersQualifiers(ASTBase):
def __init__(self, args: List[ASTFunctionParameter], volatile: bool, const: bool,
refQual: Optional[str], exceptionSpec: ASTNoexceptSpec,
trailingReturn: "ASTType",
- override: bool, final: bool, attrs: List[ASTAttribute],
+ override: bool, final: bool, attrs: ASTAttributeList,
initializer: Optional[str]) -> None:
self.args = args
self.volatile = volatile
@@ -2118,9 +2118,9 @@ class ASTParametersQualifiers(ASTBase):
res.append(' final')
if self.override:
res.append(' override')
- for attr in self.attrs:
+ if len(self.attrs) != 0:
res.append(' ')
- res.append(transform(attr))
+ res.append(transform(self.attrs))
if self.initializer:
res.append(' = ')
res.append(self.initializer)
@@ -2171,9 +2171,9 @@ class ASTParametersQualifiers(ASTBase):
_add_anno(signode, 'final')
if self.override:
_add_anno(signode, 'override')
- for attr in self.attrs:
+ if len(self.attrs) != 0:
signode += addnodes.desc_sig_space()
- attr.describe_signature(signode)
+ self.attrs.describe_signature(signode)
if self.initializer:
signode += addnodes.desc_sig_space()
signode += addnodes.desc_sig_punctuation('=', '=')
@@ -2211,7 +2211,7 @@ class ASTDeclSpecsSimple(ASTBase):
explicitSpec: Optional[ASTExplicitSpec],
consteval: bool, constexpr: bool, constinit: bool,
volatile: bool, const: bool, friend: bool,
- attrs: List[ASTAttribute]) -> None:
+ attrs: ASTAttributeList) -> None:
self.storage = storage
self.threadLocal = threadLocal
self.inline = inline
@@ -2243,7 +2243,8 @@ class ASTDeclSpecsSimple(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
res: List[str] = []
- res.extend(transform(attr) for attr in self.attrs)
+ if len(self.attrs) != 0:
+ res.append(transform(self.attrs))
if self.storage:
res.append(self.storage)
if self.threadLocal:
@@ -2270,12 +2271,8 @@ class ASTDeclSpecsSimple(ASTBase):
def describe_signature(self, signode: TextElement,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- addSpace = False
- for attr in self.attrs:
- if addSpace:
- signode += addnodes.desc_sig_space()
- addSpace = True
- attr.describe_signature(signode)
+ self.attrs.describe_signature(signode)
+ addSpace = len(self.attrs) != 0
def _add(signode: TextElement, text: str) -> bool:
if addSpace:
@@ -2592,7 +2589,7 @@ class ASTDeclaratorNameBitField(ASTDeclarator):
class ASTDeclaratorPtr(ASTDeclarator):
def __init__(self, next: ASTDeclarator, volatile: bool, const: bool,
- attrs: List[ASTAttribute]) -> None:
+ attrs: ASTAttributeList) -> None:
assert next
self.next = next
self.volatile = volatile
@@ -2620,9 +2617,8 @@ class ASTDeclaratorPtr(ASTDeclarator):
def _stringify(self, transform: StringifyTransform) -> str:
res = ['*']
- for a in self.attrs:
- res.append(transform(a))
- if len(self.attrs) > 0 and (self.volatile or self.const):
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0 and (self.volatile or self.const):
res.append(' ')
if self.volatile:
res.append('volatile')
@@ -2677,9 +2673,8 @@ class ASTDeclaratorPtr(ASTDeclarator):
env: "BuildEnvironment", symbol: "Symbol") -> None:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('*', '*')
- for a in self.attrs:
- a.describe_signature(signode)
- if len(self.attrs) > 0 and (self.volatile or self.const):
+ self.attrs.describe_signature(signode)
+ if len(self.attrs) != 0 and (self.volatile or self.const):
signode += addnodes.desc_sig_space()
def _add_anno(signode: TextElement, text: str) -> None:
@@ -2697,7 +2692,7 @@ class ASTDeclaratorPtr(ASTDeclarator):
class ASTDeclaratorRef(ASTDeclarator):
- def __init__(self, next: ASTDeclarator, attrs: List[ASTAttribute]) -> None:
+ def __init__(self, next: ASTDeclarator, attrs: ASTAttributeList) -> None:
assert next
self.next = next
self.attrs = attrs
@@ -2727,9 +2722,8 @@ class ASTDeclaratorRef(ASTDeclarator):
def _stringify(self, transform: StringifyTransform) -> str:
res = ['&']
- for a in self.attrs:
- res.append(transform(a))
- if len(self.attrs) > 0 and self.next.require_space_after_declSpecs():
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0 and self.next.require_space_after_declSpecs():
res.append(' ')
res.append(transform(self.next))
return ''.join(res)
@@ -2758,8 +2752,7 @@ class ASTDeclaratorRef(ASTDeclarator):
env: "BuildEnvironment", symbol: "Symbol") -> None:
verify_description_mode(mode)
signode += addnodes.desc_sig_punctuation('&', '&')
- for a in self.attrs:
- a.describe_signature(signode)
+ self.attrs.describe_signature(signode)
if len(self.attrs) > 0 and self.next.require_space_after_declSpecs():
signode += addnodes.desc_sig_space()
self.next.describe_signature(signode, mode, env, symbol)
@@ -3349,7 +3342,7 @@ class ASTBaseClass(ASTBase):
class ASTClass(ASTBase):
def __init__(self, name: ASTNestedName, final: bool, bases: List[ASTBaseClass],
- attrs: List[ASTAttribute]) -> None:
+ attrs: ASTAttributeList) -> None:
self.name = name
self.final = final
self.bases = bases
@@ -3360,8 +3353,9 @@ class ASTClass(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
res = []
- for attr in self.attrs:
- res.append(transform(attr) + ' ')
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0:
+ res.append(' ')
res.append(transform(self.name))
if self.final:
res.append(' final')
@@ -3378,8 +3372,8 @@ class ASTClass(ASTBase):
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)
+ self.attrs.describe_signature(signode)
+ if len(self.attrs) != 0:
signode += addnodes.desc_sig_space()
self.name.describe_signature(signode, mode, env, symbol=symbol)
if self.final:
@@ -3398,7 +3392,7 @@ class ASTClass(ASTBase):
class ASTUnion(ASTBase):
- def __init__(self, name: ASTNestedName, attrs: List[ASTAttribute]) -> None:
+ def __init__(self, name: ASTNestedName, attrs: ASTAttributeList) -> None:
self.name = name
self.attrs = attrs
@@ -3409,23 +3403,24 @@ class ASTUnion(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
res = []
- for attr in self.attrs:
- res.append(transform(attr) + ' ')
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0:
+ res.append(' ')
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)
+ self.attrs.describe_signature(signode)
+ if len(self.attrs) != 0:
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,
- attrs: List[ASTAttribute]) -> None:
+ attrs: ASTAttributeList) -> None:
self.name = name
self.scoped = scoped
self.underlyingType = underlyingType
@@ -3441,8 +3436,9 @@ class ASTEnum(ASTBase):
if self.scoped:
res.append(self.scoped)
res.append(' ')
- for attr in self.attrs:
- res.append(transform(attr) + ' ')
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0:
+ res.append(' ')
res.append(transform(self.name))
if self.underlyingType:
res.append(' : ')
@@ -3453,8 +3449,8 @@ class ASTEnum(ASTBase):
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)
+ self.attrs.describe_signature(signode)
+ if len(self.attrs) != 0:
signode += addnodes.desc_sig_space()
self.name.describe_signature(signode, mode, env, symbol=symbol)
if self.underlyingType:
@@ -6118,12 +6114,7 @@ class DefinitionParser(BaseParser):
override = self.skip_word_and_ws(
'override') # they can be permuted
- attrs = []
- while True:
- attr = self._parse_attribute()
- if attr is None:
- break
- attrs.append(attr)
+ attrs = self._parse_attribute_list()
self.skip_ws()
initializer = None
@@ -6235,7 +6226,7 @@ class DefinitionParser(BaseParser):
break
return ASTDeclSpecsSimple(storage, threadLocal, inline, virtual,
explicitSpec, consteval, constexpr, constinit,
- volatile, const, friend, attrs)
+ volatile, const, friend, ASTAttributeList(attrs))
def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs:
if outer:
@@ -6332,7 +6323,7 @@ class DefinitionParser(BaseParser):
self.skip_ws()
volatile = False
const = False
- attrs = []
+ attrList = []
while 1:
if not volatile:
volatile = self.skip_word_and_ws('volatile')
@@ -6344,19 +6335,15 @@ class DefinitionParser(BaseParser):
continue
attr = self._parse_attribute()
if attr is not None:
- attrs.append(attr)
+ attrList.append(attr)
continue
break
next = self._parse_declarator(named, paramMode, typed)
- return ASTDeclaratorPtr(next=next, volatile=volatile, const=const, attrs=attrs)
+ return ASTDeclaratorPtr(next=next, volatile=volatile, const=const,
+ attrs=ASTAttributeList(attrList))
# TODO: shouldn't we parse an R-value ref here first?
if typed and self.skip_string("&"):
- attrs = []
- while 1:
- attr = self._parse_attribute()
- if attr is None:
- break
- attrs.append(attr)
+ attrs = self._parse_attribute_list()
next = self._parse_declarator(named, paramMode, typed)
return ASTDeclaratorRef(next=next, attrs=attrs)
if typed and self.skip_string("..."):
@@ -6628,12 +6615,7 @@ class DefinitionParser(BaseParser):
return ASTConcept(nestedName, initializer)
def _parse_class(self) -> ASTClass:
- attrs = []
- while 1:
- attr = self._parse_attribute()
- if attr is None:
- break
- attrs.append(attr)
+ attrs = self._parse_attribute_list()
name = self._parse_nested_name()
self.skip_ws()
final = self.skip_word_and_ws('final')
@@ -6664,24 +6646,13 @@ class DefinitionParser(BaseParser):
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)
+ attrs = self._parse_attribute_list()
name = self._parse_nested_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()
+ attrs = self._parse_attribute_list()
name = self._parse_nested_name()
self.skip_ws()
underlyingType = None
diff --git a/sphinx/util/cfamily.py b/sphinx/util/cfamily.py
index e751ae9bb..027417dd6 100644
--- a/sphinx/util/cfamily.py
+++ b/sphinx/util/cfamily.py
@@ -192,6 +192,30 @@ class ASTParenAttribute(ASTAttribute):
signode.append(nodes.Text(txt, txt))
+class ASTAttributeList(ASTBaseBase):
+ def __init__(self, attrs: List[ASTAttribute]) -> None:
+ self.attrs = attrs
+
+ def __len__(self) -> int:
+ return len(self.attrs)
+
+ def __add__(self, other: "ASTAttributeList") -> "ASTAttributeList":
+ return ASTAttributeList(self.attrs + other.attrs)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return ' '.join(transform(attr) for attr in self.attrs)
+
+ def describe_signature(self, signode: TextElement) -> None:
+ if len(self.attrs) == 0:
+ return
+ self.attrs[0].describe_signature(signode)
+ if len(self.attrs) == 1:
+ return
+ for attr in self.attrs[1:]:
+ signode.append(addnodes.desc_sig_space())
+ attr.describe_signature(signode)
+
+
################################################################################
class ASTBaseParenExprList(ASTBaseBase):
@@ -423,5 +447,14 @@ class BaseParser:
return None
+ def _parse_attribute_list(self) -> ASTAttributeList:
+ res = []
+ while True:
+ attr = self._parse_attribute()
+ if attr is None:
+ break
+ res.append(attr)
+ return ASTAttributeList(res)
+
def _parse_paren_expression_list(self) -> ASTBaseParenExprList:
raise NotImplementedError
diff --git a/tests/test_domain_c.py b/tests/test_domain_c.py
index 16a71d9fe..dcae320e3 100644
--- a/tests/test_domain_c.py
+++ b/tests/test_domain_c.py
@@ -573,10 +573,10 @@ def test_domain_c_ast_attributes():
output='__attribute__(()) static inline void f()')
check('function', '[[attr1]] [[attr2]] void f()', {1: 'f'})
# position: declarator
- check('member', 'int *[[attr]] i', {1: 'i'})
- check('member', 'int *const [[attr]] volatile i', {1: 'i'},
- output='int *[[attr]] volatile const i')
- check('member', 'int *[[attr]] *i', {1: 'i'})
+ check('member', 'int *[[attr1]] [[attr2]] i', {1: 'i'})
+ check('member', 'int *const [[attr1]] [[attr2]] volatile i', {1: 'i'},
+ output='int *[[attr1]] [[attr2]] volatile const i')
+ check('member', 'int *[[attr1]] [[attr2]] *i', {1: 'i'})
# position: parameters
check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f'})
diff --git a/tests/test_domain_cpp.py b/tests/test_domain_cpp.py
index 5f4c19171..e344ce45b 100644
--- a/tests/test_domain_cpp.py
+++ b/tests/test_domain_cpp.py
@@ -983,18 +983,18 @@ def test_domain_cpp_ast_attributes():
output='__attribute__(()) static inline void f()')
check('function', '[[attr1]] [[attr2]] void f()', {1: 'f', 2: '1fv'})
# position: declarator
- check('member', 'int *[[attr]] i', {1: 'i__iP', 2: '1i'})
- check('member', 'int *const [[attr]] volatile i', {1: 'i__iPVC', 2: '1i'},
- output='int *[[attr]] volatile const i')
- check('member', 'int &[[attr]] i', {1: 'i__iR', 2: '1i'})
- check('member', 'int *[[attr]] *i', {1: 'i__iPP', 2: '1i'})
+ check('member', 'int *[[attr1]] [[attr2]] i', {1: 'i__iP', 2: '1i'})
+ check('member', 'int *const [[attr1]] [[attr2]] volatile i', {1: 'i__iPVC', 2: '1i'},
+ output='int *[[attr1]] [[attr2]] volatile const i')
+ check('member', 'int &[[attr1]] [[attr2]] i', {1: 'i__iR', 2: '1i'})
+ check('member', 'int *[[attr1]] [[attr2]] *i', {1: 'i__iPP', 2: '1i'})
# position: parameters and qualifiers
check('function', 'void f() [[attr1]] [[attr2]]', {1: 'f', 2: '1fv'})
# position: class, union, enum
- check('class', '{key}[[nodiscard]] Foo', {1: 'Foo', 2: '3Foo'}, key='class')
- check('union', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo'}, key='union')
- check('enum', '{key}[[nodiscard]] Foo', {1: None, 2: '3Foo'}, key='enum')
+ check('class', '{key}[[attr1]] [[attr2]] Foo', {1: 'Foo', 2: '3Foo'}, key='class')
+ check('union', '{key}[[attr1]] [[attr2]] Foo', {1: None, 2: '3Foo'}, key='union')
+ check('enum', '{key}[[attr1]] [[attr2]] Foo', {1: None, 2: '3Foo'}, key='enum')
def test_domain_cpp_ast_xref_parsing():