summaryrefslogtreecommitdiff
path: root/sphinx/domains/cpp.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/domains/cpp.py')
-rw-r--r--sphinx/domains/cpp.py3558
1 files changed, 1906 insertions, 1652 deletions
diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py
index 53c958601..7f7558cb3 100644
--- a/sphinx/domains/cpp.py
+++ b/sphinx/domains/cpp.py
@@ -9,12 +9,12 @@
"""
import re
-import warnings
-from copy import deepcopy
-from typing import Any, Callable, Dict, Iterator, List, Match, Pattern, Tuple, Type, Union
+from typing import (
+ Any, Callable, Dict, Iterator, List, Tuple, Type, TypeVar, Union
+)
-from docutils import nodes, utils
-from docutils.nodes import Element, Node, TextElement
+from docutils import nodes
+from docutils.nodes import Element, Node, TextElement, system_message
from docutils.parsers.rst import directives
from sphinx import addnodes
@@ -22,23 +22,29 @@ from sphinx.addnodes import desc_signature, pending_xref
from sphinx.application import Sphinx
from sphinx.builders import Builder
from sphinx.config import Config
-from sphinx.deprecation import RemovedInSphinx40Warning
from sphinx.directives import ObjectDescription
from sphinx.domains import Domain, ObjType
from sphinx.environment import BuildEnvironment
from sphinx.errors import NoUri
from sphinx.locale import _, __
-from sphinx.roles import XRefRole
+from sphinx.roles import SphinxRole, XRefRole
from sphinx.transforms import SphinxTransform
from sphinx.transforms.post_transforms import ReferencesResolver
from sphinx.util import logging
+from sphinx.util.cfamily import (
+ NoOldIdError, ASTBaseBase, verify_description_mode, StringifyTransform,
+ BaseParser, DefinitionError, UnsupportedMultiCharacterCharLiteral,
+ identifier_re, anon_identifier_re, integer_literal_re, octal_literal_re,
+ hex_literal_re, binary_literal_re, float_literal_re,
+ char_literal_re
+)
from sphinx.util.docfields import Field, GroupedField
from sphinx.util.docutils import SphinxDirective
from sphinx.util.nodes import make_refnode
logger = logging.getLogger(__name__)
-StringifyTransform = Callable[[Any], str]
+T = TypeVar('T')
"""
Important note on ids
@@ -61,7 +67,7 @@ StringifyTransform = Callable[[Any], str]
Each signature is in a desc_signature node, where all children are
desc_signature_line nodes. Each of these lines will have the attribute
- 'sphinx_cpp_tagname' set to one of the following (prioritized):
+ 'sphinx_line_type' set to one of the following (prioritized):
- 'declarator', if the line contains the name of the declared object.
- 'templateParams', if the line starts a template parameter list,
- 'templateParams', if the line has template parameters
@@ -290,47 +296,6 @@ StringifyTransform = Callable[[Any], str]
nested-name
"""
-_integer_literal_re = re.compile(r'[1-9][0-9]*')
-_octal_literal_re = re.compile(r'0[0-7]*')
-_hex_literal_re = re.compile(r'0[xX][0-9a-fA-F][0-9a-fA-F]*')
-_binary_literal_re = re.compile(r'0[bB][01][01]*')
-_integer_suffix_re = re.compile(r'')
-_float_literal_re = re.compile(r'''(?x)
- [+-]?(
- # decimal
- ([0-9]+[eE][+-]?[0-9]+)
- | ([0-9]*\.[0-9]+([eE][+-]?[0-9]+)?)
- | ([0-9]+\.([eE][+-]?[0-9]+)?)
- # hex
- | (0[xX][0-9a-fA-F]+[pP][+-]?[0-9a-fA-F]+)
- | (0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9a-fA-F]+)?)
- | (0[xX][0-9a-fA-F]+\.([pP][+-]?[0-9a-fA-F]+)?)
- )
-''')
-_char_literal_re = re.compile(r'''(?x)
- ((?:u8)|u|U|L)?
- '(
- (?:[^\\'])
- | (\\(
- (?:['"?\\abfnrtv])
- | (?:[0-7]{1,3})
- | (?:x[0-9a-fA-F]{2})
- | (?:u[0-9a-fA-F]{4})
- | (?:U[0-9a-fA-F]{8})
- ))
- )'
-''')
-
-_anon_identifier_re = re.compile(r'(@[a-zA-Z0-9_])[a-zA-Z0-9_]*\b')
-_identifier_re = re.compile(r'''(?x)
- ( # This 'extends' _anon_identifier_re with the ordinary identifiers,
- # make sure they are in sync.
- (~?\b[a-zA-Z_]) # ordinary identifiers
- | (@[a-zA-Z0-9_]) # our extension for names of anonymous entities
- )
- [a-zA-Z0-9_]*\b
-''')
-_whitespace_re = re.compile(r'(?u)\s+')
_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'"
r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
_visibility_re = re.compile(r'\b(public|private|protected)\b')
@@ -367,6 +332,8 @@ _keywords = [
_max_id = 4
_id_prefix = [None, '', '_CPPv2', '_CPPv3', '_CPPv4']
+# Ids are used in lookup keys which are used across pickled files,
+# so when _max_id changes, make sure to update the ENV_VERSION.
# ------------------------------------------------------------------------------
# Id v1 constants
@@ -576,27 +543,8 @@ _id_explicit_cast = {
}
-class NoOldIdError(Exception):
- # Used to avoid implementing unneeded id generation for old id schemes.
- @property
- def description(self) -> str:
- warnings.warn('%s.description is deprecated. '
- 'Coerce the instance to a string instead.' % self.__class__.__name__,
- RemovedInSphinx40Warning, stacklevel=2)
- return str(self)
-
-
-class DefinitionError(Exception):
- @property
- def description(self) -> str:
- warnings.warn('%s.description is deprecated. '
- 'Coerce the instance to a string instead.' % self.__class__.__name__,
- RemovedInSphinx40Warning, stacklevel=2)
- return str(self)
-
-
class _DuplicateSymbolError(Exception):
- def __init__(self, symbol: "Symbol", declaration: Any) -> None:
+ def __init__(self, symbol: "Symbol", declaration: "ASTDeclaration") -> None:
assert symbol
assert declaration
self.symbol = symbol
@@ -606,54 +554,237 @@ class _DuplicateSymbolError(Exception):
return "Internal C++ duplicate symbol error:\n%s" % self.symbol.dump(0)
-class ASTBase:
- def __eq__(self, other: Any) -> bool:
- if type(self) is not type(other):
- return False
- try:
- for key, value in self.__dict__.items():
- if value != getattr(other, key):
- return False
- except AttributeError:
- return False
- return True
+class ASTBase(ASTBaseBase):
+ pass
- __hash__ = None # type: Callable[[], int]
- def clone(self) -> Any:
- """Clone a definition expression node."""
- return deepcopy(self)
+# Names
+################################################################################
- def _stringify(self, transform: StringifyTransform) -> str:
- raise NotImplementedError(repr(self))
+class ASTIdentifier(ASTBase):
+ def __init__(self, identifier: str) -> None:
+ assert identifier is not None
+ assert len(identifier) != 0
+ self.identifier = 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._stringify(lambda ast: str(ast))
+ return self.identifier
def get_display_string(self) -> str:
- return self._stringify(lambda ast: ast.get_display_string())
+ 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 mode == 'markType':
+ targetText = prefix + self.identifier + templateArgs
+ pnode = addnodes.pending_xref('', refdomain='cpp',
+ reftype='identifier',
+ reftarget=targetText, modname=None,
+ classname=None)
+ key = symbol.get_lookup_key()
+ pnode['cpp:parent_key'] = key
+ if self.is_anon():
+ pnode += nodes.strong(text="[anonymous]")
+ else:
+ pnode += nodes.Text(self.identifier)
+ signode += pnode
+ elif mode == 'lastIsName':
+ if self.is_anon():
+ signode += nodes.strong(text="[anonymous]")
+ else:
+ signode += addnodes.desc_name(self.identifier, self.identifier)
+ elif mode == 'noneIsName':
+ if self.is_anon():
+ signode += nodes.strong(text="[anonymous]")
+ else:
+ signode += nodes.Text(self.identifier)
+ else:
+ raise Exception('Unknown description mode: %s' % mode)
+
+
+class ASTNestedNameElement(ASTBase):
+ def __init__(self, identOrOp: Union[ASTIdentifier, "ASTOperator"],
+ templateArgs: "ASTTemplateArgs") -> 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, mode, 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)
- def __repr__(self) -> str:
- return '<%s>' % self.__class__.__name__
+ res = []
+ if len(self.names) > 1 or len(modifiers) > 0:
+ res.append('N')
+ res.append(modifiers)
+ for n in self.names:
+ res.append(n.get_id(version))
+ 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]
+ t = self.templates[i]
+ if t:
+ res.append("template " + transform(n))
+ else:
+ res.append(transform(n))
+ return '::'.join(res)
-def _verify_description_mode(mode: str) -> None:
- if mode not in ('lastIsName', 'noneIsName', 'markType', 'markName', 'param'):
- raise Exception("Description mode '%s' is invalid." % mode)
+ 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':
+ signode += nodes.Text(str(self))
+ elif mode == 'param':
+ name = str(self)
+ signode += nodes.emphasis(name, name)
+ elif mode == 'markType' or mode == 'lastIsName' or mode == '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 = [] # type: 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 relies 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()
+ for i in range(len(names)):
+ nne = names[i]
+ template = self.templates[i]
+ if not first:
+ dest += nodes.Text('::')
+ prefix += '::'
+ if template:
+ dest += nodes.Text("template ")
+ 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_addname('::', '::')
+ signode += dest
+ if self.templates[-1]:
+ signode += nodes.Text("template ")
+ self.names[-1].describe_signature(signode, mode, env, '', symbol)
+ else:
+ raise Exception('Unknown description mode: %s' % mode)
################################################################################
# Attributes
################################################################################
-class ASTCPPAttribute(ASTBase):
+class ASTAttribute(ASTBase):
+ def describe_signature(self, signode: TextElement) -> None:
+ raise NotImplementedError(repr(self))
+
+
+class ASTCPPAttribute(ASTAttribute):
def __init__(self, arg: str) -> None:
self.arg = arg
- def _stringify(self, transform):
+ def _stringify(self, transform: StringifyTransform) -> str:
return "[[" + self.arg + "]]"
- def describe_signature(self, signode: desc_signature) -> None:
+ def describe_signature(self, signode: TextElement) -> None:
txt = str(self)
signode.append(nodes.Text(txt, txt))
@@ -672,8 +803,8 @@ class ASTGnuAttribute(ASTBase):
return ''.join(res)
-class ASTGnuAttributeList(ASTBase):
- def __init__(self, attrs: List[Any]) -> None:
+class ASTGnuAttributeList(ASTAttribute):
+ def __init__(self, attrs: List[ASTGnuAttribute]) -> None:
self.attrs = attrs
def _stringify(self, transform: StringifyTransform) -> str:
@@ -687,12 +818,12 @@ class ASTGnuAttributeList(ASTBase):
res.append('))')
return ''.join(res)
- def describe_signature(self, signode: desc_signature) -> None:
+ def describe_signature(self, signode: TextElement) -> None:
txt = str(self)
signode.append(nodes.Text(txt, txt))
-class ASTIdAttribute(ASTBase):
+class ASTIdAttribute(ASTAttribute):
"""For simple attributes defined by the user."""
def __init__(self, id: str) -> None:
@@ -701,11 +832,11 @@ class ASTIdAttribute(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
return self.id
- def describe_signature(self, signode: desc_signature) -> None:
+ def describe_signature(self, signode: TextElement) -> None:
signode.append(nodes.Text(self.id, self.id))
-class ASTParenAttribute(ASTBase):
+class ASTParenAttribute(ASTAttribute):
"""For paren attributes defined by the user."""
def __init__(self, id: str, arg: str) -> None:
@@ -715,28 +846,45 @@ class ASTParenAttribute(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
return self.id + '(' + self.arg + ')'
- def describe_signature(self, signode: desc_signature) -> None:
+ def describe_signature(self, signode: TextElement) -> None:
txt = str(self)
signode.append(nodes.Text(txt, txt))
################################################################################
-# Expressions and Literals
+# 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 ASTPointerLiteral(ASTBase):
+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, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('nullptr'))
-class ASTBooleanLiteral(ASTBase):
- def __init__(self, value):
+class ASTBooleanLiteral(ASTLiteral):
+ def __init__(self, value: bool) -> None:
self.value = value
def _stringify(self, transform: StringifyTransform) -> str:
@@ -751,11 +899,12 @@ class ASTBooleanLiteral(ASTBase):
else:
return 'L0E'
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text(str(self)))
-class ASTNumberLiteral(ASTBase):
+class ASTNumberLiteral(ASTLiteral):
def __init__(self, data: str) -> None:
self.data = data
@@ -765,21 +914,30 @@ class ASTNumberLiteral(ASTBase):
def get_id(self, version: int) -> str:
return "L%sE" % self.data
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
txt = str(self)
signode.append(nodes.Text(txt, txt))
-class UnsupportedMultiCharacterCharLiteral(Exception):
- @property
- def decoded(self) -> str:
- warnings.warn('%s.decoded is deprecated. '
- 'Coerce the instance to a string instead.' % self.__class__.__name__,
- RemovedInSphinx40Warning, stacklevel=2)
- return str(self)
+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)
-class ASTCharLiteral(ASTBase):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ txt = str(self)
+ signode.append(nodes.Text(txt, txt))
+
+
+class ASTCharLiteral(ASTLiteral):
def __init__(self, prefix: str, data: str) -> None:
self.prefix = prefix # may be None when no prefix
self.data = data
@@ -800,56 +958,27 @@ class ASTCharLiteral(ASTBase):
def get_id(self, version: int) -> str:
return self.type + str(self.value)
- def describe_signature(self, signode, mode, env, symbol):
- txt = str(self)
- signode.append(nodes.Text(txt, txt))
-
-
-class ASTStringLiteral(ASTBase):
- 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, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
txt = str(self)
signode.append(nodes.Text(txt, txt))
-class ASTThisLiteral(ASTBase):
+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, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text("this"))
-class ASTParenExpr(ASTBase):
- def __init__(self, expr):
- 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, mode, env, symbol):
- signode.append(nodes.Text('(', '('))
- self.expr.describe_signature(signode, mode, env, symbol)
- signode.append(nodes.Text(')', ')'))
-
-
-class ASTFoldExpr(ASTBase):
- def __init__(self, leftExpr: Any, op: str, rightExpr: Any) -> None:
+class ASTFoldExpr(ASTExpression):
+ def __init__(self, leftExpr: ASTExpression,
+ op: str, rightExpr: ASTExpression) -> None:
assert leftExpr is not None or rightExpr is not None
self.leftExpr = leftExpr
self.op = op
@@ -892,7 +1021,8 @@ class ASTFoldExpr(ASTBase):
res.append(self.rightExpr.get_id(version))
return ''.join(res)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('('))
if self.leftExpr:
self.leftExpr.describe_signature(signode, mode, env, symbol)
@@ -908,99 +1038,224 @@ class ASTFoldExpr(ASTBase):
signode.append(nodes.Text(')'))
-class ASTBinOpExpr(ASTBase):
- def __init__(self, exprs, ops):
- assert len(exprs) > 0
- assert len(exprs) == len(ops) + 1
- self.exprs = exprs
- self.ops = ops
+class ASTParenExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression):
+ self.expr = expr
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)
+ return '(' + transform(self.expr) + ')'
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 self.expr.get_id(version)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ signode.append(nodes.Text('(', '('))
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode.append(nodes.Text(')', ')'))
+
+
+class ASTIdExpression(ASTExpression):
+ def __init__(self, name: ASTNestedName):
+ # 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):
+ 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.append(nodes.Text('['))
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode.append(nodes.Text(']'))
+
+
+class ASTPostfixMember(ASTPostfixOp):
+ def __init__(self, name: ASTNestedName):
+ 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.append(nodes.Text('.'))
+ self.name.describe_signature(signode, 'noneIsName', env, symbol)
+
+
+class ASTPostfixMemberOfPointer(ASTPostfixOp):
+ def __init__(self, name: ASTNestedName):
+ 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.append(nodes.Text('->'))
+ 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.append(nodes.Text('++'))
+
+
+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.append(nodes.Text('--'))
+
+
+class ASTPostfixCallExpr(ASTPostfixOp):
+ def __init__(self, lst: Union["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:
+ res = ['cl', idPrefix]
+ for e in self.lst.exprs:
+ res.append(e.get_id(version))
+ res.append('E')
return ''.join(res)
- def describe_signature(self, signode, mode, env, symbol):
- self.exprs[0].describe_signature(signode, mode, env, symbol)
- for i in range(1, len(self.exprs)):
- signode.append(nodes.Text(' '))
- signode.append(nodes.Text(self.ops[i - 1]))
- signode.append(nodes.Text(' '))
- self.exprs[i].describe_signature(signode, mode, env, symbol)
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ self.lst.describe_signature(signode, mode, env, symbol)
-class ASTAssignmentExpr(ASTBase):
- def __init__(self, exprs, ops):
- assert len(exprs) > 0
- assert len(exprs) == len(ops) + 1
- self.exprs = exprs
- self.ops = ops
+class ASTPostfixExpr(ASTExpression):
+ def __init__(self, prefix: "ASTType", postFixes: List[ASTPostfixOp]):
+ self.prefix = prefix
+ self.postFixes = postFixes
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]))
+ res = [transform(self.prefix)]
+ for p in self.postFixes:
+ res.append(transform(p))
return ''.join(res)
def get_id(self, version: int) -> str:
- 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)
+ id = self.prefix.get_id(version)
+ for p in self.postFixes:
+ id = p.get_id(id, version)
+ return id
- def describe_signature(self, signode, mode, env, symbol):
- self.exprs[0].describe_signature(signode, mode, env, symbol)
- for i in range(1, len(self.exprs)):
- signode.append(nodes.Text(' '))
- signode.append(nodes.Text(self.ops[i - 1]))
- signode.append(nodes.Text(' '))
- self.exprs[i].describe_signature(signode, mode, env, symbol)
+ 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 ASTCastExpr(ASTBase):
- def __init__(self, typ, expr):
+class ASTExplicitCast(ASTExpression):
+ def __init__(self, cast: str, typ: "ASTType", expr: ASTExpression):
+ assert cast in _id_explicit_cast
+ self.cast = cast
self.typ = typ
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
- res = ['(']
+ res = [self.cast]
+ res.append('<')
res.append(transform(self.typ))
- res.append(')')
+ res.append('>(')
res.append(transform(self.expr))
+ res.append(')')
return ''.join(res)
def get_id(self, version: int) -> str:
- return 'cv' + self.typ.get_id(version) + self.expr.get_id(version)
+ return (_id_explicit_cast[self.cast] +
+ self.typ.get_id(version) +
+ self.expr.get_id(version))
- def describe_signature(self, signode, mode, env, symbol):
- signode.append(nodes.Text('('))
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ signode.append(nodes.Text(self.cast))
+ signode.append(nodes.Text('<'))
self.typ.describe_signature(signode, mode, env, symbol)
- signode.append(nodes.Text(')'))
+ signode.append(nodes.Text('>'))
+ signode.append(nodes.Text('('))
self.expr.describe_signature(signode, mode, env, symbol)
+ signode.append(nodes.Text(')'))
-class ASTUnaryOpExpr(ASTBase):
- def __init__(self, op, expr):
+class ASTTypeId(ASTExpression):
+ def __init__(self, typeOrExpr: Union["ASTType", ASTExpression], isType: bool):
+ 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.append(nodes.Text('typeid'))
+ signode.append(nodes.Text('('))
+ self.typeOrExpr.describe_signature(signode, mode, env, symbol)
+ signode.append(nodes.Text(')'))
+
+
+# Unary expressions
+################################################################################
+
+class ASTUnaryOpExpr(ASTExpression):
+ def __init__(self, op: str, expr: ASTExpression):
self.op = op
self.expr = expr
@@ -1010,13 +1265,14 @@ class ASTUnaryOpExpr(ASTBase):
def get_id(self, version: int) -> str:
return _id_operator_unary_v2[self.op] + self.expr.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text(self.op))
self.expr.describe_signature(signode, mode, env, symbol)
-class ASTSizeofParamPack(ASTBase):
- def __init__(self, identifier):
+class ASTSizeofParamPack(ASTExpression):
+ def __init__(self, identifier: ASTIdentifier):
self.identifier = identifier
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1025,15 +1281,16 @@ class ASTSizeofParamPack(ASTBase):
def get_id(self, version: int) -> str:
return 'sZ' + self.identifier.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('sizeof...('))
self.identifier.describe_signature(signode, mode, env,
symbol=symbol, prefix="", templateArgs="")
signode.append(nodes.Text(')'))
-class ASTSizeofType(ASTBase):
- def __init__(self, typ):
+class ASTSizeofType(ASTExpression):
+ def __init__(self, typ: "ASTType"):
self.typ = typ
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1042,14 +1299,15 @@ class ASTSizeofType(ASTBase):
def get_id(self, version: int) -> str:
return 'st' + self.typ.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('sizeof('))
self.typ.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
-class ASTSizeofExpr(ASTBase):
- def __init__(self, expr):
+class ASTSizeofExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression):
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1058,13 +1316,14 @@ class ASTSizeofExpr(ASTBase):
def get_id(self, version: int) -> str:
return 'sz' + self.expr.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('sizeof '))
self.expr.describe_signature(signode, mode, env, symbol)
-class ASTAlignofExpr(ASTBase):
- def __init__(self, typ):
+class ASTAlignofExpr(ASTExpression):
+ def __init__(self, typ: "ASTType"):
self.typ = typ
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1073,14 +1332,15 @@ class ASTAlignofExpr(ASTBase):
def get_id(self, version: int) -> str:
return 'at' + self.typ.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('alignof('))
self.typ.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
-class ASTNoexceptExpr(ASTBase):
- def __init__(self, expr):
+class ASTNoexceptExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression):
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1089,14 +1349,16 @@ class ASTNoexceptExpr(ASTBase):
def get_id(self, version: int) -> str:
return 'nx' + self.expr.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('noexcept('))
self.expr.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
-class ASTNewExpr(ASTBase):
- def __init__(self, rooted: bool, isNewTypeId: bool, typ: "ASTType", initList: Any) -> None:
+class ASTNewExpr(ASTExpression):
+ def __init__(self, rooted: bool, isNewTypeId: bool, typ: "ASTType",
+ initList: Union["ASTParenExprList", "ASTBracedInitList"]) -> None:
self.rooted = rooted
self.isNewTypeId = isNewTypeId
self.typ = typ
@@ -1128,7 +1390,8 @@ class ASTNewExpr(ASTBase):
res.append('E')
return ''.join(res)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
if self.rooted:
signode.append(nodes.Text('::'))
signode.append(nodes.Text('new '))
@@ -1141,8 +1404,8 @@ class ASTNewExpr(ASTBase):
self.initList.describe_signature(signode, mode, env, symbol)
-class ASTDeleteExpr(ASTBase):
- def __init__(self, rooted, array, expr):
+class ASTDeleteExpr(ASTExpression):
+ def __init__(self, rooted: bool, array: bool, expr: ASTExpression):
self.rooted = rooted
self.array = array
self.expr = expr
@@ -1164,7 +1427,8 @@ class ASTDeleteExpr(ASTBase):
id = "dl"
return id + self.expr.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
if self.rooted:
signode.append(nodes.Text('::'))
signode.append(nodes.Text('delete '))
@@ -1173,653 +1437,127 @@ class ASTDeleteExpr(ASTBase):
self.expr.describe_signature(signode, mode, env, symbol)
-class ASTExplicitCast(ASTBase):
- def __init__(self, cast, typ, expr):
- assert cast in _id_explicit_cast
- self.cast = cast
+# Other expressions
+################################################################################
+
+class ASTCastExpr(ASTExpression):
+ def __init__(self, typ: "ASTType", expr: ASTExpression):
self.typ = typ
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
- res = [self.cast]
- res.append('<')
+ res = ['(']
res.append(transform(self.typ))
- res.append('>(')
- res.append(transform(self.expr))
res.append(')')
+ res.append(transform(self.expr))
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, mode, env, symbol):
- signode.append(nodes.Text(self.cast))
- signode.append(nodes.Text('<'))
- self.typ.describe_signature(signode, mode, env, symbol)
- signode.append(nodes.Text('>'))
- signode.append(nodes.Text('('))
- self.expr.describe_signature(signode, mode, env, symbol)
- signode.append(nodes.Text(')'))
-
-
-class ASTTypeId(ASTBase):
- def __init__(self, typeOrExpr, isType):
- 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)
+ return 'cv' + self.typ.get_id(version) + self.expr.get_id(version)
- def describe_signature(self, signode, mode, env, symbol):
- signode.append(nodes.Text('typeid'))
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('('))
- self.typeOrExpr.describe_signature(signode, mode, env, symbol)
+ self.typ.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
-
-
-class ASTPostfixCallExpr(ASTBase):
- def __init__(self, lst: Union["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:
- res = ['cl', idPrefix]
- for e in self.lst.exprs:
- res.append(e.get_id(version))
- res.append('E')
- return ''.join(res)
-
- def describe_signature(self, signode, mode, env, symbol):
- self.lst.describe_signature(signode, mode, env, symbol)
-
-
-class ASTPostfixArray(ASTBase):
- def __init__(self, expr):
- 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, mode, env, symbol):
- signode.append(nodes.Text('['))
self.expr.describe_signature(signode, mode, env, symbol)
- signode.append(nodes.Text(']'))
-
-
-class ASTPostfixInc(ASTBase):
- def _stringify(self, transform: StringifyTransform) -> str:
- return '++'
-
- def get_id(self, idPrefix: str, version: int) -> str:
- return 'pp' + idPrefix
-
- def describe_signature(self, signode, mode, env, symbol):
- signode.append(nodes.Text('++'))
-
-class ASTPostfixDec(ASTBase):
- def _stringify(self, transform: StringifyTransform) -> str:
- return '--'
-
- def get_id(self, idPrefix: str, version: int) -> str:
- return 'mm' + idPrefix
- def describe_signature(self, signode, mode, env, symbol):
- signode.append(nodes.Text('--'))
-
-
-class ASTPostfixMember(ASTBase):
- def __init__(self, name):
- 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, mode, env, symbol):
- signode.append(nodes.Text('.'))
- self.name.describe_signature(signode, 'noneIsName', env, symbol)
-
-
-class ASTPostfixMemberOfPointer(ASTBase):
- def __init__(self, name):
- 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, mode, env, symbol):
- signode.append(nodes.Text('->'))
- self.name.describe_signature(signode, 'noneIsName', env, symbol)
-
-
-class ASTPostfixExpr(ASTBase):
- def __init__(self, prefix, postFixes):
- assert len(postFixes) > 0
- self.prefix = prefix
- self.postFixes = postFixes
+class ASTBinOpExpr(ASTExpression):
+ def __init__(self, exprs: List[ASTExpression], ops: List[str]):
+ assert len(exprs) > 0
+ assert len(exprs) == len(ops) + 1
+ self.exprs = exprs
+ self.ops = ops
def _stringify(self, transform: StringifyTransform) -> str:
- res = [transform(self.prefix)]
- for p in self.postFixes:
- res.append(transform(p))
+ 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:
- id = self.prefix.get_id(version)
- for p in self.postFixes:
- id = p.get_id(id, version)
- return id
-
- def describe_signature(self, signode, mode, env, symbol):
- self.prefix.describe_signature(signode, mode, env, symbol)
- for p in self.postFixes:
- p.describe_signature(signode, mode, env, symbol)
-
-
-class ASTPackExpansionExpr(ASTBase):
- def __init__(self, expr):
- 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, mode, env, symbol):
- self.expr.describe_signature(signode, mode, env, symbol)
- signode += nodes.Text('...')
-
-
-class ASTFallbackExpr(ASTBase):
- def __init__(self, expr):
- 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, mode, env, symbol):
- signode += nodes.Text(self.expr)
-
-
-################################################################################
-# The Rest
-################################################################################
-
-class ASTIdentifier(ASTBase):
- def __init__(self, identifier: str) -> None:
- assert identifier is not None
- assert len(identifier) != 0
- self.identifier = 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: Any, mode: str, env: "BuildEnvironment",
- prefix: str, templateArgs: str, symbol: "Symbol") -> None:
- _verify_description_mode(mode)
- if mode == 'markType':
- targetText = prefix + self.identifier + templateArgs
- pnode = addnodes.pending_xref('', refdomain='cpp',
- reftype='identifier',
- reftarget=targetText, modname=None,
- classname=None)
- key = symbol.get_lookup_key()
- pnode['cpp:parent_key'] = key
- if self.is_anon():
- pnode += nodes.strong(text="[anonymous]")
- else:
- pnode += nodes.Text(self.identifier)
- signode += pnode
- elif mode == 'lastIsName':
- if self.is_anon():
- signode += nodes.strong(text="[anonymous]")
- else:
- signode += addnodes.desc_name(self.identifier, self.identifier)
- elif mode == 'noneIsName':
- if self.is_anon():
- signode += nodes.strong(text="[anonymous]")
- else:
- signode += nodes.Text(self.identifier)
- else:
- raise Exception('Unknown description mode: %s' % mode)
-
-
-class ASTTemplateKeyParamPackIdDefault(ASTBase):
- 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))
+ 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: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol") -> None:
- signode += nodes.Text(self.key)
- if self.parameterPack:
- if self.identifier:
- signode += nodes.Text(' ')
- signode += nodes.Text('...')
- if self.identifier:
- if not self.parameterPack:
- signode += nodes.Text(' ')
- self.identifier.describe_signature(signode, mode, env, '', '', symbol)
- if self.default:
- signode += nodes.Text(' = ')
- self.default.describe_signature(signode, 'markType', env, symbol)
-
-
-class ASTTemplateParamType(ASTBase):
- 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, symbol: "Symbol" = 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: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol") -> None:
- self.data.describe_signature(signode, mode, env, symbol)
-
-
-class ASTTemplateParamConstrainedTypeWithInit(ASTBase):
- def __init__(self, type: Any, init: Any) -> 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, symbol: "Symbol" = 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: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol") -> None:
- self.type.describe_signature(signode, mode, env, symbol)
- if self.init:
- signode += nodes.Text(" = ")
- self.init.describe_signature(signode, mode, env, symbol)
-
-
-class ASTTemplateParamTemplateType(ASTBase):
- def __init__(self, nestedParams: Any, 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, symbol: "Symbol" = 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: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol") -> None:
- self.nestedParams.describe_signature(signode, 'noneIsName', env, symbol)
- signode += nodes.Text(' ')
- self.data.describe_signature(signode, mode, env, symbol)
-
-
-class ASTTemplateParamNonType(ASTBase):
- def __init__(self, param: Any) -> None:
- assert param
- self.param = param
-
- @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
-
- 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
- return name.names[0].identOrOp
- else:
- return None
-
- def get_id(self, version: int, objectType: str = None, symbol: "Symbol" = 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.param.get_id(version)
-
- def _stringify(self, transform: StringifyTransform) -> str:
- return transform(self.param)
-
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- self.param.describe_signature(signode, mode, env, symbol)
-
+ self.exprs[0].describe_signature(signode, mode, env, symbol)
+ for i in range(1, len(self.exprs)):
+ signode.append(nodes.Text(' '))
+ signode.append(nodes.Text(self.ops[i - 1]))
+ signode.append(nodes.Text(' '))
+ self.exprs[i].describe_signature(signode, mode, env, symbol)
-class ASTTemplateParams(ASTBase):
- def __init__(self, params: Any) -> None:
- assert params is not None
- self.params = params
- self.isNested = False # whether it's a template template param
- def get_id(self, version: int) -> str:
- assert version >= 2
- res = []
- res.append("I")
- for param in self.params:
- res.append(param.get_id(version))
- res.append("E")
- return ''.join(res)
+class ASTAssignmentExpr(ASTExpression):
+ def __init__(self, exprs: List[ASTExpression], ops: List[str]):
+ 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("template<")
- res.append(", ".join(transform(a) for a in self.params))
- res.append("> ")
+ 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 describe_signature(self, parentNode: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol", lineSpec: bool = None
- ) -> None:
- # 'lineSpec' is defaulted becuase of template template parameters
- def makeLine(parentNode=parentNode):
- signode = addnodes.desc_signature_line()
- parentNode += signode
- signode.sphinx_cpp_tagname = 'templateParams'
- return signode
- if self.isNested:
- lineNode = parentNode
- else:
- lineNode = makeLine()
- lineNode += nodes.Text("template<")
- first = True
- for param in self.params:
- if not first:
- lineNode += nodes.Text(", ")
- first = False
- if lineSpec:
- lineNode = makeLine()
- param.describe_signature(lineNode, mode, env, symbol)
- if lineSpec and not first:
- lineNode = makeLine()
- lineNode += nodes.Text(">")
-
-
-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, symbol: "Symbol" = 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:
+ def get_id(self, version: int) -> str:
res = []
- if self.parameterPack:
- res.append('...')
- res.append(transform(self.identifier))
+ 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: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- if self.parameterPack:
- signode += nodes.Text('...')
- self.identifier.describe_signature(signode, mode, env, '', '', symbol)
-
+ self.exprs[0].describe_signature(signode, mode, env, symbol)
+ for i in range(1, len(self.exprs)):
+ signode.append(nodes.Text(' '))
+ signode.append(nodes.Text(self.ops[i - 1]))
+ signode.append(nodes.Text(' '))
+ self.exprs[i].describe_signature(signode, mode, env, symbol)
-class ASTTemplateIntroduction(ASTBase):
- def __init__(self, concept: Any, params: List[Any]) -> None:
- assert len(params) > 0
- self.concept = concept
- self.params = params
- def get_id(self, version: int) -> str:
- assert version >= 2
- # first do the same as a normal template parameter list
- res = []
- res.append("I")
- for param in self.params:
- res.append(param.get_id(version))
- res.append("E")
- # let's use X expr E, which is otherwise for constant template args
- res.append("X")
- res.append(self.concept.get_id(version))
- res.append("I")
- for param in self.params:
- res.append(param.get_id_as_arg(version))
- res.append("E")
- res.append("E")
- return ''.join(res)
+class ASTFallbackExpr(ASTExpression):
+ def __init__(self, expr: str):
+ self.expr = expr
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(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_cpp_tagname = 'templateIntroduction'
- self.concept.describe_signature(signode, 'markType', env, symbol)
- signode += nodes.Text('{')
- first = True
- for param in self.params:
- if not first:
- signode += nodes.Text(', ')
- first = False
- param.describe_signature(signode, mode, env, symbol)
- signode += nodes.Text('}')
-
-
-class ASTTemplateDeclarationPrefix(ASTBase):
- def __init__(self, templates: List[Any]) -> None:
- # templates is None means it's an explicit instantiation of a variable
- self.templates = templates
+ return self.expr
def get_id(self, version: int) -> str:
- assert version >= 2
- # this is not part of a normal name mangling system
- res = []
- for t in self.templates:
- res.append(t.get_id(version))
- return ''.join(res)
-
- def _stringify(self, transform: StringifyTransform) -> str:
- res = []
- for t in self.templates:
- res.append(transform(t))
- return ''.join(res)
+ return str(self.expr)
- 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(signode, 'lastIsName', env, symbol, lineSpec)
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ signode += nodes.Text(self.expr)
-##############################################################################################
+################################################################################
+# Types
+################################################################################
+# Things for ASTNestedName
+################################################################################
class ASTOperator(ASTBase):
- def is_anon(self):
+ def is_anon(self) -> bool:
return False
def is_operator(self) -> bool:
@@ -1828,10 +1566,10 @@ class ASTOperator(ASTBase):
def get_id(self, version: int) -> str:
raise NotImplementedError()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", prefix: str, templateArgs: str,
symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
identifier = str(self)
if mode == 'lastIsName':
signode += addnodes.desc_name(identifier, identifier)
@@ -1860,42 +1598,39 @@ class ASTOperatorBuildIn(ASTOperator):
return 'operator' + self.op
-class ASTOperatorType(ASTOperator):
- def __init__(self, type: Any) -> None:
- self.type = type
+class ASTOperatorLiteral(ASTOperator):
+ def __init__(self, identifier: ASTIdentifier) -> None:
+ self.identifier = identifier
def get_id(self, version: int) -> str:
if version == 1:
- return 'castto-%s-operator' % self.type.get_id(version)
+ raise NoOldIdError()
else:
- return 'cv' + self.type.get_id(version)
+ return 'li' + self.identifier.get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
- return ''.join(['operator ', transform(self.type)])
-
- def get_name_no_template(self) -> str:
- return str(self)
+ return 'operator""' + transform(self.identifier)
-class ASTOperatorLiteral(ASTOperator):
- def __init__(self, identifier: Any) -> None:
- self.identifier = identifier
+class ASTOperatorType(ASTOperator):
+ def __init__(self, type: "ASTType") -> None:
+ self.type = type
def get_id(self, version: int) -> str:
if version == 1:
- raise NoOldIdError()
+ return 'castto-%s-operator' % self.type.get_id(version)
else:
- return 'li' + self.identifier.get_id(version)
+ return 'cv' + self.type.get_id(version)
def _stringify(self, transform: StringifyTransform) -> str:
- return 'operator""' + transform(self.identifier)
-
+ return ''.join(['operator ', transform(self.type)])
-##############################################################################################
+ def get_name_no_template(self) -> str:
+ return str(self)
class ASTTemplateArgConstant(ASTBase):
- def __init__(self, value: Any) -> None:
+ def __init__(self, value: ASTExpression) -> None:
self.value = value
def _stringify(self, transform: StringifyTransform) -> str:
@@ -1908,14 +1643,14 @@ class ASTTemplateArgConstant(ASTBase):
return 'X' + str(self) + 'E'
return 'X' + self.value.get_id(version) + 'E'
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.value.describe_signature(signode, mode, env, symbol)
class ASTTemplateArgs(ASTBase):
- def __init__(self, args: List[Any]) -> None:
+ def __init__(self, args: List[Union["ASTType", ASTTemplateArgConstant]]) -> None:
assert args is not None
self.args = args
@@ -1938,9 +1673,9 @@ class ASTTemplateArgs(ASTBase):
res = ', '.join(transform(a) for a in self.args)
return '<' + res + '>'
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode += nodes.Text('<')
first = True
for a in self.args:
@@ -1951,148 +1686,19 @@ class ASTTemplateArgs(ASTBase):
signode += nodes.Text('>')
-class ASTNestedNameElement(ASTBase):
- def __init__(self, identOrOp: Union["ASTIdentifier", "ASTOperator"],
- templateArgs: ASTTemplateArgs) -> None:
- self.identOrOp = identOrOp
- self.templateArgs = templateArgs
-
- def is_operator(self) -> bool:
- return False
+# Main part of declarations
+################################################################################
+class ASTTrailingTypeSpec(ASTBase):
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: desc_signature, 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, mode, 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)
- for n in self.names:
- res.append(n.get_id(version))
- 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]
- t = self.templates[i]
- if t:
- res.append("template " + transform(n))
- else:
- res.append(transform(n))
- return '::'.join(res)
+ raise NotImplementedError(repr(self))
- def describe_signature(self, signode: desc_signature, mode: str,
+ 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':
- signode += nodes.Text(str(self))
- elif mode == 'param':
- name = str(self)
- signode += nodes.emphasis(name, name)
- elif mode == 'markType' or mode == 'lastIsName' or mode == '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 = [] # type: 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 relies 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() # type: ignore
- for i in range(len(names)):
- nne = names[i]
- template = self.templates[i]
- if not first:
- dest += nodes.Text('::')
- prefix += '::'
- if template:
- dest += nodes.Text("template ")
- 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_addname('::', '::')
- signode += dest
- if self.templates[-1]:
- signode += nodes.Text("template ")
- self.names[-1].describe_signature(signode, mode, env, '', symbol)
- else:
- raise Exception('Unknown description mode: %s' % mode)
+ raise NotImplementedError(repr(self))
-class ASTTrailingTypeSpecFundamental(ASTBase):
+class ASTTrailingTypeSpecFundamental(ASTTrailingTypeSpec):
def __init__(self, name: str) -> None:
self.name = name
@@ -2116,40 +1722,12 @@ class ASTTrailingTypeSpecFundamental(ASTBase):
'parser should have rejected it.' % self.name)
return _id_fundamental_v2[self.name]
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
signode += nodes.Text(str(self.name))
-class ASTTrailingTypeSpecName(ASTBase):
- def __init__(self, prefix: str, nestedName: Any) -> None:
- self.prefix = prefix
- self.nestedName = nestedName
-
- @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))
- return ''.join(res)
-
- def describe_signature(self, signode: desc_signature, mode: str,
- env: "BuildEnvironment", symbol: "Symbol") -> None:
- if self.prefix:
- signode += addnodes.desc_annotation(self.prefix, self.prefix)
- signode += nodes.Text(' ')
- self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
-
-
-class ASTTrailingTypeSpecDecltypeAuto(ASTBase):
+class ASTTrailingTypeSpecDecltypeAuto(ASTTrailingTypeSpec):
def _stringify(self, transform: StringifyTransform) -> str:
return 'decltype(auto)'
@@ -2158,13 +1736,13 @@ class ASTTrailingTypeSpecDecltypeAuto(ASTBase):
raise NoOldIdError()
return 'Dc'
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text(str(self)))
-class ASTTrailingTypeSpecDecltype(ASTBase):
- def __init__(self, expr):
+class ASTTrailingTypeSpecDecltype(ASTTrailingTypeSpec):
+ def __init__(self, expr: ASTExpression):
self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
@@ -2175,15 +1753,45 @@ class ASTTrailingTypeSpecDecltype(ASTBase):
raise NoOldIdError()
return 'DT' + self.expr.get_id(version) + "E"
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
signode.append(nodes.Text('decltype('))
self.expr.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text(')'))
+class ASTTrailingTypeSpecName(ASTTrailingTypeSpec):
+ def __init__(self, prefix: str, nestedName: ASTNestedName) -> None:
+ self.prefix = prefix
+ self.nestedName = nestedName
+
+ @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))
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ if self.prefix:
+ signode += addnodes.desc_annotation(self.prefix, self.prefix)
+ signode += nodes.Text(' ')
+ self.nestedName.describe_signature(signode, mode, env, symbol=symbol)
+
+
class ASTFunctionParameter(ASTBase):
- def __init__(self, arg: Any, ellipsis: bool = False) -> None:
+ def __init__(self, arg: Union["ASTTypeWithInit",
+ "ASTTemplateParamConstrainedTypeWithInit"],
+ ellipsis: bool = False) -> None:
self.arg = arg
self.ellipsis = ellipsis
@@ -2204,9 +1812,9 @@ class ASTFunctionParameter(ASTBase):
else:
return transform(self.arg)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
if self.ellipsis:
signode += nodes.Text('...')
else:
@@ -2214,7 +1822,8 @@ class ASTFunctionParameter(ASTBase):
class ASTParametersQualifiers(ASTBase):
- def __init__(self, args: List[Any], volatile: bool, const: bool, refQual: str,
+ def __init__(self, args: List[ASTFunctionParameter],
+ volatile: bool, const: bool, refQual: str,
exceptionSpec: str, override: bool, final: bool, initializer: str) -> None:
self.args = args
self.volatile = volatile
@@ -2226,7 +1835,7 @@ class ASTParametersQualifiers(ASTBase):
self.initializer = initializer
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.args
def get_modifiers_id(self, version: int) -> str:
@@ -2284,9 +1893,9 @@ class ASTParametersQualifiers(ASTBase):
res.append(self.initializer)
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
paramlist = addnodes.desc_parameterlist()
for arg in self.args:
param = addnodes.desc_parameter('', '', noemph=True)
@@ -2297,11 +1906,11 @@ class ASTParametersQualifiers(ASTBase):
paramlist += param
signode += paramlist
- def _add_anno(signode, text):
+ def _add_anno(signode: TextElement, text: str) -> None:
signode += nodes.Text(' ')
signode += addnodes.desc_annotation(text, text)
- def _add_text(signode, text):
+ def _add_text(signode: TextElement, text: str) -> None:
signode += nodes.Text(' ' + text)
if self.volatile:
@@ -2323,7 +1932,7 @@ class ASTParametersQualifiers(ASTBase):
class ASTDeclSpecsSimple(ASTBase):
def __init__(self, storage: str, threadLocal: bool, inline: bool, virtual: bool,
explicit: bool, constexpr: bool, volatile: bool, const: bool,
- friend: bool, attrs: List[Any]) -> None:
+ friend: bool, attrs: List[ASTAttribute]) -> None:
self.storage = storage
self.threadLocal = threadLocal
self.inline = inline
@@ -2372,38 +1981,44 @@ class ASTDeclSpecsSimple(ASTBase):
res.append('const')
return ' '.join(res)
- def describe_signature(self, modifiers: List[Node]) -> None:
- def _add(modifiers, text):
- if len(modifiers) > 0:
- modifiers.append(nodes.Text(' '))
- modifiers.append(addnodes.desc_annotation(text, text))
+ def describe_signature(self, signode: TextElement) -> None:
+ addSpace = False
for attr in self.attrs:
- if len(modifiers) > 0:
- modifiers.append(nodes.Text(' '))
- modifiers.append(attr.describe_signature(modifiers))
+ if addSpace:
+ signode += nodes.Text(' ')
+ addSpace = True
+ attr.describe_signature(signode)
+
+ def _add(signode: TextElement, text: str) -> bool:
+ if addSpace:
+ signode += nodes.Text(' ')
+ signode += addnodes.desc_annotation(text, text)
+ return True
+
if self.storage:
- _add(modifiers, self.storage)
+ addSpace = _add(signode, self.storage)
if self.threadLocal:
- _add(modifiers, 'thread_local')
+ addSpace = _add(signode, 'thread_local')
if self.inline:
- _add(modifiers, 'inline')
+ addSpace = _add(signode, 'inline')
if self.friend:
- _add(modifiers, 'friend')
+ addSpace = _add(signode, 'friend')
if self.virtual:
- _add(modifiers, 'virtual')
+ addSpace = _add(signode, 'virtual')
if self.explicit:
- _add(modifiers, 'explicit')
+ addSpace = _add(signode, 'explicit')
if self.constexpr:
- _add(modifiers, 'constexpr')
+ addSpace = _add(signode, 'constexpr')
if self.volatile:
- _add(modifiers, 'volatile')
+ addSpace = _add(signode, 'volatile')
if self.const:
- _add(modifiers, 'const')
+ addSpace = _add(signode, 'const')
class ASTDeclSpecs(ASTBase):
- def __init__(self, outer: Any, leftSpecs: ASTDeclSpecsSimple,
- rightSpecs: ASTDeclSpecsSimple, trailing: Any) -> None:
+ 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
@@ -2412,10 +2027,6 @@ class ASTDeclSpecs(ASTBase):
self.allSpecs = self.leftSpecs.mergeWith(self.rightSpecs)
self.trailingTypeSpec = trailing
- @property
- def name(self) -> ASTNestedName:
- return self.trailingTypeSpec.name
-
def get_id(self, version: int) -> str:
if version == 1:
res = []
@@ -2450,35 +2061,29 @@ class ASTDeclSpecs(ASTBase):
res.append(r)
return "".join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
- modifiers = [] # type: List[nodes.Node]
-
- def _add(modifiers, text):
- if len(modifiers) > 0:
- modifiers.append(nodes.Text(' '))
- modifiers.append(addnodes.desc_annotation(text, text))
+ verify_description_mode(mode)
+ numChildren = len(signode)
+ self.leftSpecs.describe_signature(signode)
+ addSpace = len(signode) != numChildren
- self.leftSpecs.describe_signature(modifiers)
-
- for m in modifiers:
- signode += m
if self.trailingTypeSpec:
- if len(modifiers) > 0:
+ if addSpace:
signode += nodes.Text(' ')
self.trailingTypeSpec.describe_signature(signode, mode, env,
symbol=symbol)
- modifiers = []
- self.rightSpecs.describe_signature(modifiers)
- if len(modifiers) > 0:
+ numChildren = len(signode)
+ self.rightSpecs.describe_signature(signode)
+ if len(signode) != numChildren:
signode += nodes.Text(' ')
- for m in modifiers:
- signode += m
+# Declarator
+################################################################################
+
class ASTArray(ASTBase):
- def __init__(self, size):
+ def __init__(self, size: ASTExpression):
self.size = size
def _stringify(self, transform: StringifyTransform) -> str:
@@ -2500,16 +2105,174 @@ class ASTArray(ASTBase):
else:
return 'A_'
- def describe_signature(self, signode, mode, env, symbol):
- _verify_description_mode(mode)
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ verify_description_mode(mode)
signode.append(nodes.Text("["))
if self.size:
self.size.describe_signature(signode, mode, env, symbol)
signode.append(nodes.Text("]"))
-class ASTDeclaratorPtr(ASTBase):
- def __init__(self, next: Any, volatile: bool, const: bool, attrs: Any) -> None:
+class ASTDeclarator(ASTBase):
+ @property
+ def name(self) -> ASTNestedName:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def isPack(self) -> bool:
+ raise NotImplementedError(repr(self))
+
+ @property
+ def function_params(self) -> List[ASTFunctionParameter]:
+ 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
+
+ @property
+ def isPack(self) -> bool:
+ return False
+
+ @property
+ def function_params(self) -> List[ASTFunctionParameter]:
+ return self.paramQual.function_params
+
+ # 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 = []
+ # TOOD: 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))
+ for op in self.arrayOps:
+ res.append(transform(op))
+ 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):
+ self.declId = declId
+ self.size = size
+
+ @property
+ def name(self) -> ASTNestedName:
+ return self.declId
+
+ 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.append(nodes.Text(' : ', ' : '))
+ self.size.describe_signature(signode, mode, env, symbol)
+
+
+class ASTDeclaratorPtr(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator, volatile: bool, const: bool,
+ attrs: List[ASTAttribute]) -> None:
assert next
self.next = next
self.volatile = volatile
@@ -2521,12 +2284,11 @@ class ASTDeclaratorPtr(ASTBase):
return self.next.name
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
def require_space_after_declSpecs(self) -> bool:
- # TODO: if has paramPack, then False ?
- return True
+ return self.next.require_space_after_declSpecs()
def _stringify(self, transform: StringifyTransform) -> str:
res = ['*']
@@ -2541,7 +2303,7 @@ class ASTDeclaratorPtr(ASTBase):
res.append(' ')
res.append('const')
if self.const or self.volatile or len(self.attrs) > 0:
- if self.next.require_space_after_declSpecs:
+ if self.next.require_space_after_declSpecs():
res.append(' ')
res.append(transform(self.next))
return ''.join(res)
@@ -2583,16 +2345,16 @@ class ASTDeclaratorPtr(ASTBase):
def is_function_type(self) -> bool:
return self.next.is_function_type()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode += nodes.Text("*")
for a in self.attrs:
a.describe_signature(signode)
if len(self.attrs) > 0 and (self.volatile or self.const):
signode += nodes.Text(' ')
- def _add_anno(signode, text):
+ def _add_anno(signode: TextElement, text: str) -> None:
signode += addnodes.desc_annotation(text, text)
if self.volatile:
_add_anno(signode, 'volatile')
@@ -2601,13 +2363,13 @@ class ASTDeclaratorPtr(ASTBase):
signode += nodes.Text(' ')
_add_anno(signode, 'const')
if self.const or self.volatile or len(self.attrs) > 0:
- if self.next.require_space_after_declSpecs:
+ if self.next.require_space_after_declSpecs():
signode += nodes.Text(' ')
self.next.describe_signature(signode, mode, env, symbol)
-class ASTDeclaratorRef(ASTBase):
- def __init__(self, next: Any, attrs: Any) -> None:
+class ASTDeclaratorRef(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator, attrs: List[ASTAttribute]) -> None:
assert next
self.next = next
self.attrs = attrs
@@ -2621,7 +2383,7 @@ class ASTDeclaratorRef(ASTBase):
return True
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
def require_space_after_declSpecs(self) -> bool:
@@ -2631,7 +2393,7 @@ class ASTDeclaratorRef(ASTBase):
res = ['&']
for a in self.attrs:
res.append(transform(a))
- if len(self.attrs) > 0 and self.next.require_space_after_declSpecs:
+ if len(self.attrs) > 0 and self.next.require_space_after_declSpecs():
res.append(' ')
res.append(transform(self.next))
return ''.join(res)
@@ -2656,19 +2418,19 @@ class ASTDeclaratorRef(ASTBase):
def is_function_type(self) -> bool:
return self.next.is_function_type()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode += nodes.Text("&")
for a in self.attrs:
a.describe_signature(signode)
- if len(self.attrs) > 0 and self.next.require_space_after_declSpecs:
+ if len(self.attrs) > 0 and self.next.require_space_after_declSpecs():
signode += nodes.Text(' ')
self.next.describe_signature(signode, mode, env, symbol)
-class ASTDeclaratorParamPack(ASTBase):
- def __init__(self, next: Any) -> None:
+class ASTDeclaratorParamPack(ASTDeclarator):
+ def __init__(self, next: ASTDeclarator) -> None:
assert next
self.next = next
@@ -2677,7 +2439,7 @@ class ASTDeclaratorParamPack(ASTBase):
return self.next.name
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
def require_space_after_declSpecs(self) -> bool:
@@ -2709,17 +2471,18 @@ class ASTDeclaratorParamPack(ASTBase):
def is_function_type(self) -> bool:
return self.next.is_function_type()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode += nodes.Text("...")
if self.next.name:
signode += nodes.Text(' ')
self.next.describe_signature(signode, mode, env, symbol)
-class ASTDeclaratorMemPtr(ASTBase):
- def __init__(self, className: Any, const: bool, volatile: bool, next: Any) -> None:
+class ASTDeclaratorMemPtr(ASTDeclarator):
+ def __init__(self, className: ASTNestedName,
+ const: bool, volatile: bool, next: ASTDeclarator) -> None:
assert className
assert next
self.className = className
@@ -2732,7 +2495,7 @@ class ASTDeclaratorMemPtr(ASTBase):
return self.next.name
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.next.function_params
def require_space_after_declSpecs(self) -> bool:
@@ -2743,9 +2506,11 @@ class ASTDeclaratorMemPtr(ASTBase):
res.append(transform(self.className))
res.append('::*')
if self.volatile:
- res.append(' volatile')
+ res.append('volatile')
if self.const:
- res.append(' const')
+ if self.volatile:
+ res.append(' ')
+ res.append('const')
if self.next.require_space_after_declSpecs():
res.append(' ')
res.append(transform(self.next))
@@ -2786,13 +2551,13 @@ class ASTDeclaratorMemPtr(ASTBase):
def is_function_type(self) -> bool:
return self.next.is_function_type()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.className.describe_signature(signode, mode, env, symbol)
signode += nodes.Text('::*')
- def _add_anno(signode, text):
+ def _add_anno(signode: TextElement, text: str) -> None:
signode += addnodes.desc_annotation(text, text)
if self.volatile:
_add_anno(signode, 'volatile')
@@ -2801,13 +2566,12 @@ class ASTDeclaratorMemPtr(ASTBase):
signode += nodes.Text(' ')
_add_anno(signode, 'const')
if self.next.require_space_after_declSpecs():
- if self.volatile or self.const:
- signode += nodes.Text(' ')
+ signode += nodes.Text(' ')
self.next.describe_signature(signode, mode, env, symbol)
-class ASTDeclaratorParen(ASTBase):
- def __init__(self, inner: Any, next: Any) -> None:
+class ASTDeclaratorParen(ASTDeclarator):
+ def __init__(self, inner: ASTDeclarator, next: ASTDeclarator) -> None:
assert inner
assert next
self.inner = inner
@@ -2819,7 +2583,7 @@ class ASTDeclaratorParen(ASTBase):
return self.inner.name
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.inner.function_params
def require_space_after_declSpecs(self) -> bool:
@@ -2856,135 +2620,37 @@ class ASTDeclaratorParen(ASTBase):
def is_function_type(self) -> bool:
return self.inner.is_function_type()
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode += nodes.Text('(')
self.inner.describe_signature(signode, mode, env, symbol)
signode += nodes.Text(')')
self.next.describe_signature(signode, "noneIsName", env, symbol)
-class ASTDeclaratorNameParamQual(ASTBase):
- def __init__(self, declId: Any, arrayOps: List[Any], paramQual: Any) -> None:
- self.declId = declId
- self.arrayOps = arrayOps
- self.paramQual = paramQual
-
- @property
- def name(self) -> ASTNestedName:
- return self.declId
-
- @property
- def isPack(self) -> bool:
- return False
-
- @property
- def function_params(self) -> Any:
- return self.paramQual.function_params
-
- # 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 = []
- # TOOD: 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
+# Type and initializer stuff
+##############################################################################################
- def is_function_type(self) -> bool:
- return self.paramQual is not None
+class ASTPackExpansionExpr(ASTExpression):
+ def __init__(self, expr: ASTExpression):
+ self.expr = expr
def _stringify(self, transform: StringifyTransform) -> str:
- res = []
- if self.declId:
- res.append(transform(self.declId))
- for op in self.arrayOps:
- res.append(transform(op))
- if self.paramQual:
- res.append(transform(self.paramQual))
- return ''.join(res)
-
- def describe_signature(self, signode: desc_signature, 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(ASTBase):
- def __init__(self, declId, size):
- self.declId = declId
- self.size = size
-
- @property
- def name(self) -> ASTNestedName:
- return self.declId
-
- 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
+ return transform(self.expr) + '...'
- 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 get_id(self, version: int) -> str:
+ id = self.expr.get_id(version)
+ return 'sp' + id
- def describe_signature(self, signode: desc_signature, mode: str,
+ 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.append(nodes.Text(' : ', ' : '))
- self.size.describe_signature(signode, mode, env, symbol)
+ self.expr.describe_signature(signode, mode, env, symbol)
+ signode += nodes.Text('...')
class ASTParenExprList(ASTBase):
- def __init__(self, exprs: List[Any]) -> None:
+ def __init__(self, exprs: List[ASTExpression]) -> None:
self.exprs = exprs
def get_id(self, version: int) -> str:
@@ -2994,9 +2660,9 @@ class ASTParenExprList(ASTBase):
exprs = [transform(e) for e in self.exprs]
return '(%s)' % ', '.join(exprs)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode.append(nodes.Text('('))
first = True
for e in self.exprs:
@@ -3009,7 +2675,7 @@ class ASTParenExprList(ASTBase):
class ASTBracedInitList(ASTBase):
- def __init__(self, exprs: List[Any], trailingComma: bool) -> None:
+ def __init__(self, exprs: List[ASTExpression], trailingComma: bool) -> None:
self.exprs = exprs
self.trailingComma = trailingComma
@@ -3021,9 +2687,9 @@ class ASTBracedInitList(ASTBase):
trailingComma = ',' if self.trailingComma else ''
return '{%s%s}' % (', '.join(exprs), trailingComma)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
signode.append(nodes.Text('{'))
first = True
for e in self.exprs:
@@ -3038,7 +2704,8 @@ class ASTBracedInitList(ASTBase):
class ASTInitializer(ASTBase):
- def __init__(self, value: Any, hasAssign: bool = True) -> None:
+ def __init__(self, value: Union[ASTExpression, ASTBracedInitList],
+ hasAssign: bool = True) -> None:
self.value = value
self.hasAssign = hasAssign
@@ -3049,16 +2716,16 @@ class ASTInitializer(ASTBase):
else:
return val
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
if self.hasAssign:
signode.append(nodes.Text(' = '))
self.value.describe_signature(signode, 'markType', env, symbol)
class ASTType(ASTBase):
- def __init__(self, declSpecs: Any, decl: Any) -> None:
+ def __init__(self, declSpecs: ASTDeclSpecs, decl: ASTDeclarator) -> None:
assert declSpecs
assert decl
self.declSpecs = declSpecs
@@ -3073,7 +2740,7 @@ class ASTType(ASTBase):
return self.decl.isPack
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
return self.decl.function_params
def get_id(self, version: int, objectType: str = None,
@@ -3144,9 +2811,9 @@ class ASTType(ASTBase):
else:
return 'type'
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ 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):
@@ -3158,8 +2825,46 @@ class ASTType(ASTBase):
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, symbol: "Symbol" = 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 += nodes.Text(" = ")
+ self.init.describe_signature(signode, mode, env, symbol)
+
+
class ASTTypeWithInit(ASTBase):
- def __init__(self, type: Any, init: Any) -> None:
+ def __init__(self, type: ASTType, init: ASTInitializer) -> None:
self.type = type
self.init = init
@@ -3187,16 +2892,16 @@ class ASTTypeWithInit(ASTBase):
res.append(transform(self.init))
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ 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: Any, type: Any) -> None:
+ def __init__(self, name: ASTNestedName, type: ASTType) -> None:
self.name = name
self.type = type
@@ -3217,17 +2922,20 @@ class ASTTypeUsing(ASTBase):
def get_type_declaration_prefix(self) -> str:
return 'using'
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.name.describe_signature(signode, mode, env, symbol=symbol)
if self.type:
signode += nodes.Text(' = ')
self.type.describe_signature(signode, 'markType', env, symbol=symbol)
+# Other declarations
+##############################################################################################
+
class ASTConcept(ASTBase):
- def __init__(self, nestedName: Any, initializer: Any) -> None:
+ def __init__(self, nestedName: ASTNestedName, initializer: ASTInitializer) -> None:
self.nestedName = nestedName
self.initializer = initializer
@@ -3247,7 +2955,7 @@ class ASTConcept(ASTBase):
res += transform(self.initializer)
return res
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
self.nestedName.describe_signature(signode, mode, env, symbol)
if self.initializer:
@@ -3275,9 +2983,9 @@ class ASTBaseClass(ASTBase):
res.append('...')
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
if self.visibility is not None:
signode += addnodes.desc_annotation(self.visibility,
self.visibility)
@@ -3314,9 +3022,9 @@ class ASTClass(ASTBase):
res.append(transform(b))
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.name.describe_signature(signode, mode, env, symbol=symbol)
if self.final:
signode += nodes.Text(' ')
@@ -3330,7 +3038,7 @@ class ASTClass(ASTBase):
class ASTUnion(ASTBase):
- def __init__(self, name: Any) -> None:
+ def __init__(self, name: ASTNestedName) -> None:
self.name = name
def get_id(self, version: int, objectType: str, symbol: "Symbol") -> str:
@@ -3341,14 +3049,15 @@ class ASTUnion(ASTBase):
def _stringify(self, transform: StringifyTransform) -> str:
return transform(self.name)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.name.describe_signature(signode, mode, env, symbol=symbol)
class ASTEnum(ASTBase):
- def __init__(self, name: Any, scoped: str, underlyingType: Any) -> None:
+ def __init__(self, name: ASTNestedName, scoped: str,
+ underlyingType: ASTType) -> None:
self.name = name
self.scoped = scoped
self.underlyingType = underlyingType
@@ -3369,9 +3078,9 @@ class ASTEnum(ASTBase):
res.append(transform(self.underlyingType))
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
# self.scoped has been done by the CPPEnumObject
self.name.describe_signature(signode, mode, env, symbol=symbol)
if self.underlyingType:
@@ -3381,7 +3090,7 @@ class ASTEnum(ASTBase):
class ASTEnumerator(ASTBase):
- def __init__(self, name: Any, init: Any) -> None:
+ def __init__(self, name: ASTNestedName, init: ASTInitializer) -> None:
self.name = name
self.init = init
@@ -3397,14 +3106,398 @@ class ASTEnumerator(ASTBase):
res.append(transform(self.init))
return ''.join(res)
- def describe_signature(self, signode: desc_signature, mode: str,
+ def describe_signature(self, signode: TextElement, mode: str,
env: "BuildEnvironment", symbol: "Symbol") -> None:
- _verify_description_mode(mode)
+ verify_description_mode(mode)
self.name.describe_signature(signode, mode, env, symbol)
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))
+
+
+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 += nodes.Text(self.key)
+ if self.parameterPack:
+ if self.identifier:
+ signode += nodes.Text(' ')
+ signode += nodes.Text('...')
+ if self.identifier:
+ if not self.parameterPack:
+ signode += nodes.Text(' ')
+ self.identifier.describe_signature(signode, mode, env, '', '', symbol)
+ if self.default:
+ signode += nodes.Text(' = ')
+ 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, symbol: "Symbol" = 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, symbol: "Symbol" = 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 += nodes.Text(' ')
+ self.data.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateParamNonType(ASTTemplateParam):
+ def __init__(self,
+ param: Union[ASTTypeWithInit,
+ ASTTemplateParamConstrainedTypeWithInit]) -> None:
+ assert param
+ self.param = param
+
+ @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
+
+ 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, symbol: "Symbol" = 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.param.get_id(version)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ return transform(self.param)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ self.param.describe_signature(signode, mode, env, symbol)
+
+
+class ASTTemplateParams(ASTBase):
+ def __init__(self, params: List[ASTTemplateParam]) -> None:
+ assert params is not None
+ self.params = params
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ res = []
+ res.append("I")
+ for param in self.params:
+ res.append(param.get_id(version))
+ res.append("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("> ")
+ return ''.join(res)
+
+ def describe_signature(self, signode: TextElement, mode: str,
+ env: "BuildEnvironment", symbol: "Symbol") -> None:
+ signode += nodes.Text("template<")
+ first = True
+ for param in self.params:
+ if not first:
+ signode += nodes.Text(", ")
+ first = False
+ param.describe_signature(signode, mode, env, symbol)
+ signode += nodes.Text(">")
+
+ 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 += nodes.Text("template<")
+ first = True
+ for param in self.params:
+ if not first:
+ lineNode += nodes.Text(", ")
+ first = False
+ if lineSpec:
+ lineNode = makeLine(parentNode)
+ param.describe_signature(lineNode, mode, env, symbol)
+ if lineSpec and not first:
+ lineNode = makeLine(parentNode)
+ lineNode += nodes.Text(">")
+
+
+# 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, symbol: "Symbol" = 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 += nodes.Text('...')
+ 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
+ # first do the same as a normal template parameter list
+ res = []
+ res.append("I")
+ for param in self.params:
+ res.append(param.get_id(version))
+ res.append("E")
+ # let's use X expr E, which is otherwise for constant template args
+ res.append("X")
+ res.append(self.concept.get_id(version))
+ res.append("I")
+ for param in self.params:
+ res.append(param.get_id_as_arg(version))
+ res.append("E")
+ res.append("E")
+ return ''.join(res)
+
+ 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 += nodes.Text('{')
+ first = True
+ for param in self.params:
+ if not first:
+ signode += nodes.Text(', ')
+ first = False
+ param.describe_signature(signode, mode, env, symbol)
+ signode += nodes.Text('}')
+
+
+class ASTTemplateDeclarationPrefix(ASTBase):
+ def __init__(self,
+ templates: List[Union[ASTTemplateParams,
+ ASTTemplateIntroduction]]) -> None:
+ # templates is None means it's an explicit instantiation of a variable
+ self.templates = templates
+
+ def get_id(self, version: int) -> str:
+ assert version >= 2
+ # this is not part of a normal name mangling system
+ res = []
+ for t in self.templates:
+ res.append(t.get_id(version))
+ return ''.join(res)
+
+ def _stringify(self, transform: StringifyTransform) -> str:
+ res = []
+ for t in self.templates:
+ res.append(transform(t))
+ return ''.join(res)
+
+ 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 ASTDeclaration(ASTBase):
def __init__(self, objectType: str, directiveType: str, visibility: str,
templatePrefix: ASTTemplateDeclarationPrefix, declaration: Any) -> None:
@@ -3432,7 +3525,7 @@ class ASTDeclaration(ASTBase):
return self.declaration.name
@property
- def function_params(self) -> Any:
+ def function_params(self) -> List[ASTFunctionParameter]:
if self.objectType != 'function':
return None
return self.declaration.function_params
@@ -3471,14 +3564,14 @@ class ASTDeclaration(ASTBase):
def describe_signature(self, signode: desc_signature, mode: str,
env: "BuildEnvironment", options: Dict) -> None:
- _verify_description_mode(mode)
+ 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_cpp_tagname = 'declarator'
+ mainDeclNode.sphinx_line_type = 'declarator'
mainDeclNode['add_permalink'] = not self.symbol.isRedeclaration
if self.templatePrefix:
@@ -3547,10 +3640,25 @@ class SymbolLookupResult:
self.templateArgs = templateArgs
+class LookupKey:
+ def __init__(self, data: List[Tuple[ASTNestedNameElement,
+ Union[ASTTemplateParams,
+ ASTTemplateIntroduction],
+ str]]) -> None:
+ self.data = data
+
+
class Symbol:
+ debug_indent = 0
+ debug_indent_string = " "
debug_lookup = False
debug_show_tree = False
+ @staticmethod
+ def debug_print(*args: Any) -> None:
+ print(Symbol.debug_indent_string * Symbol.debug_indent, end="")
+ print(*args)
+
def _assert_invariants(self) -> None:
if not self.parent:
# parent == None means global scope, so declaration means a parent
@@ -3570,9 +3678,12 @@ class Symbol:
return super().__setattr__(key, value)
def __init__(self, parent: "Symbol", identOrOp: Union[ASTIdentifier, ASTOperator],
- templateParams: Any, templateArgs: Any, declaration: ASTDeclaration,
- docname: str) -> None:
+ templateParams: Union[ASTTemplateParams, ASTTemplateIntroduction],
+ templateArgs: Any, declaration: ASTDeclaration, docname: str) -> None:
self.parent = parent
+ # declarations in a single directive are linked together
+ self.siblingAbove = None # type: Symbol
+ self.siblingBelow = None # type: Symbol
self.identOrOp = identOrOp
self.templateParams = templateParams # template<templateParams>
self.templateArgs = templateArgs # identifier<templateArgs>
@@ -3606,38 +3717,43 @@ class Symbol:
# and symbol addition should be done as well
self._add_template_and_function_params()
- def _add_template_and_function_params(self):
+ def _add_template_and_function_params(self) -> None:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("_add_template_and_function_params:")
# Note: we may be called from _fill_empty, so the symbols we want
# to add may actually already be present (as empty symbols).
# add symbols for the template params
if self.templateParams:
- for p in self.templateParams.params:
- if not p.get_identifier():
+ for tp in self.templateParams.params:
+ if not tp.get_identifier():
continue
# only add a declaration if we our self are from a declaration
if self.declaration:
- decl = ASTDeclaration('templateParam', None, None, None, p)
+ decl = ASTDeclaration('templateParam', None, None, None, tp)
else:
decl = None
- nne = ASTNestedNameElement(p.get_identifier(), None)
+ nne = ASTNestedNameElement(tp.get_identifier(), None)
nn = ASTNestedName([nne], [False], rooted=False)
self._add_symbols(nn, [], decl, self.docname)
# add symbols for function parameters, if any
if self.declaration is not None and self.declaration.function_params is not None:
- for p in self.declaration.function_params:
- if p.arg is None:
+ for fp in self.declaration.function_params:
+ if fp.arg is None:
continue
- nn = p.arg.name
+ nn = fp.arg.name
if nn is None:
continue
# (comparing to the template params: we have checked that we are a declaration)
- decl = ASTDeclaration('functionParam', None, None, None, p)
+ decl = ASTDeclaration('functionParam', None, None, None, fp)
assert not nn.rooted
assert len(nn.names) == 1
self._add_symbols(nn, [], decl, self.docname)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 1
- def remove(self):
+ def remove(self) -> None:
if self.parent is None:
return
assert self in self.parent._children
@@ -3645,12 +3761,18 @@ class Symbol:
self.parent = None
def clear_doc(self, docname: str) -> None:
- newChildren = []
+ newChildren = [] # type: List[Symbol]
for sChild in self._children:
sChild.clear_doc(docname)
if sChild.declaration and sChild.docname == docname:
sChild.declaration = None
sChild.docname = None
+ if sChild.siblingAbove is not None:
+ sChild.siblingAbove.siblingBelow = sChild.siblingBelow
+ if sChild.siblingBelow is not None:
+ sChild.siblingBelow.siblingAbove = sChild.siblingAbove
+ sChild.siblingAbove = None
+ sChild.siblingBelow = None
newChildren.append(sChild)
self._children = newChildren
@@ -3669,7 +3791,11 @@ class Symbol:
yield from c.children_recurse_anon
- def get_lookup_key(self) -> List[Tuple[ASTNestedNameElement, Any]]:
+ def get_lookup_key(self) -> "LookupKey":
+ # The pickle files for the environment and for each document are distinct.
+ # The environment has all the symbols, but the documents has xrefs that
+ # must know their scope. A lookup key is essentially a specification of
+ # how to find a specific symbol.
symbols = []
s = self
while s.parent:
@@ -3679,14 +3805,23 @@ class Symbol:
key = []
for s in symbols:
nne = ASTNestedNameElement(s.identOrOp, s.templateArgs)
- key.append((nne, s.templateParams))
- return key
+ if s.declaration is not None:
+ key.append((nne, s.templateParams, s.declaration.get_newest_id()))
+ else:
+ key.append((nne, s.templateParams, None))
+ return LookupKey(key)
def get_full_nested_name(self) -> ASTNestedName:
+ symbols = []
+ s = self
+ while s.parent:
+ symbols.append(s)
+ s = s.parent
+ symbols.reverse()
names = []
templates = []
- for nne, templateParams in self.get_lookup_key():
- names.append(nne)
+ for s in symbols:
+ names.append(ASTNestedNameElement(s.identOrOp, s.templateArgs))
templates.append(False)
return ASTNestedName(names, templates, rooted=False)
@@ -3695,9 +3830,12 @@ class Symbol:
templateShorthand: bool, matchSelf: bool,
recurseInAnon: bool, correctPrimaryTemplateArgs: bool
) -> "Symbol":
+ if Symbol.debug_lookup:
+ Symbol.debug_print("_find_first_named_symbol ->")
res = self._find_named_symbols(identOrOp, templateParams, templateArgs,
templateShorthand, matchSelf, recurseInAnon,
- correctPrimaryTemplateArgs)
+ correctPrimaryTemplateArgs,
+ searchInSiblings=False)
try:
return next(res)
except StopIteration:
@@ -3706,10 +3844,24 @@ class Symbol:
def _find_named_symbols(self, identOrOp: Union[ASTIdentifier, ASTOperator],
templateParams: Any, templateArgs: ASTTemplateArgs,
templateShorthand: bool, matchSelf: bool,
- recurseInAnon: bool, correctPrimaryTemplateArgs: bool
- ) -> Iterator["Symbol"]:
-
- def isSpecialization():
+ recurseInAnon: bool, correctPrimaryTemplateArgs: bool,
+ searchInSiblings: bool) -> Iterator["Symbol"]:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("_find_named_symbols:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("self:")
+ print(self.to_string(Symbol.debug_indent + 1), end="")
+ Symbol.debug_print("identOrOp: ", identOrOp)
+ Symbol.debug_print("templateParams: ", templateParams)
+ Symbol.debug_print("templateArgs: ", templateArgs)
+ Symbol.debug_print("templateShorthand: ", templateShorthand)
+ Symbol.debug_print("matchSelf: ", matchSelf)
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
+ Symbol.debug_print("correctPrimaryTemplateAargs:", correctPrimaryTemplateArgs)
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
+
+ def isSpecialization() -> bool:
# the names of the template parameters must be given exactly as args
# and params that are packs must in the args be the name expanded
if len(templateParams.params) != len(templateArgs.args):
@@ -3759,20 +3911,64 @@ class Symbol:
if str(s.templateArgs) != str(templateArgs):
return False
return True
- if matchSelf and matches(self):
- yield self
- children = self.children_recurse_anon if recurseInAnon else self._children
- for s in children:
+
+ def candidates():
+ s = self
+ if Symbol.debug_lookup:
+ Symbol.debug_print("searching in self:")
+ print(s.to_string(Symbol.debug_indent + 1), end="")
+ while True:
+ if matchSelf:
+ yield s
+ if recurseInAnon:
+ yield from s.children_recurse_anon
+ else:
+ yield from s._children
+
+ if s.siblingAbove is None:
+ break
+ s = s.siblingAbove
+ if Symbol.debug_lookup:
+ Symbol.debug_print("searching in sibling:")
+ print(s.to_string(Symbol.debug_indent + 1), end="")
+
+ for s in candidates():
+ if Symbol.debug_lookup:
+ Symbol.debug_print("candidate:")
+ print(s.to_string(Symbol.debug_indent + 1), end="")
if matches(s):
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("matches")
+ Symbol.debug_indent -= 3
yield s
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 2
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
def _symbol_lookup(self, nestedName: ASTNestedName, templateDecls: List[Any],
onMissingQualifiedSymbol: Callable[["Symbol", Union[ASTIdentifier, ASTOperator], Any, ASTTemplateArgs], "Symbol"], # NOQA
strictTemplateParamArgLists: bool, ancestorLookupType: str,
templateShorthand: bool, matchSelf: bool,
- recurseInAnon: bool, correctPrimaryTemplateArgs: bool
- ) -> SymbolLookupResult:
+ recurseInAnon: bool, correctPrimaryTemplateArgs: bool,
+ searchInSiblings: bool) -> SymbolLookupResult:
# ancestorLookupType: if not None, specifies the target type of the lookup
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("_symbol_lookup:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("self:")
+ print(self.to_string(Symbol.debug_indent + 1), end="")
+ Symbol.debug_print("nestedName: ", nestedName)
+ Symbol.debug_print("templateDecls: ", templateDecls)
+ Symbol.debug_print("strictTemplateParamArgLists:", strictTemplateParamArgLists)
+ Symbol.debug_print("ancestorLookupType:", ancestorLookupType)
+ Symbol.debug_print("templateShorthand: ", templateShorthand)
+ Symbol.debug_print("matchSelf: ", matchSelf)
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
+ Symbol.debug_print("correctPrimaryTemplateArgs: ", correctPrimaryTemplateArgs)
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
if strictTemplateParamArgLists:
# Each template argument list must have a template parameter list.
@@ -3796,7 +3992,8 @@ class Symbol:
while parentSymbol.parent:
if parentSymbol.find_identifier(firstName.identOrOp,
matchSelf=matchSelf,
- recurseInAnon=recurseInAnon):
+ recurseInAnon=recurseInAnon,
+ searchInSiblings=searchInSiblings):
# if we are in the scope of a constructor but wants to
# reference the class we need to walk one extra up
if (len(names) == 1 and ancestorLookupType == 'class' and matchSelf and
@@ -3807,6 +4004,10 @@ class Symbol:
break
parentSymbol = parentSymbol.parent
+ if Symbol.debug_lookup:
+ Symbol.debug_print("starting point:")
+ print(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
+
# and now the actual lookup
iTemplateDecl = 0
for name in names[:-1]:
@@ -3840,6 +4041,8 @@ class Symbol:
symbol = onMissingQualifiedSymbol(parentSymbol, identOrOp,
templateParams, templateArgs)
if symbol is None:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
return None
# We have now matched part of a nested name, and need to match more
# so even if we should matchSelf before, we definitely shouldn't
@@ -3847,6 +4050,10 @@ class Symbol:
matchSelf = False
parentSymbol = symbol
+ if Symbol.debug_lookup:
+ Symbol.debug_print("handle last name from:")
+ print(parentSymbol.to_string(Symbol.debug_indent + 1), end="")
+
# handle the last name
name = names[-1]
identOrOp = name.identOrOp
@@ -3861,7 +4068,11 @@ class Symbol:
symbols = parentSymbol._find_named_symbols(
identOrOp, templateParams, templateArgs,
templateShorthand=templateShorthand, matchSelf=matchSelf,
- recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False)
+ recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False,
+ searchInSiblings=searchInSiblings)
+ if Symbol.debug_lookup:
+ symbols = list(symbols) # type: ignore
+ Symbol.debug_indent -= 2
return SymbolLookupResult(symbols, parentSymbol,
identOrOp, templateParams, templateArgs)
@@ -3871,21 +4082,26 @@ class Symbol:
# be an actual declaration.
if Symbol.debug_lookup:
- print("_add_symbols:")
- print(" tdecls:", templateDecls)
- print(" nn: ", nestedName)
- print(" decl: ", declaration)
- print(" doc: ", docname)
+ Symbol.debug_indent += 1
+ Symbol.debug_print("_add_symbols:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("tdecls:", templateDecls)
+ Symbol.debug_print("nn: ", nestedName)
+ Symbol.debug_print("decl: ", declaration)
+ Symbol.debug_print("doc: ", docname)
def onMissingQualifiedSymbol(parentSymbol: "Symbol",
identOrOp: Union[ASTIdentifier, ASTOperator],
templateParams: Any, templateArgs: ASTTemplateArgs
) -> "Symbol":
if Symbol.debug_lookup:
- print(" _add_symbols, onMissingQualifiedSymbol:")
- print(" templateParams:", templateParams)
- print(" identOrOp: ", identOrOp)
- print(" templateARgs: ", templateArgs)
+ Symbol.debug_indent += 1
+ Symbol.debug_print("_add_symbols, onMissingQualifiedSymbol:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("templateParams:", templateParams)
+ Symbol.debug_print("identOrOp: ", identOrOp)
+ Symbol.debug_print("templateARgs: ", templateArgs)
+ Symbol.debug_indent -= 2
return Symbol(parent=parentSymbol, identOrOp=identOrOp,
templateParams=templateParams,
templateArgs=templateArgs, declaration=None,
@@ -3898,32 +4114,40 @@ class Symbol:
templateShorthand=False,
matchSelf=False,
recurseInAnon=True,
- correctPrimaryTemplateArgs=True)
+ correctPrimaryTemplateArgs=True,
+ searchInSiblings=False)
assert lookupResult is not None # we create symbols all the way, so that can't happen
symbols = list(lookupResult.symbols)
if len(symbols) == 0:
if Symbol.debug_lookup:
- print(" _add_symbols, result, no symbol:")
- print(" templateParams:", lookupResult.templateParams)
- print(" identOrOp: ", lookupResult.identOrOp)
- print(" templateArgs: ", lookupResult.templateArgs)
- print(" declaration: ", declaration)
- print(" docname: ", docname)
+ Symbol.debug_print("_add_symbols, result, no symbol:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("templateParams:", lookupResult.templateParams)
+ Symbol.debug_print("identOrOp: ", lookupResult.identOrOp)
+ Symbol.debug_print("templateArgs: ", lookupResult.templateArgs)
+ Symbol.debug_print("declaration: ", declaration)
+ Symbol.debug_print("docname: ", docname)
+ Symbol.debug_indent -= 1
symbol = Symbol(parent=lookupResult.parentSymbol,
identOrOp=lookupResult.identOrOp,
templateParams=lookupResult.templateParams,
templateArgs=lookupResult.templateArgs,
declaration=declaration,
docname=docname)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
return symbol
if Symbol.debug_lookup:
- print(" _add_symbols, result, symbols:")
- print(" number symbols:", len(symbols))
+ Symbol.debug_print("_add_symbols, result, symbols:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("number symbols:", len(symbols))
+ Symbol.debug_indent -= 1
if not declaration:
if Symbol.debug_lookup:
- print(" no delcaration")
+ Symbol.debug_print("no delcaration")
+ Symbol.debug_indent -= 2
# good, just a scope creation
# TODO: what if we have more than one symbol?
return symbols[0]
@@ -3939,9 +4163,9 @@ class Symbol:
else:
withDecl.append(s)
if Symbol.debug_lookup:
- print(" #noDecl: ", len(noDecl))
- print(" #withDecl:", len(withDecl))
- print(" #dupDecl: ", len(dupDecl))
+ Symbol.debug_print("#noDecl: ", len(noDecl))
+ Symbol.debug_print("#withDecl:", len(withDecl))
+ Symbol.debug_print("#dupDecl: ", len(dupDecl))
# With partial builds we may start with a large symbol tree stripped of declarations.
# Essentially any combination of noDecl, withDecl, and dupDecls seems possible.
# TODO: make partial builds fully work. What should happen when the primary symbol gets
@@ -3952,7 +4176,7 @@ class Symbol:
# otherwise there should be only one symbol with a declaration.
def makeCandSymbol():
if Symbol.debug_lookup:
- print(" begin: creating candidate symbol")
+ Symbol.debug_print("begin: creating candidate symbol")
symbol = Symbol(parent=lookupResult.parentSymbol,
identOrOp=lookupResult.identOrOp,
templateParams=lookupResult.templateParams,
@@ -3960,7 +4184,7 @@ class Symbol:
declaration=declaration,
docname=docname)
if Symbol.debug_lookup:
- print(" end: creating candidate symbol")
+ Symbol.debug_print("end: creating candidate symbol")
return symbol
if len(withDecl) == 0:
candSymbol = None
@@ -3969,7 +4193,10 @@ class Symbol:
def handleDuplicateDeclaration(symbol, candSymbol):
if Symbol.debug_lookup:
- print(" redeclaration")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("redeclaration")
+ Symbol.debug_indent -= 1
+ Symbol.debug_indent -= 2
# Redeclaration of the same symbol.
# Let the new one be there, but raise an error to the client
# so it can use the real symbol as subscope.
@@ -3985,11 +4212,11 @@ class Symbol:
# a function, so compare IDs
candId = declaration.get_newest_id()
if Symbol.debug_lookup:
- print(" candId:", candId)
+ Symbol.debug_print("candId:", candId)
for symbol in withDecl:
oldId = symbol.declaration.get_newest_id()
if Symbol.debug_lookup:
- print(" oldId: ", oldId)
+ Symbol.debug_print("oldId: ", oldId)
if candId == oldId:
handleDuplicateDeclaration(symbol, candSymbol)
# (not reachable)
@@ -3997,14 +4224,16 @@ class Symbol:
# if there is an empty symbol, fill that one
if len(noDecl) == 0:
if Symbol.debug_lookup:
- print(" no match, no empty, candSybmol is not None?:", candSymbol is not None) # NOQA
+ Symbol.debug_print("no match, no empty, candSybmol is not None?:", candSymbol is not None) # NOQA
+ Symbol.debug_indent -= 2
if candSymbol is not None:
return candSymbol
else:
return makeCandSymbol()
else:
if Symbol.debug_lookup:
- print(" no match, but fill an empty declaration, candSybmol is not None?:", candSymbol is not None) # NOQA
+ Symbol.debug_print("no match, but fill an empty declaration, candSybmol is not None?:", candSymbol is not None) # NOQA
+ Symbol.debug_indent -= 2
if candSymbol is not None:
candSymbol.remove()
# assert len(noDecl) == 1
@@ -4021,6 +4250,9 @@ class Symbol:
def merge_with(self, other: "Symbol", docnames: List[str],
env: "BuildEnvironment") -> None:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("merge_with:")
assert other is not None
for otherChild in other._children:
ourChild = self._find_first_named_symbol(
@@ -4050,17 +4282,28 @@ class Symbol:
# just ignore it, right?
pass
ourChild.merge_with(otherChild, docnames, env)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 1
def add_name(self, nestedName: ASTNestedName,
templatePrefix: ASTTemplateDeclarationPrefix = None) -> "Symbol":
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("add_name:")
if templatePrefix:
templateDecls = templatePrefix.templates
else:
templateDecls = []
- return self._add_symbols(nestedName, templateDecls,
- declaration=None, docname=None)
+ res = self._add_symbols(nestedName, templateDecls,
+ declaration=None, docname=None)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 1
+ return res
def add_declaration(self, declaration: ASTDeclaration, docname: str) -> "Symbol":
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("add_declaration:")
assert declaration
assert docname
nestedName = declaration.name
@@ -4068,37 +4311,105 @@ class Symbol:
templateDecls = declaration.templatePrefix.templates
else:
templateDecls = []
- return self._add_symbols(nestedName, templateDecls, declaration, docname)
+ res = self._add_symbols(nestedName, templateDecls, declaration, docname)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 1
+ return res
def find_identifier(self, identOrOp: Union[ASTIdentifier, ASTOperator],
- matchSelf: bool, recurseInAnon: bool) -> "Symbol":
- if matchSelf and self.identOrOp == identOrOp:
- return self
- children = self.children_recurse_anon if recurseInAnon else self._children
- for s in children:
- if s.identOrOp == identOrOp:
- return s
+ matchSelf: bool, recurseInAnon: bool, searchInSiblings: bool
+ ) -> "Symbol":
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("find_identifier:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("identOrOp: ", identOrOp)
+ Symbol.debug_print("matchSelf: ", matchSelf)
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
+ Symbol.debug_print("searchInSiblings:", searchInSiblings)
+ print(self.to_string(Symbol.debug_indent + 1), end="")
+ Symbol.debug_indent -= 2
+ current = self
+ while current is not None:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 2
+ Symbol.debug_print("trying:")
+ print(current.to_string(Symbol.debug_indent + 1), end="")
+ Symbol.debug_indent -= 2
+ if matchSelf and current.identOrOp == identOrOp:
+ return current
+ children = current.children_recurse_anon if recurseInAnon else current._children
+ for s in children:
+ if s.identOrOp == identOrOp:
+ return s
+ if not searchInSiblings:
+ break
+ current = current.siblingAbove
return None
- def direct_lookup(self, key: List[Tuple[ASTNestedNameElement, Any]]) -> "Symbol":
+ def direct_lookup(self, key: "LookupKey") -> "Symbol":
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("direct_lookup:")
+ Symbol.debug_indent += 1
s = self
- for name, templateParams in key:
- identOrOp = name.identOrOp
- templateArgs = name.templateArgs
- s = s._find_first_named_symbol(identOrOp,
- templateParams, templateArgs,
- templateShorthand=False,
- matchSelf=False,
- recurseInAnon=False,
- correctPrimaryTemplateArgs=False)
- if not s:
+ for name, templateParams, id_ in key.data:
+ if id_ is not None:
+ res = None
+ for cand in s._children:
+ if cand.declaration is None:
+ continue
+ if cand.declaration.get_newest_id() == id_:
+ res = cand
+ break
+ s = res
+ else:
+ identOrOp = name.identOrOp
+ templateArgs = name.templateArgs
+ s = s._find_first_named_symbol(identOrOp,
+ templateParams, templateArgs,
+ templateShorthand=False,
+ matchSelf=False,
+ recurseInAnon=False,
+ correctPrimaryTemplateArgs=False)
+ if Symbol.debug_lookup:
+ Symbol.debug_print("name: ", name)
+ Symbol.debug_print("templateParams:", templateParams)
+ Symbol.debug_print("id: ", id_)
+ if s is not None:
+ print(s.to_string(Symbol.debug_indent + 1), end="")
+ else:
+ Symbol.debug_print("not found")
+ if s is None:
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
return None
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
return s
def find_name(self, nestedName: ASTNestedName, templateDecls: List[Any],
typ: str, templateShorthand: bool, matchSelf: bool,
- recurseInAnon: bool) -> List["Symbol"]:
+ recurseInAnon: bool, searchInSiblings: bool) -> Tuple[List["Symbol"], str]:
# templateShorthand: missing template parameter lists for templates is ok
+ # If the first component is None,
+ # then the second component _may_ be a string explaining why.
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("find_name:")
+ Symbol.debug_indent += 1
+ Symbol.debug_print("self:")
+ print(self.to_string(Symbol.debug_indent + 1), end="")
+ Symbol.debug_print("nestedName: ", nestedName)
+ Symbol.debug_print("templateDecls: ", templateDecls)
+ Symbol.debug_print("typ: ", typ)
+ Symbol.debug_print("templateShorthand:", templateShorthand)
+ Symbol.debug_print("matchSelf: ", matchSelf)
+ Symbol.debug_print("recurseInAnon: ", recurseInAnon)
+ Symbol.debug_print("searchInSiblings: ", searchInSiblings)
+
+ class QualifiedSymbolIsTemplateParam(Exception):
+ pass
def onMissingQualifiedSymbol(parentSymbol: "Symbol",
identOrOp: Union[ASTIdentifier, ASTOperator],
@@ -4108,37 +4419,58 @@ class Symbol:
# Though, the correctPrimaryTemplateArgs does
# that for primary templates.
# Is there another case where it would be good?
+ if parentSymbol.declaration is not None:
+ if parentSymbol.declaration.objectType == 'templateParam':
+ raise QualifiedSymbolIsTemplateParam()
return None
- lookupResult = self._symbol_lookup(nestedName, templateDecls,
- onMissingQualifiedSymbol,
- strictTemplateParamArgLists=False,
- ancestorLookupType=typ,
- templateShorthand=templateShorthand,
- matchSelf=matchSelf,
- recurseInAnon=recurseInAnon,
- correctPrimaryTemplateArgs=False)
+ try:
+ lookupResult = self._symbol_lookup(nestedName, templateDecls,
+ onMissingQualifiedSymbol,
+ strictTemplateParamArgLists=False,
+ ancestorLookupType=typ,
+ templateShorthand=templateShorthand,
+ matchSelf=matchSelf,
+ recurseInAnon=recurseInAnon,
+ correctPrimaryTemplateArgs=False,
+ searchInSiblings=searchInSiblings)
+ except QualifiedSymbolIsTemplateParam:
+ return None, "templateParamInQualified"
+
if lookupResult is None:
# if it was a part of the qualification that could not be found
- return None
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
+ return None, None
res = list(lookupResult.symbols)
if len(res) != 0:
- return res
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
+ return res, None
+
+ if lookupResult.parentSymbol.declaration is not None:
+ if lookupResult.parentSymbol.declaration.objectType == 'templateParam':
+ return None, "templateParamInQualified"
# try without template params and args
symbol = lookupResult.parentSymbol._find_first_named_symbol(
lookupResult.identOrOp, None, None,
templateShorthand=templateShorthand, matchSelf=matchSelf,
recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 2
if symbol is not None:
- return [symbol]
+ return [symbol], None
else:
- return None
+ return None, None
def find_declaration(self, declaration: ASTDeclaration, typ: str, templateShorthand: bool,
matchSelf: bool, recurseInAnon: bool) -> "Symbol":
# templateShorthand: missing template parameter lists for templates is ok
+ if Symbol.debug_lookup:
+ Symbol.debug_indent += 1
+ Symbol.debug_print("find_declaration:")
nestedName = declaration.name
if declaration.templatePrefix:
templateDecls = declaration.templatePrefix.templates
@@ -4158,8 +4490,10 @@ class Symbol:
templateShorthand=templateShorthand,
matchSelf=matchSelf,
recurseInAnon=recurseInAnon,
- correctPrimaryTemplateArgs=False)
-
+ correctPrimaryTemplateArgs=False,
+ searchInSiblings=False)
+ if Symbol.debug_lookup:
+ Symbol.debug_indent -= 1
if lookupResult is None:
return None
@@ -4185,14 +4519,14 @@ class Symbol:
return None
def to_string(self, indent: int) -> str:
- res = ['\t' * indent]
+ res = [Symbol.debug_indent_string * indent]
if not self.parent:
res.append('::')
else:
if self.templateParams:
res.append(str(self.templateParams))
res.append('\n')
- res.append('\t' * indent)
+ res.append(Symbol.debug_indent_string * indent)
if self.identOrOp:
res.append(str(self.identOrOp))
else:
@@ -4218,7 +4552,7 @@ class Symbol:
return ''.join(res)
-class DefinitionParser:
+class DefinitionParser(BaseParser):
# those without signedness and size modifiers
# see https://en.cppreference.com/w/cpp/language/types
_simple_fundemental_types = (
@@ -4228,130 +4562,13 @@ class DefinitionParser:
_prefix_keys = ('class', 'struct', 'enum', 'union', 'typename')
- def __init__(self, definition: Any, warnEnv: Any, config: "Config") -> None:
- self.definition = definition.strip()
- self.pos = 0
- self.end = len(self.definition)
- self.last_match = None # type: Match
- self._previous_state = (0, None) # type: Tuple[int, Match]
- self.otherErrors = [] # type: List[DefinitionError]
- # in our tests the following is set to False to capture bad parsing
- self.allowFallbackExpressionParsing = True
-
- self.warnEnv = warnEnv
+ def __init__(self, definition: str, *,
+ location: Union[nodes.Node, Tuple[str, int]],
+ config: "Config") -> None:
+ super().__init__(definition, location=location)
self.config = config
- def _make_multi_error(self, errors: List[Any], header: str) -> DefinitionError:
- if len(errors) == 1:
- if len(header) > 0:
- return DefinitionError(header + '\n' + str(errors[0][0]))
- else:
- return DefinitionError(str(errors[0][0]))
- result = [header, '\n']
- for e in errors:
- if len(e[1]) > 0:
- ident = ' '
- result.append(e[1])
- result.append(':\n')
- for line in str(e[0]).split('\n'):
- if len(line) == 0:
- continue
- result.append(ident)
- result.append(line)
- result.append('\n')
- else:
- result.append(str(e[0]))
- return DefinitionError(''.join(result))
-
- def status(self, msg: str) -> None:
- # for debugging
- indicator = '-' * self.pos + '^'
- print("%s\n%s\n%s" % (msg, self.definition, indicator))
-
- def fail(self, msg: str) -> None:
- errors = []
- indicator = '-' * self.pos + '^'
- exMain = DefinitionError(
- 'Invalid definition: %s [error at %d]\n %s\n %s' %
- (msg, self.pos, self.definition, indicator))
- errors.append((exMain, "Main error"))
- for err in self.otherErrors:
- errors.append((err, "Potential other error"))
- self.otherErrors = []
- raise self._make_multi_error(errors, '')
-
- def warn(self, msg: str) -> None:
- if self.warnEnv:
- self.warnEnv.warn(msg)
- else:
- print("Warning: %s" % msg)
-
- def match(self, regex: Pattern) -> bool:
- match = regex.match(self.definition, self.pos)
- if match is not None:
- self._previous_state = (self.pos, self.last_match)
- self.pos = match.end()
- self.last_match = match
- return True
- return False
-
- def backout(self) -> None:
- self.pos, self.last_match = self._previous_state
-
- def skip_string(self, string: str) -> bool:
- strlen = len(string)
- if self.definition[self.pos:self.pos + strlen] == string:
- self.pos += strlen
- return True
- return False
-
- def skip_word(self, word: str) -> bool:
- return self.match(re.compile(r'\b%s\b' % re.escape(word)))
-
- def skip_ws(self) -> bool:
- return self.match(_whitespace_re)
-
- def skip_word_and_ws(self, word: str) -> bool:
- if self.skip_word(word):
- self.skip_ws()
- return True
- return False
-
- def skip_string_and_ws(self, string: str) -> bool:
- if self.skip_string(string):
- self.skip_ws()
- return True
- return False
-
- @property
- def eof(self) -> bool:
- return self.pos >= self.end
-
- @property
- def current_char(self) -> str:
- try:
- return self.definition[self.pos]
- except IndexError:
- return 'EOF'
-
- @property
- def matched_text(self) -> str:
- if self.last_match is not None:
- return self.last_match.group()
- else:
- return None
-
- def read_rest(self) -> str:
- rv = self.definition[self.pos:]
- self.pos = self.end
- return rv
-
- def assert_end(self) -> None:
- self.skip_ws()
- if not self.eof:
- self.fail('Expected end of definition.')
-
- def _parse_string(self):
+ def _parse_string(self) -> str:
if self.current_char != '"':
return None
startPos = self.pos
@@ -4390,7 +4607,7 @@ class DefinitionParser:
% startPos)
return self.definition[startPos:self.pos]
- def _parse_attribute(self) -> Any:
+ def _parse_attribute(self) -> ASTAttribute:
self.skip_ws()
# try C++11 style
startPos = self.pos
@@ -4414,7 +4631,7 @@ class DefinitionParser:
self.fail("Expected '(' after '__attribute__('.")
attrs = []
while 1:
- if self.match(_identifier_re):
+ if self.match(identifier_re):
name = self.matched_text
self.skip_ws()
if self.skip_string_and_ws('('):
@@ -4449,7 +4666,7 @@ class DefinitionParser:
return None
- def _parse_literal(self):
+ def _parse_literal(self) -> ASTLiteral:
# -> integer-literal
# | character-literal
# | floating-literal
@@ -4464,8 +4681,8 @@ class DefinitionParser:
return ASTBooleanLiteral(True)
if self.skip_word('false'):
return ASTBooleanLiteral(False)
- for regex in [_float_literal_re, _binary_literal_re, _hex_literal_re,
- _integer_literal_re, _octal_literal_re]:
+ for regex in [float_literal_re, binary_literal_re, hex_literal_re,
+ integer_literal_re, octal_literal_re]:
pos = self.pos
if self.match(regex):
while self.current_char in 'uUlLfF':
@@ -4477,7 +4694,7 @@ class DefinitionParser:
return ASTStringLiteral(string)
# character-literal
- if self.match(_char_literal_re):
+ if self.match(char_literal_re):
prefix = self.last_match.group(1) # may be None when no prefix
data = self.last_match.group(2)
try:
@@ -4491,7 +4708,7 @@ class DefinitionParser:
# TODO: user-defined lit
return None
- def _parse_fold_or_paren_expression(self):
+ def _parse_fold_or_paren_expression(self) -> ASTExpression:
# "(" expression ")"
# fold-expression
# -> ( cast-expression fold-operator ... )
@@ -4550,7 +4767,7 @@ class DefinitionParser:
self.fail("Expected ')' to end binary fold expression.")
return ASTFoldExpr(leftExpr, op, rightExpr)
- def _parse_primary_expression(self):
+ def _parse_primary_expression(self) -> ASTExpression:
# literal
# "this"
# lambda-expression
@@ -4558,7 +4775,7 @@ class DefinitionParser:
# fold-expression
# id-expression -> we parse this with _parse_nested_name
self.skip_ws()
- res = self._parse_literal()
+ res = self._parse_literal() # type: ASTExpression
if res is not None:
return res
self.skip_ws()
@@ -4568,10 +4785,13 @@ class DefinitionParser:
res = self._parse_fold_or_paren_expression()
if res is not None:
return res
- return self._parse_nested_name()
+ nn = self._parse_nested_name()
+ if nn is not None:
+ return ASTIdExpression(nn)
+ return None
def _parse_initializer_list(self, name: str, open: str, close: str
- ) -> Tuple[List[Any], bool]:
+ ) -> Tuple[List[ASTExpression], bool]:
# Parse open and close with the actual initializer-list inbetween
# -> initializer-clause '...'[opt]
# | initializer-list ',' initializer-clause '...'[opt]
@@ -4581,7 +4801,7 @@ class DefinitionParser:
if self.skip_string(close):
return [], False
- exprs = []
+ exprs = [] # type: List[ASTExpression]
trailingComma = False
while True:
self.skip_ws()
@@ -4631,7 +4851,7 @@ class DefinitionParser:
return paren
return self._parse_braced_init_list()
- def _parse_postfix_expression(self):
+ def _parse_postfix_expression(self) -> ASTPostfixExpr:
# -> primary
# | postfix "[" expression "]"
# | postfix "[" braced-init-list [opt] "]"
@@ -4737,7 +4957,7 @@ class DefinitionParser:
raise self._make_multi_error(errors, header)
# and now parse postfixes
- postFixes = [] # type: List[Any]
+ postFixes = [] # type: List[ASTPostfixOp]
while True:
self.skip_ws()
if prefixType in ['expr', 'cast', 'typeid']:
@@ -4778,12 +4998,9 @@ class DefinitionParser:
postFixes.append(ASTPostfixCallExpr(lst))
continue
break
- if len(postFixes) == 0:
- return prefix
- else:
- return ASTPostfixExpr(prefix, postFixes)
+ return ASTPostfixExpr(prefix, postFixes)
- def _parse_unary_expression(self):
+ def _parse_unary_expression(self) -> ASTExpression:
# -> postfix
# | "++" cast
# | "--" cast
@@ -4806,7 +5023,7 @@ class DefinitionParser:
if self.skip_string_and_ws('...'):
if not self.skip_string_and_ws('('):
self.fail("Expecting '(' after 'sizeof...'.")
- if not self.match(_identifier_re):
+ if not self.match(identifier_re):
self.fail("Expecting identifier for 'sizeof...'.")
ident = ASTIdentifier(self.matched_text)
self.skip_ws()
@@ -4874,7 +5091,7 @@ class DefinitionParser:
return ASTDeleteExpr(rooted, array, expr)
return self._parse_postfix_expression()
- def _parse_cast_expression(self):
+ def _parse_cast_expression(self) -> ASTExpression:
# -> unary | "(" type-id ")" cast
pos = self.pos
self.skip_ws()
@@ -4897,7 +5114,7 @@ class DefinitionParser:
else:
return self._parse_unary_expression()
- def _parse_logical_or_expression(self, inTemplate):
+ def _parse_logical_or_expression(self, inTemplate: bool) -> ASTExpression:
# logical-or = logical-and ||
# logical-and = inclusive-or &&
# inclusive-or = exclusive-or |
@@ -4909,12 +5126,13 @@ class DefinitionParser:
# additive = multiplicative +, -
# multiplicative = pm *, /, %
# pm = cast .*, ->*
- def _parse_bin_op_expr(self, opId, inTemplate):
+ def _parse_bin_op_expr(self: DefinitionParser,
+ opId: int, inTemplate: bool) -> ASTExpression:
if opId + 1 == len(_expression_bin_ops):
- def parser(inTemplate):
+ def parser(inTemplate: bool) -> ASTExpression:
return self._parse_cast_expression()
else:
- def parser(inTemplate):
+ def parser(inTemplate: bool) -> ASTExpression:
return _parse_bin_op_expr(self, opId + 1, inTemplate=inTemplate)
exprs = []
ops = []
@@ -4950,7 +5168,7 @@ class DefinitionParser:
# -> "?" expression ":" assignment-expression
return None
- def _parse_assignment_expression(self, inTemplate):
+ def _parse_assignment_expression(self, inTemplate: bool) -> ASTExpression:
# -> conditional-expression
# | logical-or-expression assignment-operator initializer-clause
# | throw-expression
@@ -4982,19 +5200,21 @@ class DefinitionParser:
else:
return ASTAssignmentExpr(exprs, ops)
- def _parse_constant_expression(self, inTemplate):
+ def _parse_constant_expression(self, inTemplate: bool) -> ASTExpression:
# -> conditional-expression
orExpr = self._parse_logical_or_expression(inTemplate=inTemplate)
# TODO: use _parse_conditional_expression_tail
return orExpr
- def _parse_expression(self, inTemplate):
+ def _parse_expression(self, inTemplate: bool) -> ASTExpression:
# -> assignment-expression
# | expression "," assignment-expresion
# TODO: actually parse the second production
return self._parse_assignment_expression(inTemplate=inTemplate)
- def _parse_expression_fallback(self, end, parser, allow=True):
+ def _parse_expression_fallback(self, end: List[str],
+ parser: Callable[[], ASTExpression],
+ allow: bool = True) -> ASTExpression:
# Stupidly "parse" an expression.
# 'end' should be a list of characters which ends the expression.
@@ -5034,10 +5254,12 @@ class DefinitionParser:
value = self.definition[startPos:self.pos].strip()
return ASTFallbackExpr(value.strip())
+ # ==========================================================================
+
def _parse_operator(self) -> ASTOperator:
self.skip_ws()
# adapted from the old code
- # thank god, a regular operator definition
+ # yay, a regular operator definition
if self.match(_operator_re):
return ASTOperatorBuildIn(self.matched_text)
@@ -5056,7 +5278,7 @@ class DefinitionParser:
# user-defined literal?
if self.skip_string('""'):
self.skip_ws()
- if not self.match(_identifier_re):
+ if not self.match(identifier_re):
self.fail("Expected user-defined literal suffix.")
identifier = ASTIdentifier(self.matched_text)
return ASTOperatorLiteral(identifier)
@@ -5073,7 +5295,7 @@ class DefinitionParser:
if self.skip_string('>'):
return ASTTemplateArgs([])
prevErrors = []
- templateArgs = [] # type: List
+ templateArgs = [] # type: List[Union[ASTType, ASTTemplateArgConstant]]
while 1:
pos = self.pos
parsedComma = False
@@ -5092,9 +5314,13 @@ class DefinitionParser:
prevErrors.append((e, "If type argument"))
self.pos = pos
try:
+ # actually here we shouldn't use the fallback parser (hence allow=False),
+ # because if actually took the < in an expression, then we _will_ fail,
+ # which is handled elsewhere. E.g., :cpp:expr:`A <= 0`.
def parser():
return self._parse_constant_expression(inTemplate=True)
- value = self._parse_expression_fallback([',', '>'], parser)
+ value = self._parse_expression_fallback(
+ [',', '>'], parser, allow=False)
self.skip_ws()
if self.skip_string('>'):
parsedEnd = True
@@ -5114,7 +5340,7 @@ class DefinitionParser:
return ASTTemplateArgs(templateArgs)
def _parse_nested_name(self, memberPointer: bool = False) -> ASTNestedName:
- names = [] # type: List[Any]
+ names = [] # type: List[ASTNestedNameElement]
templates = [] # type: List[bool]
self.skip_ws()
@@ -5132,7 +5358,7 @@ class DefinitionParser:
if self.skip_word_and_ws('operator'):
identOrOp = self._parse_operator()
else:
- if not self.match(_identifier_re):
+ if not self.match(identifier_re):
if memberPointer and len(names) > 0:
templates.pop()
break
@@ -5161,7 +5387,9 @@ class DefinitionParser:
break
return ASTNestedName(names, templates, rooted)
- def _parse_trailing_type_spec(self) -> Any:
+ # ==========================================================================
+
+ def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec:
# fundemental types
self.skip_ws()
for t in self._simple_fundemental_types:
@@ -5420,7 +5648,7 @@ class DefinitionParser:
self.pos = pos
declId = None
elif named == 'single':
- if self.match(_identifier_re):
+ if self.match(identifier_re):
identifier = ASTIdentifier(self.matched_text)
nne = ASTNestedNameElement(identifier, None)
declId = ASTNestedName([nne], [False], rooted=False)
@@ -5464,7 +5692,8 @@ class DefinitionParser:
paramQual=paramQual)
def _parse_declarator(self, named: Union[bool, str], paramMode: str,
- typed: bool = True) -> Any:
+ typed: bool = True
+ ) -> ASTDeclarator:
# 'typed' here means 'parse return type stuff'
if paramMode not in ('type', 'function', 'operatorCast', 'new'):
raise Exception(
@@ -5706,7 +5935,9 @@ class DefinitionParser:
decl = self._parse_declarator(named=named, paramMode=paramMode)
return ASTType(declSpecs, decl)
- def _parse_type_with_init(self, named: Union[bool, str], outer: str) -> Any:
+ def _parse_type_with_init(
+ self, named: Union[bool, str],
+ outer: str) -> Union[ASTTypeWithInit, ASTTemplateParamConstrainedTypeWithInit]:
if outer:
assert outer in ('type', 'member', 'function', 'templateParam')
type = self._parse_type(outer=outer, named=named)
@@ -5820,10 +6051,12 @@ class DefinitionParser:
init = ASTInitializer(initVal)
return ASTEnumerator(name, init)
- def _parse_template_parameter_list(self) -> "ASTTemplateParams":
+ # ==========================================================================
+
+ def _parse_template_parameter_list(self) -> ASTTemplateParams:
# only: '<' parameter-list '>'
# we assume that 'template' has just been parsed
- templateParams = [] # type: List
+ templateParams = [] # type: List[ASTTemplateParam]
self.skip_ws()
if not self.skip_string("<"):
self.fail("Expected '<' after 'template'")
@@ -5833,7 +6066,6 @@ class DefinitionParser:
if self.skip_word('template'):
# declare a tenplate template parameter
nestedParams = self._parse_template_parameter_list()
- nestedParams.isNested = True
else:
nestedParams = None
self.skip_ws()
@@ -5850,7 +6082,7 @@ class DefinitionParser:
self.skip_ws()
parameterPack = self.skip_string('...')
self.skip_ws()
- if self.match(_identifier_re):
+ if self.match(identifier_re):
identifier = ASTIdentifier(self.matched_text)
else:
identifier = None
@@ -5863,11 +6095,11 @@ class DefinitionParser:
parameterPack, default)
if nestedParams:
# template type
- param = ASTTemplateParamTemplateType(nestedParams, data) # type: Any
+ templateParams.append(
+ ASTTemplateParamTemplateType(nestedParams, data))
else:
# type
- param = ASTTemplateParamType(data)
- templateParams.append(param)
+ templateParams.append(ASTTemplateParamType(data))
else:
# declare a non-type parameter, or constrained type parameter
pos = self.pos
@@ -5891,7 +6123,7 @@ class DefinitionParser:
prevErrors.append((e, ""))
raise self._make_multi_error(prevErrors, header)
- def _parse_template_introduction(self) -> "ASTTemplateIntroduction":
+ def _parse_template_introduction(self) -> ASTTemplateIntroduction:
pos = self.pos
try:
concept = self._parse_nested_name()
@@ -5909,7 +6141,7 @@ class DefinitionParser:
self.skip_ws()
parameterPack = self.skip_string('...')
self.skip_ws()
- if not self.match(_identifier_re):
+ if not self.match(identifier_re):
self.fail("Expected identifier in template introduction list.")
txt_identifier = self.matched_text
# make sure there isn't a keyword
@@ -5931,14 +6163,15 @@ class DefinitionParser:
def _parse_template_declaration_prefix(self, objectType: str
) -> ASTTemplateDeclarationPrefix:
- templates = [] # type: List[str]
+ templates = [] # type: List[Union[ASTTemplateParams, ASTTemplateIntroduction]]
while 1:
self.skip_ws()
# the saved position is only used to provide a better error message
+ params = None # type: Union[ASTTemplateParams, ASTTemplateIntroduction]
pos = self.pos
if self.skip_word("template"):
try:
- params = self._parse_template_parameter_list() # type: Any
+ params = self._parse_template_parameter_list()
except DefinitionError as e:
if objectType == 'member' and len(templates) == 0:
return ASTTemplateDeclarationPrefix(None)
@@ -5990,7 +6223,7 @@ class DefinitionParser:
msg += str(nestedName)
self.warn(msg)
- newTemplates = []
+ newTemplates = [] # type: List[Union[ASTTemplateParams, ASTTemplateIntroduction]]
for i in range(numExtra):
newTemplates.append(ASTTemplateParams([]))
if templatePrefix and not isMemberInstantiation:
@@ -6067,7 +6300,7 @@ class DefinitionParser:
res.objectType = 'namespace' # type: ignore
return res
- def parse_xref_object(self) -> Tuple[Any, bool]:
+ def parse_xref_object(self) -> Tuple[Union[ASTNamespace, ASTDeclaration], bool]:
pos = self.pos
try:
templatePrefix = self._parse_template_declaration_prefix(objectType="xref")
@@ -6097,25 +6330,26 @@ class DefinitionParser:
msg = "Error in cross-reference."
raise self._make_multi_error(errs, msg)
- def parse_expression(self):
+ def parse_expression(self) -> Union[ASTExpression, ASTType]:
pos = self.pos
try:
expr = self._parse_expression(False)
self.skip_ws()
self.assert_end()
+ return expr
except DefinitionError as exExpr:
self.pos = pos
try:
- expr = self._parse_type(False)
+ typ = self._parse_type(False)
self.skip_ws()
self.assert_end()
+ return typ
except DefinitionError as exType:
header = "Error when parsing (type) expression."
errs = []
errs.append((exExpr, "If expression"))
errs.append((exType, "If type"))
raise self._make_multi_error(errs, header)
- return expr
def _make_phony_error_name() -> ASTNestedName:
@@ -6143,9 +6377,6 @@ class CPPObject(ObjectDescription):
option_spec = dict(ObjectDescription.option_spec)
option_spec['tparam-line-spec'] = directives.flag
- def warn(self, msg: Union[str, Exception]) -> None:
- self.state_machine.reporter.warning(msg, line=self.lineno)
-
def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None:
assert ast.objectType == 'enumerator'
# find the parent, if it exists && is an enum
@@ -6176,7 +6407,8 @@ class CPPObject(ObjectDescription):
return
targetSymbol = parentSymbol.parent
- s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False, recurseInAnon=True)
+ s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False, recurseInAnon=True,
+ searchInSiblings=False)
if s is not None:
# something is already declared with that name
return
@@ -6187,8 +6419,8 @@ class CPPObject(ObjectDescription):
declaration=declClone,
docname=self.env.docname)
- def add_target_and_index(self, ast: ASTDeclaration, sig: str, signode: desc_signature
- ) -> None:
+ def add_target_and_index(self, ast: ASTDeclaration, sig: str,
+ signode: TextElement) -> None:
# general note: name must be lstrip(':')'ed, to remove "::"
ids = []
for i in range(1, _max_id + 1):
@@ -6202,8 +6434,9 @@ class CPPObject(ObjectDescription):
newestId = ids[0]
assert newestId # shouldn't be None
if not re.compile(r'^[a-zA-Z0-9_]*$').match(newestId):
- self.warn('Index id generation for C++ object "%s" failed, please '
- 'report as bug (id=%s).' % (ast, newestId))
+ logger.warning('Index id generation for C++ object "%s" failed, please '
+ 'report as bug (id=%s).', ast, newestId,
+ location=self.get_source_info())
name = ast.symbol.get_full_nested_name().get_display_string().lstrip(':')
# Add index entry, but not if it's a declaration inside a concept
@@ -6231,10 +6464,6 @@ class CPPObject(ObjectDescription):
names = self.env.domaindata['cpp']['names']
if name not in names:
names[name] = ast.symbol.docname
- signode['names'].append(name)
- else:
- # print("[CPP] non-unique name:", name)
- pass
# always add the newest id
assert newestId
signode['ids'].append(newestId)
@@ -6244,7 +6473,6 @@ class CPPObject(ObjectDescription):
continue
if id not in self.state.document.ids:
signode['ids'].append(id)
- signode['first'] = (not self.names) # hmm, what is this about?
self.state.document.note_explicit_target(signode)
@property
@@ -6261,10 +6489,11 @@ class CPPObject(ObjectDescription):
def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration:
return parser.parse_declaration(self.object_type, self.objtype)
- def describe_signature(self, signode: desc_signature, ast: Any, options: Dict) -> None:
+ def describe_signature(self, signode: desc_signature,
+ ast: ASTDeclaration, options: Dict) -> None:
ast.describe_signature(signode, 'lastIsName', self.env, options)
- def run(self):
+ def run(self) -> List[Node]:
env = self.state.document.settings.env # from ObjectDescription.run
if 'cpp:parent_symbol' not in env.temp_data:
root = env.domaindata['cpp']['root_symbol']
@@ -6285,23 +6514,29 @@ class CPPObject(ObjectDescription):
parentSymbol = env.temp_data['cpp:parent_symbol']
parentDecl = parentSymbol.declaration
if parentDecl is not None and parentDecl.objectType == 'function':
- self.warn("C++ declarations inside functions are not supported." +
- " Parent function is " + str(parentSymbol.get_full_nested_name()))
+ logger.warning("C++ declarations inside functions are not supported." +
+ " Parent function is " +
+ str(parentSymbol.get_full_nested_name()),
+ location=self.get_source_info())
name = _make_phony_error_name()
symbol = parentSymbol.add_name(name)
env.temp_data['cpp:last_symbol'] = symbol
return []
+ # When multiple declarations are made in the same directive
+ # they need to know about each other to provide symbol lookup for function parameters.
+ # We use last_symbol to store the latest added declaration in a directive.
+ env.temp_data['cpp:last_symbol'] = None
return super().run()
def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration:
parentSymbol = self.env.temp_data['cpp:parent_symbol']
- parser = DefinitionParser(sig, self, self.env.config)
+ parser = DefinitionParser(sig, location=signode, config=self.env.config)
try:
ast = self.parse_definition(parser)
parser.assert_end()
except DefinitionError as e:
- self.warn(e)
+ logger.warning(e, location=signode)
# It is easier to assume some phony name than handling the error in
# the possibly inner declarations.
name = _make_phony_error_name()
@@ -6311,12 +6546,19 @@ class CPPObject(ObjectDescription):
try:
symbol = parentSymbol.add_declaration(ast, docname=self.env.docname)
+ # append the new declaration to the sibling list
+ assert symbol.siblingAbove is None
+ assert symbol.siblingBelow is None
+ symbol.siblingAbove = self.env.temp_data['cpp:last_symbol']
+ if symbol.siblingAbove is not None:
+ assert symbol.siblingAbove.siblingBelow is None
+ symbol.siblingAbove.siblingBelow = symbol
self.env.temp_data['cpp:last_symbol'] = symbol
except _DuplicateSymbolError as e:
# Assume we are actually in the old symbol,
# instead of the newly created duplicate.
self.env.temp_data['cpp:last_symbol'] = e.symbol
- self.warn("Duplicate declaration, %s" % sig)
+ logger.warning("Duplicate declaration, %s", sig, location=signode)
if ast.objectType == 'enumerator':
self._add_enumerator_to_parent(ast)
@@ -6329,10 +6571,10 @@ class CPPObject(ObjectDescription):
return ast
def before_content(self) -> None:
- lastSymbol = self.env.temp_data['cpp:last_symbol']
+ lastSymbol = self.env.temp_data['cpp:last_symbol'] # type: Symbol
assert lastSymbol
self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol']
- self.oldParentKey = self.env.ref_context['cpp:parent_key']
+ self.oldParentKey = self.env.ref_context['cpp:parent_key'] # type: LookupKey
self.env.temp_data['cpp:parent_symbol'] = lastSymbol
self.env.ref_context['cpp:parent_key'] = lastSymbol.get_lookup_key()
@@ -6361,7 +6603,7 @@ class CPPClassObject(CPPObject):
object_type = 'class'
@property
- def display_object_type(self):
+ def display_object_type(self) -> str:
# the distinction between class and struct is only cosmetic
assert self.objtype in ('class', 'struct')
return self.objtype
@@ -6391,21 +6633,20 @@ class CPPNamespaceObject(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
- def warn(self, msg: Union[str, Exception]) -> None:
- self.state_machine.reporter.warning(msg, line=self.lineno)
-
def run(self) -> List[Node]:
rootSymbol = self.env.domaindata['cpp']['root_symbol']
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
symbol = rootSymbol
stack = [] # type: List[Symbol]
else:
- parser = DefinitionParser(self.arguments[0], self, self.config)
+ parser = DefinitionParser(self.arguments[0],
+ location=self.get_source_info(),
+ config=self.config)
try:
ast = parser.parse_namespace_object()
parser.assert_end()
except DefinitionError as e:
- self.warn(e)
+ logger.warning(e, location=self.get_source_info())
name = _make_phony_error_name()
ast = ASTNamespace(name, None)
symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix)
@@ -6423,18 +6664,17 @@ class CPPNamespacePushObject(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
- def warn(self, msg: Union[str, Exception]) -> None:
- self.state_machine.reporter.warning(msg, line=self.lineno)
-
def run(self) -> List[Node]:
if self.arguments[0].strip() in ('NULL', '0', 'nullptr'):
return []
- parser = DefinitionParser(self.arguments[0], self, self.config)
+ parser = DefinitionParser(self.arguments[0],
+ location=self.get_source_info(),
+ config=self.config)
try:
ast = parser.parse_namespace_object()
parser.assert_end()
except DefinitionError as e:
- self.warn(e)
+ logger.warning(e, location=self.get_source_info())
name = _make_phony_error_name()
ast = ASTNamespace(name, None)
oldParent = self.env.temp_data.get('cpp:parent_symbol', None)
@@ -6456,13 +6696,11 @@ class CPPNamespacePopObject(SphinxDirective):
final_argument_whitespace = True
option_spec = {} # type: Dict
- def warn(self, msg: Union[str, Exception]) -> None:
- self.state_machine.reporter.warning(msg, line=self.lineno)
-
def run(self) -> List[Node]:
stack = self.env.temp_data.get('cpp:namespace_stack', None)
if not stack or len(stack) == 0:
- self.warn("C++ namespace pop on empty stack. Defaulting to gobal scope.")
+ logger.warning("C++ namespace pop on empty stack. Defaulting to gobal scope.",
+ location=self.get_source_info())
stack = []
else:
stack.pop()
@@ -6477,7 +6715,8 @@ class CPPNamespacePopObject(SphinxDirective):
class AliasNode(nodes.Element):
- def __init__(self, sig, env=None, parentKey=None):
+ def __init__(self, sig: str, env: "BuildEnvironment" = None,
+ parentKey: LookupKey = None) -> None:
super().__init__()
self.sig = sig
if env is not None:
@@ -6489,8 +6728,8 @@ class AliasNode(nodes.Element):
assert parentKey is not None
self.parentKey = parentKey
- def copy(self):
- return self.__class__(self.sig, env=None, parentKey=self.parentKey)
+ def copy(self: T) -> T:
+ return self.__class__(self.sig, env=None, parentKey=self.parentKey) # type: ignore
class AliasTransform(SphinxTransform):
@@ -6498,31 +6737,27 @@ class AliasTransform(SphinxTransform):
def apply(self, **kwargs: Any) -> None:
for node in self.document.traverse(AliasNode):
- class Warner:
- def warn(self, msg):
- logger.warning(msg, location=node)
- warner = Warner()
sig = node.sig
parentKey = node.parentKey
try:
- parser = DefinitionParser(sig, warner, self.env.config)
+ parser = DefinitionParser(sig, location=node,
+ config=self.env.config)
ast, isShorthand = parser.parse_xref_object()
parser.assert_end()
except DefinitionError as e:
- warner.warn(e)
+ logger.warning(e, location=node)
ast, isShorthand = None, None
if ast is None:
# could not be parsed, so stop here
signode = addnodes.desc_signature(sig, '')
- signode['first'] = False
signode.clear()
signode += addnodes.desc_name(sig, sig)
node.replace_self(signode)
continue
- rootSymbol = self.env.domains['cpp'].data['root_symbol']
- parentSymbol = rootSymbol.direct_lookup(parentKey)
+ rootSymbol = self.env.domains['cpp'].data['root_symbol'] # type: Symbol
+ parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
if not parentSymbol:
print("Target: ", sig)
print("ParentKey: ", parentKey)
@@ -6531,19 +6766,25 @@ class AliasTransform(SphinxTransform):
symbols = [] # type: List[Symbol]
if isShorthand:
- ns = ast # type: ASTNamespace
+ assert isinstance(ast, ASTNamespace)
+ ns = ast
name = ns.nestedName
if ns.templatePrefix:
templateDecls = ns.templatePrefix.templates
else:
templateDecls = []
- symbols = parentSymbol.find_name(name, templateDecls, 'any',
- templateShorthand=True,
- matchSelf=True, recurseInAnon=True)
+ symbols, failReason = parentSymbol.find_name(
+ nestedName=name,
+ templateDecls=templateDecls,
+ typ='any',
+ templateShorthand=True,
+ matchSelf=True, recurseInAnon=True,
+ searchInSiblings=False)
if symbols is None:
symbols = []
else:
- decl = ast # type: ASTDeclaration
+ assert isinstance(ast, ASTDeclaration)
+ decl = ast
name = decl.name
s = parentSymbol.find_declaration(decl, 'any',
templateShorthand=True,
@@ -6555,7 +6796,6 @@ class AliasTransform(SphinxTransform):
if len(symbols) == 0:
signode = addnodes.desc_signature(sig, '')
- signode['first'] = False
node.append(signode)
signode.clear()
signode += addnodes.desc_name(sig, sig)
@@ -6569,7 +6809,6 @@ class AliasTransform(SphinxTransform):
options['tparam-line-spec'] = False
for s in symbols:
signode = addnodes.desc_signature(sig, '')
- signode['first'] = False
nodes.append(signode)
s.declaration.describe_signature(signode, 'markName', self.env, options)
node.replace_self(nodes)
@@ -6618,7 +6857,7 @@ class CPPXRefRole(XRefRole):
if not has_explicit_title:
# major hax: replace anon names via simple string manipulation.
# Can this actually fail?
- title = _anon_identifier_re.sub("[anonymous]", str(title))
+ title = anon_identifier_re.sub("[anonymous]", str(title))
if refnode['reftype'] == 'any':
# Assume the removal part of fix_parens for :any: refs.
@@ -6640,8 +6879,9 @@ class CPPXRefRole(XRefRole):
return title, target
-class CPPExprRole:
- def __init__(self, asCode):
+class CPPExprRole(SphinxRole):
+ def __init__(self, asCode: bool) -> None:
+ super().__init__()
if asCode:
# render the expression as inline code
self.class_type = 'cpp-expr'
@@ -6651,28 +6891,27 @@ class CPPExprRole:
self.class_type = 'cpp-texpr'
self.node_type = nodes.inline
- def __call__(self, typ, rawtext, text, lineno, inliner, options={}, content=[]):
- class Warner:
- def warn(self, msg):
- inliner.reporter.warning(msg, line=lineno)
- text = utils.unescape(text).replace('\n', ' ')
- env = inliner.document.settings.env
- parser = DefinitionParser(text, Warner(), env.config)
+ def run(self) -> Tuple[List[Node], List[system_message]]:
+ text = self.text.replace('\n', ' ')
+ parser = DefinitionParser(text,
+ location=self.get_source_info(),
+ config=self.config)
# attempt to mimic XRefRole classes, except that...
classes = ['xref', 'cpp', self.class_type]
try:
ast = parser.parse_expression()
except DefinitionError as ex:
- Warner().warn('Unparseable C++ expression: %r\n%s' % (text, ex))
+ logger.warning('Unparseable C++ expression: %r\n%s', text, ex,
+ location=self.get_source_info())
# see below
return [self.node_type(text, text, classes=classes)], []
- parentSymbol = env.temp_data.get('cpp:parent_symbol', None)
+ parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None)
if parentSymbol is None:
- parentSymbol = env.domaindata['cpp']['root_symbol']
+ parentSymbol = self.env.domaindata['cpp']['root_symbol']
# ...most if not all of these classes should really apply to the individual references,
# not the container node
signode = self.node_type(classes=classes)
- ast.describe_signature(signode, 'markType', env, parentSymbol)
+ ast.describe_signature(signode, 'markType', self.env, parentSymbol)
return [signode], []
@@ -6796,25 +7035,24 @@ class CPPDomain(Domain):
ourNames[name] = docname
def _resolve_xref_inner(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
- typ: str, target: str, node: pending_xref, contnode: Element,
- emitWarnings: bool = True) -> Tuple[Element, str]:
- class Warner:
- def warn(self, msg):
- if emitWarnings:
- logger.warning(msg, location=node)
- warner = Warner()
+ typ: str, target: str, node: pending_xref,
+ contnode: Element) -> Tuple[Element, str]:
# add parens again for those that could be functions
if typ == 'any' or typ == 'func':
target += '()'
- parser = DefinitionParser(target, warner, env.config)
+ parser = DefinitionParser(target, location=node,
+ config=env.config)
try:
ast, isShorthand = parser.parse_xref_object()
except DefinitionError as e:
- def findWarning(e): # as arg to stop flake8 from complaining
+ # as arg to stop flake8 from complaining
+ def findWarning(e: Exception) -> Tuple[str, Exception]:
if typ != 'any' and typ != 'func':
return target, e
# hax on top of the paren hax to try to get correct errors
- parser2 = DefinitionParser(target[:-2], warner, env.config)
+ parser2 = DefinitionParser(target[:-2],
+ location=node,
+ config=env.config)
try:
parser2.parse_xref_object()
except DefinitionError as e2:
@@ -6822,34 +7060,49 @@ class CPPDomain(Domain):
# strange, that we don't get the error now, use the original
return target, e
t, ex = findWarning(e)
- warner.warn('Unparseable C++ cross-reference: %r\n%s' % (t, ex))
+ logger.warning('Unparseable C++ cross-reference: %r\n%s', t, ex,
+ location=node)
return None, None
- parentKey = node.get("cpp:parent_key", None)
+ parentKey = node.get("cpp:parent_key", None) # type: LookupKey
rootSymbol = self.data['root_symbol']
if parentKey:
- parentSymbol = rootSymbol.direct_lookup(parentKey)
+ parentSymbol = rootSymbol.direct_lookup(parentKey) # type: Symbol
if not parentSymbol:
print("Target: ", target)
- print("ParentKey: ", parentKey)
+ print("ParentKey: ", parentKey.data)
print(rootSymbol.dump(1))
assert parentSymbol # should be there
else:
parentSymbol = rootSymbol
if isShorthand:
- ns = ast # type: ASTNamespace
+ assert isinstance(ast, ASTNamespace)
+ ns = ast
name = ns.nestedName
if ns.templatePrefix:
templateDecls = ns.templatePrefix.templates
else:
templateDecls = []
- symbols = parentSymbol.find_name(name, templateDecls, typ,
- templateShorthand=True,
- matchSelf=True, recurseInAnon=True)
- # just refer to the arbitrarily first symbol
- s = None if symbols is None else symbols[0]
+ # let's be conservative with the sibling lookup for now
+ searchInSiblings = (not name.rooted) and len(name.names) == 1
+ symbols, failReason = parentSymbol.find_name(
+ name, templateDecls, typ,
+ templateShorthand=True,
+ matchSelf=True, recurseInAnon=True,
+ searchInSiblings=searchInSiblings)
+ if symbols is None:
+ if typ == 'identifier':
+ if failReason == 'templateParamInQualified':
+ # this is an xref we created as part of a signature,
+ # so don't warn for names nested in template parameters
+ raise NoUri(str(name), typ)
+ s = None
+ else:
+ # just refer to the arbitrarily first symbol
+ s = symbols[0]
else:
- decl = ast # type: ASTDeclaration
+ assert isinstance(ast, ASTDeclaration)
+ decl = ast
name = decl.name
s = parentSymbol.find_declaration(decl, typ,
templateShorthand=True,
@@ -6869,7 +7122,7 @@ class CPPDomain(Domain):
typ = 'class'
declTyp = s.declaration.objectType
- def checkType():
+ def checkType() -> bool:
if typ == 'any' or typ == 'identifier':
return True
if declTyp == 'templateParam':
@@ -6884,9 +7137,10 @@ class CPPDomain(Domain):
print("Type is %s (originally: %s), declType is %s" % (typ, origTyp, declTyp))
assert False
if not checkType():
- warner.warn("cpp:%s targets a %s (%s)."
- % (origTyp, s.declaration.objectType,
- s.get_full_nested_name()))
+ logger.warning("cpp:%s targets a %s (%s).",
+ origTyp, s.declaration.objectType,
+ s.get_full_nested_name(),
+ location=node)
declaration = s.declaration
if isShorthand:
@@ -6949,9 +7203,9 @@ class CPPDomain(Domain):
def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder,
target: str, node: pending_xref, contnode: Element
) -> List[Tuple[str, Element]]:
- retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder,
- 'any', target, node, contnode,
- emitWarnings=False)
+ with logging.suppress_logging():
+ retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder,
+ 'any', target, node, contnode)
if retnode:
if objtype == 'templateParam':
return [('cpp:templateParam', retnode)]
@@ -6977,8 +7231,8 @@ class CPPDomain(Domain):
target = node.get('reftarget', None)
if target is None:
return None
- parentKey = node.get("cpp:parent_key", None)
- if parentKey is None or len(parentKey) <= 0:
+ parentKey = node.get("cpp:parent_key", None) # type: LookupKey
+ if parentKey is None or len(parentKey.data) <= 0:
return None
rootSymbol = self.data['root_symbol']
@@ -6996,7 +7250,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
return {
'version': 'builtin',
- 'env_version': 1,
+ 'env_version': 2,
'parallel_read_safe': True,
'parallel_write_safe': True,
}