summaryrefslogtreecommitdiffstats
path: root/sphinx/domains/cpp/_ast.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sphinx/domains/cpp/_ast.py3635
1 files changed, 3635 insertions, 0 deletions
diff --git a/sphinx/domains/cpp/_ast.py b/sphinx/domains/cpp/_ast.py
new file mode 100644
index 0000000..ad57695
--- /dev/null
+++ b/sphinx/domains/cpp/_ast.py
@@ -0,0 +1,3635 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from docutils import nodes
+
+from sphinx import addnodes
+from sphinx.domains.cpp._ids import (
+ _id_char_from_prefix,
+ _id_explicit_cast,
+ _id_fundamental_v1,
+ _id_fundamental_v2,
+ _id_operator_unary_v2,
+ _id_operator_v1,
+ _id_operator_v2,
+ _id_prefix,
+ _id_shorthands_v1,
+ _max_id,
+)
+from sphinx.util.cfamily import (
+ ASTAttributeList,
+ ASTBaseBase,
+ ASTBaseParenExprList,
+ NoOldIdError,
+ StringifyTransform,
+ UnsupportedMultiCharacterCharLiteral,
+ verify_description_mode,
+)
+
+if TYPE_CHECKING:
+
+ from docutils.nodes import Element, TextElement
+
+ from sphinx.addnodes import desc_signature
+ from sphinx.domains.cpp._symbol import Symbol
+ from sphinx.environment import BuildEnvironment
+
+
+class ASTBase(ASTBaseBase):
+ pass
+
+
+# Names
+################################################################################
+
+class ASTIdentifier(ASTBase):
+ def __init__(self, identifier: str) -> None:
+ assert identifier is not None
+ assert len(identifier) != 0
+ self.identifier = identifier
+
+ # ASTBaseBase already implements this method,
+ # but specialising it here improves performance
+ def __eq__(self, other: object) -> bool:
+ if type(other) is not ASTIdentifier:
+ return NotImplemented
+ return self.identifier == other.identifier
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.identifier)
+
+ def is_anon(self) -> bool:
+ return self.identifier[0] == '@'
+
+ def get_id(self, version: int) -> str:
+ if self.is_anon() and version < 3:
+ raise NoOldIdError
+ if version == 1:
+ if self.identifier == 'size_t':
+ return 's'
+ else:
+ return self.identifier
+ if self.identifier == "std":
+ return 'St'
+ elif self.identifier[0] == "~":
+ # a destructor, just use an arbitrary version of dtors
+ return 'D0'
+ else:
+ if self.is_anon():
+ return 'Ut%d_%s' % (len(self.identifier) - 1, self.identifier[1:])
+ else:
+ return str(len(self.identifier)) + self.identifier
+
+ # and this is where we finally make a difference between __str__ and the display string
+
+ def __str__(self) -> str:
+ return self.identifier
+
+ def get_display_string(self) -> str:
+ return "[anonymous]" if self.is_anon() else self.identifier
+
+ def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment,
+ prefix: str, templateArgs: str, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.is_anon():
+ node = addnodes.desc_sig_name(text="[anonymous]")
+ else:
+ node = addnodes.desc_sig_name(self.identifier, self.identifier)
+ if mode == 'markType':
+ targetText = prefix + self.identifier + templateArgs
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='identifier',
+ reftarget=targetText, modname=None,
+ classname=None)
+ pnode['cpp:parent_key'] = symbol.get_lookup_key()
+ pnode += node
+ signode += pnode
+ elif mode == 'lastIsName':
+ nameNode = addnodes.desc_name()
+ nameNode += node
+ signode += nameNode
+ elif mode == 'noneIsName':
+ signode += node
+ elif mode == 'param':
+ node['classes'].append('sig-param')
+ signode += node
+ elif mode == 'udl':
+ # the target is 'operator""id' instead of just 'id'
+ assert len(prefix) == 0
+ assert len(templateArgs) == 0
+ assert not self.is_anon()
+ targetText = 'operator""' + self.identifier
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='identifier',
+ reftarget=targetText, modname=None,
+ classname=None)
+ pnode['cpp:parent_key'] = symbol.get_lookup_key()
+ pnode += node
+ signode += pnode
+ else:
+ raise Exception('Unknown description mode: %s' % mode)
+
+
+class ASTNestedNameElement(ASTBase):
+ def __init__(self, identOrOp: ASTIdentifier | ASTOperator,
+ templateArgs: ASTTemplateArgs | None) -> None:
+ self.identOrOp = identOrOp
+ self.templateArgs = templateArgs
+
+ def is_operator(self) -> bool:
+ return False
+
+ def get_id(self, version: int) -> str:
+ res = self.identOrOp.get_id(version)
+ if self.templateArgs:
+ res += self.templateArgs.get_id(version)
+ return res
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = transform(self.identOrOp)
+ if self.templateArgs:
+ res += transform(self.templateArgs)
+ return res
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, prefix: str, symbol: Symbol) -> None:
+ tArgs = str(self.templateArgs) if self.templateArgs is not None else ''
+ self.identOrOp.describe_signature(signode, mode, env, prefix, tArgs, symbol)
+ if self.templateArgs is not None:
+ self.templateArgs.describe_signature(signode, 'markType', env, symbol)
+
+
+class ASTNestedName(ASTBase):
+ def __init__(self, names: list[ASTNestedNameElement],
+ templates: list[bool], rooted: bool) -> None:
+ assert len(names) > 0
+ self.names = names
+ self.templates = templates
+ assert len(self.names) == len(self.templates)
+ self.rooted = rooted
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self
+
+ def num_templates(self) -> int:
+ count = 0
+ for n in self.names:
+ if n.is_operator():
+ continue
+ if n.templateArgs:
+ count += 1
+ return count
+
+ def get_id(self, version: int, modifiers: str = '') -> str:
+ if version == 1:
+ tt = str(self)
+ if tt in _id_shorthands_v1:
+ return _id_shorthands_v1[tt]
+ else:
+ return '::'.join(n.get_id(version) for n in self.names)
+
+ res = []
+ if len(self.names) > 1 or len(modifiers) > 0:
+ res.append('N')
+ res.append(modifiers)
+ res.extend(n.get_id(version) for n in self.names)
+ if len(self.names) > 1 or len(modifiers) > 0:
+ res.append('E')
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.rooted:
+ res.append('')
+ for i in range(len(self.names)):
+ n = self.names[i]
+ if self.templates[i]:
+ res.append("template " + transform(n))
+ else:
+ res.append(transform(n))
+ return '::'.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ # just print the name part, with template args, not template params
+ if mode == 'noneIsName':
+ if self.rooted:
+ unreachable = "Can this happen?"
+ raise AssertionError(unreachable) # TODO
+ signode += nodes.Text('::')
+ for i in range(len(self.names)):
+ if i != 0:
+ unreachable = "Can this happen?"
+ raise AssertionError(unreachable) # TODO
+ signode += nodes.Text('::blah')
+ n = self.names[i]
+ if self.templates[i]:
+ unreachable = "Can this happen?"
+ raise AssertionError(unreachable) # TODO
+ signode += nodes.Text("template")
+ signode += nodes.Text(" ")
+ n.describe_signature(signode, mode, env, '', symbol)
+ elif mode == 'param':
+ assert not self.rooted, str(self)
+ assert len(self.names) == 1
+ assert not self.templates[0]
+ self.names[0].describe_signature(signode, 'param', env, '', symbol)
+ elif mode in ('markType', 'lastIsName', 'markName'):
+ # Each element should be a pending xref targeting the complete
+ # prefix. however, only the identifier part should be a link, such
+ # that template args can be a link as well.
+ # For 'lastIsName' we should also prepend template parameter lists.
+ templateParams: list[Any] = []
+ if mode == 'lastIsName':
+ assert symbol is not None
+ if symbol.declaration.templatePrefix is not None:
+ templateParams = symbol.declaration.templatePrefix.templates
+ iTemplateParams = 0
+ templateParamsPrefix = ''
+ prefix = ''
+ first = True
+ names = self.names[:-1] if mode == 'lastIsName' else self.names
+ # If lastIsName, then wrap all of the prefix in a desc_addname,
+ # else append directly to signode.
+ # NOTE: Breathe previously relied on the prefix being in the desc_addname node,
+ # so it can remove it in inner declarations.
+ dest = signode
+ if mode == 'lastIsName':
+ dest = addnodes.desc_addname()
+ if self.rooted:
+ prefix += '::'
+ if mode == 'lastIsName' and len(names) == 0:
+ signode += addnodes.desc_sig_punctuation('::', '::')
+ else:
+ dest += addnodes.desc_sig_punctuation('::', '::')
+ for i in range(len(names)):
+ nne = names[i]
+ template = self.templates[i]
+ if not first:
+ dest += addnodes.desc_sig_punctuation('::', '::')
+ prefix += '::'
+ if template:
+ dest += addnodes.desc_sig_keyword('template', 'template')
+ dest += addnodes.desc_sig_space()
+ first = False
+ txt_nne = str(nne)
+ if txt_nne != '':
+ if nne.templateArgs and iTemplateParams < len(templateParams):
+ templateParamsPrefix += str(templateParams[iTemplateParams])
+ iTemplateParams += 1
+ nne.describe_signature(dest, 'markType',
+ env, templateParamsPrefix + prefix, symbol)
+ prefix += txt_nne
+ if mode == 'lastIsName':
+ if len(self.names) > 1:
+ dest += addnodes.desc_sig_punctuation('::', '::')
+ signode += dest
+ if self.templates[-1]:
+ signode += addnodes.desc_sig_keyword('template', 'template')
+ signode += addnodes.desc_sig_space()
+ self.names[-1].describe_signature(signode, mode, env, '', symbol)
+ else:
+ raise Exception('Unknown description mode: %s' % mode)
+
+
+################################################################################
+# Expressions
+################################################################################
+
+class ASTExpression(ASTBase):
+ def get_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ raise NotImplementedError(repr(self))
+
+
+# Primary expressions
+################################################################################
+
+class ASTLiteral(ASTExpression):
+ pass
+
+
+class ASTPointerLiteral(ASTLiteral):
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'nullptr'
+
+ def get_id(self, version: int) -> str:
+ return 'LDnE'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('nullptr', 'nullptr')
+
+
+class ASTBooleanLiteral(ASTLiteral):
+ def __init__(self, value: bool) -> None:
+ self.value = value
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.value:
+ return 'true'
+ else:
+ return 'false'
+
+ def get_id(self, version: int) -> str:
+ if self.value:
+ return 'L1E'
+ else:
+ return 'L0E'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword(str(self), str(self))
+
+
+class ASTNumberLiteral(ASTLiteral):
+ def __init__(self, data: str) -> None:
+ self.data = data
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return self.data
+
+ def get_id(self, version: int) -> str:
+ # TODO: floats should be mangled by writing the hex of the binary representation
+ return "L%sE" % self.data.replace("'", "")
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_literal_number(self.data, self.data)
+
+
+class ASTStringLiteral(ASTLiteral):
+ def __init__(self, data: str) -> None:
+ self.data = data
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return self.data
+
+ def get_id(self, version: int) -> str:
+ # note: the length is not really correct with escaping
+ return "LA%d_KcE" % (len(self.data) - 2)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_literal_string(self.data, self.data)
+
+
+class ASTCharLiteral(ASTLiteral):
+ def __init__(self, prefix: str, data: str) -> None:
+ self.prefix = prefix # may be None when no prefix
+ self.data = data
+ assert prefix in _id_char_from_prefix
+ self.type = _id_char_from_prefix[prefix]
+ decoded = data.encode().decode('unicode-escape')
+ if len(decoded) == 1:
+ self.value = ord(decoded)
+ else:
+ raise UnsupportedMultiCharacterCharLiteral(decoded)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.prefix is None:
+ return "'" + self.data + "'"
+ else:
+ return self.prefix + "'" + self.data + "'"
+
+ def get_id(self, version: int) -> str:
+ # TODO: the ID should be have L E around it
+ return self.type + str(self.value)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.prefix is not None:
+ signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
+ txt = "'" + self.data + "'"
+ signode += addnodes.desc_sig_literal_char(txt, txt)
+
+
+class ASTUserDefinedLiteral(ASTLiteral):
+ def __init__(self, literal: ASTLiteral, ident: ASTIdentifier) -> None:
+ self.literal = literal
+ self.ident = ident
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.literal) + transform(self.ident)
+
+ def get_id(self, version: int) -> str:
+ # mangle as if it was a function call: ident(literal)
+ return f'clL_Zli{self.ident.get_id(version)}E{self.literal.get_id(version)}E'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.literal.describe_signature(signode, mode, env, symbol)
+ self.ident.describe_signature(signode, "udl", env, "", "", symbol)
+
+
+################################################################################
+
+class ASTThisLiteral(ASTExpression):
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return "this"
+
+ def get_id(self, version: int) -> str:
+ return "fpT"
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('this', 'this')
+
+
+class ASTFoldExpr(ASTExpression):
+ def __init__(self, leftExpr: ASTExpression | None,
+ op: str, rightExpr: ASTExpression | None) -> None:
+ assert leftExpr is not None or rightExpr is not None
+ self.leftExpr = leftExpr
+ self.op = op
+ self.rightExpr = rightExpr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['(']
+ if self.leftExpr:
+ res.append(transform(self.leftExpr))
+ res.append(' ')
+ res.append(self.op)
+ res.append(' ')
+ res.append('...')
+ if self.rightExpr:
+ res.append(' ')
+ res.append(self.op)
+ res.append(' ')
+ res.append(transform(self.rightExpr))
+ res.append(')')
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ assert version >= 3
+ if version == 3:
+ return str(self)
+ # https://github.com/itanium-cxx-abi/cxx-abi/pull/67
+ res = []
+ if self.leftExpr is None: # (... op expr)
+ res.append('fl')
+ elif self.rightExpr is None: # (expr op ...)
+ res.append('fr')
+ else: # (expr op ... op expr)
+ # we don't check where the parameter pack is,
+ # we just always call this a binary left fold
+ res.append('fL')
+ res.append(_id_operator_v2[self.op])
+ if self.leftExpr:
+ res.append(self.leftExpr.get_id(version))
+ if self.rightExpr:
+ res.append(self.rightExpr.get_id(version))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ if self.leftExpr:
+ self.leftExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_operator(self.op, self.op)
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ if self.rightExpr:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_operator(self.op, self.op)
+ signode += addnodes.desc_sig_space()
+ self.rightExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTParenExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '(' + transform(self.expr) + ')'
+
+ def get_id(self, version: int) -> str:
+ return self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTIdExpression(ASTExpression):
+ def __init__(self, name: ASTNestedName) -> None:
+ # note: this class is basically to cast a nested name as an expression
+ self.name = name
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.name)
+
+ def get_id(self, version: int) -> str:
+ return self.name.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.name.describe_signature(signode, mode, env, symbol)
+
+
+# Postfix expressions
+################################################################################
+
+class ASTPostfixOp(ASTBase):
+ def get_id(self, idPrefix: str, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ raise NotImplementedError(repr(self))
+
+
+class ASTPostfixArray(ASTPostfixOp):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '[' + transform(self.expr) + ']'
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return 'ix' + idPrefix + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_punctuation('[', '[')
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(']', ']')
+
+
+class ASTPostfixMember(ASTPostfixOp):
+ def __init__(self, name: ASTNestedName) -> None:
+ self.name = name
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '.' + transform(self.name)
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return 'dt' + idPrefix + self.name.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_punctuation('.', '.')
+ self.name.describe_signature(signode, 'noneIsName', env, symbol)
+
+
+class ASTPostfixMemberOfPointer(ASTPostfixOp):
+ def __init__(self, name: ASTNestedName) -> None:
+ self.name = name
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '->' + transform(self.name)
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return 'pt' + idPrefix + self.name.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_operator('->', '->')
+ self.name.describe_signature(signode, 'noneIsName', env, symbol)
+
+
+class ASTPostfixInc(ASTPostfixOp):
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '++'
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return 'pp' + idPrefix
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_operator('++', '++')
+
+
+class ASTPostfixDec(ASTPostfixOp):
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return '--'
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return 'mm' + idPrefix
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_operator('--', '--')
+
+
+class ASTPostfixCallExpr(ASTPostfixOp):
+ def __init__(self, lst: ASTParenExprList | ASTBracedInitList) -> None:
+ self.lst = lst
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.lst)
+
+ def get_id(self, idPrefix: str, version: int) -> str:
+ return ''.join([
+ 'cl',
+ idPrefix,
+ *(e.get_id(version) for e in self.lst.exprs),
+ 'E',
+ ])
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.lst.describe_signature(signode, mode, env, symbol)
+
+
+class ASTPostfixExpr(ASTExpression):
+ def __init__(self, prefix: ASTType, postFixes: list[ASTPostfixOp]) -> None:
+ self.prefix = prefix
+ self.postFixes = postFixes
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return ''.join([transform(self.prefix), *(transform(p) for p in self.postFixes)])
+
+ def get_id(self, version: int) -> str:
+ id = self.prefix.get_id(version)
+ for p in self.postFixes:
+ id = p.get_id(id, version)
+ return id
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.prefix.describe_signature(signode, mode, env, symbol)
+ for p in self.postFixes:
+ p.describe_signature(signode, mode, env, symbol)
+
+
+class ASTExplicitCast(ASTExpression):
+ def __init__(self, cast: str, typ: ASTType, expr: ASTExpression) -> None:
+ assert cast in _id_explicit_cast
+ self.cast = cast
+ self.typ = typ
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = [self.cast]
+ res.append('<')
+ res.append(transform(self.typ))
+ res.append('>(')
+ res.append(transform(self.expr))
+ res.append(')')
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ return (_id_explicit_cast[self.cast] +
+ self.typ.get_id(version) +
+ self.expr.get_id(version))
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword(self.cast, self.cast)
+ signode += addnodes.desc_sig_punctuation('<', '<')
+ self.typ.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation('>', '>')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTTypeId(ASTExpression):
+ def __init__(self, typeOrExpr: ASTType | ASTExpression, isType: bool) -> None:
+ self.typeOrExpr = typeOrExpr
+ self.isType = isType
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'typeid(' + transform(self.typeOrExpr) + ')'
+
+ def get_id(self, version: int) -> str:
+ prefix = 'ti' if self.isType else 'te'
+ return prefix + self.typeOrExpr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('typeid', 'typeid')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.typeOrExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+# Unary expressions
+################################################################################
+
+class ASTUnaryOpExpr(ASTExpression):
+ def __init__(self, op: str, expr: ASTExpression) -> None:
+ self.op = op
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.op[0] in 'cn':
+ return self.op + " " + transform(self.expr)
+ else:
+ return self.op + transform(self.expr)
+
+ def get_id(self, version: int) -> str:
+ return _id_operator_unary_v2[self.op] + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.op[0] in 'cn':
+ signode += addnodes.desc_sig_keyword(self.op, self.op)
+ signode += addnodes.desc_sig_space()
+ else:
+ signode += addnodes.desc_sig_operator(self.op, self.op)
+ self.expr.describe_signature(signode, mode, env, symbol)
+
+
+class ASTSizeofParamPack(ASTExpression):
+ def __init__(self, identifier: ASTIdentifier) -> None:
+ self.identifier = identifier
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return "sizeof...(" + transform(self.identifier) + ")"
+
+ def get_id(self, version: int) -> str:
+ return 'sZ' + self.identifier.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.identifier.describe_signature(signode, 'markType', env,
+ symbol=symbol, prefix="", templateArgs="")
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTSizeofType(ASTExpression):
+ def __init__(self, typ: ASTType) -> None:
+ self.typ = typ
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return "sizeof(" + transform(self.typ) + ")"
+
+ def get_id(self, version: int) -> str:
+ return 'st' + self.typ.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.typ.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTSizeofExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return "sizeof " + transform(self.expr)
+
+ def get_id(self, version: int) -> str:
+ return 'sz' + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('sizeof', 'sizeof')
+ signode += addnodes.desc_sig_space()
+ self.expr.describe_signature(signode, mode, env, symbol)
+
+
+class ASTAlignofExpr(ASTExpression):
+ def __init__(self, typ: ASTType) -> None:
+ self.typ = typ
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return "alignof(" + transform(self.typ) + ")"
+
+ def get_id(self, version: int) -> str:
+ return 'at' + self.typ.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('alignof', 'alignof')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.typ.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTNoexceptExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'noexcept(' + transform(self.expr) + ')'
+
+ def get_id(self, version: int) -> str:
+ return 'nx' + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('noexcept', 'noexcept')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTNewExpr(ASTExpression):
+ def __init__(self, rooted: bool, isNewTypeId: bool, typ: ASTType,
+ initList: ASTParenExprList | ASTBracedInitList) -> None:
+ self.rooted = rooted
+ self.isNewTypeId = isNewTypeId
+ self.typ = typ
+ self.initList = initList
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.rooted:
+ res.append('::')
+ res.append('new ')
+ # TODO: placement
+ if self.isNewTypeId:
+ res.append(transform(self.typ))
+ else:
+ raise AssertionError
+ if self.initList is not None:
+ res.append(transform(self.initList))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ # the array part will be in the type mangling, so na is not used
+ res = ['nw']
+ # TODO: placement
+ res.append('_')
+ res.append(self.typ.get_id(version))
+ if self.initList is not None:
+ res.append(self.initList.get_id(version))
+ else:
+ res.append('E')
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.rooted:
+ signode += addnodes.desc_sig_punctuation('::', '::')
+ signode += addnodes.desc_sig_keyword('new', 'new')
+ signode += addnodes.desc_sig_space()
+ # TODO: placement
+ if self.isNewTypeId:
+ self.typ.describe_signature(signode, mode, env, symbol)
+ else:
+ raise AssertionError
+ if self.initList is not None:
+ self.initList.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeleteExpr(ASTExpression):
+ def __init__(self, rooted: bool, array: bool, expr: ASTExpression) -> None:
+ self.rooted = rooted
+ self.array = array
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.rooted:
+ res.append('::')
+ res.append('delete ')
+ if self.array:
+ res.append('[] ')
+ res.append(transform(self.expr))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ if self.array:
+ id = "da"
+ else:
+ id = "dl"
+ return id + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.rooted:
+ signode += addnodes.desc_sig_punctuation('::', '::')
+ signode += addnodes.desc_sig_keyword('delete', 'delete')
+ signode += addnodes.desc_sig_space()
+ if self.array:
+ signode += addnodes.desc_sig_punctuation('[]', '[]')
+ signode += addnodes.desc_sig_space()
+ self.expr.describe_signature(signode, mode, env, symbol)
+
+
+# Other expressions
+################################################################################
+
+class ASTCastExpr(ASTExpression):
+ def __init__(self, typ: ASTType, expr: ASTExpression) -> None:
+ self.typ = typ
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['(']
+ res.append(transform(self.typ))
+ res.append(')')
+ res.append(transform(self.expr))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ return 'cv' + self.typ.get_id(version) + self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.typ.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+ self.expr.describe_signature(signode, mode, env, symbol)
+
+
+class ASTBinOpExpr(ASTExpression):
+ def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None:
+ assert len(exprs) > 0
+ assert len(exprs) == len(ops) + 1
+ self.exprs = exprs
+ self.ops = ops
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.exprs[0]))
+ for i in range(1, len(self.exprs)):
+ res.append(' ')
+ res.append(self.ops[i - 1])
+ res.append(' ')
+ res.append(transform(self.exprs[i]))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ res = []
+ for i in range(len(self.ops)):
+ res.append(_id_operator_v2[self.ops[i]])
+ res.append(self.exprs[i].get_id(version))
+ res.append(self.exprs[-1].get_id(version))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.exprs[0].describe_signature(signode, mode, env, symbol)
+ for i in range(1, len(self.exprs)):
+ signode += addnodes.desc_sig_space()
+ op = self.ops[i - 1]
+ if ord(op[0]) >= ord('a') and ord(op[0]) <= ord('z'):
+ signode += addnodes.desc_sig_keyword(op, op)
+ else:
+ signode += addnodes.desc_sig_operator(op, op)
+ signode += addnodes.desc_sig_space()
+ self.exprs[i].describe_signature(signode, mode, env, symbol)
+
+
+class ASTConditionalExpr(ASTExpression):
+ def __init__(self, ifExpr: ASTExpression, thenExpr: ASTExpression,
+ elseExpr: ASTExpression) -> None:
+ self.ifExpr = ifExpr
+ self.thenExpr = thenExpr
+ self.elseExpr = elseExpr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.ifExpr))
+ res.append(' ? ')
+ res.append(transform(self.thenExpr))
+ res.append(' : ')
+ res.append(transform(self.elseExpr))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ res = []
+ res.append(_id_operator_v2['?'])
+ res.append(self.ifExpr.get_id(version))
+ res.append(self.thenExpr.get_id(version))
+ res.append(self.elseExpr.get_id(version))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.ifExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_operator('?', '?')
+ signode += addnodes.desc_sig_space()
+ self.thenExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_operator(':', ':')
+ signode += addnodes.desc_sig_space()
+ self.elseExpr.describe_signature(signode, mode, env, symbol)
+
+
+class ASTBracedInitList(ASTBase):
+ def __init__(self, exprs: list[ASTExpression | ASTBracedInitList],
+ trailingComma: bool) -> None:
+ self.exprs = exprs
+ self.trailingComma = trailingComma
+
+ def get_id(self, version: int) -> str:
+ return "il%sE" % ''.join(e.get_id(version) for e in self.exprs)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ exprs = ', '.join(transform(e) for e in self.exprs)
+ trailingComma = ',' if self.trailingComma else ''
+ return f'{{{exprs}{trailingComma}}}'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('{', '{')
+ first = True
+ for e in self.exprs:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ else:
+ first = False
+ e.describe_signature(signode, mode, env, symbol)
+ if self.trailingComma:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_punctuation('}', '}')
+
+
+class ASTAssignmentExpr(ASTExpression):
+ def __init__(self, leftExpr: ASTExpression, op: str,
+ rightExpr: ASTExpression | ASTBracedInitList) -> None:
+ self.leftExpr = leftExpr
+ self.op = op
+ self.rightExpr = rightExpr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.leftExpr))
+ res.append(' ')
+ res.append(self.op)
+ res.append(' ')
+ res.append(transform(self.rightExpr))
+ return ''.join(res)
+
+ def get_id(self, version: int) -> str:
+ # we end up generating the ID from left to right, instead of right to left
+ res = []
+ res.append(_id_operator_v2[self.op])
+ res.append(self.leftExpr.get_id(version))
+ res.append(self.rightExpr.get_id(version))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.leftExpr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_space()
+ if ord(self.op[0]) >= ord('a') and ord(self.op[0]) <= ord('z'):
+ signode += addnodes.desc_sig_keyword(self.op, self.op)
+ else:
+ signode += addnodes.desc_sig_operator(self.op, self.op)
+ signode += addnodes.desc_sig_space()
+ self.rightExpr.describe_signature(signode, mode, env, symbol)
+
+
+class ASTCommaExpr(ASTExpression):
+ def __init__(self, exprs: list[ASTExpression]) -> None:
+ assert len(exprs) > 0
+ self.exprs = exprs
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return ', '.join(transform(e) for e in self.exprs)
+
+ def get_id(self, version: int) -> str:
+ id_ = _id_operator_v2[',']
+ res = []
+ for i in range(len(self.exprs) - 1):
+ res.append(id_)
+ res.append(self.exprs[i].get_id(version))
+ res.append(self.exprs[-1].get_id(version))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.exprs[0].describe_signature(signode, mode, env, symbol)
+ for i in range(1, len(self.exprs)):
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ self.exprs[i].describe_signature(signode, mode, env, symbol)
+
+
+class ASTFallbackExpr(ASTExpression):
+ def __init__(self, expr: str) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return self.expr
+
+ def get_id(self, version: int) -> str:
+ return str(self.expr)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += nodes.literal(self.expr, self.expr)
+
+
+################################################################################
+# Types
+################################################################################
+
+# Things for ASTNestedName
+################################################################################
+
+class ASTOperator(ASTBase):
+ def __eq__(self, other: object) -> bool:
+ raise NotImplementedError(repr(self))
+
+ def is_anon(self) -> bool:
+ return False
+
+ def is_operator(self) -> bool:
+ return True
+
+ def get_id(self, version: int) -> str:
+ raise NotImplementedError
+
+ def _describe_identifier(self, signode: TextElement, identnode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ """Render the prefix into signode, and the last part into identnode."""
+ raise NotImplementedError
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, prefix: str, templateArgs: str,
+ symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if mode == 'lastIsName':
+ mainName = addnodes.desc_name()
+ self._describe_identifier(mainName, mainName, env, symbol)
+ signode += mainName
+ elif mode == 'markType':
+ targetText = prefix + str(self) + templateArgs
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='identifier',
+ reftarget=targetText, modname=None,
+ classname=None)
+ pnode['cpp:parent_key'] = symbol.get_lookup_key()
+ # Render the identifier part, but collapse it into a string
+ # and make that the a link to this operator.
+ # E.g., if it is 'operator SomeType', then 'SomeType' becomes
+ # a link to the operator, not to 'SomeType'.
+ container = nodes.literal()
+ self._describe_identifier(signode, container, env, symbol)
+ txt = container.astext()
+ pnode += addnodes.desc_name(txt, txt)
+ signode += pnode
+ else:
+ addName = addnodes.desc_addname()
+ self._describe_identifier(addName, addName, env, symbol)
+ signode += addName
+
+
+class ASTOperatorBuildIn(ASTOperator):
+ def __init__(self, op: str) -> None:
+ self.op = op
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, ASTOperatorBuildIn):
+ return NotImplemented
+ return self.op == other.op
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ ids = _id_operator_v1
+ if self.op not in ids:
+ raise NoOldIdError
+ else:
+ ids = _id_operator_v2
+ if self.op not in ids:
+ raise Exception('Internal error: Built-in operator "%s" can not '
+ 'be mapped to an id.' % self.op)
+ return ids[self.op]
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.op in ('new', 'new[]', 'delete', 'delete[]') or self.op[0] in "abcnox":
+ return 'operator ' + self.op
+ else:
+ return 'operator' + self.op
+
+ def _describe_identifier(self, signode: TextElement, identnode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('operator', 'operator')
+ if self.op in ('new', 'new[]', 'delete', 'delete[]') or self.op[0] in "abcnox":
+ signode += addnodes.desc_sig_space()
+ identnode += addnodes.desc_sig_operator(self.op, self.op)
+
+
+class ASTOperatorLiteral(ASTOperator):
+ def __init__(self, identifier: ASTIdentifier) -> None:
+ self.identifier = identifier
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, ASTOperatorLiteral):
+ return NotImplemented
+ return self.identifier == other.identifier
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return 'li' + self.identifier.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'operator""' + transform(self.identifier)
+
+ def _describe_identifier(self, signode: TextElement, identnode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('operator', 'operator')
+ signode += addnodes.desc_sig_literal_string('""', '""')
+ self.identifier.describe_signature(identnode, 'markType', env, '', '', symbol)
+
+
+class ASTOperatorType(ASTOperator):
+ def __init__(self, type: ASTType) -> None:
+ self.type = type
+
+ def __eq__(self, other: object) -> bool:
+ if not isinstance(other, ASTOperatorType):
+ return NotImplemented
+ return self.type == other.type
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ return 'castto-%s-operator' % self.type.get_id(version)
+ else:
+ return 'cv' + self.type.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return f'operator {transform(self.type)}'
+
+ def get_name_no_template(self) -> str:
+ return str(self)
+
+ def _describe_identifier(self, signode: TextElement, identnode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('operator', 'operator')
+ signode += addnodes.desc_sig_space()
+ self.type.describe_signature(identnode, 'markType', env, symbol)
+
+
+class ASTTemplateArgConstant(ASTBase):
+ def __init__(self, value: ASTExpression) -> None:
+ self.value = value
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.value)
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ return str(self).replace(' ', '-')
+ if version == 2:
+ return 'X' + str(self) + 'E'
+ return 'X' + self.value.get_id(version) + 'E'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.value.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateArgs(ASTBase):
+ def __init__(self, args: list[ASTType | ASTTemplateArgConstant],
+ packExpansion: bool) -> None:
+ assert args is not None
+ self.args = args
+ self.packExpansion = packExpansion
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ res = []
+ res.append(':')
+ res.append('.'.join(a.get_id(version) for a in self.args))
+ res.append(':')
+ return ''.join(res)
+
+ res = []
+ res.append('I')
+ if len(self.args) > 0:
+ for a in self.args[:-1]:
+ res.append(a.get_id(version))
+ if self.packExpansion:
+ res.append('J')
+ res.append(self.args[-1].get_id(version))
+ if self.packExpansion:
+ res.append('E')
+ res.append('E')
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ', '.join(transform(a) for a in self.args)
+ if self.packExpansion:
+ res += '...'
+ return '<' + res + '>'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('<', '<')
+ first = True
+ for a in self.args:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ first = False
+ a.describe_signature(signode, 'markType', env, symbol=symbol)
+ if self.packExpansion:
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ signode += addnodes.desc_sig_punctuation('>', '>')
+
+
+# Main part of declarations
+################################################################################
+
+class ASTTrailingTypeSpec(ASTBase):
+ def get_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ raise NotImplementedError(repr(self))
+
+
+class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
+ def __init__(self, names: list[str], canonNames: list[str]) -> None:
+ assert len(names) != 0
+ assert len(names) == len(canonNames), (names, canonNames)
+ self.names = names
+ # the canonical name list is for ID lookup
+ self.canonNames = canonNames
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return ' '.join(self.names)
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ res = []
+ for a in self.canonNames:
+ if a in _id_fundamental_v1:
+ res.append(_id_fundamental_v1[a])
+ else:
+ res.append(a)
+ return '-'.join(res)
+
+ txt = ' '.join(self.canonNames)
+ if txt not in _id_fundamental_v2:
+ raise Exception(
+ 'Semi-internal error: Fundamental type "%s" can not be mapped '
+ 'to an ID. Is it a true fundamental type? If not so, the '
+ 'parser should have rejected it.' % txt)
+ return _id_fundamental_v2[txt]
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ first = True
+ for n in self.names:
+ if not first:
+ signode += addnodes.desc_sig_space()
+ else:
+ first = False
+ signode += addnodes.desc_sig_keyword_type(n, n)
+
+
+class ASTTrailingTypeSpecDecltypeAuto(ASTTrailingTypeSpec):
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'decltype(auto)'
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return 'Dc'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('decltype', 'decltype')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ signode += addnodes.desc_sig_keyword('auto', 'auto')
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'decltype(' + transform(self.expr) + ')'
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return 'DT' + self.expr.get_id(version) + "E"
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('decltype', 'decltype')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
+ def __init__(self, prefix: str, nestedName: ASTNestedName,
+ placeholderType: str | None) -> None:
+ self.prefix = prefix
+ self.nestedName = nestedName
+ self.placeholderType = placeholderType
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.nestedName
+
+ def get_id(self, version: int) -> str:
+ return self.nestedName.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.prefix:
+ res.append(self.prefix)
+ res.append(' ')
+ res.append(transform(self.nestedName))
+ if self.placeholderType is not None:
+ res.append(' ')
+ res.append(self.placeholderType)
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.prefix:
+ signode += addnodes.desc_sig_keyword(self.prefix, self.prefix)
+ signode += addnodes.desc_sig_space()
+ self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
+ if self.placeholderType is not None:
+ signode += addnodes.desc_sig_space()
+ if self.placeholderType == 'auto':
+ signode += addnodes.desc_sig_keyword('auto', 'auto')
+ elif self.placeholderType == 'decltype(auto)':
+ signode += addnodes.desc_sig_keyword('decltype', 'decltype')
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ signode += addnodes.desc_sig_keyword('auto', 'auto')
+ signode += addnodes.desc_sig_punctuation(')', ')')
+ else:
+ raise AssertionError(self.placeholderType)
+
+
+class ASTFunctionParameter(ASTBase):
+ def __init__(self, arg: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit,
+ ellipsis: bool = False) -> None:
+ self.arg = arg
+ self.ellipsis = ellipsis
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ # this is not part of the normal name mangling in C++
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=False)
+ # else, do the usual
+ if self.ellipsis:
+ return 'z'
+ else:
+ return self.arg.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.ellipsis:
+ return '...'
+ else:
+ return transform(self.arg)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.ellipsis:
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ else:
+ self.arg.describe_signature(signode, mode, env, symbol=symbol)
+
+
+class ASTNoexceptSpec(ASTBase):
+ def __init__(self, expr: ASTExpression | None) -> None:
+ 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_sig_keyword('noexcept', 'noexcept')
+ if self.expr:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, 'markType', env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTParametersQualifiers(ASTBase):
+ def __init__(self, args: list[ASTFunctionParameter], volatile: bool, const: bool,
+ refQual: str | None, exceptionSpec: ASTNoexceptSpec,
+ trailingReturn: ASTType,
+ override: bool, final: bool, attrs: ASTAttributeList,
+ initializer: str | None) -> None:
+ self.args = args
+ self.volatile = volatile
+ self.const = const
+ self.refQual = refQual
+ self.exceptionSpec = exceptionSpec
+ self.trailingReturn = trailingReturn
+ self.override = override
+ self.final = final
+ self.attrs = attrs
+ self.initializer = initializer
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.args
+
+ def get_modifiers_id(self, version: int) -> str:
+ res = []
+ if self.volatile:
+ res.append('V')
+ if self.const:
+ if version == 1:
+ res.append('C')
+ else:
+ res.append('K')
+ if self.refQual == '&&':
+ res.append('O')
+ elif self.refQual == '&':
+ res.append('R')
+ return ''.join(res)
+
+ def get_param_id(self, version: int) -> str:
+ if version == 1:
+ if len(self.args) == 0:
+ return ''
+ else:
+ return '__' + '.'.join(a.get_id(version) for a in self.args)
+ if len(self.args) == 0:
+ return 'v'
+ else:
+ return ''.join(a.get_id(version) for a in self.args)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append('(')
+ first = True
+ for a in self.args:
+ if not first:
+ res.append(', ')
+ first = False
+ res.append(str(a))
+ res.append(')')
+ if self.volatile:
+ res.append(' volatile')
+ if self.const:
+ res.append(' const')
+ if self.refQual:
+ res.append(' ')
+ res.append(self.refQual)
+ if self.exceptionSpec:
+ res.append(' ')
+ res.append(transform(self.exceptionSpec))
+ if self.trailingReturn:
+ res.append(' -> ')
+ res.append(transform(self.trailingReturn))
+ if self.final:
+ res.append(' final')
+ if self.override:
+ res.append(' override')
+ if len(self.attrs) != 0:
+ res.append(' ')
+ res.append(transform(self.attrs))
+ if self.initializer:
+ res.append(' = ')
+ res.append(self.initializer)
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ multi_line_parameter_list = False
+ test_node: Element = signode
+ while test_node.parent:
+ if not isinstance(test_node, addnodes.desc_signature):
+ test_node = test_node.parent
+ continue
+ multi_line_parameter_list = test_node.get('multi_line_parameter_list', False)
+ break
+
+ # only use the desc_parameterlist for the outer list, not for inner lists
+ if mode == 'lastIsName':
+ paramlist = addnodes.desc_parameterlist()
+ paramlist['multi_line_parameter_list'] = multi_line_parameter_list
+ for arg in self.args:
+ param = addnodes.desc_parameter('', '', noemph=True)
+ arg.describe_signature(param, 'param', env, symbol=symbol)
+ paramlist += param
+ signode += paramlist
+ else:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ first = True
+ for arg in self.args:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ first = False
+ arg.describe_signature(signode, 'markType', env, symbol=symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+ def _add_anno(signode: TextElement, text: str) -> None:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_keyword(text, text)
+
+ if self.volatile:
+ _add_anno(signode, 'volatile')
+ if self.const:
+ _add_anno(signode, 'const')
+ if self.refQual:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation(self.refQual, self.refQual)
+ if self.exceptionSpec:
+ signode += addnodes.desc_sig_space()
+ self.exceptionSpec.describe_signature(signode, mode, env, symbol)
+ if self.trailingReturn:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_operator('->', '->')
+ signode += addnodes.desc_sig_space()
+ self.trailingReturn.describe_signature(signode, mode, env, symbol)
+ if self.final:
+ _add_anno(signode, 'final')
+ if self.override:
+ _add_anno(signode, 'override')
+ if len(self.attrs) != 0:
+ signode += addnodes.desc_sig_space()
+ self.attrs.describe_signature(signode)
+ if self.initializer:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('=', '=')
+ signode += addnodes.desc_sig_space()
+ assert self.initializer in ('0', 'delete', 'default')
+ if self.initializer == '0':
+ signode += addnodes.desc_sig_literal_number('0', '0')
+ else:
+ signode += addnodes.desc_sig_keyword(self.initializer, self.initializer)
+
+
+class ASTExplicitSpec(ASTBase):
+ def __init__(self, expr: ASTExpression | None) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['explicit']
+ if self.expr is not None:
+ res.append('(')
+ res.append(transform(self.expr))
+ res.append(')')
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('explicit', 'explicit')
+ if self.expr is not None:
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.expr.describe_signature(signode, 'markType', env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTDeclSpecsSimple(ASTBase):
+ def __init__(self, storage: str, threadLocal: bool, inline: bool, virtual: bool,
+ explicitSpec: ASTExplicitSpec | None,
+ consteval: bool, constexpr: bool, constinit: bool,
+ volatile: bool, const: bool, friend: bool,
+ attrs: ASTAttributeList) -> None:
+ self.storage = storage
+ self.threadLocal = threadLocal
+ self.inline = inline
+ self.virtual = virtual
+ self.explicitSpec = explicitSpec
+ self.consteval = consteval
+ self.constexpr = constexpr
+ self.constinit = constinit
+ self.volatile = volatile
+ self.const = const
+ self.friend = friend
+ self.attrs = attrs
+
+ def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple:
+ if not other:
+ return self
+ return ASTDeclSpecsSimple(self.storage or other.storage,
+ self.threadLocal or other.threadLocal,
+ self.inline or other.inline,
+ self.virtual or other.virtual,
+ self.explicitSpec or other.explicitSpec,
+ self.consteval or other.consteval,
+ self.constexpr or other.constexpr,
+ self.constinit or other.constinit,
+ self.volatile or other.volatile,
+ self.const or other.const,
+ self.friend or other.friend,
+ self.attrs + other.attrs)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res: list[str] = []
+ if len(self.attrs) != 0:
+ res.append(transform(self.attrs))
+ if self.storage:
+ res.append(self.storage)
+ if self.threadLocal:
+ res.append('thread_local')
+ if self.inline:
+ res.append('inline')
+ if self.friend:
+ res.append('friend')
+ if self.virtual:
+ res.append('virtual')
+ if self.explicitSpec:
+ res.append(transform(self.explicitSpec))
+ if self.consteval:
+ res.append('consteval')
+ if self.constexpr:
+ res.append('constexpr')
+ if self.constinit:
+ res.append('constinit')
+ if self.volatile:
+ res.append('volatile')
+ if self.const:
+ res.append('const')
+ return ' '.join(res)
+
+ def describe_signature(self, signode: TextElement,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.attrs.describe_signature(signode)
+ addSpace = len(self.attrs) != 0
+
+ def _add(signode: TextElement, text: str) -> bool:
+ if addSpace:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_keyword(text, text)
+ return True
+
+ if self.storage:
+ addSpace = _add(signode, self.storage)
+ if self.threadLocal:
+ addSpace = _add(signode, 'thread_local')
+ if self.inline:
+ addSpace = _add(signode, 'inline')
+ if self.friend:
+ addSpace = _add(signode, 'friend')
+ if self.virtual:
+ addSpace = _add(signode, 'virtual')
+ if self.explicitSpec:
+ if addSpace:
+ signode += addnodes.desc_sig_space()
+ self.explicitSpec.describe_signature(signode, env, symbol)
+ addSpace = True
+ if self.consteval:
+ addSpace = _add(signode, 'consteval')
+ if self.constexpr:
+ addSpace = _add(signode, 'constexpr')
+ if self.constinit:
+ addSpace = _add(signode, 'constinit')
+ if self.volatile:
+ addSpace = _add(signode, 'volatile')
+ if self.const:
+ addSpace = _add(signode, 'const')
+
+
+class ASTDeclSpecs(ASTBase):
+ def __init__(self, outer: str,
+ leftSpecs: ASTDeclSpecsSimple, rightSpecs: ASTDeclSpecsSimple,
+ trailing: ASTTrailingTypeSpec) -> None:
+ # leftSpecs and rightSpecs are used for output
+ # allSpecs are used for id generation
+ self.outer = outer
+ self.leftSpecs = leftSpecs
+ self.rightSpecs = rightSpecs
+ self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
+ self.trailingTypeSpec = trailing
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ res = []
+ res.append(self.trailingTypeSpec.get_id(version))
+ if self.allSpecs.volatile:
+ res.append('V')
+ if self.allSpecs.const:
+ res.append('C')
+ return ''.join(res)
+ res = []
+ if self.allSpecs.volatile:
+ res.append('V')
+ if self.allSpecs.const:
+ res.append('K')
+ if self.trailingTypeSpec is not None:
+ res.append(self.trailingTypeSpec.get_id(version))
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res: list[str] = []
+ l = transform(self.leftSpecs)
+ if len(l) > 0:
+ res.append(l)
+ if self.trailingTypeSpec:
+ if len(res) > 0:
+ res.append(" ")
+ res.append(transform(self.trailingTypeSpec))
+ r = str(self.rightSpecs)
+ if len(r) > 0:
+ if len(res) > 0:
+ res.append(" ")
+ res.append(r)
+ return "".join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ numChildren = len(signode)
+ self.leftSpecs.describe_signature(signode, env, symbol)
+ addSpace = len(signode) != numChildren
+
+ if self.trailingTypeSpec:
+ if addSpace:
+ signode += addnodes.desc_sig_space()
+ numChildren = len(signode)
+ self.trailingTypeSpec.describe_signature(signode, mode, env,
+ symbol=symbol)
+ addSpace = len(signode) != numChildren
+
+ if len(str(self.rightSpecs)) > 0:
+ if addSpace:
+ signode += addnodes.desc_sig_space()
+ self.rightSpecs.describe_signature(signode, env, symbol)
+
+
+# Declarator
+################################################################################
+
+class ASTArray(ASTBase):
+ def __init__(self, size: ASTExpression) -> None:
+ self.size = size
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ if self.size:
+ return '[' + transform(self.size) + ']'
+ else:
+ return '[]'
+
+ def get_id(self, version: int) -> str:
+ if version == 1:
+ return 'A'
+ if version == 2:
+ if self.size:
+ return 'A' + str(self.size) + '_'
+ else:
+ return 'A_'
+ if self.size:
+ return 'A' + self.size.get_id(version) + '_'
+ else:
+ return 'A_'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('[', '[')
+ if self.size:
+ self.size.describe_signature(signode, 'markType', env, symbol)
+ signode += addnodes.desc_sig_punctuation(']', ']')
+
+
+class ASTDeclarator(ASTBase):
+ @property
+ def name(self) -> ASTNestedName:
+ raise NotImplementedError(repr(self))
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def isPack(self) -> bool:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ raise NotImplementedError(repr(self))
+
+ def require_space_after_declSpecs(self) -> bool:
+ raise NotImplementedError(repr(self))
+
+ def get_modifiers_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def get_param_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ raise NotImplementedError(repr(self))
+
+ def is_function_type(self) -> bool:
+ raise NotImplementedError(repr(self))
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ raise NotImplementedError(repr(self))
+
+
+class ASTDeclaratorNameParamQual(ASTDeclarator):
+ def __init__(self, declId: ASTNestedName,
+ arrayOps: list[ASTArray],
+ paramQual: ASTParametersQualifiers) -> None:
+ self.declId = declId
+ self.arrayOps = arrayOps
+ self.paramQual = paramQual
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.declId
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.declId = name
+
+ @property
+ def isPack(self) -> bool:
+ return False
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.paramQual.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.paramQual.trailingReturn
+
+ # only the modifiers for a function, e.g.,
+ def get_modifiers_id(self, version: int) -> str:
+ # cv-qualifiers
+ if self.paramQual:
+ return self.paramQual.get_modifiers_id(version)
+ raise Exception("This should only be called on a function: %s" % self)
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ if self.paramQual:
+ return self.paramQual.get_param_id(version)
+ else:
+ return ''
+
+ def get_ptr_suffix_id(self, version: int) -> str: # only the array specifiers
+ return ''.join(a.get_id(version) for a in self.arrayOps)
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ assert version >= 2
+ res = []
+ # TODO: can we actually have both array ops and paramQual?
+ res.append(self.get_ptr_suffix_id(version))
+ if self.paramQual:
+ res.append(self.get_modifiers_id(version))
+ res.append('F')
+ res.append(returnTypeId)
+ res.append(self.get_param_id(version))
+ res.append('E')
+ else:
+ res.append(returnTypeId)
+ return ''.join(res)
+
+ # ------------------------------------------------------------------------
+
+ def require_space_after_declSpecs(self) -> bool:
+ return self.declId is not None
+
+ def is_function_type(self) -> bool:
+ return self.paramQual is not None
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.declId:
+ res.append(transform(self.declId))
+ res.extend(transform(op) for op in self.arrayOps)
+ if self.paramQual:
+ res.append(transform(self.paramQual))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.declId:
+ self.declId.describe_signature(signode, mode, env, symbol)
+ for op in self.arrayOps:
+ op.describe_signature(signode, mode, env, symbol)
+ if self.paramQual:
+ self.paramQual.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorNameBitField(ASTDeclarator):
+ def __init__(self, declId: ASTNestedName, size: ASTExpression) -> None:
+ self.declId = declId
+ self.size = size
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.declId
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.declId = name
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ return ''
+
+ def get_ptr_suffix_id(self, version: int) -> str: # only the array specifiers
+ return ''
+
+ # ------------------------------------------------------------------------
+
+ def require_space_after_declSpecs(self) -> bool:
+ return self.declId is not None
+
+ def is_function_type(self) -> bool:
+ return False
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.declId:
+ res.append(transform(self.declId))
+ res.append(" : ")
+ res.append(transform(self.size))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.declId:
+ self.declId.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation(':', ':')
+ signode += addnodes.desc_sig_space()
+ self.size.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorPtr(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator, volatile: bool, const: bool,
+ attrs: ASTAttributeList) -> None:
+ assert next
+ self.next = next
+ self.volatile = volatile
+ self.const = const
+ self.attrs = attrs
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.next.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.next.name = name
+
+ @property
+ def isPack(self) -> bool:
+ return self.next.isPack
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.next.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.next.trailingReturn
+
+ def require_space_after_declSpecs(self) -> bool:
+ return self.next.require_space_after_declSpecs()
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['*']
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0 and (self.volatile or self.const):
+ res.append(' ')
+ if self.volatile:
+ res.append('volatile')
+ if self.const:
+ if self.volatile:
+ res.append(' ')
+ res.append('const')
+ if self.const or self.volatile or len(self.attrs) > 0:
+ if self.next.require_space_after_declSpecs():
+ res.append(' ')
+ res.append(transform(self.next))
+ return ''.join(res)
+
+ def get_modifiers_id(self, version: int) -> str:
+ return self.next.get_modifiers_id(version)
+
+ def get_param_id(self, version: int) -> str:
+ return self.next.get_param_id(version)
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ if version == 1:
+ res = ['P']
+ if self.volatile:
+ res.append('V')
+ if self.const:
+ res.append('C')
+ res.append(self.next.get_ptr_suffix_id(version))
+ return ''.join(res)
+
+ res = [self.next.get_ptr_suffix_id(version)]
+ res.append('P')
+ if self.volatile:
+ res.append('V')
+ if self.const:
+ res.append('C')
+ return ''.join(res)
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ # ReturnType *next, so we are part of the return type of 'next
+ res = ['P']
+ if self.volatile:
+ res.append('V')
+ if self.const:
+ res.append('C')
+ res.append(returnTypeId)
+ return self.next.get_type_id(version, returnTypeId=''.join(res))
+
+ def is_function_type(self) -> bool:
+ return self.next.is_function_type()
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('*', '*')
+ 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:
+ signode += addnodes.desc_sig_keyword(text, text)
+ if self.volatile:
+ _add_anno(signode, 'volatile')
+ if self.const:
+ if self.volatile:
+ signode += addnodes.desc_sig_space()
+ _add_anno(signode, 'const')
+ if self.const or self.volatile or len(self.attrs) > 0:
+ if self.next.require_space_after_declSpecs():
+ signode += addnodes.desc_sig_space()
+ self.next.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorRef(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator, attrs: ASTAttributeList) -> None:
+ assert next
+ self.next = next
+ self.attrs = attrs
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.next.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.next.name = name
+
+ @property
+ def isPack(self) -> bool:
+ return self.next.isPack
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.next.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.next.trailingReturn
+
+ def require_space_after_declSpecs(self) -> bool:
+ return self.next.require_space_after_declSpecs()
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['&']
+ 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)
+
+ def get_modifiers_id(self, version: int) -> str:
+ return self.next.get_modifiers_id(version)
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ return self.next.get_param_id(version)
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ if version == 1:
+ return 'R' + self.next.get_ptr_suffix_id(version)
+ else:
+ return self.next.get_ptr_suffix_id(version) + 'R'
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ assert version >= 2
+ # ReturnType &next, so we are part of the return type of 'next
+ return self.next.get_type_id(version, returnTypeId='R' + returnTypeId)
+
+ def is_function_type(self) -> bool:
+ return self.next.is_function_type()
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('&', '&')
+ 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)
+
+
+class ASTDeclaratorParamPack(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator) -> None:
+ assert next
+ self.next = next
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.next.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.next.name = name
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.next.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.next.trailingReturn
+
+ @property
+ def isPack(self) -> bool:
+ return True
+
+ def require_space_after_declSpecs(self) -> bool:
+ return False
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = transform(self.next)
+ if self.next.name:
+ res = ' ' + res
+ return '...' + res
+
+ def get_modifiers_id(self, version: int) -> str:
+ return self.next.get_modifiers_id(version)
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ return self.next.get_param_id(version)
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ if version == 1:
+ return 'Dp' + self.next.get_ptr_suffix_id(version)
+ else:
+ return self.next.get_ptr_suffix_id(version) + 'Dp'
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ assert version >= 2
+ # ReturnType... next, so we are part of the return type of 'next
+ return self.next.get_type_id(version, returnTypeId='Dp' + returnTypeId)
+
+ def is_function_type(self) -> bool:
+ return self.next.is_function_type()
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ if self.next.name:
+ signode += addnodes.desc_sig_space()
+ self.next.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorMemPtr(ASTDeclarator):
+ def __init__(self, className: ASTNestedName,
+ const: bool, volatile: bool, next: ASTDeclarator) -> None:
+ assert className
+ assert next
+ self.className = className
+ self.const = const
+ self.volatile = volatile
+ self.next = next
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.next.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.next.name = name
+
+ @property
+ def isPack(self) -> bool:
+ return self.next.isPack
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.next.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.next.trailingReturn
+
+ def require_space_after_declSpecs(self) -> bool:
+ return True
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.className))
+ res.append('::*')
+ if self.volatile:
+ res.append('volatile')
+ if self.const:
+ if self.volatile:
+ res.append(' ')
+ res.append('const')
+ if self.next.require_space_after_declSpecs():
+ res.append(' ')
+ res.append(transform(self.next))
+ return ''.join(res)
+
+ def get_modifiers_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return self.next.get_modifiers_id(version)
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ if version == 1:
+ raise NoOldIdError
+ return self.next.get_param_id(version)
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError
+ raise NotImplementedError
+ return self.next.get_ptr_suffix_id(version) + 'Dp'
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ assert version >= 2
+ # ReturnType name::* next, so we are part of the return type of next
+ nextReturnTypeId = ''
+ if self.volatile:
+ nextReturnTypeId += 'V'
+ if self.const:
+ nextReturnTypeId += 'K'
+ nextReturnTypeId += 'M'
+ nextReturnTypeId += self.className.get_id(version)
+ nextReturnTypeId += returnTypeId
+ return self.next.get_type_id(version, nextReturnTypeId)
+
+ def is_function_type(self) -> bool:
+ return self.next.is_function_type()
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.className.describe_signature(signode, 'markType', env, symbol)
+ signode += addnodes.desc_sig_punctuation('::', '::')
+ signode += addnodes.desc_sig_punctuation('*', '*')
+
+ def _add_anno(signode: TextElement, text: str) -> None:
+ signode += addnodes.desc_sig_keyword(text, text)
+ if self.volatile:
+ _add_anno(signode, 'volatile')
+ if self.const:
+ if self.volatile:
+ signode += addnodes.desc_sig_space()
+ _add_anno(signode, 'const')
+ if self.next.require_space_after_declSpecs():
+ signode += addnodes.desc_sig_space()
+ self.next.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorParen(ASTDeclarator):
+ def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
+ assert inner
+ assert next
+ self.inner = inner
+ self.next = next
+ # TODO: we assume the name, params, and qualifiers are in inner
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.inner.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.inner.name = name
+
+ @property
+ def isPack(self) -> bool:
+ return self.inner.isPack or self.next.isPack
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.inner.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.inner.trailingReturn
+
+ def require_space_after_declSpecs(self) -> bool:
+ return True
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = ['(']
+ res.append(transform(self.inner))
+ res.append(')')
+ res.append(transform(self.next))
+ return ''.join(res)
+
+ def get_modifiers_id(self, version: int) -> str:
+ return self.inner.get_modifiers_id(version)
+
+ def get_param_id(self, version: int) -> str: # only the parameters (if any)
+ return self.inner.get_param_id(version)
+
+ def get_ptr_suffix_id(self, version: int) -> str:
+ if version == 1:
+ raise NoOldIdError # TODO: was this implemented before?
+ return self.next.get_ptr_suffix_id(version) + \
+ self.inner.get_ptr_suffix_id(version)
+ return self.inner.get_ptr_suffix_id(version) + \
+ self.next.get_ptr_suffix_id(version)
+
+ def get_type_id(self, version: int, returnTypeId: str) -> str:
+ assert version >= 2
+ # ReturnType (inner)next, so 'inner' returns everything outside
+ nextId = self.next.get_type_id(version, returnTypeId)
+ return self.inner.get_type_id(version, returnTypeId=nextId)
+
+ def is_function_type(self) -> bool:
+ return self.inner.is_function_type()
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ self.inner.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+ self.next.describe_signature(signode, "noneIsName", env, symbol)
+
+
+# Type and initializer stuff
+##############################################################################################
+
+class ASTPackExpansionExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression | ASTBracedInitList) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.expr) + '...'
+
+ def get_id(self, version: int) -> str:
+ id = self.expr.get_id(version)
+ return 'sp' + id
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation('...', '...')
+
+
+class ASTParenExprList(ASTBaseParenExprList):
+ def __init__(self, exprs: list[ASTExpression | ASTBracedInitList]) -> None:
+ self.exprs = exprs
+
+ def get_id(self, version: int) -> str:
+ return "pi%sE" % ''.join(e.get_id(version) for e in self.exprs)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ exprs = [transform(e) for e in self.exprs]
+ return '(%s)' % ', '.join(exprs)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ signode += addnodes.desc_sig_punctuation('(', '(')
+ first = True
+ for e in self.exprs:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ else:
+ first = False
+ e.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation(')', ')')
+
+
+class ASTInitializer(ASTBase):
+ def __init__(self, value: ASTExpression | ASTBracedInitList,
+ hasAssign: bool = True) -> None:
+ self.value = value
+ self.hasAssign = hasAssign
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ val = transform(self.value)
+ if self.hasAssign:
+ return ' = ' + val
+ else:
+ return val
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.hasAssign:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('=', '=')
+ signode += addnodes.desc_sig_space()
+ self.value.describe_signature(signode, 'markType', env, symbol)
+
+
+class ASTType(ASTBase):
+ def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
+ assert declSpecs
+ assert decl
+ self.declSpecs = declSpecs
+ self.decl = decl
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.decl.name
+
+ @name.setter
+ def name(self, name: ASTNestedName) -> None:
+ self.decl.name = name
+
+ @property
+ def isPack(self) -> bool:
+ return self.decl.isPack
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ return self.decl.function_params
+
+ @property
+ def trailingReturn(self) -> ASTType:
+ return self.decl.trailingReturn
+
+ def get_id(self, version: int, objectType: str | None = None,
+ symbol: Symbol | None = None) -> str:
+ if version == 1:
+ res = []
+ if objectType: # needs the name
+ if objectType == 'function': # also modifiers
+ res.append(symbol.get_full_nested_name().get_id(version))
+ res.append(self.decl.get_param_id(version))
+ res.append(self.decl.get_modifiers_id(version))
+ if (self.declSpecs.leftSpecs.constexpr or
+ (self.declSpecs.rightSpecs and
+ self.declSpecs.rightSpecs.constexpr)):
+ res.append('CE')
+ elif objectType == 'type': # just the name
+ res.append(symbol.get_full_nested_name().get_id(version))
+ else:
+ raise AssertionError(objectType)
+ else: # only type encoding
+ if self.decl.is_function_type():
+ raise NoOldIdError
+ res.append(self.declSpecs.get_id(version))
+ res.append(self.decl.get_ptr_suffix_id(version))
+ res.append(self.decl.get_param_id(version))
+ return ''.join(res)
+ # other versions
+ res = []
+ if objectType: # needs the name
+ if objectType == 'function': # also modifiers
+ modifiers = self.decl.get_modifiers_id(version)
+ res.append(symbol.get_full_nested_name().get_id(version, modifiers))
+ if version >= 4:
+ # with templates we need to mangle the return type in as well
+ templ = symbol.declaration.templatePrefix
+ if templ is not None:
+ typeId = self.decl.get_ptr_suffix_id(version)
+ if self.trailingReturn:
+ returnTypeId = self.trailingReturn.get_id(version)
+ else:
+ returnTypeId = self.declSpecs.get_id(version)
+ res.append(typeId)
+ res.append(returnTypeId)
+ res.append(self.decl.get_param_id(version))
+ elif objectType == 'type': # just the name
+ res.append(symbol.get_full_nested_name().get_id(version))
+ else:
+ raise AssertionError(objectType)
+ else: # only type encoding
+ # the 'returnType' of a non-function type is simply just the last
+ # type, i.e., for 'int*' it is 'int'
+ returnTypeId = self.declSpecs.get_id(version)
+ typeId = self.decl.get_type_id(version, returnTypeId)
+ res.append(typeId)
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ declSpecs = transform(self.declSpecs)
+ res.append(declSpecs)
+ if self.decl.require_space_after_declSpecs() and len(declSpecs) > 0:
+ res.append(' ')
+ res.append(transform(self.decl))
+ return ''.join(res)
+
+ def get_type_declaration_prefix(self) -> str:
+ if self.declSpecs.trailingTypeSpec:
+ return 'typedef'
+ else:
+ return 'type'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.declSpecs.describe_signature(signode, 'markType', env, symbol)
+ if (self.decl.require_space_after_declSpecs() and
+ len(str(self.declSpecs)) > 0):
+ signode += addnodes.desc_sig_space()
+ # for parameters that don't really declare new names we get 'markType',
+ # this should not be propagated, but be 'noneIsName'.
+ if mode == 'markType':
+ mode = 'noneIsName'
+ self.decl.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateParamConstrainedTypeWithInit(ASTBase):
+ def __init__(self, type: ASTType, init: ASTType) -> None:
+ assert type
+ self.type = type
+ self.init = init
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.type.name
+
+ @property
+ def isPack(self) -> bool:
+ return self.type.isPack
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ # this is not part of the normal name mangling in C++
+ assert version >= 2
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=False)
+ else:
+ return self.type.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = transform(self.type)
+ if self.init:
+ res += " = "
+ res += transform(self.init)
+ return res
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.type.describe_signature(signode, mode, env, symbol)
+ if self.init:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('=', '=')
+ signode += addnodes.desc_sig_space()
+ self.init.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTypeWithInit(ASTBase):
+ def __init__(self, type: ASTType, init: ASTInitializer) -> None:
+ self.type = type
+ self.init = init
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.type.name
+
+ @property
+ def isPack(self) -> bool:
+ return self.type.isPack
+
+ def get_id(self, version: int, objectType: str | None = None,
+ symbol: Symbol | None = None) -> str:
+ if objectType != 'member':
+ return self.type.get_id(version, objectType)
+ if version == 1:
+ return (symbol.get_full_nested_name().get_id(version) + '__' +
+ self.type.get_id(version))
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.type))
+ if self.init:
+ res.append(transform(self.init))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.type.describe_signature(signode, mode, env, symbol)
+ if self.init:
+ self.init.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTypeUsing(ASTBase):
+ def __init__(self, name: ASTNestedName, type: ASTType | None) -> None:
+ self.name = name
+ self.type = type
+
+ def get_id(self, version: int, objectType: str | None = None,
+ symbol: Symbol | None = None) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.name))
+ if self.type:
+ res.append(' = ')
+ res.append(transform(self.type))
+ return ''.join(res)
+
+ def get_type_declaration_prefix(self) -> str:
+ return 'using'
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.name.describe_signature(signode, mode, env, symbol=symbol)
+ if self.type:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('=', '=')
+ signode += addnodes.desc_sig_space()
+ self.type.describe_signature(signode, 'markType', env, symbol=symbol)
+
+
+# Other declarations
+##############################################################################################
+
+class ASTConcept(ASTBase):
+ def __init__(self, nestedName: ASTNestedName, initializer: ASTInitializer) -> None:
+ self.nestedName = nestedName
+ self.initializer = initializer
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.nestedName
+
+ def get_id(self, version: int, objectType: str | None = None,
+ symbol: Symbol | None = None) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = transform(self.nestedName)
+ if self.initializer:
+ res += transform(self.initializer)
+ return res
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.nestedName.describe_signature(signode, mode, env, symbol)
+ if self.initializer:
+ self.initializer.describe_signature(signode, mode, env, symbol)
+
+
+class ASTBaseClass(ASTBase):
+ def __init__(self, name: ASTNestedName, visibility: str,
+ virtual: bool, pack: bool) -> None:
+ self.name = name
+ self.visibility = visibility
+ self.virtual = virtual
+ self.pack = pack
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.visibility is not None:
+ res.append(self.visibility)
+ res.append(' ')
+ if self.virtual:
+ res.append('virtual ')
+ res.append(transform(self.name))
+ if self.pack:
+ res.append('...')
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ if self.visibility is not None:
+ signode += addnodes.desc_sig_keyword(self.visibility,
+ self.visibility)
+ signode += addnodes.desc_sig_space()
+ if self.virtual:
+ signode += addnodes.desc_sig_keyword('virtual', 'virtual')
+ signode += addnodes.desc_sig_space()
+ self.name.describe_signature(signode, 'markType', env, symbol=symbol)
+ if self.pack:
+ signode += addnodes.desc_sig_punctuation('...', '...')
+
+
+class ASTClass(ASTBase):
+ def __init__(self, name: ASTNestedName, final: bool, bases: list[ASTBaseClass],
+ attrs: ASTAttributeList) -> None:
+ self.name = name
+ self.final = final
+ self.bases = bases
+ self.attrs = attrs
+
+ 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 = []
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0:
+ res.append(' ')
+ res.append(transform(self.name))
+ if self.final:
+ res.append(' final')
+ if len(self.bases) > 0:
+ res.append(' : ')
+ first = True
+ for b in self.bases:
+ if not first:
+ res.append(', ')
+ first = False
+ res.append(transform(b))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ 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:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_keyword('final', 'final')
+ if len(self.bases) > 0:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation(':', ':')
+ signode += addnodes.desc_sig_space()
+ for b in self.bases:
+ b.describe_signature(signode, mode, env, symbol=symbol)
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ signode.pop()
+ signode.pop()
+
+
+class ASTUnion(ASTBase):
+ def __init__(self, name: ASTNestedName, attrs: ASTAttributeList) -> None:
+ self.name = name
+ self.attrs = attrs
+
+ def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ 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)
+ 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: ASTAttributeList) -> None:
+ self.name = name
+ self.scoped = scoped
+ self.underlyingType = underlyingType
+ self.attrs = attrs
+
+ def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.scoped:
+ res.append(self.scoped)
+ res.append(' ')
+ res.append(transform(self.attrs))
+ if len(self.attrs) != 0:
+ res.append(' ')
+ res.append(transform(self.name))
+ if self.underlyingType:
+ res.append(' : ')
+ res.append(transform(self.underlyingType))
+ return ''.join(res)
+
+ 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
+ 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:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation(':', ':')
+ signode += addnodes.desc_sig_space()
+ self.underlyingType.describe_signature(signode, 'noneIsName',
+ env, symbol=symbol)
+
+
+class ASTEnumerator(ASTBase):
+ def __init__(self, name: ASTNestedName, init: ASTInitializer | None,
+ attrs: ASTAttributeList) -> None:
+ self.name = name
+ self.init = init
+ self.attrs = attrs
+
+ def get_id(self, version: int, objectType: str, symbol: Symbol) -> str:
+ if version == 1:
+ raise NoOldIdError
+ return symbol.get_full_nested_name().get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.name))
+ if len(self.attrs) != 0:
+ res.append(' ')
+ res.append(transform(self.attrs))
+ if self.init:
+ res.append(transform(self.init))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ verify_description_mode(mode)
+ self.name.describe_signature(signode, mode, env, symbol)
+ if len(self.attrs) != 0:
+ signode += addnodes.desc_sig_space()
+ self.attrs.describe_signature(signode)
+ if self.init:
+ self.init.describe_signature(signode, 'markType', env, symbol)
+
+
+################################################################################
+# Templates
+################################################################################
+
+# Parameters
+################################################################################
+
+class ASTTemplateParam(ASTBase):
+ def get_identifier(self) -> ASTIdentifier:
+ raise NotImplementedError(repr(self))
+
+ def get_id(self, version: int) -> str:
+ raise NotImplementedError(repr(self))
+
+ def describe_signature(self, parentNode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def isPack(self) -> bool:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def name(self) -> ASTNestedName:
+ raise NotImplementedError(repr(self))
+
+
+class ASTTemplateKeyParamPackIdDefault(ASTTemplateParam):
+ def __init__(self, key: str, identifier: ASTIdentifier,
+ parameterPack: bool, default: ASTType) -> None:
+ assert key
+ if parameterPack:
+ assert default is None
+ self.key = key
+ self.identifier = identifier
+ self.parameterPack = parameterPack
+ self.default = default
+
+ def get_identifier(self) -> ASTIdentifier:
+ return self.identifier
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ # this is not part of the normal name mangling in C++
+ res = []
+ if self.parameterPack:
+ res.append('Dp')
+ else:
+ res.append('0') # we need to put something
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = [self.key]
+ if self.parameterPack:
+ if self.identifier:
+ res.append(' ')
+ res.append('...')
+ if self.identifier:
+ if not self.parameterPack:
+ res.append(' ')
+ res.append(transform(self.identifier))
+ if self.default:
+ res.append(' = ')
+ res.append(transform(self.default))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword(self.key, self.key)
+ if self.parameterPack:
+ if self.identifier:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ if self.identifier:
+ if not self.parameterPack:
+ signode += addnodes.desc_sig_space()
+ self.identifier.describe_signature(signode, mode, env, '', '', symbol)
+ if self.default:
+ signode += addnodes.desc_sig_space()
+ signode += addnodes.desc_sig_punctuation('=', '=')
+ signode += addnodes.desc_sig_space()
+ self.default.describe_signature(signode, 'markType', env, symbol)
+
+
+class ASTTemplateParamType(ASTTemplateParam):
+ def __init__(self, data: ASTTemplateKeyParamPackIdDefault) -> None:
+ assert data
+ self.data = data
+
+ @property
+ def name(self) -> ASTNestedName:
+ id = self.get_identifier()
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
+
+ @property
+ def isPack(self) -> bool:
+ return self.data.parameterPack
+
+ def get_identifier(self) -> ASTIdentifier:
+ return self.data.get_identifier()
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ # this is not part of the normal name mangling in C++
+ assert version >= 2
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=False)
+ else:
+ return self.data.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.data)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.data.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateParamTemplateType(ASTTemplateParam):
+ def __init__(self, nestedParams: ASTTemplateParams,
+ data: ASTTemplateKeyParamPackIdDefault) -> None:
+ assert nestedParams
+ assert data
+ self.nestedParams = nestedParams
+ self.data = data
+
+ @property
+ def name(self) -> ASTNestedName:
+ id = self.get_identifier()
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
+
+ @property
+ def isPack(self) -> bool:
+ return self.data.parameterPack
+
+ def get_identifier(self) -> ASTIdentifier:
+ return self.data.get_identifier()
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ assert version >= 2
+ # this is not part of the normal name mangling in C++
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=None)
+ else:
+ return self.nestedParams.get_id(version) + self.data.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.nestedParams) + transform(self.data)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.nestedParams.describe_signature(signode, 'noneIsName', env, symbol)
+ signode += addnodes.desc_sig_space()
+ self.data.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateParamNonType(ASTTemplateParam):
+ def __init__(self,
+ param: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit,
+ parameterPack: bool = False) -> None:
+ assert param
+ self.param = param
+ self.parameterPack = parameterPack
+
+ @property
+ def name(self) -> ASTNestedName:
+ id = self.get_identifier()
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
+
+ @property
+ def isPack(self) -> bool:
+ return self.param.isPack or self.parameterPack
+
+ def get_identifier(self) -> ASTIdentifier:
+ name = self.param.name
+ if name:
+ assert len(name.names) == 1
+ assert name.names[0].identOrOp
+ assert not name.names[0].templateArgs
+ res = name.names[0].identOrOp
+ assert isinstance(res, ASTIdentifier)
+ return res
+ else:
+ return None
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ assert version >= 2
+ # this is not part of the normal name mangling in C++
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=None)
+ else:
+ res = '_'
+ if self.parameterPack:
+ res += 'Dp'
+ return res + self.param.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = transform(self.param)
+ if self.parameterPack:
+ res += '...'
+ return res
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ self.param.describe_signature(signode, mode, env, symbol)
+ if self.parameterPack:
+ signode += addnodes.desc_sig_punctuation('...', '...')
+
+
+class ASTTemplateParams(ASTBase):
+ def __init__(self, params: list[ASTTemplateParam],
+ requiresClause: ASTRequiresClause | None) -> None:
+ assert params is not None
+ self.params = params
+ self.requiresClause = requiresClause
+
+ def get_id(self, version: int, excludeRequires: bool = False) -> str:
+ assert version >= 2
+ res = []
+ res.append("I")
+ res.extend(param.get_id(version) for param in self.params)
+ res.append("E")
+ if not excludeRequires and self.requiresClause:
+ res.extend(['IQ', self.requiresClause.expr.get_id(version), 'E'])
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append("template<")
+ res.append(", ".join(transform(a) for a in self.params))
+ res.append("> ")
+ if self.requiresClause is not None:
+ res.append(transform(self.requiresClause))
+ res.append(" ")
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('template', 'template')
+ signode += addnodes.desc_sig_punctuation('<', '<')
+ first = True
+ for param in self.params:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ first = False
+ param.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation('>', '>')
+ if self.requiresClause is not None:
+ signode += addnodes.desc_sig_space()
+ self.requiresClause.describe_signature(signode, mode, env, symbol)
+
+ def describe_signature_as_introducer(
+ self, parentNode: desc_signature, mode: str, env: BuildEnvironment,
+ symbol: Symbol, lineSpec: bool) -> None:
+ def makeLine(parentNode: desc_signature) -> addnodes.desc_signature_line:
+ signode = addnodes.desc_signature_line()
+ parentNode += signode
+ signode.sphinx_line_type = 'templateParams'
+ return signode
+ lineNode = makeLine(parentNode)
+ lineNode += addnodes.desc_sig_keyword('template', 'template')
+ lineNode += addnodes.desc_sig_punctuation('<', '<')
+ first = True
+ for param in self.params:
+ if not first:
+ lineNode += addnodes.desc_sig_punctuation(',', ',')
+ lineNode += addnodes.desc_sig_space()
+ first = False
+ if lineSpec:
+ lineNode = makeLine(parentNode)
+ param.describe_signature(lineNode, mode, env, symbol)
+ if lineSpec and not first:
+ lineNode = makeLine(parentNode)
+ lineNode += addnodes.desc_sig_punctuation('>', '>')
+ if self.requiresClause:
+ reqNode = addnodes.desc_signature_line()
+ reqNode.sphinx_line_type = 'requiresClause'
+ parentNode += reqNode
+ self.requiresClause.describe_signature(reqNode, 'markType', env, symbol)
+
+
+# Template introducers
+################################################################################
+
+class ASTTemplateIntroductionParameter(ASTBase):
+ def __init__(self, identifier: ASTIdentifier, parameterPack: bool) -> None:
+ self.identifier = identifier
+ self.parameterPack = parameterPack
+
+ @property
+ def name(self) -> ASTNestedName:
+ id = self.get_identifier()
+ return ASTNestedName([ASTNestedNameElement(id, None)], [False], rooted=False)
+
+ @property
+ def isPack(self) -> bool:
+ return self.parameterPack
+
+ def get_identifier(self) -> ASTIdentifier:
+ return self.identifier
+
+ def get_id(
+ self, version: int, objectType: str | None = None, symbol: Symbol | None = None,
+ ) -> str:
+ assert version >= 2
+ # this is not part of the normal name mangling in C++
+ if symbol:
+ # the anchor will be our parent
+ return symbol.parent.declaration.get_id(version, prefixed=None)
+ else:
+ if self.parameterPack:
+ return 'Dp'
+ else:
+ return '0' # we need to put something
+
+ def get_id_as_arg(self, version: int) -> str:
+ assert version >= 2
+ # used for the implicit requires clause
+ res = self.identifier.get_id(version)
+ if self.parameterPack:
+ return 'sp' + res
+ else:
+ return res
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.parameterPack:
+ res.append('...')
+ res.append(transform(self.identifier))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ if self.parameterPack:
+ signode += addnodes.desc_sig_punctuation('...', '...')
+ self.identifier.describe_signature(signode, mode, env, '', '', symbol)
+
+
+class ASTTemplateIntroduction(ASTBase):
+ def __init__(self, concept: ASTNestedName,
+ params: list[ASTTemplateIntroductionParameter]) -> None:
+ assert len(params) > 0
+ self.concept = concept
+ self.params = params
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ return ''.join([
+ # first do the same as a normal template parameter list
+ "I",
+ *(param.get_id(version) for param in self.params),
+ "E",
+ # let's use X expr E, which is otherwise for constant template args
+ "X",
+ self.concept.get_id(version),
+ "I",
+ *(param.get_id_as_arg(version) for param in self.params),
+ "E",
+ "E",
+ ])
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ res.append(transform(self.concept))
+ res.append('{')
+ res.append(', '.join(transform(param) for param in self.params))
+ res.append('} ')
+ return ''.join(res)
+
+ def describe_signature_as_introducer(
+ self, parentNode: desc_signature, mode: str,
+ env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None:
+ # Note: 'lineSpec' has no effect on template introductions.
+ signode = addnodes.desc_signature_line()
+ parentNode += signode
+ signode.sphinx_line_type = 'templateIntroduction'
+ self.concept.describe_signature(signode, 'markType', env, symbol)
+ signode += addnodes.desc_sig_punctuation('{', '{')
+ first = True
+ for param in self.params:
+ if not first:
+ signode += addnodes.desc_sig_punctuation(',', ',')
+ signode += addnodes.desc_sig_space()
+ first = False
+ param.describe_signature(signode, mode, env, symbol)
+ signode += addnodes.desc_sig_punctuation('}', '}')
+
+
+################################################################################
+
+class ASTTemplateDeclarationPrefix(ASTBase):
+ def __init__(self,
+ templates: list[ASTTemplateParams | ASTTemplateIntroduction] | None) -> None:
+ # templates is None means it's an explicit instantiation of a variable
+ self.templates = templates
+
+ def get_requires_clause_in_last(self) -> ASTRequiresClause | None:
+ if self.templates is None:
+ return None
+ lastList = self.templates[-1]
+ if not isinstance(lastList, ASTTemplateParams):
+ return None
+ return lastList.requiresClause # which may be None
+
+ def get_id_except_requires_clause_in_last(self, version: int) -> str:
+ assert version >= 2
+ # This is not part of the Itanium ABI mangling system.
+ res = []
+ lastIndex = len(self.templates) - 1
+ for i, t in enumerate(self.templates):
+ if isinstance(t, ASTTemplateParams):
+ res.append(t.get_id(version, excludeRequires=(i == lastIndex)))
+ else:
+ res.append(t.get_id(version))
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return ''.join(map(transform, self.templates))
+
+ def describe_signature(self, signode: desc_signature, mode: str,
+ env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None:
+ verify_description_mode(mode)
+ for t in self.templates:
+ t.describe_signature_as_introducer(signode, 'lastIsName', env, symbol, lineSpec)
+
+
+class ASTRequiresClause(ASTBase):
+ def __init__(self, expr: ASTExpression) -> None:
+ self.expr = expr
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return 'requires ' + transform(self.expr)
+
+ def describe_signature(self, signode: nodes.TextElement, mode: str,
+ env: BuildEnvironment, symbol: Symbol) -> None:
+ signode += addnodes.desc_sig_keyword('requires', 'requires')
+ signode += addnodes.desc_sig_space()
+ self.expr.describe_signature(signode, mode, env, symbol)
+
+
+################################################################################
+################################################################################
+
+class ASTDeclaration(ASTBase):
+ def __init__(self, objectType: str, directiveType: str | None = None,
+ visibility: str | None = None,
+ templatePrefix: ASTTemplateDeclarationPrefix | None = None,
+ declaration: Any = None,
+ trailingRequiresClause: ASTRequiresClause | None = None,
+ semicolon: bool = False) -> None:
+ self.objectType = objectType
+ self.directiveType = directiveType
+ self.visibility = visibility
+ self.templatePrefix = templatePrefix
+ self.declaration = declaration
+ self.trailingRequiresClause = trailingRequiresClause
+ self.semicolon = semicolon
+
+ self.symbol: Symbol | None = None
+ # set by CPPObject._add_enumerator_to_parent
+ self.enumeratorScopedSymbol: Symbol | None = None
+
+ # the cache assumes that by the time get_newest_id is called, no
+ # further changes will be made to this object
+ self._newest_id_cache: str | None = None
+
+ def clone(self) -> ASTDeclaration:
+ templatePrefixClone = self.templatePrefix.clone() if self.templatePrefix else None
+ trailingRequiresClasueClone = self.trailingRequiresClause.clone() \
+ if self.trailingRequiresClause else None
+ return ASTDeclaration(self.objectType, self.directiveType, self.visibility,
+ templatePrefixClone,
+ self.declaration.clone(), trailingRequiresClasueClone,
+ self.semicolon)
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.declaration.name
+
+ @property
+ def function_params(self) -> list[ASTFunctionParameter]:
+ if self.objectType != 'function':
+ return None
+ return self.declaration.function_params
+
+ def get_id(self, version: int, prefixed: bool = True) -> str:
+ if version == 1:
+ if self.templatePrefix or self.trailingRequiresClause:
+ raise NoOldIdError
+ if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
+ return self.enumeratorScopedSymbol.declaration.get_id(version)
+ return self.declaration.get_id(version, self.objectType, self.symbol)
+ # version >= 2
+ if self.objectType == 'enumerator' and self.enumeratorScopedSymbol:
+ return self.enumeratorScopedSymbol.declaration.get_id(version, prefixed)
+ if prefixed:
+ res = [_id_prefix[version]]
+ else:
+ res = []
+ # (See also https://github.com/sphinx-doc/sphinx/pull/10286#issuecomment-1168102147)
+ # The first implementation of requires clauses only supported a single clause after the
+ # template prefix, and no trailing clause. It put the ID after the template parameter
+ # list, i.e.,
+ # "I" + template_parameter_list_id + "E" + "IQ" + requires_clause_id + "E"
+ # but the second implementation associates the requires clause with each list, i.e.,
+ # "I" + template_parameter_list_id + "IQ" + requires_clause_id + "E" + "E"
+ # To avoid making a new ID version, we make an exception for the last requires clause
+ # in the template prefix, and still put it in the end.
+ # As we now support trailing requires clauses we add that as if it was a conjunction.
+ if self.templatePrefix is not None:
+ res.append(self.templatePrefix.get_id_except_requires_clause_in_last(version))
+ requiresClauseInLast = self.templatePrefix.get_requires_clause_in_last()
+ else:
+ requiresClauseInLast = None
+
+ if requiresClauseInLast or self.trailingRequiresClause:
+ if version < 4:
+ raise NoOldIdError
+ res.append('IQ')
+ if requiresClauseInLast and self.trailingRequiresClause:
+ # make a conjunction of them
+ res.append('aa')
+ if requiresClauseInLast:
+ res.append(requiresClauseInLast.expr.get_id(version))
+ if self.trailingRequiresClause:
+ res.append(self.trailingRequiresClause.expr.get_id(version))
+ res.append('E')
+ res.append(self.declaration.get_id(version, self.objectType, self.symbol))
+ return ''.join(res)
+
+ def get_newest_id(self) -> str:
+ if self._newest_id_cache is None:
+ self._newest_id_cache = self.get_id(_max_id, True)
+ return self._newest_id_cache
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.visibility and self.visibility != "public":
+ res.append(self.visibility)
+ res.append(' ')
+ if self.templatePrefix:
+ res.append(transform(self.templatePrefix))
+ res.append(transform(self.declaration))
+ if self.trailingRequiresClause:
+ res.append(' ')
+ res.append(transform(self.trailingRequiresClause))
+ if self.semicolon:
+ res.append(';')
+ return ''.join(res)
+
+ def describe_signature(self, signode: desc_signature, mode: str,
+ env: BuildEnvironment, options: dict[str, bool]) -> None:
+ verify_description_mode(mode)
+ assert self.symbol
+ # The caller of the domain added a desc_signature node.
+ # Always enable multiline:
+ signode['is_multiline'] = True
+ # Put each line in a desc_signature_line node.
+ mainDeclNode = addnodes.desc_signature_line()
+ mainDeclNode.sphinx_line_type = 'declarator'
+ mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
+
+ if self.templatePrefix:
+ self.templatePrefix.describe_signature(signode, mode, env,
+ symbol=self.symbol,
+ lineSpec=options.get('tparam-line-spec'))
+ signode += mainDeclNode
+ if self.visibility and self.visibility != "public":
+ mainDeclNode += addnodes.desc_sig_keyword(self.visibility, self.visibility)
+ mainDeclNode += addnodes.desc_sig_space()
+ if self.objectType == 'type':
+ prefix = self.declaration.get_type_declaration_prefix()
+ mainDeclNode += addnodes.desc_sig_keyword(prefix, prefix)
+ mainDeclNode += addnodes.desc_sig_space()
+ elif self.objectType == 'concept':
+ mainDeclNode += addnodes.desc_sig_keyword('concept', 'concept')
+ mainDeclNode += addnodes.desc_sig_space()
+ elif self.objectType in {'member', 'function'}:
+ pass
+ elif self.objectType == 'class':
+ assert self.directiveType in ('class', 'struct')
+ mainDeclNode += addnodes.desc_sig_keyword(self.directiveType, self.directiveType)
+ mainDeclNode += addnodes.desc_sig_space()
+ elif self.objectType == 'union':
+ mainDeclNode += addnodes.desc_sig_keyword('union', 'union')
+ mainDeclNode += addnodes.desc_sig_space()
+ elif self.objectType == 'enum':
+ mainDeclNode += addnodes.desc_sig_keyword('enum', 'enum')
+ mainDeclNode += addnodes.desc_sig_space()
+ if self.directiveType == 'enum-class':
+ mainDeclNode += addnodes.desc_sig_keyword('class', 'class')
+ mainDeclNode += addnodes.desc_sig_space()
+ elif self.directiveType == 'enum-struct':
+ mainDeclNode += addnodes.desc_sig_keyword('struct', 'struct')
+ mainDeclNode += addnodes.desc_sig_space()
+ else:
+ assert self.directiveType == 'enum', self.directiveType
+ elif self.objectType == 'enumerator':
+ mainDeclNode += addnodes.desc_sig_keyword('enumerator', 'enumerator')
+ mainDeclNode += addnodes.desc_sig_space()
+ else:
+ raise AssertionError(self.objectType)
+ self.declaration.describe_signature(mainDeclNode, mode, env, self.symbol)
+ lastDeclNode = mainDeclNode
+ if self.trailingRequiresClause:
+ trailingReqNode = addnodes.desc_signature_line()
+ trailingReqNode.sphinx_line_type = 'trailingRequiresClause'
+ signode.append(trailingReqNode)
+ lastDeclNode = trailingReqNode
+ self.trailingRequiresClause.describe_signature(
+ trailingReqNode, 'markType', env, self.symbol)
+ if self.semicolon:
+ lastDeclNode += addnodes.desc_sig_punctuation(';', ';')
+
+
+class ASTNamespace(ASTBase):
+ def __init__(self, nestedName: ASTNestedName,
+ templatePrefix: ASTTemplateDeclarationPrefix) -> None:
+ self.nestedName = nestedName
+ self.templatePrefix = templatePrefix
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ if self.templatePrefix:
+ res.append(transform(self.templatePrefix))
+ res.append(transform(self.nestedName))
+ return ''.join(res)