From 51a38d5f98be4c53a6b13faef2187ef2c60e1a81 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+aa-turner@users.noreply.github.com> Date: Mon, 30 Dec 2024 02:40:27 +0000 Subject: [PATCH] Enable automatic formatting for ``sphinx/domains/cpp/`` --- .ruff.toml | 5 - sphinx/domains/cpp/__init__.py | 764 +++++++++++++--------- sphinx/domains/cpp/_ast.py | 1127 ++++++++++++++++++++------------ sphinx/domains/cpp/_ids.py | 161 +++-- sphinx/domains/cpp/_parser.py | 615 ++++++++++------- sphinx/domains/cpp/_symbol.py | 1056 +++++++++++++++++------------- 6 files changed, 2258 insertions(+), 1470 deletions(-) diff --git a/.ruff.toml b/.ruff.toml index 4497d2a92b3..26d001b370f 100644 --- a/.ruff.toml +++ b/.ruff.toml @@ -396,11 +396,6 @@ exclude = [ "sphinx/builders/latex/constants.py", "sphinx/domains/changeset.py", "sphinx/domains/citation.py", - "sphinx/domains/cpp/_parser.py", - "sphinx/domains/cpp/_ids.py", - "sphinx/domains/cpp/__init__.py", - "sphinx/domains/cpp/_symbol.py", - "sphinx/domains/cpp/_ast.py", "sphinx/domains/index.py", "sphinx/domains/javascript.py", "sphinx/domains/math.py", diff --git a/sphinx/domains/cpp/__init__.py b/sphinx/domains/cpp/__init__.py index 743aa0d1018..8043bc3d33b 100644 --- a/sphinx/domains/cpp/__init__.py +++ b/sphinx/domains/cpp/__init__.py @@ -144,7 +144,7 @@ def _make_phony_error_name() -> ASTNestedName: - nne = ASTNestedNameElement(ASTIdentifier("PhonyNameDueToError"), None) + nne = ASTNestedNameElement(ASTIdentifier('PhonyNameDueToError'), None) return ASTNestedName([nne], [False], rooted=False) @@ -152,9 +152,12 @@ class CPPObject(ObjectDescription[ASTDeclaration]): """Description of a C++ language object.""" doc_field_types: list[Field] = [ - GroupedField('template parameter', label=_('Template Parameters'), - names=('tparam', 'template parameter'), - can_collapse=True), + GroupedField( + 'template parameter', + label=_('Template Parameters'), + names=('tparam', 'template parameter'), + can_collapse=True, + ), ] option_spec: ClassVar[OptionSpec] = { @@ -177,40 +180,50 @@ def _add_enumerator_to_parent(self, ast: ASTDeclaration) -> None: assert symbol.identOrOp is not None assert symbol.templateParams is None assert symbol.templateArgs is None - parentSymbol = symbol.parent - assert parentSymbol - if parentSymbol.parent is None: + parent_symbol = symbol.parent + assert parent_symbol + if parent_symbol.parent is None: # TODO: we could warn, but it is somewhat equivalent to unscoped # enums, without the enum return # no parent - parentDecl = parentSymbol.declaration - if parentDecl is None: + parent_decl = parent_symbol.declaration + if parent_decl is None: # the parent is not explicitly declared # TODO: we could warn, but it could be a style to just assume # enumerator parents to be scoped return - if parentDecl.objectType != 'enum': + if parent_decl.objectType != 'enum': # TODO: maybe issue a warning, enumerators in non-enums is weird, # but it is somewhat equivalent to unscoped enums, without the enum return - if parentDecl.directiveType != 'enum': + if parent_decl.directiveType != 'enum': return - targetSymbol = parentSymbol.parent - s = targetSymbol.find_identifier(symbol.identOrOp, matchSelf=False, recurseInAnon=True, - searchInSiblings=False) + target_symbol = parent_symbol.parent + s = target_symbol.find_identifier( + symbol.identOrOp, + matchSelf=False, + recurseInAnon=True, + searchInSiblings=False, + ) if s is not None: # something is already declared with that name return - declClone = symbol.declaration.clone() - declClone.enumeratorScopedSymbol = symbol - Symbol(parent=targetSymbol, identOrOp=symbol.identOrOp, - templateParams=None, templateArgs=None, - declaration=declClone, - docname=self.env.docname, line=self.get_source_info()[1]) - - def add_target_and_index(self, ast: ASTDeclaration, sig: str, - signode: TextElement) -> None: + decl_clone = symbol.declaration.clone() + decl_clone.enumeratorScopedSymbol = symbol + Symbol( + parent=target_symbol, + identOrOp=symbol.identOrOp, + templateParams=None, + templateArgs=None, + declaration=decl_clone, + docname=self.env.docname, + line=self.get_source_info()[1], + ) + + 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): @@ -221,16 +234,20 @@ def add_target_and_index(self, ast: ASTDeclaration, sig: str, assert i < _max_id # let's keep the newest first ids.reverse() - newestId = ids[0] - assert newestId # shouldn't be None - if not re.compile(r'^[a-zA-Z0-9_]*$').match(newestId): - logger.warning('Index id generation for C++ object "%s" failed, please ' - 'report as bug (id=%s).', ast, newestId, - location=self.get_location()) + newest_id = ids[0] + assert newest_id # shouldn't be None + if not re.compile(r'^[a-zA-Z0-9_]*$').match(newest_id): + logger.warning( + 'Index id generation for C++ object "%s" failed, please ' + 'report as bug (id=%s).', + ast, + newest_id, + location=self.get_location(), + ) name = ast.symbol.get_full_nested_name().get_display_string().lstrip(':') # Add index entry, but not if it's a declaration inside a concept - isInConcept = False + is_in_concept = False s = ast.symbol.parent while s is not None: decl = s.declaration @@ -238,25 +255,31 @@ def add_target_and_index(self, ast: ASTDeclaration, sig: str, if decl is None: continue if decl.objectType == 'concept': - isInConcept = True + is_in_concept = True break - if not isInConcept and 'no-index-entry' not in self.options: - strippedName = name + if not is_in_concept and 'no-index-entry' not in self.options: + stripped_name = name for prefix in self.env.config.cpp_index_common_prefix: if name.startswith(prefix): - strippedName = strippedName[len(prefix):] + stripped_name = stripped_name[len(prefix) :] break - indexText = self.get_index_text(strippedName) - self.indexnode['entries'].append(('single', indexText, newestId, '', None)) - - if newestId not in self.state.document.ids: + index_text = self.get_index_text(stripped_name) + self.indexnode['entries'].append(( + 'single', + index_text, + newest_id, + '', + None, + )) + + if newest_id not in self.state.document.ids: # if the name is not unique, the first one will win names = self.env.domaindata['cpp']['names'] if name not in names: names[name] = ast.symbol.docname # always add the newest id - assert newestId - signode['ids'].append(newestId) + assert newest_id + signode['ids'].append(newest_id) # only add compatibility ids when there are no conflicts for id in ids[1:]: if not id: # is None when the element didn't exist in that version @@ -279,8 +302,9 @@ def get_index_text(self, name: str) -> str: def parse_definition(self, parser: DefinitionParser) -> ASTDeclaration: return parser.parse_declaration(self.object_type, self.objtype) - def describe_signature(self, signode: desc_signature, - ast: ASTDeclaration, 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) -> list[Node]: @@ -301,15 +325,17 @@ def run(self) -> list[Node]: # :cpp:any:`boom` # # So we disallow any signatures inside functions. - parentSymbol = env.temp_data['cpp:parent_symbol'] - parentDecl = parentSymbol.declaration - if parentDecl is not None and parentDecl.objectType == 'function': - msg = ("C++ declarations inside functions are not supported. " - f"Parent function: {parentSymbol.get_full_nested_name()}\n" - f"Directive name: {self.name}\nDirective arg: {self.arguments[0]}") + parent_symbol = env.temp_data['cpp:parent_symbol'] + parent_decl = parent_symbol.declaration + if parent_decl is not None and parent_decl.objectType == 'function': + msg = ( + 'C++ declarations inside functions are not supported. ' + f'Parent function: {parent_symbol.get_full_nested_name()}\n' + f'Directive name: {self.name}\nDirective arg: {self.arguments[0]}' + ) logger.warning(msg, location=self.get_location()) name = _make_phony_error_name() - symbol = parentSymbol.add_name(name) + symbol = parent_symbol.add_name(name) env.temp_data['cpp:last_symbol'] = symbol return [] # When multiple declarations are made in the same directive @@ -319,11 +345,13 @@ def run(self) -> list[Node]: return super().run() def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration: - parentSymbol: Symbol = self.env.temp_data['cpp:parent_symbol'] + parent_symbol: Symbol = self.env.temp_data['cpp:parent_symbol'] - max_len = (self.env.config.cpp_maximum_signature_line_length - or self.env.config.maximum_signature_line_length - or 0) + max_len = ( + self.env.config.cpp_maximum_signature_line_length + or self.env.config.maximum_signature_line_length + or 0 + ) signode['multi_line_parameter_list'] = ( 'single-line-parameter-list' not in self.options and (len(sig) > max_len > 0) @@ -338,13 +366,14 @@ def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration: # It is easier to assume some phony name than handling the error in # the possibly inner declarations. name = _make_phony_error_name() - symbol = parentSymbol.add_name(name) + symbol = parent_symbol.add_name(name) self.env.temp_data['cpp:last_symbol'] = symbol raise ValueError from e try: - symbol = parentSymbol.add_declaration( - ast, docname=self.env.docname, line=self.get_source_info()[1]) + symbol = parent_symbol.add_declaration( + ast, docname=self.env.docname, line=self.get_source_info()[1] + ) # append the new declaration to the sibling list assert symbol.siblingAbove is None assert symbol.siblingBelow is None @@ -357,8 +386,10 @@ def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration: # Assume we are actually in the old symbol, # instead of the newly created duplicate. self.env.temp_data['cpp:last_symbol'] = e.symbol - msg = __("Duplicate C++ declaration, also defined at %s:%s.\n" - "Declaration is '.. cpp:%s:: %s'.") + msg = __( + 'Duplicate C++ declaration, also defined at %s:%s.\n' + "Declaration is '.. cpp:%s:: %s'." + ) logger.warning( msg, e.symbol.docname, @@ -379,25 +410,28 @@ def handle_signature(self, sig: str, signode: desc_signature) -> ASTDeclaration: return ast def before_content(self) -> None: - lastSymbol: Symbol = self.env.temp_data['cpp:last_symbol'] - assert lastSymbol + last_symbol: Symbol = self.env.temp_data['cpp:last_symbol'] + assert last_symbol self.oldParentSymbol = self.env.temp_data['cpp:parent_symbol'] self.oldParentKey: LookupKey = self.env.ref_context['cpp:parent_key'] - self.env.temp_data['cpp:parent_symbol'] = lastSymbol - self.env.ref_context['cpp:parent_key'] = lastSymbol.get_lookup_key() + self.env.temp_data['cpp:parent_symbol'] = last_symbol + self.env.ref_context['cpp:parent_key'] = last_symbol.get_lookup_key() self.env.temp_data['cpp:domain_name'] = ( *self.env.temp_data.get('cpp:domain_name', ()), - lastSymbol.identOrOp._stringify(str), + last_symbol.identOrOp._stringify(str), ) def after_content(self) -> None: - self.env.temp_data['cpp:parent_symbol'] = self.oldParentSymbol + temp_data = self.env.temp_data + temp_data['cpp:parent_symbol'] = self.oldParentSymbol self.env.ref_context['cpp:parent_key'] = self.oldParentKey - self.env.temp_data['cpp:domain_name'] = self.env.temp_data['cpp:domain_name'][:-1] + temp_data['cpp:domain_name'] = temp_data['cpp:domain_name'][:-1] def _object_hierarchy_parts(self, sig_node: desc_signature) -> tuple[str, ...]: - return tuple(s.identOrOp._stringify(str) for s in - self.env.temp_data['cpp:last_symbol'].get_full_nested_name().names) + return tuple( + s.identOrOp._stringify(str) + for s in self.env.temp_data['cpp:last_symbol'].get_full_nested_name().names + ) def _toc_entry_name(self, sig_node: desc_signature) -> str: if not sig_node.get('_toc_parts'): @@ -411,7 +445,10 @@ def _toc_entry_name(self, sig_node: desc_signature) -> str: parens = '' *parents, name = sig_node['_toc_parts'] if config.toc_object_entries_show_parents == 'domain': - return '::'.join((*self.env.temp_data.get('cpp:domain_name', ()), name + parens)) + return '::'.join(( + *self.env.temp_data.get('cpp:domain_name', ()), + name + parens, + )) if config.toc_object_entries_show_parents == 'hide': return name + parens if config.toc_object_entries_show_parents == 'all': @@ -437,25 +474,30 @@ class CPPFunctionObject(CPPObject): doc_field_types = [ *CPPObject.doc_field_types, GroupedField( - "parameter", - label=_("Parameters"), - names=("param", "parameter", "arg", "argument"), + 'parameter', + label=_('Parameters'), + names=('param', 'parameter', 'arg', 'argument'), can_collapse=True, ), GroupedField( - "exceptions", - label=_("Throws"), - rolename="expr", - names=("throws", "throw", "exception"), + 'exceptions', + label=_('Throws'), + rolename='expr', + names=('throws', 'throw', 'exception'), can_collapse=True, ), GroupedField( - "retval", - label=_("Return values"), - names=("retvals", "retval"), + 'retval', + label=_('Return values'), + names=('retvals', 'retval'), can_collapse=True, ), - Field("returnvalue", label=_("Returns"), has_arg=False, names=("returns", "return")), + Field( + 'returnvalue', + label=_('Returns'), + has_arg=False, + names=('returns', 'return'), + ), ] @@ -494,14 +536,14 @@ class CPPNamespaceObject(SphinxDirective): option_spec: ClassVar[OptionSpec] = {} def run(self) -> list[Node]: - rootSymbol = self.env.domaindata['cpp']['root_symbol'] + root_symbol = self.env.domaindata['cpp']['root_symbol'] if self.arguments[0].strip() in {'NULL', '0', 'nullptr'}: - symbol = rootSymbol + symbol = root_symbol stack: list[Symbol] = [] else: - parser = DefinitionParser(self.arguments[0], - location=self.get_location(), - config=self.config) + parser = DefinitionParser( + self.arguments[0], location=self.get_location(), config=self.config + ) try: ast = parser.parse_namespace_object() parser.assert_end() @@ -509,7 +551,7 @@ def run(self) -> list[Node]: logger.warning(e, location=self.get_location()) name = _make_phony_error_name() ast = ASTNamespace(name, None) - symbol = rootSymbol.add_name(ast.nestedName, ast.templatePrefix) + symbol = root_symbol.add_name(ast.nestedName, ast.templatePrefix) stack = [symbol] self.env.temp_data['cpp:parent_symbol'] = symbol self.env.temp_data['cpp:namespace_stack'] = stack @@ -527,9 +569,9 @@ class CPPNamespacePushObject(SphinxDirective): def run(self) -> list[Node]: if self.arguments[0].strip() in {'NULL', '0', 'nullptr'}: return [] - parser = DefinitionParser(self.arguments[0], - location=self.get_location(), - config=self.config) + parser = DefinitionParser( + self.arguments[0], location=self.get_location(), config=self.config + ) try: ast = parser.parse_namespace_object() parser.assert_end() @@ -537,10 +579,10 @@ def run(self) -> list[Node]: logger.warning(e, location=self.get_location()) name = _make_phony_error_name() ast = ASTNamespace(name, None) - oldParent = self.env.temp_data.get('cpp:parent_symbol', None) - if not oldParent: - oldParent = self.env.domaindata['cpp']['root_symbol'] - symbol = oldParent.add_name(ast.nestedName, ast.templatePrefix) + old_parent = self.env.temp_data.get('cpp:parent_symbol', None) + if not old_parent: + old_parent = self.env.domaindata['cpp']['root_symbol'] + symbol = old_parent.add_name(ast.nestedName, ast.templatePrefix) stack = self.env.temp_data.get('cpp:namespace_stack', []) stack.append(symbol) self.env.temp_data['cpp:parent_symbol'] = symbol @@ -559,8 +601,10 @@ class CPPNamespacePopObject(SphinxDirective): def run(self) -> list[Node]: stack = self.env.temp_data.get('cpp:namespace_stack', None) if not stack or len(stack) == 0: - logger.warning("C++ namespace pop on empty stack. Defaulting to global scope.", - location=self.get_location()) + logger.warning( + 'C++ namespace pop on empty stack. Defaulting to global scope.', + location=self.get_location(), + ) stack = [] else: stack.pop() @@ -575,9 +619,13 @@ def run(self) -> list[Node]: class AliasNode(nodes.Element): - def __init__(self, sig: str, aliasOptions: dict, - env: BuildEnvironment | None = None, - parentKey: LookupKey | None = None) -> None: + def __init__( + self, + sig: str, + aliasOptions: dict, + env: BuildEnvironment | None = None, + parentKey: LookupKey | None = None, + ) -> None: super().__init__() self.sig = sig self.aliasOptions = aliasOptions @@ -592,16 +640,23 @@ def __init__(self, sig: str, aliasOptions: dict, self.parentKey = parentKey def copy(self) -> AliasNode: - return self.__class__(self.sig, self.aliasOptions, - env=None, parentKey=self.parentKey) + return self.__class__( + self.sig, self.aliasOptions, env=None, parentKey=self.parentKey + ) class AliasTransform(SphinxTransform): default_priority = ReferencesResolver.default_priority - 1 - def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool, - aliasOptions: dict, renderOptions: dict, - document: Any) -> list[Node]: + def _render_symbol( + self, + s: Symbol, + maxdepth: int, + skip_this: bool, + alias_options: dict, + render_options: dict, + document: Any, + ) -> list[Node]: if maxdepth == 0: recurse = True elif maxdepth == 1: @@ -611,14 +666,16 @@ def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool, recurse = True nodes: list[Node] = [] - if not skipThis: + if not skip_this: signode = addnodes.desc_signature('', '') nodes.append(signode) - s.declaration.describe_signature(signode, 'markName', self.env, renderOptions) + s.declaration.describe_signature( + signode, 'markName', self.env, render_options + ) if recurse: - if skipThis: - childContainer: list[Node] | addnodes.desc = nodes + if skip_this: + child_container: list[Node] | addnodes.desc = nodes else: content = addnodes.desc_content() desc = addnodes.desc() @@ -628,35 +685,38 @@ def _render_symbol(self, s: Symbol, maxdepth: int, skipThis: bool, # 'desctype' is a backwards compatible attribute desc['objtype'] = desc['desctype'] = 'alias' desc['no-index'] = True - childContainer = desc + child_container = desc - for sChild in s._children: - if sChild.declaration is None: + for s_child in s._children: + if s_child.declaration is None: continue - if sChild.declaration.objectType in {"templateParam", "functionParam"}: + if s_child.declaration.objectType in {'templateParam', 'functionParam'}: continue - childNodes = self._render_symbol( - sChild, maxdepth=maxdepth, skipThis=False, - aliasOptions=aliasOptions, renderOptions=renderOptions, - document=document) - childContainer.extend(childNodes) - - if not skipThis and len(desc.children) != 0: + child_nodes = self._render_symbol( + s_child, + maxdepth=maxdepth, + skip_this=False, + alias_options=alias_options, + render_options=render_options, + document=document, + ) + child_container.extend(child_nodes) + + if not skip_this and len(desc.children) != 0: nodes.append(content) return nodes def apply(self, **kwargs: Any) -> None: for node in self.document.findall(AliasNode): sig = node.sig - parentKey = node.parentKey + parent_key = node.parentKey try: - parser = DefinitionParser(sig, location=node, - config=self.env.config) - ast, isShorthand = parser.parse_xref_object() + parser = DefinitionParser(sig, location=node, config=self.env.config) + ast, is_shorthand = parser.parse_xref_object() parser.assert_end() except DefinitionError as e: logger.warning(e, location=node) - ast, isShorthand = None, None + ast, is_shorthand = None, None if ast is None: # could not be parsed, so stop here @@ -666,39 +726,45 @@ def apply(self, **kwargs: Any) -> None: node.replace_self(signode) continue - rootSymbol: Symbol = self.env.domains.cpp_domain.data['root_symbol'] - parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey) - if not parentSymbol: - logger.debug("Target: %s", sig) - logger.debug("ParentKey: %s", parentKey) - logger.debug(rootSymbol.dump(1)) - assert parentSymbol # should be there + root_symbol: Symbol = self.env.domains.cpp_domain.data['root_symbol'] + parent_symbol: Symbol = root_symbol.direct_lookup(parent_key) + if not parent_symbol: + logger.debug('Target: %s', sig) + logger.debug('ParentKey: %s', parent_key) + logger.debug(root_symbol.dump(1)) + assert parent_symbol # should be there symbols: list[Symbol] = [] - if isShorthand: + if is_shorthand: assert isinstance(ast, ASTNamespace) ns = ast name = ns.nestedName if ns.templatePrefix: - templateDecls = ns.templatePrefix.templates + template_decls = ns.templatePrefix.templates else: - templateDecls = [] - symbols, failReason = parentSymbol.find_name( + template_decls = [] + symbols, fail_reason = parent_symbol.find_name( nestedName=name, - templateDecls=templateDecls, + templateDecls=template_decls, typ='any', templateShorthand=True, - matchSelf=True, recurseInAnon=True, - searchInSiblings=False) + matchSelf=True, + recurseInAnon=True, + searchInSiblings=False, + ) if symbols is None: symbols = [] else: assert isinstance(ast, ASTDeclaration) decl = ast name = decl.name - s = parentSymbol.find_declaration(decl, 'any', - templateShorthand=True, - matchSelf=True, recurseInAnon=True) + s = parent_symbol.find_declaration( + decl, + 'any', + templateShorthand=True, + matchSelf=True, + recurseInAnon=True, + ) if s is not None: symbols.append(s) @@ -710,22 +776,25 @@ def apply(self, **kwargs: Any) -> None: signode.clear() signode += addnodes.desc_name(sig, sig) - logger.warning("Can not find C++ declaration for alias '%s'.", ast, - location=node) + logger.warning( + "Can not find C++ declaration for alias '%s'.", ast, location=node + ) node.replace_self(signode) else: nodes = [] - renderOptions = { + render_options = { 'tparam-line-spec': False, } for s in symbols: assert s.declaration is not None res = self._render_symbol( - s, maxdepth=node.aliasOptions['maxdepth'], - skipThis=node.aliasOptions['noroot'], - aliasOptions=node.aliasOptions, - renderOptions=renderOptions, - document=node.document) + s, + maxdepth=node.aliasOptions['maxdepth'], + skip_this=node.aliasOptions['noroot'], + alias_options=node.aliasOptions, + render_options=render_options, + document=node.document, + ) nodes.extend(res) node.replace_self(nodes) @@ -754,19 +823,21 @@ def run(self) -> list[Node]: node['objtype'] = node['desctype'] = self.objtype self.names: list[str] = [] - aliasOptions = { + alias_options = { 'maxdepth': self.options.get('maxdepth', 1), 'noroot': 'noroot' in self.options, } - if aliasOptions['noroot'] and aliasOptions['maxdepth'] == 1: - logger.warning("Error in C++ alias declaration." - " Requested 'noroot' but 'maxdepth' 1." - " When skipping the root declaration," - " need 'maxdepth' 0 for infinite or at least 2.", - location=self.get_location()) + if alias_options['noroot'] and alias_options['maxdepth'] == 1: + logger.warning( + 'Error in C++ alias declaration.' + " Requested 'noroot' but 'maxdepth' 1." + ' When skipping the root declaration,' + " need 'maxdepth' 0 for infinite or at least 2.", + location=self.get_location(), + ) signatures = self.get_signatures() for sig in signatures: - node.append(AliasNode(sig, aliasOptions, env=self.env)) + node.append(AliasNode(sig, alias_options, env=self.env)) self.before_content() content_node = addnodes.desc_content('', *self.parse_content_to_nodes()) @@ -777,14 +848,20 @@ def run(self) -> list[Node]: class CPPXRefRole(XRefRole): - def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_title: bool, - title: str, target: str) -> tuple[str, str]: + def process_link( + self, + env: BuildEnvironment, + refnode: Element, + has_explicit_title: bool, + title: str, + target: str, + ) -> tuple[str, str]: refnode.attributes.update(env.ref_context) 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. @@ -801,7 +878,7 @@ def process_link(self, env: BuildEnvironment, refnode: Element, has_explicit_tit title = title[1:] dcolon = title.rfind('::') if dcolon != -1: - title = title[dcolon + 2:] + title = title[dcolon + 2 :] return title, target @@ -817,24 +894,29 @@ def __init__(self, asCode: bool) -> None: def run(self) -> tuple[list[Node], list[system_message]]: text = self.text.replace('\n', ' ') - parser = DefinitionParser(text, - location=self.get_location(), - config=self.config) + parser = DefinitionParser( + text, location=self.get_location(), config=self.config + ) # attempt to mimic XRefRole classes, except that... try: ast = parser.parse_expression() except DefinitionError as ex: - logger.warning('Unparseable C++ expression: %r\n%s', text, ex, - location=self.get_location()) + logger.warning( + 'Unparseable C++ expression: %r\n%s', + text, + ex, + location=self.get_location(), + ) # see below - return [addnodes.desc_inline('cpp', text, text, classes=[self.class_type])], [] - parentSymbol = self.env.temp_data.get('cpp:parent_symbol', None) - if parentSymbol is None: - parentSymbol = self.env.domaindata['cpp']['root_symbol'] + node = addnodes.desc_inline('cpp', text, text, classes=[self.class_type]) + return [node], [] + parent_symbol = self.env.temp_data.get('cpp:parent_symbol', None) + if parent_symbol is None: + parent_symbol = 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 = addnodes.desc_inline('cpp', classes=[self.class_type]) - ast.describe_signature(signode, 'markType', self.env, parentSymbol) + ast.describe_signature(signode, 'markType', self.env, parent_symbol) return [signode], [] @@ -854,18 +936,28 @@ class CPPDomain(Domain): name = 'cpp' label = 'C++' object_types = { - 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'), - 'union': ObjType(_('union'), 'union', 'identifier', 'type'), - 'function': ObjType(_('function'), 'func', 'identifier', 'type'), - 'member': ObjType(_('member'), 'member', 'var', 'identifier'), - 'type': ObjType(_('type'), 'identifier', 'type'), - 'concept': ObjType(_('concept'), 'concept', 'identifier'), - 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'), - 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'), + 'class': ObjType(_('class'), 'class', 'struct', 'identifier', 'type'), + 'union': ObjType(_('union'), 'union', 'identifier', 'type'), + 'function': ObjType(_('function'), 'func', 'identifier', 'type'), + 'member': ObjType(_('member'), 'member', 'var', 'identifier'), + 'type': ObjType(_('type'), 'identifier', 'type'), + 'concept': ObjType(_('concept'), 'concept', 'identifier'), + 'enum': ObjType(_('enum'), 'enum', 'identifier', 'type'), + 'enumerator': ObjType(_('enumerator'), 'enumerator', 'identifier'), # generated object types - 'functionParam': ObjType(_('function parameter'), 'identifier', 'member', 'var'), # NoQA: E501 - 'templateParam': ObjType(_('template parameter'), - 'identifier', 'class', 'struct', 'union', 'member', 'var', 'type'), # NoQA: E501 + 'functionParam': ObjType( + _('function parameter'), 'identifier', 'member', 'var' + ), # NoQA: E501 + 'templateParam': ObjType( + _('template parameter'), + 'identifier', + 'class', + 'struct', + 'union', + 'member', + 'var', + 'type', + ), # NoQA: E501 } directives = { @@ -911,116 +1003,130 @@ class CPPDomain(Domain): def clear_doc(self, docname: str) -> None: if Symbol.debug_show_tree: - logger.debug("clear_doc: %s", docname) - logger.debug("\tbefore:") + logger.debug('clear_doc: %s', docname) + logger.debug('\tbefore:') logger.debug(self.data['root_symbol'].dump(1)) - logger.debug("\tbefore end") + logger.debug('\tbefore end') - rootSymbol = self.data['root_symbol'] - rootSymbol.clear_doc(docname) + root_symbol = self.data['root_symbol'] + root_symbol.clear_doc(docname) if Symbol.debug_show_tree: - logger.debug("\tafter:") + logger.debug('\tafter:') logger.debug(self.data['root_symbol'].dump(1)) - logger.debug("\tafter end") - logger.debug("clear_doc end: %s", docname) - for name, nDocname in list(self.data['names'].items()): - if nDocname == docname: + logger.debug('\tafter end') + logger.debug('clear_doc end: %s', docname) + for name, n_docname in list(self.data['names'].items()): + if n_docname == docname: del self.data['names'][name] - def process_doc(self, env: BuildEnvironment, docname: str, - document: nodes.document) -> None: + def process_doc( + self, env: BuildEnvironment, docname: str, document: nodes.document + ) -> None: if Symbol.debug_show_tree: - logger.debug("process_doc: %s", docname) + logger.debug('process_doc: %s', docname) logger.debug(self.data['root_symbol'].dump(0)) - logger.debug("process_doc end: %s", docname) + logger.debug('process_doc end: %s', docname) def process_field_xref(self, pnode: pending_xref) -> None: pnode.attributes.update(self.env.ref_context) def merge_domaindata(self, docnames: Set[str], otherdata: dict[str, Any]) -> None: if Symbol.debug_show_tree: - logger.debug("merge_domaindata:") - logger.debug("\tself:") + logger.debug('merge_domaindata:') + logger.debug('\tself:') logger.debug(self.data['root_symbol'].dump(1)) - logger.debug("\tself end") - logger.debug("\tother:") + logger.debug('\tself end') + logger.debug('\tother:') logger.debug(otherdata['root_symbol'].dump(1)) - logger.debug("\tother end") + logger.debug('\tother end') - self.data['root_symbol'].merge_with(otherdata['root_symbol'], - docnames, self.env) - ourNames = self.data['names'] + self.data['root_symbol'].merge_with( + otherdata['root_symbol'], docnames, self.env + ) + our_names = self.data['names'] for name, docname in otherdata['names'].items(): if docname in docnames: - if name not in ourNames: - ourNames[name] = docname + if name not in our_names: + our_names[name] = docname # no need to warn on duplicates, the symbol merge already does that if Symbol.debug_show_tree: - logger.debug("\tresult:") + logger.debug('\tresult:') logger.debug(self.data['root_symbol'].dump(1)) - logger.debug("\tresult end") - logger.debug("merge_domaindata end") + logger.debug('\tresult end') + logger.debug('merge_domaindata end') def _resolve_xref_inner( - self, env: BuildEnvironment, fromdocname: str, builder: Builder, - typ: str, target: str, node: pending_xref, contnode: Element + self, + env: BuildEnvironment, + fromdocname: str, + builder: Builder, + typ: str, + target: str, + node: pending_xref, + contnode: Element, ) -> tuple[nodes.reference, str] | tuple[None, None]: # add parens again for those that could be functions if typ in {'any', 'func'}: target += '()' parser = DefinitionParser(target, location=node, config=env.config) try: - ast, isShorthand = parser.parse_xref_object() + ast, is_shorthand = parser.parse_xref_object() except DefinitionError as e: # as arg to stop flake8 from complaining - def findWarning(e: Exception) -> tuple[str, Exception]: - if typ not in {"any", "func"}: + def find_warning(e: Exception) -> tuple[str, Exception]: + if typ not in {'any', 'func'}: return target, e # hax on top of the paren hax to try to get correct errors - parser2 = DefinitionParser(target[:-2], - location=node, - config=env.config) + parser2 = DefinitionParser( + target[:-2], location=node, config=env.config + ) try: parser2.parse_xref_object() except DefinitionError as e2: return target[:-2], e2 # strange, that we don't get the error now, use the original return target, e - t, ex = findWarning(e) - logger.warning('Unparseable C++ cross-reference: %r\n%s', t, ex, - location=node) + + t, ex = find_warning(e) + logger.warning( + 'Unparseable C++ cross-reference: %r\n%s', t, ex, location=node + ) return None, None - parentKey: LookupKey = node.get("cpp:parent_key", None) - rootSymbol = self.data['root_symbol'] - if parentKey: - parentSymbol: Symbol = rootSymbol.direct_lookup(parentKey) - if not parentSymbol: - logger.debug("Target: %s", target) - logger.debug("ParentKey: %s", parentKey.data) - logger.debug(rootSymbol.dump(1)) - assert parentSymbol # should be there + parent_key: LookupKey = node.get('cpp:parent_key', None) + root_symbol = self.data['root_symbol'] + if parent_key: + parent_symbol: Symbol = root_symbol.direct_lookup(parent_key) + if not parent_symbol: + logger.debug('Target: %s', target) + logger.debug('ParentKey: %s', parent_key.data) + logger.debug(root_symbol.dump(1)) + assert parent_symbol # should be there else: - parentSymbol = rootSymbol + parent_symbol = root_symbol - if isShorthand: + if is_shorthand: assert isinstance(ast, ASTNamespace) ns = ast name = ns.nestedName if ns.templatePrefix: - templateDecls = ns.templatePrefix.templates + template_decls = ns.templatePrefix.templates else: - templateDecls = [] + template_decls = [] # 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, + search_in_siblings = (not name.rooted) and len(name.names) == 1 + symbols, fail_reason = parent_symbol.find_name( + name, + template_decls, + typ, templateShorthand=True, - matchSelf=True, recurseInAnon=True, - searchInSiblings=searchInSiblings) + matchSelf=True, + recurseInAnon=True, + searchInSiblings=search_in_siblings, + ) if symbols is None: if typ == 'identifier': - if failReason == 'templateParamInQualified': + if fail_reason == '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) @@ -1032,44 +1138,48 @@ def findWarning(e: Exception) -> tuple[str, Exception]: assert isinstance(ast, ASTDeclaration) decl = ast name = decl.name - s = parentSymbol.find_declaration(decl, typ, - templateShorthand=True, - matchSelf=True, recurseInAnon=True) + s = parent_symbol.find_declaration( + decl, typ, templateShorthand=True, matchSelf=True, recurseInAnon=True + ) if s is None or s.declaration is None: - txtName = str(name) - if txtName.startswith('std::') or txtName == 'std': - raise NoUri(txtName, typ) + txt_name = str(name) + if txt_name.startswith('std::') or txt_name == 'std': + raise NoUri(txt_name, typ) return None, None typ = typ.removeprefix('cpp:') - declTyp = s.declaration.objectType + decl_typ = s.declaration.objectType - def checkType() -> bool: + def check_type() -> bool: if typ == 'any': return True objtypes = self.objtypes_for_role(typ) if objtypes: - return declTyp in objtypes - logger.debug(f"Type is {typ}, declaration type is {declTyp}") # NoQA: G004 + return decl_typ in objtypes + logger.debug(f'Type is {typ}, declaration type is {decl_typ}') # NoQA: G004 raise AssertionError - if not checkType(): - logger.warning("cpp:%s targets a %s (%s).", - typ, s.declaration.objectType, - s.get_full_nested_name(), - location=node) + + if not check_type(): + logger.warning( + 'cpp:%s targets a %s (%s).', + typ, + s.declaration.objectType, + s.get_full_nested_name(), + location=node, + ) declaration = s.declaration - if isShorthand: - fullNestedName = s.get_full_nested_name() - displayName = fullNestedName.get_display_string().lstrip(':') + if is_shorthand: + full_nested_name = s.get_full_nested_name() + display_name = full_nested_name.get_display_string().lstrip(':') else: - displayName = decl.get_display_string() + display_name = decl.get_display_string() docname = s.docname assert docname # the non-identifier refs are cross-references, which should be processed: # - fix parenthesis due to operator() and add_function_parentheses - if typ != "identifier": + if typ != 'identifier': title = contnode.pop(0).astext() # If it's operator(), we need to add '()' if explicit function parens # are requested. Then the Sphinx machinery will add another pair. @@ -1077,52 +1187,83 @@ def checkType() -> bool: # parens as well. # However, if it's a non-shorthand function ref, for a function that # takes no arguments, then we may need to add parens again as well. - addParen = 0 - if not node.get('refexplicit', False) and declaration.objectType == 'function': - if isShorthand: + add_paren = 0 + if ( + not node.get('refexplicit', False) + and declaration.objectType == 'function' + ): + if is_shorthand: # this is just the normal haxing for 'any' roles if env.config.add_function_parentheses and typ == 'any': - addParen += 1 + add_paren += 1 # and now this stuff for operator() - if (env.config.add_function_parentheses and typ == 'func' and - title.endswith('operator()')): - addParen += 1 - if (typ in {'any', 'func'} and - title.endswith('operator') and - displayName.endswith('operator()')): - addParen += 1 + if ( + env.config.add_function_parentheses + and typ == 'func' + and title.endswith('operator()') + ): + add_paren += 1 + if ( + typ in {'any', 'func'} + and title.endswith('operator') + and display_name.endswith('operator()') + ): + add_paren += 1 else: # our job here is to essentially nullify add_function_parentheses if env.config.add_function_parentheses: - if typ == 'any' and displayName.endswith('()'): - addParen += 1 + if typ == 'any' and display_name.endswith('()'): + add_paren += 1 elif typ == 'func': - if not displayName.endswith('()'): + if not display_name.endswith('()'): title = title.removesuffix('()') else: - if displayName.endswith('()'): - addParen += 1 - if addParen > 0: - title += '()' * addParen + if display_name.endswith('()'): + add_paren += 1 + if add_paren > 0: + title += '()' * add_paren # and reconstruct the title again contnode += nodes.Text(title) - res = make_refnode(builder, fromdocname, docname, - declaration.get_newest_id(), contnode, displayName, - ), declaration.objectType + res = ( + make_refnode( + builder, + fromdocname, + docname, + declaration.get_newest_id(), + contnode, + display_name, + ), + declaration.objectType, + ) return res - def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, - typ: str, target: str, node: pending_xref, contnode: Element, - ) -> nodes.reference | None: - return self._resolve_xref_inner(env, fromdocname, builder, typ, - target, node, contnode)[0] - - def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, - target: str, node: pending_xref, contnode: Element, - ) -> list[tuple[str, nodes.reference]]: + def resolve_xref( + self, + env: BuildEnvironment, + fromdocname: str, + builder: Builder, + typ: str, + target: str, + node: pending_xref, + contnode: Element, + ) -> nodes.reference | None: + return self._resolve_xref_inner( + env, fromdocname, builder, typ, target, node, contnode + )[0] + + def resolve_any_xref( + self, + env: BuildEnvironment, + fromdocname: str, + builder: Builder, + target: str, + node: pending_xref, + contnode: Element, + ) -> list[tuple[str, nodes.reference]]: with logging.suppress_logging(): - retnode, objtype = self._resolve_xref_inner(env, fromdocname, builder, - 'any', target, node, contnode) + retnode, objtype = self._resolve_xref_inner( + env, fromdocname, builder, 'any', target, node, contnode + ) if retnode: if objtype == 'templateParam': return [('cpp:templateParam', retnode)] @@ -1131,52 +1272,53 @@ def resolve_any_xref(self, env: BuildEnvironment, fromdocname: str, builder: Bui return [] def get_objects(self) -> Iterator[tuple[str, str, str, str, str, int]]: - rootSymbol = self.data['root_symbol'] - for symbol in rootSymbol.get_all_symbols(): + root_symbol = self.data['root_symbol'] + for symbol in root_symbol.get_all_symbols(): if symbol.declaration is None: continue assert symbol.docname - fullNestedName = symbol.get_full_nested_name() - name = str(fullNestedName).lstrip(':') - dispname = fullNestedName.get_display_string().lstrip(':') - objectType = symbol.declaration.objectType + full_nested_name = symbol.get_full_nested_name() + name = str(full_nested_name).lstrip(':') + dispname = full_nested_name.get_display_string().lstrip(':') + object_type = symbol.declaration.objectType docname = symbol.docname - newestId = symbol.declaration.get_newest_id() - yield name, dispname, objectType, docname, newestId, 1 + newest_id = symbol.declaration.get_newest_id() + yield name, dispname, object_type, docname, newest_id, 1 def get_full_qualified_name(self, node: Element) -> str | None: target = node.get('reftarget', None) if target is None: return None - parentKey: LookupKey = node.get("cpp:parent_key", None) - if parentKey is None or len(parentKey.data) <= 0: + parent_key: LookupKey = node.get('cpp:parent_key', None) + if parent_key is None or len(parent_key.data) <= 0: return None - rootSymbol = self.data['root_symbol'] - parentSymbol = rootSymbol.direct_lookup(parentKey) - parentName = parentSymbol.get_full_nested_name() - return f'{parentName}::{target}' + root_symbol = self.data['root_symbol'] + parent_symbol = root_symbol.direct_lookup(parent_key) + parent_name = parent_symbol.get_full_nested_name() + return f'{parent_name}::{target}' def setup(app: Sphinx) -> ExtensionMetadata: app.add_domain(CPPDomain) - app.add_config_value("cpp_index_common_prefix", [], 'env') - app.add_config_value("cpp_id_attributes", [], 'env', types={list, tuple}) - app.add_config_value("cpp_paren_attributes", [], 'env', types={list, tuple}) + app.add_config_value('cpp_index_common_prefix', [], 'env') + app.add_config_value('cpp_id_attributes', [], 'env', types={list, tuple}) + app.add_config_value('cpp_paren_attributes', [], 'env', types={list, tuple}) app.add_config_value( - "cpp_maximum_signature_line_length", None, 'env', types={int, type(None)} + 'cpp_maximum_signature_line_length', None, 'env', types={int, type(None)} ) app.add_post_transform(AliasTransform) # debug stuff - app.add_config_value("cpp_debug_lookup", False, '') - app.add_config_value("cpp_debug_show_tree", False, '') + app.add_config_value('cpp_debug_lookup', False, '') + app.add_config_value('cpp_debug_show_tree', False, '') - def initStuff(app: Sphinx) -> None: + def init_stuff(app: Sphinx) -> None: Symbol.debug_lookup = app.config.cpp_debug_lookup Symbol.debug_show_tree = app.config.cpp_debug_show_tree app.config.cpp_index_common_prefix.sort(reverse=True) - app.connect("builder-inited", initStuff) + + app.connect('builder-inited', init_stuff) return { 'version': 'builtin', diff --git a/sphinx/domains/cpp/_ast.py b/sphinx/domains/cpp/_ast.py index 47864709279..e3643453149 100644 --- a/sphinx/domains/cpp/_ast.py +++ b/sphinx/domains/cpp/_ast.py @@ -44,6 +44,7 @@ class ASTBase(ASTBaseBase): # Names ################################################################################ + class ASTIdentifier(ASTBase): def __init__(self, name: str) -> None: if not isinstance(name, str) or len(name) == 0: @@ -75,9 +76,9 @@ def get_id(self, version: int) -> str: return 's' else: return self.name - if self.name == "std": + if self.name == 'std': return 'St' - elif self.name[0] == "~": + elif self.name[0] == '~': # a destructor, just use an arbitrary version of dtors return 'D0' else: @@ -92,21 +93,32 @@ def __str__(self) -> str: return self.name def get_display_string(self) -> str: - return "[anonymous]" if self.is_anonymous else self.name - - def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironment, - prefix: str, templateArgs: str, symbol: Symbol) -> None: + return '[anonymous]' if self.is_anonymous else self.name + + def describe_signature( + self, + signode: TextElement, + mode: str, + env: BuildEnvironment, + prefix: str, + templateArgs: str, + symbol: Symbol, + ) -> None: verify_description_mode(mode) if self.is_anonymous: - node = addnodes.desc_sig_name(text="[anonymous]") + node = addnodes.desc_sig_name(text='[anonymous]') else: node = addnodes.desc_sig_name(self.name, self.name) if mode == 'markType': target_text = prefix + self.name + templateArgs - pnode = addnodes.pending_xref('', refdomain='cpp', - reftype='identifier', - reftarget=target_text, modname=None, - classname=None) + pnode = addnodes.pending_xref( + '', + refdomain='cpp', + reftype='identifier', + reftarget=target_text, + modname=None, + classname=None, + ) pnode['cpp:parent_key'] = symbol.get_lookup_key() pnode += node signode += pnode @@ -125,10 +137,14 @@ def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironm assert len(templateArgs) == 0 assert not self.is_anonymous target_text = 'operator""' + self.name - pnode = addnodes.pending_xref('', refdomain='cpp', - reftype='identifier', - reftarget=target_text, modname=None, - classname=None) + pnode = addnodes.pending_xref( + '', + refdomain='cpp', + reftype='identifier', + reftarget=target_text, + modname=None, + classname=None, + ) pnode['cpp:parent_key'] = symbol.get_lookup_key() pnode += node signode += pnode @@ -139,21 +155,28 @@ def describe_signature(self, signode: TextElement, mode: str, env: BuildEnvironm def identifier(self) -> str: warnings.warn( '`ASTIdentifier.identifier` is deprecated, use `ASTIdentifier.name` instead', - DeprecationWarning, stacklevel=2, + DeprecationWarning, + stacklevel=2, ) return self.name class ASTNestedNameElement(ASTBase): - def __init__(self, identOrOp: ASTIdentifier | ASTOperator, - templateArgs: ASTTemplateArgs | None) -> None: + def __init__( + self, + identOrOp: ASTIdentifier | ASTOperator, + templateArgs: ASTTemplateArgs | None, + ) -> None: self.identOrOp = identOrOp self.templateArgs = templateArgs def __eq__(self, other: object) -> bool: if not isinstance(other, ASTNestedNameElement): return NotImplemented - return self.identOrOp == other.identOrOp and self.templateArgs == other.templateArgs + return ( + self.identOrOp == other.identOrOp + and self.templateArgs == other.templateArgs + ) def __hash__(self) -> int: return hash((self.identOrOp, self.templateArgs)) @@ -173,8 +196,14 @@ def _stringify(self, transform: StringifyTransform) -> str: res += transform(self.templateArgs) return res - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, prefix: str, symbol: Symbol) -> None: + def describe_signature( + self, + signode: TextElement, + mode: str, + env: BuildEnvironment, + prefix: str, + symbol: Symbol, + ) -> None: t_args = str(self.templateArgs) if self.templateArgs is not None else '' self.identOrOp.describe_signature(signode, mode, env, prefix, t_args, symbol) if self.templateArgs is not None: @@ -182,8 +211,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTNestedName(ASTBase): - def __init__(self, names: list[ASTNestedNameElement], - templates: list[bool], rooted: bool) -> None: + def __init__( + self, names: list[ASTNestedNameElement], templates: list[bool], rooted: bool + ) -> None: assert len(names) > 0 self.names = names self.templates = templates @@ -239,31 +269,32 @@ def _stringify(self, transform: StringifyTransform) -> str: for i in range(len(self.names)): n = self.names[i] if self.templates[i]: - res.append("template " + transform(n)) + res.append('template ' + transform(n)) else: res.append(transform(n)) return '::'.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) # just print the name part, with template args, not template params if mode == 'noneIsName': if self.rooted: - unreachable = "Can this happen?" + unreachable = 'Can this happen?' raise AssertionError(unreachable) # TODO signode += nodes.Text('::') for i in range(len(self.names)): if i != 0: - unreachable = "Can this happen?" + unreachable = 'Can this happen?' raise AssertionError(unreachable) # TODO signode += nodes.Text('::blah') n = self.names[i] if self.templates[i]: - unreachable = "Can this happen?" + unreachable = 'Can this happen?' raise AssertionError(unreachable) # TODO - signode += nodes.Text("template") - signode += nodes.Text(" ") + signode += nodes.Text('template') + signode += nodes.Text(' ') n.describe_signature(signode, mode, env, '', symbol) elif mode == 'param': assert not self.rooted, str(self) @@ -311,10 +342,13 @@ def describe_signature(self, signode: TextElement, mode: str, txt_nne = str(nne) if txt_nne: if nne.templateArgs and i_template_params < len(template_params): - template_params_prefix += str(template_params[i_template_params]) + template_params_prefix += str( + template_params[i_template_params] + ) i_template_params += 1 - nne.describe_signature(dest, 'markType', - env, template_params_prefix + prefix, symbol) + nne.describe_signature( + dest, 'markType', env, template_params_prefix + prefix, symbol + ) prefix += txt_nne if mode == 'lastIsName': if len(self.names) > 1: @@ -332,18 +366,21 @@ def describe_signature(self, signode: TextElement, mode: str, # 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: raise NotImplementedError(repr(self)) # Primary expressions ################################################################################ + class ASTLiteral(ASTExpression): pass @@ -361,8 +398,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: return 'LDnE' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('nullptr', 'nullptr') @@ -390,8 +428,9 @@ def get_id(self, version: int) -> str: else: return 'L0E' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword(str(self), str(self)) @@ -412,10 +451,11 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: # TODO: floats should be mangled by writing the hex of the binary representation - return "L%sE" % self.data.replace("'", "") + return 'L%sE' % self.data.replace("'", '') - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_literal_number(self.data, self.data) @@ -436,10 +476,11 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: # note: the length is not really correct with escaping - return "LA%d_KcE" % (len(self.data) - 2) + return 'LA%d_KcE' % (len(self.data) - 2) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_literal_string(self.data, self.data) @@ -458,10 +499,7 @@ def __init__(self, prefix: str, data: str) -> None: def __eq__(self, other: object) -> bool: if not isinstance(other, ASTCharLiteral): return NotImplemented - return ( - self.prefix == other.prefix - and self.value == other.value - ) + return self.prefix == other.prefix and self.value == other.value def __hash__(self) -> int: return hash((self.prefix, self.value)) @@ -476,8 +514,9 @@ def get_id(self, version: int) -> str: # TODO: the ID should be have L E around it return self.type + str(self.value) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.prefix is not None: signode += addnodes.desc_sig_keyword(self.prefix, self.prefix) txt = "'" + self.data + "'" @@ -504,35 +543,39 @@ def get_id(self, version: int) -> str: # mangle as if it was a function call: ident(literal) return f'clL_Zli{self.ident.get_id(version)}E{self.literal.get_id(version)}E' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.literal.describe_signature(signode, mode, env, symbol) - self.ident.describe_signature(signode, "udl", env, "", "", symbol) + self.ident.describe_signature(signode, 'udl', env, '', '', symbol) ################################################################################ + class ASTThisLiteral(ASTExpression): def __eq__(self, other: object) -> bool: return isinstance(other, ASTThisLiteral) def __hash__(self) -> int: - return hash("this") + return hash('this') def _stringify(self, transform: StringifyTransform) -> str: - return "this" + return 'this' def get_id(self, version: int) -> str: - return "fpT" + return 'fpT' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('this', 'this') class ASTFoldExpr(ASTExpression): - def __init__(self, leftExpr: ASTExpression | None, - op: str, rightExpr: ASTExpression | None) -> None: + def __init__( + self, leftExpr: ASTExpression | None, op: str, rightExpr: ASTExpression | None + ) -> None: assert leftExpr is not None or rightExpr is not None self.leftExpr = leftExpr self.op = op @@ -587,8 +630,9 @@ def get_id(self, version: int) -> str: res.append(self.rightExpr.get_id(version)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_punctuation('(', '(') if self.leftExpr: self.leftExpr.describe_signature(signode, mode, env, symbol) @@ -622,8 +666,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: return self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_punctuation(')', ')') @@ -648,20 +693,23 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: raise NotImplementedError(repr(self)) @@ -683,8 +731,9 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_punctuation('[', '[') self.expr.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_punctuation(']', ']') @@ -708,8 +757,9 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_punctuation('.', '.') self.name.describe_signature(signode, 'noneIsName', env, symbol) @@ -732,8 +782,9 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_operator('->', '->') self.name.describe_signature(signode, 'noneIsName', env, symbol) @@ -751,8 +802,9 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_operator('++', '++') @@ -769,8 +821,9 @@ def _stringify(self, transform: StringifyTransform) -> str: 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_operator('--', '--') @@ -797,8 +850,9 @@ def get_id(self, idPrefix: str, version: int) -> str: 'E', ]) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.lst.describe_signature(signode, mode, env, symbol) @@ -816,7 +870,10 @@ def __hash__(self) -> int: return hash((self.prefix, self.postFixes)) def _stringify(self, transform: StringifyTransform) -> str: - return ''.join([transform(self.prefix), *(transform(p) for p in self.postFixes)]) + return ''.join([ + transform(self.prefix), + *(transform(p) for p in self.postFixes), + ]) def get_id(self, version: int) -> str: id = self.prefix.get_id(version) @@ -824,8 +881,9 @@ def get_id(self, version: int) -> str: id = p.get_id(id, version) return id - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + 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) @@ -841,7 +899,11 @@ def __init__(self, cast: str, typ: ASTType, expr: ASTExpression) -> None: def __eq__(self, other: object) -> bool: if not isinstance(other, ASTExplicitCast): return NotImplemented - return self.cast == other.cast and self.typ == other.typ and self.expr == other.expr + return ( + self.cast == other.cast + and self.typ == other.typ + and self.expr == other.expr + ) def __hash__(self) -> int: return hash((self.cast, self.typ, self.expr)) @@ -856,12 +918,15 @@ def _stringify(self, transform: StringifyTransform) -> str: 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)) + return ( + _id_explicit_cast[self.cast] + + self.typ.get_id(version) + + self.expr.get_id(version) + ) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword(self.cast, self.cast) signode += addnodes.desc_sig_punctuation('<', '<') self.typ.describe_signature(signode, mode, env, symbol) @@ -891,8 +956,9 @@ 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('typeid', 'typeid') signode += addnodes.desc_sig_punctuation('(', '(') self.typeOrExpr.describe_signature(signode, mode, env, symbol) @@ -902,6 +968,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Unary expressions ################################################################################ + class ASTUnaryOpExpr(ASTExpression): def __init__(self, op: str, expr: ASTExpression) -> None: self.op = op @@ -917,15 +984,16 @@ def __hash__(self) -> int: def _stringify(self, transform: StringifyTransform) -> str: if self.op[0] in 'cn': - return self.op + " " + transform(self.expr) + return self.op + ' ' + transform(self.expr) else: return self.op + transform(self.expr) def get_id(self, version: int) -> str: return _id_operator_unary_v2[self.op] + self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.op[0] in 'cn': signode += addnodes.desc_sig_keyword(self.op, self.op) signode += addnodes.desc_sig_space() @@ -947,18 +1015,20 @@ def __hash__(self) -> int: return hash(self.identifier) def _stringify(self, transform: StringifyTransform) -> str: - return "sizeof...(" + transform(self.identifier) + ")" + return 'sizeof...(' + transform(self.identifier) + ')' def get_id(self, version: int) -> str: return 'sZ' + self.identifier.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') signode += addnodes.desc_sig_punctuation('...', '...') signode += addnodes.desc_sig_punctuation('(', '(') - self.identifier.describe_signature(signode, 'markType', env, - symbol=symbol, prefix="", templateArgs="") + self.identifier.describe_signature( + signode, 'markType', env, symbol=symbol, prefix='', templateArgs='' + ) signode += addnodes.desc_sig_punctuation(')', ')') @@ -975,13 +1045,14 @@ def __hash__(self) -> int: return hash(self.typ) def _stringify(self, transform: StringifyTransform) -> str: - return "sizeof(" + transform(self.typ) + ")" + return 'sizeof(' + transform(self.typ) + ')' def get_id(self, version: int) -> str: return 'st' + self.typ.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) @@ -1001,13 +1072,14 @@ def __hash__(self) -> int: return hash(self.expr) def _stringify(self, transform: StringifyTransform) -> str: - return "sizeof " + transform(self.expr) + return 'sizeof ' + transform(self.expr) def get_id(self, version: int) -> str: return 'sz' + self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('sizeof', 'sizeof') signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -1026,13 +1098,14 @@ def __hash__(self) -> int: return hash(self.typ) def _stringify(self, transform: StringifyTransform) -> str: - return "alignof(" + transform(self.typ) + ")" + return 'alignof(' + transform(self.typ) + ')' def get_id(self, version: int) -> str: return 'at' + self.typ.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('alignof', 'alignof') signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) @@ -1057,8 +1130,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: return 'nx' + self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('noexcept', 'noexcept') signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) @@ -1066,8 +1140,13 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTNewExpr(ASTExpression): - def __init__(self, rooted: bool, isNewTypeId: bool, typ: ASTType, - initList: ASTParenExprList | ASTBracedInitList) -> None: + def __init__( + self, + rooted: bool, + isNewTypeId: bool, + typ: ASTType, + initList: ASTParenExprList | ASTBracedInitList, + ) -> None: self.rooted = rooted self.isNewTypeId = isNewTypeId self.typ = typ @@ -1112,8 +1191,9 @@ def get_id(self, version: int) -> str: res.append('E') return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.rooted: signode += addnodes.desc_sig_punctuation('::', '::') signode += addnodes.desc_sig_keyword('new', 'new') @@ -1157,13 +1237,14 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: if self.array: - id = "da" + id = 'da' else: - id = "dl" + id = 'dl' return id + self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.rooted: signode += addnodes.desc_sig_punctuation('::', '::') signode += addnodes.desc_sig_keyword('delete', 'delete') @@ -1177,6 +1258,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Other expressions ################################################################################ + class ASTCastExpr(ASTExpression): def __init__(self, typ: ASTType, expr: ASTExpression) -> None: self.typ = typ @@ -1185,10 +1267,7 @@ def __init__(self, typ: ASTType, expr: ASTExpression) -> None: def __eq__(self, other: object) -> bool: if not isinstance(other, ASTCastExpr): return NotImplemented - return ( - self.typ == other.typ - and self.expr == other.expr - ) + return self.typ == other.typ and self.expr == other.expr def __hash__(self) -> int: return hash((self.typ, self.expr)) @@ -1203,8 +1282,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: return 'cv' + self.typ.get_id(version) + self.expr.get_id(version) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_punctuation('(', '(') self.typ.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_punctuation(')', ')') @@ -1221,10 +1301,7 @@ def __init__(self, exprs: list[ASTExpression], ops: list[str]) -> None: def __eq__(self, other: object) -> bool: if not isinstance(other, ASTBinOpExpr): return NotImplemented - return ( - self.exprs == other.exprs - and self.ops == other.ops - ) + return self.exprs == other.exprs and self.ops == other.ops def __hash__(self) -> int: return hash((self.exprs, self.ops)) @@ -1248,8 +1325,9 @@ def get_id(self, version: int) -> str: res.append(self.exprs[-1].get_id(version)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): signode += addnodes.desc_sig_space() @@ -1263,8 +1341,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTConditionalExpr(ASTExpression): - def __init__(self, ifExpr: ASTExpression, thenExpr: ASTExpression, - elseExpr: ASTExpression) -> None: + def __init__( + self, ifExpr: ASTExpression, thenExpr: ASTExpression, elseExpr: ASTExpression + ) -> None: self.ifExpr = ifExpr self.thenExpr = thenExpr self.elseExpr = elseExpr @@ -1299,8 +1378,9 @@ def get_id(self, version: int) -> str: res.append(self.elseExpr.get_id(version)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.ifExpr.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_space() signode += addnodes.desc_sig_operator('?', '?') @@ -1313,8 +1393,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTBracedInitList(ASTBase): - def __init__(self, exprs: list[ASTExpression | ASTBracedInitList], - trailingComma: bool) -> None: + def __init__( + self, exprs: list[ASTExpression | ASTBracedInitList], trailingComma: bool + ) -> None: self.exprs = exprs self.trailingComma = trailingComma @@ -1327,15 +1408,16 @@ def __hash__(self) -> int: return hash((self.exprs, self.trailingComma)) def get_id(self, version: int) -> str: - return "il%sE" % ''.join(e.get_id(version) for e in self.exprs) + return 'il%sE' % ''.join(e.get_id(version) for e in self.exprs) def _stringify(self, transform: StringifyTransform) -> str: exprs = ', '.join(transform(e) for e in self.exprs) trailing_comma = ',' if self.trailingComma else '' return f'{{{exprs}{trailing_comma}}}' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('{', '{') first = True @@ -1352,8 +1434,12 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTAssignmentExpr(ASTExpression): - def __init__(self, leftExpr: ASTExpression, op: str, - rightExpr: ASTExpression | ASTBracedInitList) -> None: + def __init__( + self, + leftExpr: ASTExpression, + op: str, + rightExpr: ASTExpression | ASTBracedInitList, + ) -> None: self.leftExpr = leftExpr self.op = op self.rightExpr = rightExpr @@ -1387,8 +1473,9 @@ def get_id(self, version: int) -> str: res.append(self.rightExpr.get_id(version)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.leftExpr.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_space() if ord(self.op[0]) >= ord('a') and ord(self.op[0]) <= ord('z'): @@ -1424,8 +1511,9 @@ def get_id(self, version: int) -> str: res.append(self.exprs[-1].get_id(version)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.exprs[0].describe_signature(signode, mode, env, symbol) for i in range(1, len(self.exprs)): signode += addnodes.desc_sig_punctuation(',', ',') @@ -1451,8 +1539,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: return str(self.expr) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += nodes.literal(self.expr, self.expr) @@ -1463,6 +1552,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Things for ASTNestedName ################################################################################ + class ASTOperator(ASTBase): is_anonymous: ClassVar[Literal[False]] = False @@ -1481,14 +1571,25 @@ def is_operator(self) -> bool: def get_id(self, version: int) -> str: raise NotImplementedError - def _describe_identifier(self, signode: TextElement, identnode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def _describe_identifier( + self, + signode: TextElement, + identnode: TextElement, + env: BuildEnvironment, + symbol: Symbol, + ) -> None: """Render the prefix into signode, and the last part into identnode.""" raise NotImplementedError - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, prefix: str, templateArgs: str, - symbol: Symbol) -> None: + def describe_signature( + self, + signode: TextElement, + mode: str, + env: BuildEnvironment, + prefix: str, + templateArgs: str, + symbol: Symbol, + ) -> None: verify_description_mode(mode) if mode == 'lastIsName': main_name = addnodes.desc_name() @@ -1496,10 +1597,14 @@ def describe_signature(self, signode: TextElement, mode: str, signode += main_name elif mode == 'markType': target_text = prefix + str(self) + templateArgs - pnode = addnodes.pending_xref('', refdomain='cpp', - reftype='identifier', - reftarget=target_text, modname=None, - classname=None) + pnode = addnodes.pending_xref( + '', + refdomain='cpp', + reftype='identifier', + reftarget=target_text, + modname=None, + classname=None, + ) pnode['cpp:parent_key'] = symbol.get_lookup_key() # Render the identifier part, but collapse it into a string # and make that the a link to this operator. @@ -1536,20 +1641,27 @@ def get_id(self, version: int) -> str: else: ids = _id_operator_v2 if self.op not in ids: - raise Exception('Internal error: Built-in operator "%s" can not ' - 'be mapped to an id.' % self.op) + raise Exception( + 'Internal error: Built-in operator "%s" can not ' + 'be mapped to an id.' % self.op + ) return ids[self.op] def _stringify(self, transform: StringifyTransform) -> str: - if self.op in {'new', 'new[]', 'delete', 'delete[]'} or self.op[0] in "abcnox": + if self.op in {'new', 'new[]', 'delete', 'delete[]'} or self.op[0] in 'abcnox': return 'operator ' + self.op else: return 'operator' + self.op - def _describe_identifier(self, signode: TextElement, identnode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def _describe_identifier( + self, + signode: TextElement, + identnode: TextElement, + env: BuildEnvironment, + symbol: Symbol, + ) -> None: signode += addnodes.desc_sig_keyword('operator', 'operator') - if self.op in {'new', 'new[]', 'delete', 'delete[]'} or self.op[0] in "abcnox": + if self.op in {'new', 'new[]', 'delete', 'delete[]'} or self.op[0] in 'abcnox': signode += addnodes.desc_sig_space() identnode += addnodes.desc_sig_operator(self.op, self.op) @@ -1574,8 +1686,13 @@ def get_id(self, version: int) -> str: def _stringify(self, transform: StringifyTransform) -> str: return 'operator""' + transform(self.identifier) - def _describe_identifier(self, signode: TextElement, identnode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def _describe_identifier( + self, + signode: TextElement, + identnode: TextElement, + env: BuildEnvironment, + symbol: Symbol, + ) -> None: signode += addnodes.desc_sig_keyword('operator', 'operator') signode += addnodes.desc_sig_literal_string('""', '""') self.identifier.describe_signature(identnode, 'markType', env, '', '', symbol) @@ -1605,8 +1722,13 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_name_no_template(self) -> str: return str(self) - def _describe_identifier(self, signode: TextElement, identnode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def _describe_identifier( + self, + signode: TextElement, + identnode: TextElement, + env: BuildEnvironment, + symbol: Symbol, + ) -> None: signode += addnodes.desc_sig_keyword('operator', 'operator') signode += addnodes.desc_sig_space() self.type.describe_signature(identnode, 'markType', env, symbol) @@ -1634,15 +1756,17 @@ def get_id(self, version: int) -> str: return 'X' + str(self) + 'E' return 'X' + self.value.get_id(version) + 'E' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.value.describe_signature(signode, mode, env, symbol) class ASTTemplateArgs(ASTBase): - def __init__(self, args: list[ASTType | ASTTemplateArgConstant], - packExpansion: bool) -> None: + def __init__( + self, args: list[ASTType | ASTTemplateArgConstant], packExpansion: bool + ) -> None: assert args is not None self.args = args self.packExpansion = packExpansion @@ -1682,8 +1806,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res += '...' return '<' + res + '>' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('<', '<') first = True @@ -1701,12 +1826,14 @@ def describe_signature(self, signode: TextElement, mode: str, # Main part of declarations ################################################################################ + class ASTTrailingTypeSpec(ASTBase): def get_id(self, version: int) -> str: raise NotImplementedError(repr(self)) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: raise NotImplementedError(repr(self)) @@ -1744,11 +1871,13 @@ def get_id(self, version: int) -> str: raise Exception( 'Semi-internal error: Fundamental type "%s" can not be mapped ' 'to an ID. Is it a true fundamental type? If not so, the ' - 'parser should have rejected it.' % txt) + 'parser should have rejected it.' % txt + ) return _id_fundamental_v2[txt] - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: first = True for n in self.names: if not first: @@ -1773,8 +1902,9 @@ def get_id(self, version: int) -> str: raise NoOldIdError return 'Dc' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('decltype', 'decltype') signode += addnodes.desc_sig_punctuation('(', '(') signode += addnodes.desc_sig_keyword('auto', 'auto') @@ -1799,10 +1929,11 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_id(self, version: int) -> str: if version == 1: raise NoOldIdError - return 'DT' + self.expr.get_id(version) + "E" + return 'DT' + self.expr.get_id(version) + 'E' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('decltype', 'decltype') signode += addnodes.desc_sig_punctuation('(', '(') self.expr.describe_signature(signode, mode, env, symbol) @@ -1810,8 +1941,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTTrailingTypeSpecName(ASTTrailingTypeSpec): - def __init__(self, prefix: str, nestedName: ASTNestedName, - placeholderType: str | None) -> None: + def __init__( + self, prefix: str, nestedName: ASTNestedName, placeholderType: str | None + ) -> None: self.prefix = prefix self.nestedName = nestedName self.placeholderType = placeholderType @@ -1846,8 +1978,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(self.placeholderType) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.prefix: signode += addnodes.desc_sig_keyword(self.prefix, self.prefix) signode += addnodes.desc_sig_space() @@ -1866,8 +1999,11 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTFunctionParameter(ASTBase): - def __init__(self, arg: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit, - ellipsis: bool = False) -> None: + def __init__( + self, + arg: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit, + ellipsis: bool = False, + ) -> None: self.arg = arg self.ellipsis = ellipsis @@ -1880,7 +2016,7 @@ def __hash__(self) -> int: return hash((self.arg, self.ellipsis)) def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: # this is not part of the normal name mangling in C++ if symbol: @@ -1898,8 +2034,9 @@ def _stringify(self, transform: StringifyTransform) -> str: else: return transform(self.arg) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) if self.ellipsis: signode += addnodes.desc_sig_punctuation('...', '...') @@ -1924,8 +2061,9 @@ def _stringify(self, transform: StringifyTransform) -> str: return 'noexcept(' + transform(self.expr) + ')' return 'noexcept' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('noexcept', 'noexcept') if self.expr: signode += addnodes.desc_sig_punctuation('(', '(') @@ -1934,11 +2072,19 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTParametersQualifiers(ASTBase): - def __init__(self, args: list[ASTFunctionParameter], volatile: bool, const: bool, - refQual: str | None, exceptionSpec: ASTNoexceptSpec, - trailingReturn: ASTType, - override: bool, final: bool, attrs: ASTAttributeList, - initializer: str | None) -> None: + def __init__( + self, + args: list[ASTFunctionParameter], + volatile: bool, + const: bool, + refQual: str | None, + exceptionSpec: ASTNoexceptSpec, + trailingReturn: ASTType, + override: bool, + final: bool, + attrs: ASTAttributeList, + initializer: str | None, + ) -> None: self.args = args self.volatile = volatile self.const = const @@ -1968,8 +2114,16 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: return hash(( - self.args, self.volatile, self.const, self.refQual, self.exceptionSpec, - self.trailingReturn, self.override, self.final, self.attrs, self.initializer + self.args, + self.volatile, + self.const, + self.refQual, + self.exceptionSpec, + self.trailingReturn, + self.override, + self.final, + self.attrs, + self.initializer, )) @property @@ -2037,8 +2191,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(self.initializer) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) multi_line_parameter_list = False test_node: Element = signode @@ -2046,7 +2201,9 @@ def describe_signature(self, signode: TextElement, mode: str, if not isinstance(test_node, addnodes.desc_signature): test_node = test_node.parent continue - multi_line_parameter_list = test_node.get('multi_line_parameter_list', False) + multi_line_parameter_list = test_node.get( + 'multi_line_parameter_list', False + ) break # only use the desc_parameterlist for the outer list, not for inner lists @@ -2126,8 +2283,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(')') return ''.join(res) - def describe_signature(self, signode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('explicit', 'explicit') if self.expr is not None: signode += addnodes.desc_sig_punctuation('(', '(') @@ -2136,11 +2294,21 @@ def describe_signature(self, signode: TextElement, class ASTDeclSpecsSimple(ASTBase): - def __init__(self, storage: str, threadLocal: bool, inline: bool, virtual: bool, - explicitSpec: ASTExplicitSpec | None, - consteval: bool, constexpr: bool, constinit: bool, - volatile: bool, const: bool, friend: bool, - attrs: ASTAttributeList) -> None: + def __init__( + self, + storage: str, + threadLocal: bool, + inline: bool, + virtual: bool, + explicitSpec: ASTExplicitSpec | None, + consteval: bool, + constexpr: bool, + constinit: bool, + volatile: bool, + const: bool, + friend: bool, + attrs: ASTAttributeList, + ) -> None: self.storage = storage self.threadLocal = threadLocal self.inline = inline @@ -2191,18 +2359,20 @@ def __hash__(self) -> int: def mergeWith(self, other: ASTDeclSpecsSimple) -> ASTDeclSpecsSimple: if not other: return self - return ASTDeclSpecsSimple(self.storage or other.storage, - self.threadLocal or other.threadLocal, - self.inline or other.inline, - self.virtual or other.virtual, - self.explicitSpec or other.explicitSpec, - self.consteval or other.consteval, - self.constexpr or other.constexpr, - self.constinit or other.constinit, - self.volatile or other.volatile, - self.const or other.const, - self.friend or other.friend, - self.attrs + other.attrs) + return ASTDeclSpecsSimple( + self.storage or other.storage, + self.threadLocal or other.threadLocal, + self.inline or other.inline, + self.virtual or other.virtual, + self.explicitSpec or other.explicitSpec, + self.consteval or other.consteval, + self.constexpr or other.constexpr, + self.constinit or other.constinit, + self.volatile or other.volatile, + self.const or other.const, + self.friend or other.friend, + self.attrs + other.attrs, + ) def _stringify(self, transform: StringifyTransform) -> str: res: list[str] = [] @@ -2232,8 +2402,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append('const') return ' '.join(res) - def describe_signature(self, signode: TextElement, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, env: BuildEnvironment, symbol: Symbol + ) -> None: self.attrs.describe_signature(signode) add_space = len(self.attrs) != 0 @@ -2271,9 +2442,13 @@ def _add(signode: TextElement, text: str) -> bool: class ASTDeclSpecs(ASTBase): - def __init__(self, outer: str, - leftSpecs: ASTDeclSpecsSimple, rightSpecs: ASTDeclSpecsSimple, - trailing: ASTTrailingTypeSpec) -> 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 @@ -2325,17 +2500,18 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(l) if self.trailingTypeSpec: if len(res) > 0: - res.append(" ") + res.append(' ') res.append(transform(self.trailingTypeSpec)) r = str(self.rightSpecs) if len(r) > 0: if len(res) > 0: - res.append(" ") + res.append(' ') res.append(r) - return "".join(res) + return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) num_children = len(signode) self.leftSpecs.describe_signature(signode, env, symbol) @@ -2345,8 +2521,7 @@ def describe_signature(self, signode: TextElement, mode: str, if add_space: signode += addnodes.desc_sig_space() num_children = len(signode) - self.trailingTypeSpec.describe_signature(signode, mode, env, - symbol=symbol) + self.trailingTypeSpec.describe_signature(signode, mode, env, symbol=symbol) add_space = len(signode) != num_children if len(str(self.rightSpecs)) > 0: @@ -2358,6 +2533,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Declarator ################################################################################ + class ASTArray(ASTBase): def __init__(self, size: ASTExpression) -> None: self.size = size @@ -2389,8 +2565,9 @@ def get_id(self, version: int) -> str: else: return 'A_' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('[', '[') if self.size: @@ -2437,15 +2614,19 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: raise NotImplementedError(repr(self)) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + 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: + def __init__( + self, + declId: ASTNestedName, + arrayOps: list[ASTArray], + paramQual: ASTParametersQualifiers, + ) -> None: self.declId = declId self.arrayOps = arrayOps self.paramQual = paramQual @@ -2487,7 +2668,7 @@ 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) + 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: @@ -2530,8 +2711,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.paramQual)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + 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) @@ -2580,12 +2762,13 @@ def _stringify(self, transform: StringifyTransform) -> str: res = [] if self.declId: res.append(transform(self.declId)) - res.append(" : ") + res.append(' : ') res.append(transform(self.size)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + 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) @@ -2596,8 +2779,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTDeclaratorPtr(ASTDeclarator): - def __init__(self, next: ASTDeclarator, volatile: bool, const: bool, - attrs: ASTAttributeList) -> None: + def __init__( + self, next: ASTDeclarator, volatile: bool, const: bool, attrs: ASTAttributeList + ) -> None: assert next self.next = next self.volatile = volatile @@ -2694,8 +2878,9 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: return self.next.is_function_type() - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('*', '*') self.attrs.describe_signature(signode) @@ -2704,6 +2889,7 @@ def describe_signature(self, signode: TextElement, mode: str, def _add_anno(signode: TextElement, text: str) -> None: signode += addnodes.desc_sig_keyword(text, text) + if self.volatile: _add_anno(signode, 'volatile') if self.const: @@ -2781,8 +2967,9 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: return self.next.is_function_type() - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('&', '&') self.attrs.describe_signature(signode) @@ -2853,8 +3040,9 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: return self.next.is_function_type() - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('...', '...') if self.next.name: @@ -2863,8 +3051,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTDeclaratorMemPtr(ASTDeclarator): - def __init__(self, className: ASTNestedName, - const: bool, volatile: bool, next: ASTDeclarator) -> None: + def __init__( + self, className: ASTNestedName, const: bool, volatile: bool, next: ASTDeclarator + ) -> None: assert className assert next self.className = className @@ -2955,8 +3144,9 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: return self.next.is_function_type() - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.className.describe_signature(signode, 'markType', env, symbol) signode += addnodes.desc_sig_punctuation('::', '::') @@ -2964,6 +3154,7 @@ def describe_signature(self, signode: TextElement, mode: str, def _add_anno(signode: TextElement, text: str) -> None: signode += addnodes.desc_sig_keyword(text, text) + if self.volatile: _add_anno(signode, 'volatile') if self.const: @@ -3030,10 +3221,12 @@ def get_param_id(self, version: int) -> str: # only the parameters (if any) def get_ptr_suffix_id(self, version: int) -> str: if version == 1: raise NoOldIdError # TODO: was this implemented before? - return self.next.get_ptr_suffix_id(version) + \ - self.inner.get_ptr_suffix_id(version) - return self.inner.get_ptr_suffix_id(version) + \ - self.next.get_ptr_suffix_id(version) + ptr_suffix_id_next = self.next.get_ptr_suffix_id(version) + ptr_suffix_id_inner = self.inner.get_ptr_suffix_id(version) + return ptr_suffix_id_next + ptr_suffix_id_inner + ptr_suffix_id_inner = self.inner.get_ptr_suffix_id(version) + ptr_suffix_id_next = self.next.get_ptr_suffix_id(version) + return ptr_suffix_id_inner + ptr_suffix_id_next def get_type_id(self, version: int, returnTypeId: str) -> str: assert version >= 2 @@ -3044,18 +3237,20 @@ def get_type_id(self, version: int, returnTypeId: str) -> str: def is_function_type(self) -> bool: return self.inner.is_function_type() - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('(', '(') self.inner.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_punctuation(')', ')') - self.next.describe_signature(signode, "noneIsName", env, symbol) + self.next.describe_signature(signode, 'noneIsName', env, symbol) # Type and initializer stuff ############################################################################################## + class ASTPackExpansionExpr(ASTExpression): def __init__(self, expr: ASTExpression | ASTBracedInitList) -> None: self.expr = expr @@ -3075,8 +3270,9 @@ def get_id(self, version: int) -> str: id = self.expr.get_id(version) return 'sp' + id - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.expr.describe_signature(signode, mode, env, symbol) signode += addnodes.desc_sig_punctuation('...', '...') @@ -3094,14 +3290,15 @@ def __hash__(self) -> int: return hash(self.exprs) def get_id(self, version: int) -> str: - return "pi%sE" % ''.join(e.get_id(version) for e in self.exprs) + return 'pi%sE' % ''.join(e.get_id(version) for e in self.exprs) def _stringify(self, transform: StringifyTransform) -> str: exprs = [transform(e) for e in self.exprs] return '(%s)' % ', '.join(exprs) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) signode += addnodes.desc_sig_punctuation('(', '(') first = True @@ -3116,8 +3313,9 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTInitializer(ASTBase): - def __init__(self, value: ASTExpression | ASTBracedInitList, - hasAssign: bool = True) -> None: + def __init__( + self, value: ASTExpression | ASTBracedInitList, hasAssign: bool = True + ) -> None: self.value = value self.hasAssign = hasAssign @@ -3136,8 +3334,9 @@ def _stringify(self, transform: StringifyTransform) -> str: else: return val - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) if self.hasAssign: signode += addnodes.desc_sig_space() @@ -3181,8 +3380,9 @@ def function_params(self) -> list[ASTFunctionParameter]: def trailingReturn(self) -> ASTType: return self.decl.trailingReturn - def get_id(self, version: int, objectType: str | None = None, - symbol: Symbol | None = None) -> str: + def get_id( + self, version: int, objectType: str | None = None, symbol: Symbol | None = None + ) -> str: if version == 1: res = [] if objectType: # needs the name @@ -3190,9 +3390,10 @@ def get_id(self, version: int, objectType: str | None = None, res.append(symbol.get_full_nested_name().get_id(version)) res.append(self.decl.get_param_id(version)) res.append(self.decl.get_modifiers_id(version)) - if (self.declSpecs.leftSpecs.constexpr or - (self.declSpecs.rightSpecs and - self.declSpecs.rightSpecs.constexpr)): + if self.declSpecs.leftSpecs.constexpr or ( + self.declSpecs.rightSpecs + and self.declSpecs.rightSpecs.constexpr + ): res.append('CE') elif objectType == 'type': # just the name res.append(symbol.get_full_nested_name().get_id(version)) @@ -3250,12 +3451,12 @@ def get_type_declaration_prefix(self) -> str: else: return 'type' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.declSpecs.describe_signature(signode, 'markType', env, symbol) - if (self.decl.require_space_after_declSpecs() and - len(str(self.declSpecs)) > 0): + if self.decl.require_space_after_declSpecs() and len(str(self.declSpecs)) > 0: signode += addnodes.desc_sig_space() # for parameters that don't really declare new names we get 'markType', # this should not be propagated, but be 'noneIsName'. @@ -3287,7 +3488,7 @@ def isPack(self) -> bool: return self.type.isPack def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: # this is not part of the normal name mangling in C++ assert version >= 2 @@ -3300,12 +3501,13 @@ def get_id( def _stringify(self, transform: StringifyTransform) -> str: res = transform(self.type) if self.init: - res += " = " + res += ' = ' res += transform(self.init) return res - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.type.describe_signature(signode, mode, env, symbol) if self.init: signode += addnodes.desc_sig_space() @@ -3335,13 +3537,17 @@ def name(self) -> ASTNestedName: def isPack(self) -> bool: return self.type.isPack - def get_id(self, version: int, objectType: str | None = None, - symbol: Symbol | None = None) -> str: + def get_id( + self, version: int, objectType: str | None = None, symbol: Symbol | None = None + ) -> str: if objectType != 'member': return self.type.get_id(version, objectType) if version == 1: - return (symbol.get_full_nested_name().get_id(version) + '__' + - self.type.get_id(version)) + return ( + symbol.get_full_nested_name().get_id(version) + + '__' + + self.type.get_id(version) + ) return symbol.get_full_nested_name().get_id(version) def _stringify(self, transform: StringifyTransform) -> str: @@ -3351,8 +3557,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.init)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.type.describe_signature(signode, mode, env, symbol) if self.init: @@ -3372,8 +3579,9 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: return hash((self.name, self.type)) - def get_id(self, version: int, objectType: str | None = None, - symbol: Symbol | None = None) -> str: + def get_id( + self, version: int, objectType: str | None = None, symbol: Symbol | None = None + ) -> str: if version == 1: raise NoOldIdError return symbol.get_full_nested_name().get_id(version) @@ -3389,8 +3597,9 @@ def _stringify(self, transform: StringifyTransform) -> str: def get_type_declaration_prefix(self) -> str: return 'using' - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.name.describe_signature(signode, mode, env, symbol=symbol) if self.type: @@ -3403,6 +3612,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Other declarations ############################################################################################## + class ASTConcept(ASTBase): def __init__(self, nestedName: ASTNestedName, initializer: ASTInitializer) -> None: self.nestedName = nestedName @@ -3411,7 +3621,10 @@ def __init__(self, nestedName: ASTNestedName, initializer: ASTInitializer) -> No def __eq__(self, other: object) -> bool: if not isinstance(other, ASTConcept): return NotImplemented - return self.nestedName == other.nestedName and self.initializer == other.initializer + return ( + self.nestedName == other.nestedName + and self.initializer == other.initializer + ) def __hash__(self) -> int: return hash((self.nestedName, self.initializer)) @@ -3420,8 +3633,9 @@ def __hash__(self) -> int: def name(self) -> ASTNestedName: return self.nestedName - def get_id(self, version: int, objectType: str | None = None, - symbol: Symbol | None = None) -> str: + def get_id( + self, version: int, objectType: str | None = None, symbol: Symbol | None = None + ) -> str: if version == 1: raise NoOldIdError return symbol.get_full_nested_name().get_id(version) @@ -3432,16 +3646,18 @@ def _stringify(self, transform: StringifyTransform) -> str: res += transform(self.initializer) return res - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.nestedName.describe_signature(signode, mode, env, symbol) if self.initializer: self.initializer.describe_signature(signode, mode, env, symbol) class ASTBaseClass(ASTBase): - def __init__(self, name: ASTNestedName, visibility: str, - virtual: bool, pack: bool) -> None: + def __init__( + self, name: ASTNestedName, visibility: str, virtual: bool, pack: bool + ) -> None: self.name = name self.visibility = visibility self.virtual = virtual @@ -3472,12 +3688,12 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append('...') return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) if self.visibility is not None: - signode += addnodes.desc_sig_keyword(self.visibility, - self.visibility) + signode += addnodes.desc_sig_keyword(self.visibility, self.visibility) signode += addnodes.desc_sig_space() if self.virtual: signode += addnodes.desc_sig_keyword('virtual', 'virtual') @@ -3488,8 +3704,13 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTClass(ASTBase): - def __init__(self, name: ASTNestedName, final: bool, bases: list[ASTBaseClass], - attrs: ASTAttributeList) -> None: + def __init__( + self, + name: ASTNestedName, + final: bool, + bases: list[ASTBaseClass], + attrs: ASTAttributeList, + ) -> None: self.name = name self.final = final self.bases = bases @@ -3529,8 +3750,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(b)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.attrs.describe_signature(signode) if len(self.attrs) != 0: @@ -3577,8 +3799,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.name)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.attrs.describe_signature(signode) if len(self.attrs) != 0: @@ -3587,8 +3810,13 @@ def describe_signature(self, signode: TextElement, mode: str, class ASTEnum(ASTBase): - def __init__(self, name: ASTNestedName, scoped: str, underlyingType: ASTType, - attrs: ASTAttributeList) -> None: + def __init__( + self, + name: ASTNestedName, + scoped: str, + underlyingType: ASTType, + attrs: ASTAttributeList, + ) -> None: self.name = name self.scoped = scoped self.underlyingType = underlyingType @@ -3626,8 +3854,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.underlyingType)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) # self.scoped has been done by the CPPEnumObject self.attrs.describe_signature(signode) @@ -3638,13 +3867,15 @@ def describe_signature(self, signode: TextElement, mode: str, signode += addnodes.desc_sig_space() signode += addnodes.desc_sig_punctuation(':', ':') signode += addnodes.desc_sig_space() - self.underlyingType.describe_signature(signode, 'noneIsName', - env, symbol=symbol) + self.underlyingType.describe_signature( + signode, 'noneIsName', env, symbol=symbol + ) class ASTEnumerator(ASTBase): - def __init__(self, name: ASTNestedName, init: ASTInitializer | None, - attrs: ASTAttributeList) -> None: + def __init__( + self, name: ASTNestedName, init: ASTInitializer | None, attrs: ASTAttributeList + ) -> None: self.name = name self.init = init self.attrs = attrs @@ -3676,8 +3907,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.init)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: verify_description_mode(mode) self.name.describe_signature(signode, mode, env, symbol) if len(self.attrs) != 0: @@ -3694,6 +3926,7 @@ def describe_signature(self, signode: TextElement, mode: str, # Parameters ################################################################################ + class ASTTemplateParam(ASTBase): def get_identifier(self) -> ASTIdentifier: raise NotImplementedError(repr(self)) @@ -3701,8 +3934,9 @@ def get_identifier(self) -> ASTIdentifier: def get_id(self, version: int) -> str: raise NotImplementedError(repr(self)) - def describe_signature(self, parentNode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, parentNode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: raise NotImplementedError(repr(self)) @property @@ -3715,8 +3949,9 @@ def name(self) -> ASTNestedName: class ASTTemplateKeyParamPackIdDefault(ASTTemplateParam): - def __init__(self, key: str, identifier: ASTIdentifier, - parameterPack: bool, default: ASTType) -> None: + def __init__( + self, key: str, identifier: ASTIdentifier, parameterPack: bool, default: ASTType + ) -> None: assert key if parameterPack: assert default is None @@ -3766,8 +4001,9 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.default)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword(self.key, self.key) if self.parameterPack: if self.identifier: @@ -3810,7 +4046,7 @@ def get_identifier(self) -> ASTIdentifier: return self.data.get_identifier() def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: # this is not part of the normal name mangling in C++ assert version >= 2 @@ -3823,14 +4059,16 @@ def get_id( def _stringify(self, transform: StringifyTransform) -> str: return transform(self.data) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + 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: + def __init__( + self, nestedParams: ASTTemplateParams, data: ASTTemplateKeyParamPackIdDefault + ) -> None: assert nestedParams assert data self.nestedParams = nestedParams @@ -3839,10 +4077,7 @@ def __init__(self, nestedParams: ASTTemplateParams, def __eq__(self, other: object) -> bool: if not isinstance(other, ASTTemplateParamTemplateType): return NotImplemented - return ( - self.nestedParams == other.nestedParams - and self.data == other.data - ) + return self.nestedParams == other.nestedParams and self.data == other.data def __hash__(self) -> int: return hash((self.nestedParams, self.data)) @@ -3860,7 +4095,7 @@ def get_identifier(self) -> ASTIdentifier: return self.data.get_identifier() def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: assert version >= 2 # this is not part of the normal name mangling in C++ @@ -3873,17 +4108,20 @@ def get_id( 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: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.nestedParams.describe_signature(signode, 'noneIsName', env, symbol) signode += addnodes.desc_sig_space() self.data.describe_signature(signode, mode, env, symbol) class ASTTemplateParamNonType(ASTTemplateParam): - def __init__(self, - param: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit, - parameterPack: bool = False) -> None: + def __init__( + self, + param: ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit, + parameterPack: bool = False, + ) -> None: assert param self.param = param self.parameterPack = parameterPack @@ -3891,10 +4129,7 @@ def __init__(self, def __eq__(self, other: object) -> bool: if not isinstance(other, ASTTemplateParamNonType): return NotImplemented - return ( - self.param == other.param - and self.parameterPack == other.parameterPack - ) + return self.param == other.param and self.parameterPack == other.parameterPack def __hash__(self) -> int: return hash((self.param, self.parameterPack)) @@ -3921,7 +4156,7 @@ def get_identifier(self) -> ASTIdentifier: return None def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: assert version >= 2 # this is not part of the normal name mangling in C++ @@ -3940,16 +4175,18 @@ def _stringify(self, transform: StringifyTransform) -> str: res += '...' return res - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: self.param.describe_signature(signode, mode, env, symbol) if self.parameterPack: signode += addnodes.desc_sig_punctuation('...', '...') class ASTTemplateParams(ASTBase): - def __init__(self, params: list[ASTTemplateParam], - requiresClause: ASTRequiresClause | None) -> None: + def __init__( + self, params: list[ASTTemplateParam], requiresClause: ASTRequiresClause | None + ) -> None: assert params is not None self.params = params self.requiresClause = requiresClause @@ -3957,7 +4194,9 @@ def __init__(self, params: list[ASTTemplateParam], def __eq__(self, other: object) -> bool: if not isinstance(other, ASTTemplateParams): return NotImplemented - return self.params == other.params and self.requiresClause == other.requiresClause + return ( + self.params == other.params and self.requiresClause == other.requiresClause + ) def __hash__(self) -> int: return hash((self.params, self.requiresClause)) @@ -3965,25 +4204,26 @@ def __hash__(self) -> int: def get_id(self, version: int, excludeRequires: bool = False) -> str: assert version >= 2 res = [] - res.append("I") + res.append('I') res.extend(param.get_id(version) for param in self.params) - res.append("E") + res.append('E') if not excludeRequires and self.requiresClause: res.extend(['IQ', self.requiresClause.expr.get_id(version), 'E']) return ''.join(res) def _stringify(self, transform: StringifyTransform) -> str: res = [] - res.append("template<") - res.append(", ".join(transform(a) for a in self.params)) - res.append("> ") + res.append('template<') + res.append(', '.join(transform(a) for a in self.params)) + res.append('> ') if self.requiresClause is not None: res.append(transform(self.requiresClause)) - res.append(" ") + res.append(' ') return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: signode += addnodes.desc_sig_keyword('template', 'template') signode += addnodes.desc_sig_punctuation('<', '<') first = True @@ -3999,13 +4239,19 @@ def describe_signature(self, signode: TextElement, mode: str, self.requiresClause.describe_signature(signode, mode, env, symbol) def describe_signature_as_introducer( - self, parentNode: desc_signature, mode: str, env: BuildEnvironment, - symbol: Symbol, lineSpec: bool) -> None: + self, + parentNode: desc_signature, + mode: str, + env: BuildEnvironment, + symbol: Symbol, + lineSpec: bool, + ) -> None: def make_line(parent_node: desc_signature) -> addnodes.desc_signature_line: signode = addnodes.desc_signature_line() parent_node += signode signode.sphinx_line_type = 'templateParams' return signode + line_node = make_line(parentNode) line_node += addnodes.desc_sig_keyword('template', 'template') line_node += addnodes.desc_sig_punctuation('<', '<') @@ -4031,6 +4277,7 @@ def make_line(parent_node: desc_signature) -> addnodes.desc_signature_line: # Template introducers ################################################################################ + class ASTTemplateIntroductionParameter(ASTBase): def __init__(self, identifier: ASTIdentifier, parameterPack: bool) -> None: self.identifier = identifier @@ -4060,7 +4307,7 @@ def get_identifier(self) -> ASTIdentifier: return self.identifier def get_id( - self, version: int, objectType: str | None = None, symbol: Symbol | None = None, + self, version: int, objectType: str | None = None, symbol: Symbol | None = None ) -> str: assert version >= 2 # this is not part of the normal name mangling in C++ @@ -4089,16 +4336,18 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(transform(self.identifier)) return ''.join(res) - def describe_signature(self, signode: TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, signode: TextElement, mode: str, env: BuildEnvironment, symbol: Symbol + ) -> None: if self.parameterPack: signode += addnodes.desc_sig_punctuation('...', '...') self.identifier.describe_signature(signode, mode, env, '', '', symbol) class ASTTemplateIntroduction(ASTBase): - def __init__(self, concept: ASTNestedName, - params: list[ASTTemplateIntroductionParameter]) -> None: + def __init__( + self, concept: ASTNestedName, params: list[ASTTemplateIntroductionParameter] + ) -> None: assert len(params) > 0 self.concept = concept self.params = params @@ -4115,16 +4364,16 @@ def get_id(self, version: int) -> str: assert version >= 2 return ''.join([ # first do the same as a normal template parameter list - "I", + 'I', *(param.get_id(version) for param in self.params), - "E", + 'E', # let's use X expr E, which is otherwise for constant template args - "X", + 'X', self.concept.get_id(version), - "I", + 'I', *(param.get_id_as_arg(version) for param in self.params), - "E", - "E", + 'E', + 'E', ]) def _stringify(self, transform: StringifyTransform) -> str: @@ -4136,8 +4385,13 @@ def _stringify(self, transform: StringifyTransform) -> str: return ''.join(res) def describe_signature_as_introducer( - self, parentNode: desc_signature, mode: str, - env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None: + 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 @@ -4156,9 +4410,11 @@ def describe_signature_as_introducer( ################################################################################ + class ASTTemplateDeclarationPrefix(ASTBase): - def __init__(self, - templates: list[ASTTemplateParams | ASTTemplateIntroduction] | None) -> None: + def __init__( + self, templates: list[ASTTemplateParams | ASTTemplateIntroduction] | None + ) -> None: # templates is None means it's an explicit instantiation of a variable self.templates = templates @@ -4193,11 +4449,19 @@ def get_id_except_requires_clause_in_last(self, version: int) -> str: def _stringify(self, transform: StringifyTransform) -> str: return ''.join(map(transform, self.templates)) - def describe_signature(self, signode: desc_signature, mode: str, - env: BuildEnvironment, symbol: Symbol, lineSpec: bool) -> None: + 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) + t.describe_signature_as_introducer( + signode, 'lastIsName', env, symbol, lineSpec + ) class ASTRequiresClause(ASTBase): @@ -4215,8 +4479,13 @@ def __hash__(self) -> int: def _stringify(self, transform: StringifyTransform) -> str: return 'requires ' + transform(self.expr) - def describe_signature(self, signode: nodes.TextElement, mode: str, - env: BuildEnvironment, symbol: Symbol) -> None: + def describe_signature( + self, + signode: nodes.TextElement, + mode: str, + env: BuildEnvironment, + symbol: Symbol, + ) -> None: signode += addnodes.desc_sig_keyword('requires', 'requires') signode += addnodes.desc_sig_space() self.expr.describe_signature(signode, mode, env, symbol) @@ -4225,13 +4494,18 @@ def describe_signature(self, signode: nodes.TextElement, mode: str, ################################################################################ ################################################################################ + class ASTDeclaration(ASTBase): - def __init__(self, objectType: str, directiveType: str | None = None, - visibility: str | None = None, - templatePrefix: ASTTemplateDeclarationPrefix | None = None, - declaration: Any = None, - trailingRequiresClause: ASTRequiresClause | None = None, - semicolon: bool = False) -> None: + def __init__( + self, + objectType: str, + directiveType: str | None = None, + visibility: str | None = None, + templatePrefix: ASTTemplateDeclarationPrefix | None = None, + declaration: Any = None, + trailingRequiresClause: ASTRequiresClause | None = None, + semicolon: bool = False, + ) -> None: self.objectType = objectType self.directiveType = directiveType self.visibility = visibility @@ -4277,13 +4551,21 @@ def __hash__(self) -> int: )) def clone(self) -> ASTDeclaration: - template_prefix_clone = self.templatePrefix.clone() if self.templatePrefix else None - trailing_requires_clasue_clone = self.trailingRequiresClause.clone() \ - if self.trailingRequiresClause else None - return ASTDeclaration(self.objectType, self.directiveType, self.visibility, - template_prefix_clone, - self.declaration.clone(), trailing_requires_clasue_clone, - self.semicolon) + template_prefix_clone = ( + self.templatePrefix.clone() if self.templatePrefix else None + ) + trailing_requires_clasue_clone = ( + self.trailingRequiresClause.clone() if self.trailingRequiresClause else None + ) + return ASTDeclaration( + self.objectType, + self.directiveType, + self.visibility, + template_prefix_clone, + self.declaration.clone(), + trailing_requires_clasue_clone, + self.semicolon, + ) @property def name(self) -> ASTNestedName: @@ -4320,7 +4602,9 @@ def get_id(self, version: int, prefixed: bool = True) -> str: # in the template prefix, and still put it in the end. # As we now support trailing requires clauses we add that as if it was a conjunction. if self.templatePrefix is not None: - res.append(self.templatePrefix.get_id_except_requires_clause_in_last(version)) + res.append( + self.templatePrefix.get_id_except_requires_clause_in_last(version) + ) requires_clause_in_last = self.templatePrefix.get_requires_clause_in_last() else: requires_clause_in_last = None @@ -4347,7 +4631,7 @@ def get_newest_id(self) -> str: def _stringify(self, transform: StringifyTransform) -> str: res = [] - if self.visibility and self.visibility != "public": + if self.visibility and self.visibility != 'public': res.append(self.visibility) res.append(' ') if self.templatePrefix: @@ -4360,8 +4644,13 @@ def _stringify(self, transform: StringifyTransform) -> str: res.append(';') return ''.join(res) - def describe_signature(self, signode: desc_signature, mode: str, - env: BuildEnvironment, options: dict[str, bool]) -> None: + def describe_signature( + self, + signode: desc_signature, + mode: str, + env: BuildEnvironment, + options: dict[str, bool], + ) -> None: verify_description_mode(mode) assert self.symbol # The caller of the domain added a desc_signature node. @@ -4373,12 +4662,18 @@ def describe_signature(self, signode: desc_signature, mode: str, main_decl_node['add_permalink'] = not self.symbol.isRedeclaration if self.templatePrefix: - self.templatePrefix.describe_signature(signode, mode, env, - symbol=self.symbol, - lineSpec=options.get('tparam-line-spec')) + self.templatePrefix.describe_signature( + signode, + mode, + env, + symbol=self.symbol, + lineSpec=options.get('tparam-line-spec'), + ) signode += main_decl_node - if self.visibility and self.visibility != "public": - main_decl_node += addnodes.desc_sig_keyword(self.visibility, self.visibility) + if self.visibility and self.visibility != 'public': + main_decl_node += addnodes.desc_sig_keyword( + self.visibility, self.visibility + ) main_decl_node += addnodes.desc_sig_space() if self.objectType == 'type': prefix = self.declaration.get_type_declaration_prefix() @@ -4391,7 +4686,9 @@ def describe_signature(self, signode: desc_signature, mode: str, pass elif self.objectType == 'class': assert self.directiveType in {'class', 'struct'} - main_decl_node += addnodes.desc_sig_keyword(self.directiveType, self.directiveType) + main_decl_node += addnodes.desc_sig_keyword( + self.directiveType, self.directiveType + ) main_decl_node += addnodes.desc_sig_space() elif self.objectType == 'union': main_decl_node += addnodes.desc_sig_keyword('union', 'union') @@ -4420,14 +4717,16 @@ def describe_signature(self, signode: desc_signature, mode: str, signode.append(trailing_req_node) last_decl_node = trailing_req_node self.trailingRequiresClause.describe_signature( - trailing_req_node, 'markType', env, self.symbol) + trailing_req_node, 'markType', env, self.symbol + ) if self.semicolon: last_decl_node += addnodes.desc_sig_punctuation(';', ';') class ASTNamespace(ASTBase): - def __init__(self, nestedName: ASTNestedName, - templatePrefix: ASTTemplateDeclarationPrefix) -> None: + def __init__( + self, nestedName: ASTNestedName, templatePrefix: ASTTemplateDeclarationPrefix + ) -> None: self.nestedName = nestedName self.templatePrefix = templatePrefix diff --git a/sphinx/domains/cpp/_ids.py b/sphinx/domains/cpp/_ids.py index ee8eb4920cd..a0410ca21df 100644 --- a/sphinx/domains/cpp/_ids.py +++ b/sphinx/domains/cpp/_ids.py @@ -254,13 +254,17 @@ import re -udl_identifier_re = re.compile(r''' - [a-zA-Z_][a-zA-Z0-9_]*\b # note, no word boundary in the beginning -''', re.VERBOSE) -_string_re = re.compile(r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" - r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.DOTALL) +udl_identifier_re = re.compile( + r'[a-zA-Z_][a-zA-Z0-9_]*\b' # note, no word boundary in the beginning +) +_string_re = re.compile( + r"[LuU8]?('([^'\\]*(?:\\.[^'\\]*)*)'" + r'|"([^"\\]*(?:\\.[^"\\]*)*)")', + re.DOTALL, +) _visibility_re = re.compile(r'\b(public|private|protected)\b') -_operator_re = re.compile(r''' +_operator_re = re.compile( + r""" \[\s*\] | \(\s*\) | \+\+ | -- @@ -269,33 +273,49 @@ | <=> | [!<>=/*%+|&^~-]=? | (\b(and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|xor|xor_eq)\b) -''', re.VERBOSE) -_fold_operator_re = re.compile(r''' + """, + re.VERBOSE, +) +_fold_operator_re = re.compile( + r""" ->\* | \.\* | \, | (<<|>>)=? | && | \|\| | != | [<>=/*%+|&^~-]=? -''', re.VERBOSE) + """, + re.VERBOSE, +) # see https://en.cppreference.com/w/cpp/keyword _keywords = [ - 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', - 'bool', 'break', 'case', 'catch', 'char', 'char8_t', 'char16_t', 'char32_t', - 'class', 'compl', 'concept', 'const', 'consteval', 'constexpr', 'constinit', - 'const_cast', 'continue', - 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', - 'enum', 'explicit', 'export', 'extern', 'false', 'float', 'for', 'friend', - 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', - 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', - 'private', 'protected', 'public', 'register', 'reinterpret_cast', - 'requires', 'return', 'short', 'signed', 'sizeof', 'static', - 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this', - 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', - 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', - 'while', 'xor', 'xor_eq', -] - - -_simple_type_specifiers_re = re.compile(r""" + 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'auto', + 'bitand', 'bitor', 'bool', 'break', + 'case', 'catch', 'class', 'compl', 'concept', 'continue', + 'char', 'char8_t', 'char16_t', 'char32_t', + 'const', 'const_cast', 'consteval', 'constexpr', 'constinit', + 'decltype', 'default', 'delete', 'do', 'double', 'dynamic_cast', + 'else', 'enum', 'explicit', 'export', 'extern', + 'false', 'float', 'for', 'friend', + 'goto', + 'if', 'inline', 'int', + 'long', + 'mutable', + 'namespace', 'new', 'noexcept', 'not', 'not_eq', 'nullptr', + 'operator', 'or', 'or_eq', + 'private', 'protected', 'public', + 'register', 'reinterpret_cast', 'requires', 'return', + 'short', 'signed', 'sizeof', 'static', + 'static_assert', 'static_cast', 'struct', 'switch', + 'template', 'this', 'thread_local', 'throw', + 'true', 'try', 'typedef', 'typeid', 'typename', + 'union', 'unsigned', 'using', + 'virtual', 'void', 'volatile', + 'wchar_t', 'while', + 'xor', 'xor_eq', +] # fmt: skip + + +_simple_type_specifiers_re = re.compile( + r""" \b( auto|void|bool |signed|unsigned @@ -307,7 +327,9 @@ |__float80|_Float64x|__float128|_Float128 # extension |_Complex|_Imaginary # extension )\b -""", re.VERBOSE) + """, + re.VERBOSE, +) _max_id = 4 _id_prefix = [None, '', '_CPPv2', '_CPPv3', '_CPPv4'] @@ -433,8 +455,10 @@ 'float': 'f', 'double': 'd', 'long double': 'e', - '__float80': 'e', '_Float64x': 'e', - '__float128': 'g', '_Float128': 'g', + '__float80': 'e', + '_Float64x': 'e', + '__float128': 'g', + '_Float128': 'g', '_Complex float': 'Cf', '_Complex double': 'Cd', '_Complex long double': 'Ce', @@ -456,38 +480,49 @@ # '-(unary)' : 'ng', # '&(unary)' : 'ad', # '*(unary)' : 'de', - '~': 'co', 'compl': 'co', + '~': 'co', + 'compl': 'co', '+': 'pl', '-': 'mi', '*': 'ml', '/': 'dv', '%': 'rm', - '&': 'an', 'bitand': 'an', - '|': 'or', 'bitor': 'or', - '^': 'eo', 'xor': 'eo', + '&': 'an', + 'bitand': 'an', + '|': 'or', + 'bitor': 'or', + '^': 'eo', + 'xor': 'eo', '=': 'aS', '+=': 'pL', '-=': 'mI', '*=': 'mL', '/=': 'dV', '%=': 'rM', - '&=': 'aN', 'and_eq': 'aN', - '|=': 'oR', 'or_eq': 'oR', - '^=': 'eO', 'xor_eq': 'eO', + '&=': 'aN', + 'and_eq': 'aN', + '|=': 'oR', + 'or_eq': 'oR', + '^=': 'eO', + 'xor_eq': 'eO', '<<': 'ls', '>>': 'rs', '<<=': 'lS', '>>=': 'rS', '==': 'eq', - '!=': 'ne', 'not_eq': 'ne', + '!=': 'ne', + 'not_eq': 'ne', '<': 'lt', '>': 'gt', '<=': 'le', '>=': 'ge', '<=>': 'ss', - '!': 'nt', 'not': 'nt', - '&&': 'aa', 'and': 'aa', - '||': 'oo', 'or': 'oo', + '!': 'nt', + 'not': 'nt', + '&&': 'aa', + 'and': 'aa', + '||': 'oo', + 'or': 'oo', '++': 'pp', '--': 'mm', ',': 'cm', @@ -505,12 +540,17 @@ '&': 'ad', '+': 'ps', '-': 'ng', - '!': 'nt', 'not': 'nt', - '~': 'co', 'compl': 'co', + '!': 'nt', + 'not': 'nt', + '~': 'co', + 'compl': 'co', } _id_char_from_prefix: dict[str | None, str] = { - None: 'c', 'u8': 'c', - 'u': 'Ds', 'U': 'Di', 'L': 'w', + None: 'c', + 'u8': 'c', + 'u': 'Ds', + 'U': 'Di', + 'L': 'w', } # these are ordered by preceedence _expression_bin_ops = [ @@ -526,9 +566,34 @@ ['*', '/', '%'], ['.*', '->*'], ] -_expression_unary_ops = ["++", "--", "*", "&", "+", "-", "!", "not", "~", "compl"] -_expression_assignment_ops = ["=", "*=", "/=", "%=", "+=", "-=", - ">>=", "<<=", "&=", "and_eq", "^=", "|=", "xor_eq", "or_eq"] +_expression_unary_ops = [ + '++', + '--', + '*', + '&', + '+', + '-', + '!', + 'not', + '~', + 'compl', +] +_expression_assignment_ops = [ + '=', + '*=', + '/=', + '%=', + '+=', + '-=', + '>>=', + '<<=', + '&=', + 'and_eq', + '^=', + '|=', + 'xor_eq', + 'or_eq', +] _id_explicit_cast = { 'dynamic_cast': 'dc', 'static_cast': 'sc', diff --git a/sphinx/domains/cpp/_parser.py b/sphinx/domains/cpp/_parser.py index de5303cd414..47bedcea238 100644 --- a/sphinx/domains/cpp/_parser.py +++ b/sphinx/domains/cpp/_parser.py @@ -153,7 +153,7 @@ def _parse_string(self) -> str: escape = False while True: if self.eof: - self.fail("Unexpected end during inside string.") + self.fail('Unexpected end during inside string.') elif self.current_char == '"' and not escape: self.pos += 1 break @@ -162,7 +162,7 @@ def _parse_string(self) -> str: else: escape = False self.pos += 1 - return self.definition[start_pos:self.pos] + return self.definition[start_pos : self.pos] def _parse_literal(self) -> ASTLiteral: # -> integer-literal @@ -191,16 +191,20 @@ def _udl(literal: ASTLiteral) -> ASTLiteral: pos = self.pos if self.match(float_literal_re): has_suffix = self.match(float_literal_suffix_re) - float_lit = ASTNumberLiteral(self.definition[pos:self.pos]) + float_lit = ASTNumberLiteral(self.definition[pos : self.pos]) if has_suffix: return float_lit else: return _udl(float_lit) - for regex in (binary_literal_re, hex_literal_re, - integer_literal_re, octal_literal_re): + for regex in ( + binary_literal_re, + hex_literal_re, + integer_literal_re, + octal_literal_re, + ): if self.match(regex): has_suffix = self.match(integers_literal_suffix_re) - int_lit = ASTNumberLiteral(self.definition[pos:self.pos]) + int_lit = ASTNumberLiteral(self.definition[pos : self.pos]) if has_suffix: return int_lit else: @@ -217,10 +221,14 @@ def _udl(literal: ASTLiteral) -> ASTLiteral: try: char_lit = ASTCharLiteral(prefix, data) except UnicodeDecodeError as e: - self.fail("Can not handle character literal. Internal error was: %s" % e) + self.fail( + 'Can not handle character literal. Internal error was: %s' % e + ) except UnsupportedMultiCharacterCharLiteral: - self.fail("Can not handle character literal" - " resulting in multiple decoded characters.") + self.fail( + 'Can not handle character literal' + ' resulting in multiple decoded characters.' + ) return _udl(char_lit) return None @@ -234,7 +242,7 @@ def _parse_fold_or_paren_expression(self) -> ASTExpression | None: return None self.pos += 1 self.skip_ws() - if self.skip_string_and_ws("..."): + if self.skip_string_and_ws('...'): # ( ... fold-operator cast-expression ) if not self.match(_fold_operator_re): self.fail("Expected fold operator after '...' in fold expression.") @@ -250,7 +258,9 @@ def _parse_fold_or_paren_expression(self) -> ASTExpression | None: left_expr = self._parse_cast_expression() self.skip_ws() if not self.match(_fold_operator_re): - self.fail("Expected fold operator after left expression in fold expression.") + self.fail( + 'Expected fold operator after left expression in fold expression.' + ) op = self.matched_text self.skip_ws() if not self.skip_string_and_ws('...'): @@ -264,10 +274,13 @@ def _parse_fold_or_paren_expression(self) -> ASTExpression | None: if not self.skip_string(')'): self.fail("Expected ')' in end of parenthesized expression.") except DefinitionError as e_expr: - raise self._make_multi_error([ - (e_fold, "If fold expression"), - (e_expr, "If parenthesized expression"), - ], "Error in fold expression or parenthesized expression.") from e_expr + raise self._make_multi_error( + [ + (e_fold, 'If fold expression'), + (e_expr, 'If parenthesized expression'), + ], + 'Error in fold expression or parenthesized expression.', + ) from e_expr return ASTParenExpr(res) # now it definitely is a fold expression if self.skip_string(')'): @@ -275,8 +288,10 @@ def _parse_fold_or_paren_expression(self) -> ASTExpression | None: if not self.match(_fold_operator_re): self.fail("Expected fold operator or ')' after '...' in fold expression.") if op != self.matched_text: - self.fail("Operators are different in binary fold: '%s' and '%s'." - % (op, self.matched_text)) + self.fail( + "Operators are different in binary fold: '%s' and '%s'." + % (op, self.matched_text) + ) right_expr = self._parse_cast_expression() self.skip_ws() if not self.skip_string(')'): @@ -295,7 +310,7 @@ def _parse_primary_expression(self) -> ASTExpression: if res is not None: return res self.skip_ws() - if self.skip_word("this"): + if self.skip_word('this'): return ASTThisLiteral() # TODO: try lambda expression res = self._parse_fold_or_paren_expression() @@ -306,9 +321,9 @@ def _parse_primary_expression(self) -> ASTExpression: return ASTIdExpression(nn) return None - def _parse_initializer_list(self, name: str, open: str, close: str, - ) -> tuple[list[ASTExpression | ASTBracedInitList], - bool]: + def _parse_initializer_list( + self, name: str, open: str, close: str + ) -> tuple[list[ASTExpression | ASTBracedInitList], bool]: # Parse open and close with the actual initializer-list in between # -> initializer-clause '...'[opt] # | initializer-list ',' initializer-clause '...'[opt] @@ -346,8 +361,9 @@ def _parse_paren_expression_list(self) -> ASTParenExprList: # # expression-list # -> initializer-list - exprs, trailing_comma = self._parse_initializer_list("parenthesized expression-list", - '(', ')') + exprs, trailing_comma = self._parse_initializer_list( + 'parenthesized expression-list', '(', ')' + ) if exprs is None: return None return ASTParenExprList(exprs) @@ -361,7 +377,9 @@ def _parse_initializer_clause(self) -> ASTExpression | ASTBracedInitList: def _parse_braced_init_list(self) -> ASTBracedInitList: # -> '{' initializer-list ','[opt] '}' # | '{' '}' - exprs, trailing_comma = self._parse_initializer_list("braced-init-list", '{', '}') + exprs, trailing_comma = self._parse_initializer_list( + 'braced-init-list', '{', '}' + ) if exprs is None: return None return ASTBracedInitList(exprs, trailing_comma) @@ -406,25 +424,26 @@ def _parse_postfix_expression(self) -> ASTPostfixExpr: cast = c break if cast is not None: - prefix_type = "cast" - if not self.skip_string("<"): + prefix_type = 'cast' + if not self.skip_string('<'): self.fail("Expected '<' after '%s'." % cast) typ = self._parse_type(False) self.skip_ws() - if not self.skip_string_and_ws(">"): + if not self.skip_string_and_ws('>'): self.fail("Expected '>' after type in '%s'." % cast) - if not self.skip_string("("): + if not self.skip_string('('): self.fail("Expected '(' in '%s'." % cast) def parser() -> ASTExpression: return self._parse_expression() + expr = self._parse_expression_fallback([')'], parser) self.skip_ws() - if not self.skip_string(")"): + if not self.skip_string(')'): self.fail("Expected ')' to end '%s'." % cast) prefix = ASTExplicitCast(cast, typ, expr) - elif self.skip_word_and_ws("typeid"): - prefix_type = "typeid" + elif self.skip_word_and_ws('typeid'): + prefix_type = 'typeid' if not self.skip_string_and_ws('('): self.fail("Expected '(' after 'typeid'.") pos = self.pos @@ -439,6 +458,7 @@ def parser() -> ASTExpression: def parser() -> ASTExpression: return self._parse_expression() + expr = self._parse_expression_fallback([')'], parser) prefix = ASTTypeId(expr, isType=False) if not self.skip_string(')'): @@ -446,10 +466,10 @@ def parser() -> ASTExpression: except DefinitionError as e_expr: self.pos = pos header = "Error in 'typeid(...)'." - header += " Expected type or expression." + header += ' Expected type or expression.' errors = [] - errors.append((e_type, "If type")) - errors.append((e_expr, "If expression")) + errors.append((e_type, 'If type')) + errors.append((e_expr, 'If expression')) raise self._make_multi_error(errors, header) from e_expr else: # a primary expression or a type pos = self.pos @@ -472,11 +492,11 @@ def parser() -> ASTExpression: self.fail("Expecting '(' or '{' after type in cast expression.") except DefinitionError as e_inner: self.pos = pos - header = "Error in postfix expression," - header += " expected primary expression or type." + header = 'Error in postfix expression,' + header += ' expected primary expression or type.' errors = [] - errors.append((e_outer, "If primary expression")) - errors.append((e_inner, "If type")) + errors.append((e_outer, 'If primary expression')) + errors.append((e_inner, 'If type')) raise self._make_multi_error(errors, header) from e_inner # and now parse postfixes @@ -554,7 +574,7 @@ def _parse_unary_expression(self) -> ASTExpression: self.fail("Expecting identifier for 'sizeof...'.") ident = ASTIdentifier(self.matched_text) self.skip_ws() - if not self.skip_string(")"): + if not self.skip_string(')'): self.fail("Expecting ')' to end 'sizeof...'.") return ASTSizeofParamPack(ident) if self.skip_string_and_ws('('): @@ -594,14 +614,18 @@ def _parse_unary_expression(self) -> ASTExpression: if self.skip_string_and_ws('('): # either this is a new-placement or it's the second production # without placement, and it's actually the ( type-id ) part - self.fail("Sorry, neither new-placement nor parenthesised type-id " - "in new-epression is supported yet.") + self.fail( + 'Sorry, neither new-placement nor parenthesised type-id ' + 'in new-epression is supported yet.' + ) # set is_new_type_id = False if it's (type-id) if is_new_type_id: decl_specs = self._parse_decl_specs(outer=None) - decl = self._parse_declarator(named=False, param_mode="new") + decl = self._parse_declarator(named=False, param_mode='new') else: - self.fail("Sorry, parenthesised type-id in new expression not yet supported.") + self.fail( + 'Sorry, parenthesised type-id in new expression not yet supported.' + ) lst = self._parse_expression_list_or_braced_init_list() return ASTNewExpr(rooted, is_new_type_id, ASTType(decl_specs, decl), lst) # delete-expression @@ -635,10 +659,11 @@ def _parse_cast_expression(self) -> ASTExpression: return self._parse_unary_expression() except DefinitionError as ex_unary: errs = [] - errs.append((ex_cast, "If type cast expression")) - errs.append((ex_unary, "If unary expression")) - raise self._make_multi_error(errs, - "Error in cast expression.") from ex_unary + errs.append((ex_cast, 'If type cast expression')) + errs.append((ex_unary, 'If unary expression')) + raise self._make_multi_error( + errs, 'Error in cast expression.' + ) from ex_unary else: return self._parse_unary_expression() @@ -654,14 +679,19 @@ def _parse_logical_or_expression(self, in_template: bool) -> ASTExpression: # additive = multiplicative +, - # multiplicative = pm *, /, % # pm = cast .*, ->* - def _parse_bin_op_expr(self: DefinitionParser, - op_id: int, in_template: bool) -> ASTExpression: + def _parse_bin_op_expr( + self: DefinitionParser, op_id: int, in_template: bool + ) -> ASTExpression: if op_id + 1 == len(_expression_bin_ops): + def parser(in_template: bool) -> ASTExpression: return self._parse_cast_expression() + else: + def parser(in_template: bool) -> ASTExpression: return _parse_bin_op_expr(self, op_id + 1, in_template=in_template) + exprs = [] ops = [] exprs.append(parser(in_template=in_template)) @@ -694,19 +724,21 @@ def parser(in_template: bool) -> ASTExpression: if not one_more: break return ASTBinOpExpr(exprs, ops) + return _parse_bin_op_expr(self, 0, in_template=in_template) - def _parse_conditional_expression_tail(self, or_expr_head: ASTExpression, - in_template: bool) -> ASTConditionalExpr | None: + def _parse_conditional_expression_tail( + self, or_expr_head: ASTExpression, in_template: bool + ) -> ASTConditionalExpr | None: # Consumes the or_expr_head on success. # -> "?" expression ":" assignment-expression self.skip_ws() - if not self.skip_string("?"): + if not self.skip_string('?'): return None then_expr = self._parse_expression() self.skip_ws() - if not self.skip_string(":"): + if not self.skip_string(':'): self.fail('Expected ":" after then-expression in conditional expression.') else_expr = self._parse_assignment_expression(in_template) return ASTConditionalExpr(or_expr_head, then_expr, else_expr) @@ -766,9 +798,9 @@ def _parse_expression(self) -> ASTExpression: else: return ASTCommaExpr(exprs) - def _parse_expression_fallback(self, end: list[str], - parser: Callable[[], ASTExpression], - allow: bool = True) -> ASTExpression: + 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. @@ -781,8 +813,10 @@ def _parse_expression_fallback(self, end: list[str], # and for testing we may want to globally disable it if not allow or not self.allowFallbackExpressionParsing: raise - self.warn("Parsing of expression failed. Using fallback parser." - " Error was:\n%s" % e) + self.warn( + 'Parsing of expression failed. Using fallback parser.' + ' Error was:\n%s' % e + ) self.pos = prev_pos # and then the fallback scanning assert end is not None @@ -803,9 +837,10 @@ def _parse_expression_fallback(self, end: list[str], symbols.pop() self.pos += 1 if len(end) > 0 and self.eof: - self.fail("Could not find end of expression starting at %d." - % start_pos) - value = self.definition[start_pos:self.pos].strip() + self.fail( + 'Could not find end of expression starting at %d.' % start_pos + ) + value = self.definition[start_pos : self.pos].strip() return ASTFallbackExpr(value.strip()) # ========================================================================== @@ -833,13 +868,13 @@ def _parse_operator(self) -> ASTOperator: if self.skip_string('""'): self.skip_ws() if not self.match(identifier_re): - self.fail("Expected user-defined literal suffix.") + self.fail('Expected user-defined literal suffix.') identifier = ASTIdentifier(self.matched_text) return ASTOperatorLiteral(identifier) # oh well, looks like a cast operator definition. # In that case, eat another type. - type = self._parse_type(named=False, outer="operatorCast") + type = self._parse_type(named=False, outer='operatorCast') return ASTOperatorType(type) def _parse_template_argument_list(self) -> ASTTemplateArgs: @@ -878,7 +913,7 @@ def _parse_template_argument_list(self) -> ASTTemplateArgs: self.fail('Expected "...>", ">" or "," in template argument list.') template_args.append(type) except DefinitionError as e: - prev_errors.append((e, "If type argument")) + prev_errors.append((e, 'If type argument')) self.pos = pos try: value = self._parse_constant_expression(in_template=True) @@ -887,18 +922,22 @@ def _parse_template_argument_list(self) -> ASTTemplateArgs: pack_expansion = True parsed_end = True if not self.skip_string('>'): - self.fail('Expected ">" after "..." in template argument list.') + self.fail( + 'Expected ">" after "..." in template argument list.' + ) elif self.skip_string('>'): parsed_end = True elif self.skip_string(','): parsed_comma = True else: - self.fail('Expected "...>", ">" or "," in template argument list.') + self.fail( + 'Expected "...>", ">" or "," in template argument list.' + ) template_args.append(ASTTemplateArgConstant(value)) except DefinitionError as e: self.pos = pos - prev_errors.append((e, "If non-type argument")) - header = "Error in parsing template argument list." + prev_errors.append((e, 'If non-type argument')) + header = 'Error in parsing template argument list.' raise self._make_multi_error(prev_errors, header) from e if parsed_end: assert not parsed_comma @@ -929,12 +968,14 @@ def _parse_nested_name(self, member_pointer: bool = False) -> ASTNestedName: if member_pointer and len(names) > 0: templates.pop() break - self.fail("Expected identifier in nested name.") + self.fail('Expected identifier in nested name.') identifier = self.matched_text # make sure there isn't a keyword if identifier in _keywords: - self.fail("Expected identifier in nested name, " - "got keyword: %s" % identifier) + self.fail( + 'Expected identifier in nested name, ' + 'got keyword: %s' % identifier + ) ident_or_op = ASTIdentifier(identifier) # try greedily to get template arguments, # but otherwise a < might be because we are in an expression @@ -967,71 +1008,75 @@ def _parse_simple_type_specifiers(self) -> ASTTrailingTypeSpecFundamental: while self.match(_simple_type_specifiers_re): t = self.matched_text names.append(t) - if t in {'auto', 'void', 'bool', - 'char', 'wchar_t', 'char8_t', 'char16_t', 'char32_t', - 'int', '__int64', '__int128', - 'float', 'double', - '__float80', '_Float64x', '__float128', '_Float128'}: + if t in { + 'auto', 'void', 'bool', + 'char', 'wchar_t', 'char8_t', 'char16_t', 'char32_t', + 'int', '__int64', '__int128', + 'float', 'double', + '__float80', '_Float64x', '__float128', '_Float128', + }: # fmt: skip if typ is not None: - self.fail(f"Can not have both {t} and {typ}.") + self.fail(f'Can not have both {t} and {typ}.') typ = t elif t in {'signed', 'unsigned'}: if signedness is not None: - self.fail(f"Can not have both {t} and {signedness}.") + self.fail(f'Can not have both {t} and {signedness}.') signedness = t elif t == 'short': if len(width) != 0: - self.fail(f"Can not have both {t} and {width[0]}.") + self.fail(f'Can not have both {t} and {width[0]}.') width.append(t) elif t == 'long': if len(width) != 0 and width[0] != 'long': - self.fail(f"Can not have both {t} and {width[0]}.") + self.fail(f'Can not have both {t} and {width[0]}.') width.append(t) elif t in {'_Imaginary', '_Complex'}: if modifier is not None: - self.fail(f"Can not have both {t} and {modifier}.") + self.fail(f'Can not have both {t} and {modifier}.') modifier = t self.skip_ws() if len(names) == 0: return None - if typ in {'auto', 'void', 'bool', - 'wchar_t', 'char8_t', 'char16_t', 'char32_t', - '__float80', '_Float64x', '__float128', '_Float128'}: + if typ in { + 'auto', 'void', 'bool', + 'wchar_t', 'char8_t', 'char16_t', 'char32_t', + '__float80', '_Float64x', '__float128', '_Float128', + }: # fmt: skip if modifier is not None: - self.fail(f"Can not have both {typ} and {modifier}.") + self.fail(f'Can not have both {typ} and {modifier}.') if signedness is not None: - self.fail(f"Can not have both {typ} and {signedness}.") + self.fail(f'Can not have both {typ} and {signedness}.') if len(width) != 0: - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') elif typ == 'char': if modifier is not None: - self.fail(f"Can not have both {typ} and {modifier}.") + self.fail(f'Can not have both {typ} and {modifier}.') if len(width) != 0: - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') elif typ == 'int': if modifier is not None: - self.fail(f"Can not have both {typ} and {modifier}.") + self.fail(f'Can not have both {typ} and {modifier}.') elif typ in {'__int64', '__int128'}: if modifier is not None: - self.fail(f"Can not have both {typ} and {modifier}.") + self.fail(f'Can not have both {typ} and {modifier}.') if len(width) != 0: - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') elif typ == 'float': if signedness is not None: - self.fail(f"Can not have both {typ} and {signedness}.") + self.fail(f'Can not have both {typ} and {signedness}.') if len(width) != 0: - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') elif typ == 'double': if signedness is not None: - self.fail(f"Can not have both {typ} and {signedness}.") + self.fail(f'Can not have both {typ} and {signedness}.') if len(width) > 1: - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') if len(width) == 1 and width[0] != 'long': - self.fail(f"Can not have both {typ} and {' '.join(width)}.") + self.fail(f'Can not have both {typ} and {" ".join(width)}.') elif typ is None: if modifier is not None: - self.fail(f"Can not have {modifier} without a floating point type.") + self.fail(f'Can not have {modifier} without a floating point type.') else: msg = f'Unhandled type {typ}' raise AssertionError(msg) @@ -1083,16 +1128,22 @@ def _parse_trailing_type_spec(self) -> ASTTrailingTypeSpec: placeholder_type = 'auto' elif self.skip_word_and_ws('decltype'): if not self.skip_string_and_ws('('): - self.fail("Expected '(' after 'decltype' in placeholder type specifier.") + self.fail( + "Expected '(' after 'decltype' in placeholder type specifier." + ) if not self.skip_word_and_ws('auto'): - self.fail("Expected 'auto' after 'decltype(' in placeholder type specifier.") + self.fail( + "Expected 'auto' after 'decltype(' in placeholder type specifier." + ) if not self.skip_string_and_ws(')'): - self.fail("Expected ')' after 'decltype(auto' in placeholder type specifier.") + self.fail( + "Expected ')' after 'decltype(auto' in placeholder type specifier." + ) placeholder_type = 'decltype(auto)' return ASTTrailingTypeSpecName(prefix, nested_name, placeholder_type) def _parse_parameters_and_qualifiers( - self, param_mode: str, + self, param_mode: str ) -> ASTParametersQualifiers | None: if param_mode == 'new': return None @@ -1111,8 +1162,9 @@ def _parse_parameters_and_qualifiers( args.append(ASTFunctionParameter(None, True)) self.skip_ws() if not self.skip_string(')'): - self.fail('Expected ")" after "..." in ' - 'parameters-and-qualifiers.') + self.fail( + 'Expected ")" after "..." in parameters-and-qualifiers.' + ) break # note: it seems that function arguments can always be named, # even in function pointers and similar. @@ -1125,8 +1177,10 @@ def _parse_parameters_and_qualifiers( continue if self.skip_string(')'): break - self.fail('Expecting "," or ")" in parameters-and-qualifiers, ' - f'got "{self.current_char}".') + self.fail( + 'Expecting "," or ")" in parameters-and-qualifiers, ' + f'got "{self.current_char}".' + ) self.skip_ws() const = self.skip_word_and_ws('const') @@ -1162,8 +1216,7 @@ def _parse_parameters_and_qualifiers( override = self.skip_word_and_ws('override') final = self.skip_word_and_ws('final') if not override: - override = self.skip_word_and_ws( - 'override') # they can be permuted + override = self.skip_word_and_ws('override') # they can be permuted attrs = self._parse_attribute_list() @@ -1179,12 +1232,21 @@ def _parse_parameters_and_qualifiers( break if not initializer: self.fail( - 'Expected "%s" in initializer-specifier.' - % '" or "'.join(valid)) + 'Expected "%s" in initializer-specifier.' % '" or "'.join(valid) + ) return ASTParametersQualifiers( - args, volatile, const, ref_qual, exception_spec, trailing_return, - override, final, attrs, initializer) + args, + volatile, + const, + ref_qual, + exception_spec, + trailing_return, + override, + final, + attrs, + initializer, + ) def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimple: """Just parse the simple ones.""" @@ -1230,7 +1292,7 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl if inline: continue if not constexpr and outer in {'member', 'function'}: - constexpr = self.skip_word("constexpr") + constexpr = self.skip_word('constexpr') if constexpr: continue @@ -1263,8 +1325,10 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl if self.skip_string('('): expr = self._parse_constant_expression(in_template=False) if not expr: - self.fail("Expected constant expression after '('" - " in explicit specifier.") + self.fail( + "Expected constant expression after '('" + ' in explicit specifier.' + ) self.skip_ws() if not self.skip_string(')'): self.fail("Expected ')' to end explicit specifier.") @@ -1275,9 +1339,20 @@ def _parse_decl_specs_simple(self, outer: str, typed: bool) -> ASTDeclSpecsSimpl attrs.append(attr) continue break - return ASTDeclSpecsSimple(storage, thread_local, inline, virtual, - explicit_spec, consteval, constexpr, constinit, - volatile, const, friend, ASTAttributeList(attrs)) + return ASTDeclSpecsSimple( + storage, + thread_local, + inline, + virtual, + explicit_spec, + consteval, + constexpr, + constinit, + volatile, + const, + friend, + ASTAttributeList(attrs), + ) def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs: if outer: @@ -1307,7 +1382,7 @@ def _parse_decl_specs(self, outer: str, typed: bool = True) -> ASTDeclSpecs: return ASTDeclSpecs(outer, left_specs, right_specs, trailing) def _parse_declarator_name_suffix( - self, named: bool | str, param_mode: str, typed: bool, + self, named: bool | str, param_mode: str, typed: bool ) -> ASTDeclaratorNameParamQual | ASTDeclaratorNameBitField: # now we should parse the name, and then suffixes if named == 'maybe': @@ -1343,6 +1418,7 @@ def _parse_declarator_name_suffix( def parser() -> ASTExpression: return self._parse_expression() + value = self._parse_expression_fallback([']'], parser) if not self.skip_string(']'): self.fail("Expected ']' in end of array operator.") @@ -1357,16 +1433,16 @@ def parser() -> ASTExpression: if self.skip_string(':'): size = self._parse_constant_expression(in_template=False) return ASTDeclaratorNameBitField(declId=decl_id, size=size) - return ASTDeclaratorNameParamQual(declId=decl_id, arrayOps=array_ops, - paramQual=param_qual) + return ASTDeclaratorNameParamQual( + declId=decl_id, arrayOps=array_ops, paramQual=param_qual + ) - def _parse_declarator(self, named: bool | str, param_mode: str, - typed: bool = True, - ) -> ASTDeclarator: + def _parse_declarator( + self, named: bool | str, param_mode: str, typed: bool = True + ) -> ASTDeclarator: # 'typed' here means 'parse return type stuff' if param_mode not in {'type', 'function', 'operatorCast', 'new'}: - raise Exception( - "Internal error, unknown param_mode '%s'." % param_mode) + raise Exception("Internal error, unknown param_mode '%s'." % param_mode) prev_errors = [] self.skip_ws() if typed and self.skip_string('*'): @@ -1389,33 +1465,39 @@ def _parse_declarator(self, named: bool | str, param_mode: str, continue break next = self._parse_declarator(named, param_mode, typed) - return ASTDeclaratorPtr(next=next, volatile=volatile, const=const, - attrs=ASTAttributeList(attr_list)) + return ASTDeclaratorPtr( + next=next, + volatile=volatile, + const=const, + attrs=ASTAttributeList(attr_list), + ) # TODO: shouldn't we parse an R-value ref here first? - if typed and self.skip_string("&"): + if typed and self.skip_string('&'): attrs = self._parse_attribute_list() next = self._parse_declarator(named, param_mode, typed) return ASTDeclaratorRef(next=next, attrs=attrs) - if typed and self.skip_string("..."): + if typed and self.skip_string('...'): next = self._parse_declarator(named, param_mode, False) return ASTDeclaratorParamPack(next=next) if typed and self.current_char == '(': # note: peeking, not skipping - if param_mode == "operatorCast": + if param_mode == 'operatorCast': # TODO: we should be able to parse cast operators which return # function pointers. For now, just hax it and ignore. - return ASTDeclaratorNameParamQual(declId=None, arrayOps=[], - paramQual=None) + return ASTDeclaratorNameParamQual( + declId=None, arrayOps=[], paramQual=None + ) # maybe this is the beginning of params and quals,try that first, # otherwise assume it's noptr->declarator > ( ptr-declarator ) pos = self.pos try: # assume this is params and quals - res = self._parse_declarator_name_suffix(named, param_mode, - typed) + res = self._parse_declarator_name_suffix(named, param_mode, typed) return res except DefinitionError as ex_param_qual: - prev_errors.append((ex_param_qual, - "If declarator-id with parameters-and-qualifiers")) + prev_errors.append(( + ex_param_qual, + 'If declarator-id with parameters-and-qualifiers', + )) self.pos = pos try: assert self.current_char == '(' @@ -1425,16 +1507,21 @@ def _parse_declarator(self, named: bool | str, param_mode: str, # inside, right? inner = self._parse_declarator(named, param_mode, typed) if not self.skip_string(')'): - self.fail("Expected ')' in \"( ptr-declarator )\"") - next = self._parse_declarator(named=False, - param_mode="type", - typed=typed) + self.fail('Expected \')\' in "( ptr-declarator )"') + next = self._parse_declarator( + named=False, param_mode='type', typed=typed + ) return ASTDeclaratorParen(inner=inner, next=next) except DefinitionError as ex_no_ptr_paren: self.pos = pos - prev_errors.append((ex_no_ptr_paren, "If parenthesis in noptr-declarator")) - header = "Error in declarator" - raise self._make_multi_error(prev_errors, header) from ex_no_ptr_paren + prev_errors.append(( + ex_no_ptr_paren, + 'If parenthesis in noptr-declarator', + )) + header = 'Error in declarator' + raise self._make_multi_error( + prev_errors, header + ) from ex_no_ptr_paren if typed: # pointer to member pos = self.pos try: @@ -1445,7 +1532,7 @@ def _parse_declarator(self, named: bool | str, param_mode: str, self.skip_ws() except DefinitionError as e: self.pos = pos - prev_errors.append((e, "If pointer to member declarator")) + prev_errors.append((e, 'If pointer to member declarator')) else: volatile = False const = False @@ -1467,16 +1554,17 @@ def _parse_declarator(self, named: bool | str, param_mode: str, # this is a heuristic for error messages, for when there is a < after a # nested name, but it was not a successful template argument list if self.current_char == '<': - self.otherErrors.append(self._make_multi_error(prev_errors, "")) + self.otherErrors.append(self._make_multi_error(prev_errors, '')) return res except DefinitionError as e: self.pos = pos - prev_errors.append((e, "If declarator-id")) - header = "Error in declarator or parameters-and-qualifiers" + prev_errors.append((e, 'If declarator-id')) + header = 'Error in declarator or parameters-and-qualifiers' raise self._make_multi_error(prev_errors, header) from e - def _parse_initializer(self, outer: str | None = None, allow_fallback: bool = True, - ) -> ASTInitializer | None: + def _parse_initializer( + self, outer: str | None = None, allow_fallback: bool = True + ) -> ASTInitializer | None: # initializer # global vars # -> brace-or-equal-initializer # | '(' expression-list ')' @@ -1514,14 +1602,18 @@ def _parse_initializer(self, outer: str | None = None, allow_fallback: bool = Tr elif outer is None: # function parameter fallback_end = [',', ')'] else: - self.fail("Internal error, initializer for outer '%s' not " - "implemented." % outer) + self.fail( + "Internal error, initializer for outer '%s' not implemented." % outer + ) in_template = outer == 'templateParam' def parser() -> ASTExpression: return self._parse_assignment_expression(in_template=in_template) - value = self._parse_expression_fallback(fallback_end, parser, allow=allow_fallback) + + value = self._parse_expression_fallback( + fallback_end, parser, allow=allow_fallback + ) return ASTInitializer(value) def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: @@ -1532,8 +1624,13 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: outer == operatorCast: annoying case, we should not take the params """ if outer: # always named - if outer not in {'type', 'member', 'function', - 'operatorCast', 'templateParam'}: + if outer not in { + 'type', + 'member', + 'function', + 'operatorCast', + 'templateParam', + }: raise Exception('Internal error, unknown outer "%s".' % outer) if outer != 'operatorCast': assert named @@ -1546,8 +1643,7 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: # first try without the type try: decl_specs = self._parse_decl_specs(outer=outer, typed=False) - decl = self._parse_declarator(named=True, param_mode=outer, - typed=False) + decl = self._parse_declarator(named=True, param_mode=outer, typed=False) must_end = True if outer == 'function': # Allow trailing requires on functions. @@ -1558,9 +1654,9 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: self.assert_end(allowSemicolon=True) except DefinitionError as ex_untyped: if outer == 'type': - desc = "If just a name" + desc = 'If just a name' elif outer == 'function': - desc = "If the function has no return type" + desc = 'If the function has no return type' else: raise AssertionError from ex_untyped prev_errors.append((ex_untyped, desc)) @@ -1571,9 +1667,9 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: except DefinitionError as ex_typed: self.pos = start_pos if outer == 'type': - desc = "If typedef-like declaration" + desc = 'If typedef-like declaration' elif outer == 'function': - desc = "If the function has a return type" + desc = 'If the function has a return type' else: raise AssertionError from ex_untyped prev_errors.append((ex_typed, desc)) @@ -1582,10 +1678,10 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: # and output it here. if True: if outer == 'type': - header = "Type must be either just a name or a " - header += "typedef-like declaration." + header = 'Type must be either just a name or a ' + header += 'typedef-like declaration.' elif outer == 'function': - header = "Error when parsing function declaration." + header = 'Error when parsing function declaration.' else: raise AssertionError from ex_untyped raise self._make_multi_error(prev_errors, header) from ex_typed @@ -1597,8 +1693,9 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: self.pos = start_pos typed = True decl_specs = self._parse_decl_specs(outer=outer, typed=typed) - decl = self._parse_declarator(named=True, param_mode=outer, - typed=typed) + decl = self._parse_declarator( + named=True, param_mode=outer, typed=typed + ) else: param_mode = 'type' if outer == 'member': @@ -1613,8 +1710,8 @@ def _parse_type(self, named: bool | str, outer: str | None = None) -> ASTType: return ASTType(decl_specs, decl) def _parse_type_with_init( - self, named: bool | str, - outer: str) -> ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit: + self, named: bool | str, outer: str + ) -> ASTTypeWithInit | ASTTemplateParamConstrainedTypeWithInit: if outer: assert outer in {'type', 'member', 'function', 'templateParam'} type = self._parse_type(outer=outer, named=named) @@ -1642,7 +1739,7 @@ def _parse_type_with_init( except DefinitionError as e: self.pos = pos e_expr = e - if not self.skip_string("="): + if not self.skip_string('='): return ASTTypeWithInit(type, None) try: type_init = self._parse_type(named=False, outer=None) @@ -1651,10 +1748,10 @@ def _parse_type_with_init( if e_expr is None: raise errs = [] - errs.append((e_expr, "If default template argument is an expression")) - errs.append((e_type, "If default template argument is a type")) - msg = "Error in non-type template parameter" - msg += " or constrained template parameter." + errs.append((e_expr, 'If default template argument is an expression')) + errs.append((e_type, 'If default template argument is a type')) + msg = 'Error in non-type template parameter' + msg += ' or constrained template parameter.' raise self._make_multi_error(errs, msg) from e_type def _parse_type_using(self) -> ASTTypeUsing: @@ -1726,6 +1823,7 @@ def _parse_enumerator(self) -> ASTEnumerator: def parser() -> ASTExpression: return self._parse_constant_expression(in_template=False) + init_val = self._parse_expression_fallback([], parser) init = ASTInitializer(init_val) return ASTEnumerator(name, init, attrs) @@ -1750,11 +1848,15 @@ def _parse_template_parameter(self) -> ASTTemplateParam: elif self.skip_word_and_ws('class'): key = 'class' elif nested_params: - self.fail("Expected 'typename' or 'class' after " - "template template parameter list.") + self.fail( + "Expected 'typename' or 'class' after " + 'template template parameter list.' + ) else: - self.fail("Expected 'typename' or 'class' in the " - "beginning of template type parameter.") + self.fail( + "Expected 'typename' or 'class' in the " + 'beginning of template type parameter.' + ) self.skip_ws() parameter_pack = self.skip_string('...') self.skip_ws() @@ -1769,8 +1871,9 @@ def _parse_template_parameter(self) -> ASTTemplateParam: default = None if self.current_char not in ',>': self.fail('Expected "," or ">" after (template) type parameter.') - data = ASTTemplateKeyParamPackIdDefault(key, identifier, - parameter_pack, default) + data = ASTTemplateKeyParamPackIdDefault( + key, identifier, parameter_pack, default + ) if nested_params: return ASTTemplateParamTemplateType(nested_params, data) else: @@ -1787,12 +1890,16 @@ def _parse_template_parameter(self) -> ASTTemplateParam: return ASTTemplateParamNonType(param, parameter_pack) except DefinitionError as e_non_type: self.pos = pos - header = "Error when parsing template parameter." + header = 'Error when parsing template parameter.' errs = [] - errs.append( - (e_type, "If unconstrained type parameter or template type parameter")) - errs.append( - (e_non_type, "If constrained type parameter or non-type parameter")) + errs.append(( + e_type, + 'If unconstrained type parameter or template type parameter', + )) + errs.append(( + e_non_type, + 'If constrained type parameter or non-type parameter', + )) raise self._make_multi_error(errs, header) from None def _parse_template_parameter_list(self) -> ASTTemplateParams: @@ -1800,7 +1907,7 @@ def _parse_template_parameter_list(self) -> ASTTemplateParams: # we assume that 'template' has just been parsed template_params: list[ASTTemplateParam] = [] self.skip_ws() - if not self.skip_string("<"): + if not self.skip_string('<'): self.fail("Expected '<' after 'template'") while 1: pos = self.pos @@ -1818,14 +1925,14 @@ def _parse_template_parameter_list(self) -> ASTTemplateParams: elif self.skip_string(','): continue else: - header = "Error in template parameter list." + header = 'Error in template parameter list.' errs = [] if err: - errs.append((err, "If parameter")) + errs.append((err, 'If parameter')) try: self.fail('Expected "," or ">".') except DefinitionError as e: - errs.append((e, "If no parameter")) + errs.append((e, 'If no parameter')) logger.debug(errs) raise self._make_multi_error(errs, header) @@ -1848,12 +1955,14 @@ def _parse_template_introduction(self) -> ASTTemplateIntroduction | None: parameter_pack = self.skip_string('...') self.skip_ws() if not self.match(identifier_re): - self.fail("Expected identifier in template introduction list.") + self.fail('Expected identifier in template introduction list.') txt_identifier = self.matched_text # make sure there isn't a keyword if txt_identifier in _keywords: - self.fail("Expected identifier in template introduction list, " - "got keyword: %s" % txt_identifier) + self.fail( + 'Expected identifier in template introduction list, ' + 'got keyword: %s' % txt_identifier + ) identifier = ASTIdentifier(txt_identifier) params.append(ASTTemplateIntroductionParameter(identifier, parameter_pack)) @@ -1918,15 +2027,16 @@ def parse_and_expr(self: DefinitionParser) -> ASTExpression: else: return ASTRequiresClause(ASTBinOpExpr(or_exprs, ops)) - def _parse_template_declaration_prefix(self, object_type: str, - ) -> ASTTemplateDeclarationPrefix | None: + def _parse_template_declaration_prefix( + self, object_type: str + ) -> ASTTemplateDeclarationPrefix | None: templates: list[ASTTemplateParams | ASTTemplateIntroduction] = [] while 1: self.skip_ws() # the saved position is only used to provide a better error message params: ASTTemplateParams | ASTTemplateIntroduction | None = None pos = self.pos - if self.skip_word("template"): + if self.skip_word('template'): try: params = self._parse_template_parameter_list() except DefinitionError as e: @@ -1942,7 +2052,7 @@ def _parse_template_declaration_prefix(self, object_type: str, break if object_type == 'concept' and len(templates) > 0: self.pos = pos - self.fail("More than 1 template parameter list for concept.") + self.fail('More than 1 template parameter list for concept.') templates.append(params) if len(templates) == 0 and object_type == 'concept': self.fail('Missing template parameter list for concept.') @@ -1951,10 +2061,13 @@ def _parse_template_declaration_prefix(self, object_type: str, else: return ASTTemplateDeclarationPrefix(templates) - def _check_template_consistency(self, nested_name: ASTNestedName, - template_prefix: ASTTemplateDeclarationPrefix, - full_spec_shorthand: bool, is_member: bool = False, - ) -> ASTTemplateDeclarationPrefix: + def _check_template_consistency( + self, + nested_name: ASTNestedName, + template_prefix: ASTTemplateDeclarationPrefix, + full_spec_shorthand: bool, + is_member: bool = False, + ) -> ASTTemplateDeclarationPrefix: num_args = nested_name.num_templates() is_member_instantiation = False if not template_prefix: @@ -1966,9 +2079,11 @@ def _check_template_consistency(self, nested_name: ASTNestedName, else: num_params = len(template_prefix.templates) if num_args + 1 < num_params: - self.fail("Too few template argument lists compared to parameter" - " lists. Argument lists: %d, Parameter lists: %d." - % (num_args, num_params)) + self.fail( + 'Too few template argument lists compared to parameter' + ' lists. Argument lists: %d, Parameter lists: %d.' + % (num_args, num_params) + ) if num_args > num_params: num_extra = num_args - num_params if not full_spec_shorthand and not is_member_instantiation: @@ -1979,13 +2094,12 @@ def _check_template_consistency(self, nested_name: ASTNestedName, 'Declaration:\n\t' ) if template_prefix: - msg += f"{template_prefix}\n\t" + msg += f'{template_prefix}\n\t' msg += str(nested_name) self.warn(msg) new_templates: list[ASTTemplateParams | ASTTemplateIntroduction] = [ - ASTTemplateParams([], requires_clause=None) - for _i in range(num_extra) + ASTTemplateParams([], requiresClause=None) for _i in range(num_extra) ] if template_prefix and not is_member_instantiation: new_templates.extend(template_prefix.templates) @@ -1995,13 +2109,34 @@ def _check_template_consistency(self, nested_name: ASTNestedName, def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclaration: object_type = objectType directive_type = directiveType - if object_type not in {'class', 'union', 'function', 'member', 'type', - 'concept', 'enum', 'enumerator'}: + if object_type not in { + 'class', + 'union', + 'function', + 'member', + 'type', + 'concept', + 'enum', + 'enumerator', + }: raise Exception('Internal error, unknown objectType "%s".' % object_type) - if directive_type not in {'class', 'struct', 'union', 'function', 'member', 'var', - 'type', 'concept', - 'enum', 'enum-struct', 'enum-class', 'enumerator'}: - raise Exception('Internal error, unknown directiveType "%s".' % directive_type) + if directive_type not in { + 'class', + 'struct', + 'union', + 'function', + 'member', + 'var', + 'type', + 'concept', + 'enum', + 'enum-struct', + 'enum-class', + 'enumerator', + }: + raise Exception( + 'Internal error, unknown directiveType "%s".' % directive_type + ) visibility = None template_prefix = None trailing_requires_clause = None @@ -2021,7 +2156,7 @@ def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclarati if not template_prefix: declaration = self._parse_type(named=True, outer='type') except DefinitionError as e: - prev_errors.append((e, "If typedef-like declaration")) + prev_errors.append((e, 'If typedef-like declaration')) self.pos = pos pos = self.pos try: @@ -2029,8 +2164,8 @@ def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclarati declaration = self._parse_type_using() except DefinitionError as e: self.pos = pos - prev_errors.append((e, "If type alias or template alias")) - header = "Error in type declaration." + prev_errors.append((e, 'If type alias or template alias')) + header = 'Error in type declaration.' raise self._make_multi_error(prev_errors, header) from e elif object_type == 'concept': declaration = self._parse_concept() @@ -2049,21 +2184,32 @@ def parse_declaration(self, objectType: str, directiveType: str) -> ASTDeclarati declaration = self._parse_enumerator() else: raise AssertionError - template_prefix = self._check_template_consistency(declaration.name, - template_prefix, - full_spec_shorthand=False, - is_member=object_type == 'member') + template_prefix = self._check_template_consistency( + declaration.name, + template_prefix, + full_spec_shorthand=False, + is_member=object_type == 'member', + ) self.skip_ws() semicolon = self.skip_string(';') - return ASTDeclaration(object_type, directive_type, visibility, - template_prefix, declaration, - trailing_requires_clause, semicolon) + return ASTDeclaration( + object_type, + directive_type, + visibility, + template_prefix, + declaration, + trailing_requires_clause, + semicolon, + ) def parse_namespace_object(self) -> ASTNamespace: - template_prefix = self._parse_template_declaration_prefix(object_type="namespace") + template_prefix = self._parse_template_declaration_prefix( + object_type='namespace' + ) name = self._parse_nested_name() - template_prefix = self._check_template_consistency(name, template_prefix, - full_spec_shorthand=False) + template_prefix = self._check_template_consistency( + name, template_prefix, full_spec_shorthand=False + ) res = ASTNamespace(name, template_prefix) res.objectType = 'namespace' # type: ignore[attr-defined] return res @@ -2071,14 +2217,17 @@ def parse_namespace_object(self) -> ASTNamespace: def parse_xref_object(self) -> tuple[ASTNamespace | ASTDeclaration, bool]: pos = self.pos try: - template_prefix = self._parse_template_declaration_prefix(object_type="xref") + template_prefix = self._parse_template_declaration_prefix( + object_type='xref' + ) name = self._parse_nested_name() # if there are '()' left, just skip them self.skip_ws() self.skip_string('()') self.assert_end() - template_prefix = self._check_template_consistency(name, template_prefix, - full_spec_shorthand=True) + template_prefix = self._check_template_consistency( + name, template_prefix, full_spec_shorthand=True + ) res1 = ASTNamespace(name, template_prefix) res1.objectType = 'xref' # type: ignore[attr-defined] return res1, True @@ -2093,9 +2242,9 @@ def parse_xref_object(self) -> tuple[ASTNamespace | ASTDeclaration, bool]: return res2, False except DefinitionError as e2: errs = [] - errs.append((e1, "If shorthand ref")) - errs.append((e2, "If full function ref")) - msg = "Error in cross-reference." + errs.append((e1, 'If shorthand ref')) + errs.append((e2, 'If full function ref')) + msg = 'Error in cross-reference.' raise self._make_multi_error(errs, msg) from e2 def parse_expression(self) -> ASTExpression | ASTType: @@ -2113,8 +2262,8 @@ def parse_expression(self) -> ASTExpression | ASTType: self.assert_end() return typ except DefinitionError as ex_type: - header = "Error when parsing (type) expression." + header = 'Error when parsing (type) expression.' errs = [] - errs.append((ex_expr, "If expression")) - errs.append((ex_type, "If type")) + errs.append((ex_expr, 'If expression')) + errs.append((ex_type, 'If type')) raise self._make_multi_error(errs, header) from ex_type diff --git a/sphinx/domains/cpp/_symbol.py b/sphinx/domains/cpp/_symbol.py index 1cb716955cb..bf4916eae91 100644 --- a/sphinx/domains/cpp/_symbol.py +++ b/sphinx/domains/cpp/_symbol.py @@ -17,7 +17,7 @@ from sphinx.util import logging if TYPE_CHECKING: - from collections.abc import Callable, Iterator + from collections.abc import Callable, Iterable, Iterator from sphinx.environment import BuildEnvironment @@ -32,13 +32,18 @@ def __init__(self, symbol: Symbol, declaration: ASTDeclaration) -> None: self.declaration = declaration def __str__(self) -> str: - return "Internal C++ duplicate symbol error:\n%s" % self.symbol.dump(0) + return 'Internal C++ duplicate symbol error:\n%s' % self.symbol.dump(0) class SymbolLookupResult: - def __init__(self, symbols: Iterator[Symbol], parentSymbol: Symbol, - identOrOp: ASTIdentifier | ASTOperator, templateParams: Any, - templateArgs: ASTTemplateArgs) -> None: + def __init__( + self, + symbols: Iterator[Symbol], + parentSymbol: Symbol, + identOrOp: ASTIdentifier | ASTOperator, + templateParams: Any, + templateArgs: ASTTemplateArgs, + ) -> None: self.symbols = symbols self.parentSymbol = parentSymbol self.identOrOp = identOrOp @@ -47,40 +52,47 @@ def __init__(self, symbols: Iterator[Symbol], parentSymbol: Symbol, class LookupKey: - def __init__(self, data: list[tuple[ASTNestedNameElement, - ASTTemplateParams | ASTTemplateIntroduction, - str]]) -> None: + def __init__( + self, + data: list[ + tuple[ + ASTNestedNameElement, ASTTemplateParams | ASTTemplateIntroduction, str + ] + ], + ) -> None: self.data = data -def _is_specialization(templateParams: ASTTemplateParams | ASTTemplateIntroduction, - templateArgs: ASTTemplateArgs) -> bool: - # Checks if `templateArgs` does not exactly match `templateParams`. +def _is_specialization( + template_params: ASTTemplateParams | ASTTemplateIntroduction, + template_args: ASTTemplateArgs, +) -> bool: + # Checks if `template_args` does not exactly match `template_params`. # 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): + if len(template_params.params) != len(template_args.args): return True # having no template params and no arguments is also a specialization - if len(templateParams.params) == 0: + if len(template_params.params) == 0: return True - for i in range(len(templateParams.params)): - param = templateParams.params[i] - arg = templateArgs.args[i] + for i in range(len(template_params.params)): + param = template_params.params[i] + arg = template_args.args[i] # TODO: doing this by string manipulation is probably not the most efficient - paramName = str(param.name) - argTxt = str(arg) - isArgPackExpansion = argTxt.endswith('...') - if param.isPack != isArgPackExpansion: + param_name = str(param.name) + arg_txt = str(arg) + is_arg_pack_expansion = arg_txt.endswith('...') + if param.isPack != is_arg_pack_expansion: return True - argName = argTxt[:-3] if isArgPackExpansion else argTxt - if paramName != argName: + arg_name = arg_txt[:-3] if is_arg_pack_expansion else arg_txt + if param_name != arg_name: return True return False class Symbol: debug_indent = 0 - debug_indent_string = " " + debug_indent_string = ' ' debug_lookup = False # overridden by the corresponding config value debug_show_tree = False # overridden by the corresponding config value @@ -95,7 +107,7 @@ def __deepcopy__(self, memo: Any) -> Symbol: @staticmethod def debug_print(*args: Any) -> None: - logger.debug(Symbol.debug_indent_string * Symbol.debug_indent, end="") + logger.debug(Symbol.debug_indent_string * Symbol.debug_indent, end='') logger.debug(*args) def _assert_invariants(self) -> None: @@ -111,15 +123,20 @@ def _assert_invariants(self) -> None: assert self.docname def __setattr__(self, key: str, value: Any) -> None: - if key == "children": + if key == 'children': raise AssertionError return super().__setattr__(key, value) - def __init__(self, parent: Symbol | None, - identOrOp: ASTIdentifier | ASTOperator | None, - templateParams: ASTTemplateParams | ASTTemplateIntroduction | None, - templateArgs: Any, declaration: ASTDeclaration | None, - docname: str | None, line: int | None) -> None: + def __init__( + self, + parent: Symbol | None, + identOrOp: ASTIdentifier | ASTOperator | None, + templateParams: ASTTemplateParams | ASTTemplateIntroduction | None, + templateArgs: Any, + declaration: ASTDeclaration | None, + docname: str | None, + line: int | None, + ) -> None: self.parent = parent # declarations in a single directive are linked together self.siblingAbove: Symbol | None = None @@ -132,8 +149,9 @@ def __init__(self, parent: Symbol | None, # and # # .. cpp:function:: template int A::foo() - if (templateArgs is not None and - not _is_specialization(templateParams, templateArgs)): + if templateArgs is not None and not _is_specialization( + templateParams, templateArgs + ): templateArgs = None self.templateParams = templateParams # template self.templateArgs = templateArgs # identifier @@ -177,7 +195,7 @@ def _fill_empty(self, declaration: ASTDeclaration, docname: str, line: int) -> N def _add_template_and_function_params(self) -> None: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("_add_template_and_function_params:") + 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). @@ -195,7 +213,10 @@ def _add_template_and_function_params(self) -> None: nn = ASTNestedName([nne], [False], rooted=False) self._add_symbols(nn, [], decl, self.docname, self.line) # add symbols for function parameters, if any - if self.declaration is not None and self.declaration.function_params is not None: + if ( + self.declaration is not None + and self.declaration.function_params is not None + ): for fp in self.declaration.function_params: if fp.arg is None: continue @@ -218,26 +239,26 @@ def remove(self) -> None: self.parent = None def clear_doc(self, docname: str) -> None: - newChildren: list[Symbol] = [] - for sChild in self._children: - sChild.clear_doc(docname) - if sChild.declaration and sChild.docname == docname: - sChild.declaration = None - sChild.docname = None - sChild.line = 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 + new_children: list[Symbol] = [] + for s_child in self._children: + s_child.clear_doc(docname) + if s_child.declaration and s_child.docname == docname: + s_child.declaration = None + s_child.docname = None + s_child.line = None + if s_child.siblingAbove is not None: + s_child.siblingAbove.siblingBelow = s_child.siblingBelow + if s_child.siblingBelow is not None: + s_child.siblingBelow.siblingAbove = s_child.siblingAbove + s_child.siblingAbove = None + s_child.siblingBelow = None + new_children.append(s_child) + self._children = new_children def get_all_symbols(self) -> Iterator[Any]: yield self - for sChild in self._children: - yield from sChild.get_all_symbols() + for s_child in self._children: + yield from s_child.get_all_symbols() @property def children_recurse_anon(self) -> Iterator[Symbol]: @@ -282,83 +303,100 @@ def get_full_nested_name(self) -> ASTNestedName: templates.append(False) return ASTNestedName(names, templates, rooted=False) - def _find_first_named_symbol(self, identOrOp: ASTIdentifier | ASTOperator, - templateParams: ASTTemplateParams | ASTTemplateIntroduction, - templateArgs: ASTTemplateArgs | None, - templateShorthand: bool, matchSelf: bool, - recurseInAnon: bool, correctPrimaryTemplateArgs: bool, - ) -> Symbol | None: + def _find_first_named_symbol( + self, + ident_or_op: ASTIdentifier | ASTOperator, + template_params: ASTTemplateParams | ASTTemplateIntroduction, + template_args: ASTTemplateArgs | None, + template_shorthand: bool, + match_self: bool, + recurse_in_anon: bool, + correct_primary_template_args: bool, + ) -> Symbol | None: if Symbol.debug_lookup: - Symbol.debug_print("_find_first_named_symbol ->") - res = self._find_named_symbols(identOrOp, templateParams, templateArgs, - templateShorthand, matchSelf, recurseInAnon, - correctPrimaryTemplateArgs, - searchInSiblings=False) + Symbol.debug_print('_find_first_named_symbol ->') + res = self._find_named_symbols( + ident_or_op, + template_params, + template_args, + template_shorthand, + match_self, + recurse_in_anon, + correct_primary_template_args, + search_in_siblings=False, + ) try: return next(res) except StopIteration: return None - def _find_named_symbols(self, identOrOp: ASTIdentifier | ASTOperator, - templateParams: ASTTemplateParams | ASTTemplateIntroduction, - templateArgs: ASTTemplateArgs, - templateShorthand: bool, matchSelf: bool, - recurseInAnon: bool, correctPrimaryTemplateArgs: bool, - searchInSiblings: bool) -> Iterator[Symbol]: + def _find_named_symbols( + self, + ident_or_op: ASTIdentifier | ASTOperator, + template_params: ASTTemplateParams | ASTTemplateIntroduction, + template_args: ASTTemplateArgs, + template_shorthand: bool, + match_self: bool, + recurse_in_anon: bool, + correct_primary_template_args: bool, + search_in_siblings: bool, + ) -> Iterator[Symbol]: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("_find_named_symbols:") + Symbol.debug_print('_find_named_symbols:') Symbol.debug_indent += 1 - Symbol.debug_print("self:") - logger.debug(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) - - if correctPrimaryTemplateArgs: - if templateParams is not None and templateArgs is not None: + Symbol.debug_print('self:') + logger.debug(self.to_string(Symbol.debug_indent + 1), end='') + Symbol.debug_print('ident_or_op: ', ident_or_op) + Symbol.debug_print('template_params: ', template_params) + Symbol.debug_print('template_args: ', template_args) + Symbol.debug_print('template_shorthand: ', template_shorthand) + Symbol.debug_print('match_self: ', match_self) + Symbol.debug_print('recurse_in_anon: ', recurse_in_anon) + Symbol.debug_print( + 'correct_primary_template_args:', correct_primary_template_args + ) + Symbol.debug_print('search_in_siblings: ', search_in_siblings) + + if correct_primary_template_args: + if template_params is not None and template_args is not None: # If both are given, but it's not a specialization, then do lookup as if # there is no argument list. # For example: template int A::var; - if not _is_specialization(templateParams, templateArgs): - templateArgs = None + if not _is_specialization(template_params, template_args): + template_args = None def matches(s: Symbol) -> bool: - if s.identOrOp != identOrOp: + if s.identOrOp != ident_or_op: return False - if (s.templateParams is None) != (templateParams is None): - if templateParams is not None: + if (s.templateParams is None) != (template_params is None): + if template_params is not None: # we query with params, they must match params return False - if not templateShorthand: + if not template_shorthand: # we don't query with params, and we do care about them return False - if templateParams: + if template_params: # TODO: do better comparison - if str(s.templateParams) != str(templateParams): + if str(s.templateParams) != str(template_params): return False - if (s.templateArgs is None) != (templateArgs is None): + if (s.templateArgs is None) != (template_args is None): return False if s.templateArgs: # TODO: do better comparison - if str(s.templateArgs) != str(templateArgs): + if str(s.templateArgs) != str(template_args): return False return True def candidates() -> Iterator[Symbol]: s = self if Symbol.debug_lookup: - Symbol.debug_print("searching in self:") - logger.debug(s.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('searching in self:') + logger.debug(s.to_string(Symbol.debug_indent + 1), end='') while True: - if matchSelf: + if match_self: yield s - if recurseInAnon: + if recurse_in_anon: yield from s.children_recurse_anon else: yield from s._children @@ -367,17 +405,17 @@ def candidates() -> Iterator[Symbol]: break s = s.siblingAbove if Symbol.debug_lookup: - Symbol.debug_print("searching in sibling:") - logger.debug(s.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('searching in sibling:') + logger.debug(s.to_string(Symbol.debug_indent + 1), end='') for s in candidates(): if Symbol.debug_lookup: - Symbol.debug_print("candidate:") - logger.debug(s.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('candidate:') + logger.debug(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_print('matches') Symbol.debug_indent -= 3 yield s if Symbol.debug_lookup: @@ -387,143 +425,172 @@ def candidates() -> Iterator[Symbol]: def _symbol_lookup( self, - nestedName: ASTNestedName, - templateDecls: list[Any], - onMissingQualifiedSymbol: Callable[ - [Symbol, ASTIdentifier | ASTOperator, Any, ASTTemplateArgs], Symbol | None, + nested_name: ASTNestedName, + template_decls: list[Any], + on_missing_qualified_symbol: Callable[ + [Symbol, ASTIdentifier | ASTOperator, Any, ASTTemplateArgs], + Symbol | None, ], - strictTemplateParamArgLists: bool, ancestorLookupType: str, - templateShorthand: bool, matchSelf: bool, - recurseInAnon: bool, correctPrimaryTemplateArgs: bool, - searchInSiblings: bool, + strict_template_param_arg_lists: bool, + ancestor_lookup_type: str, + template_shorthand: bool, + match_self: bool, + recurse_in_anon: bool, + correct_primary_template_args: bool, + search_in_siblings: bool, ) -> SymbolLookupResult: - # ancestorLookupType: if not None, specifies the target type of the lookup + # ancestor_lookup_type: 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_print('_symbol_lookup:') Symbol.debug_indent += 1 - Symbol.debug_print("self:") - logger.debug(self.to_string(Symbol.debug_indent + 1), end="") - Symbol.debug_print("nestedName: ", nestedName) - Symbol.debug_print("templateDecls: ", ",".join(str(t) for t in 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: + Symbol.debug_print('self:') + logger.debug(self.to_string(Symbol.debug_indent + 1), end='') + Symbol.debug_print('nested_name: ', nested_name) + Symbol.debug_print( + 'template_decls: ', ','.join(str(t) for t in template_decls) + ) + Symbol.debug_print( + 'strict_template_param_arg_lists:', strict_template_param_arg_lists + ) + Symbol.debug_print('ancestor_lookup_type:', ancestor_lookup_type) + Symbol.debug_print('template_shorthand: ', template_shorthand) + Symbol.debug_print('match_self: ', match_self) + Symbol.debug_print('recurse_in_anon: ', recurse_in_anon) + Symbol.debug_print( + 'correct_primary_template_args: ', correct_primary_template_args + ) + Symbol.debug_print('search_in_siblings: ', search_in_siblings) + + if strict_template_param_arg_lists: # Each template argument list must have a template parameter list. # But to declare a template there must be an additional template parameter list. - assert (nestedName.num_templates() == len(templateDecls) or - nestedName.num_templates() + 1 == len(templateDecls)) + num_nested_templates = nested_name.num_templates() + num_template_decls = len(template_decls) + assert ( + num_nested_templates == num_template_decls + or num_nested_templates + 1 == num_template_decls + ) else: - assert len(templateDecls) <= nestedName.num_templates() + 1 + assert len(template_decls) <= nested_name.num_templates() + 1 - names = nestedName.names + names = nested_name.names # find the right starting point for lookup - parentSymbol = self - if nestedName.rooted: - while parentSymbol.parent: - parentSymbol = parentSymbol.parent - if ancestorLookupType is not None: + parent_symbol = self + if nested_name.rooted: + while parent_symbol.parent: + parent_symbol = parent_symbol.parent + if ancestor_lookup_type is not None: # walk up until we find the first identifier - firstName = names[0] - if not firstName.is_operator(): - while parentSymbol.parent: - if parentSymbol.find_identifier(firstName.identOrOp, - matchSelf=matchSelf, - recurseInAnon=recurseInAnon, - searchInSiblings=searchInSiblings): + first_name = names[0] + if not first_name.is_operator(): + while parent_symbol.parent: + if parent_symbol.find_identifier( + first_name.identOrOp, + matchSelf=match_self, + recurseInAnon=recurse_in_anon, + searchInSiblings=search_in_siblings, + ): # 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 - parentSymbol.parent and - parentSymbol.parent.identOrOp == firstName.identOrOp): + if ( + len(names) == 1 + and ancestor_lookup_type == 'class' + and match_self + and parent_symbol.parent + and parent_symbol.parent.identOrOp == first_name.identOrOp + ): pass else: break - parentSymbol = parentSymbol.parent + parent_symbol = parent_symbol.parent if Symbol.debug_lookup: - Symbol.debug_print("starting point:") - logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('starting point:') + logger.debug(parent_symbol.to_string(Symbol.debug_indent + 1), end='') # and now the actual lookup - iTemplateDecl = 0 + i_template_decl = 0 for name in names[:-1]: - identOrOp = name.identOrOp - templateArgs = name.templateArgs - if strictTemplateParamArgLists: + ident_or_op = name.identOrOp + template_args = name.templateArgs + if strict_template_param_arg_lists: # there must be a parameter list - if templateArgs: - assert iTemplateDecl < len(templateDecls) - templateParams = templateDecls[iTemplateDecl] - iTemplateDecl += 1 + if template_args: + assert i_template_decl < len(template_decls) + template_params = template_decls[i_template_decl] + i_template_decl += 1 else: - templateParams = None + template_params = None else: # take the next template parameter list if there is one # otherwise it's ok - if templateArgs and iTemplateDecl < len(templateDecls): - templateParams = templateDecls[iTemplateDecl] - iTemplateDecl += 1 + if template_args and i_template_decl < len(template_decls): + template_params = template_decls[i_template_decl] + i_template_decl += 1 else: - templateParams = None - - symbol = parentSymbol._find_first_named_symbol( - identOrOp, - templateParams, templateArgs, - templateShorthand=templateShorthand, - matchSelf=matchSelf, - recurseInAnon=recurseInAnon, - correctPrimaryTemplateArgs=correctPrimaryTemplateArgs) + template_params = None + + symbol = parent_symbol._find_first_named_symbol( + ident_or_op, + template_params, + template_args, + template_shorthand=template_shorthand, + match_self=match_self, + recurse_in_anon=recurse_in_anon, + correct_primary_template_args=correct_primary_template_args, + ) if symbol is None: - symbol = onMissingQualifiedSymbol(parentSymbol, identOrOp, - templateParams, templateArgs) + symbol = on_missing_qualified_symbol( + parent_symbol, ident_or_op, template_params, template_args + ) 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 + # so even if we should match_self before, we definitely shouldn't # even more. (see also issue #2666) - matchSelf = False - parentSymbol = symbol + match_self = False + parent_symbol = symbol if Symbol.debug_lookup: - Symbol.debug_print("handle last name from:") - logger.debug(parentSymbol.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('handle last name from:') + logger.debug(parent_symbol.to_string(Symbol.debug_indent + 1), end='') # handle the last name name = names[-1] - identOrOp = name.identOrOp - templateArgs = name.templateArgs - if iTemplateDecl < len(templateDecls): - assert iTemplateDecl + 1 == len(templateDecls) - templateParams = templateDecls[iTemplateDecl] + ident_or_op = name.identOrOp + template_args = name.templateArgs + if i_template_decl < len(template_decls): + assert i_template_decl + 1 == len(template_decls) + template_params = template_decls[i_template_decl] else: - assert iTemplateDecl == len(templateDecls) - templateParams = None - - symbols = parentSymbol._find_named_symbols( - identOrOp, templateParams, templateArgs, - templateShorthand=templateShorthand, matchSelf=matchSelf, - recurseInAnon=recurseInAnon, correctPrimaryTemplateArgs=False, - searchInSiblings=searchInSiblings) + assert i_template_decl == len(template_decls) + template_params = None + + symbols = parent_symbol._find_named_symbols( + ident_or_op, + template_params, + template_args, + template_shorthand=template_shorthand, + match_self=match_self, + recurse_in_anon=recurse_in_anon, + correct_primary_template_args=False, + search_in_siblings=search_in_siblings, + ) if Symbol.debug_lookup: symbols = list(symbols) # type: ignore[assignment] Symbol.debug_indent -= 2 - return SymbolLookupResult(symbols, parentSymbol, - identOrOp, templateParams, templateArgs) + return SymbolLookupResult( + symbols, parent_symbol, ident_or_op, template_params, template_args + ) def _add_symbols( self, - nestedName: ASTNestedName, - templateDecls: list[Any], + nested_name: ASTNestedName, + template_decls: list[Any], declaration: ASTDeclaration | None, docname: str | None, line: int | None, @@ -533,175 +600,195 @@ def _add_symbols( if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("_add_symbols:") + Symbol.debug_print('_add_symbols:') Symbol.debug_indent += 1 - Symbol.debug_print("tdecls:", ",".join(str(t) for t in templateDecls)) - Symbol.debug_print("nn: ", nestedName) - Symbol.debug_print("decl: ", declaration) - Symbol.debug_print(f"location: {docname}:{line}") - - def onMissingQualifiedSymbol(parentSymbol: Symbol, - identOrOp: ASTIdentifier | ASTOperator, - templateParams: Any, templateArgs: ASTTemplateArgs, - ) -> Symbol | None: + Symbol.debug_print('tdecls:', ','.join(str(t) for t in template_decls)) + Symbol.debug_print('nn: ', nested_name) + Symbol.debug_print('decl: ', declaration) + Symbol.debug_print(f'location: {docname}:{line}') + + def on_missing_qualified_symbol( + parent_symbol: Symbol, + ident_or_op: ASTIdentifier | ASTOperator, + template_params: Any, + template_args: ASTTemplateArgs, + ) -> Symbol | None: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("_add_symbols, onMissingQualifiedSymbol:") + Symbol.debug_print('_add_symbols, on_missing_qualified_symbol:') Symbol.debug_indent += 1 - Symbol.debug_print("templateParams:", templateParams) - Symbol.debug_print("identOrOp: ", identOrOp) - Symbol.debug_print("templateARgs: ", templateArgs) + Symbol.debug_print('template_params:', template_params) + Symbol.debug_print('ident_or_op: ', ident_or_op) + Symbol.debug_print('template_args: ', template_args) Symbol.debug_indent -= 2 - return Symbol(parent=parentSymbol, identOrOp=identOrOp, - templateParams=templateParams, - templateArgs=templateArgs, declaration=None, - docname=None, line=None) - - lookupResult = self._symbol_lookup(nestedName, templateDecls, - onMissingQualifiedSymbol, - strictTemplateParamArgLists=True, - ancestorLookupType=None, - templateShorthand=False, - matchSelf=False, - recurseInAnon=False, - correctPrimaryTemplateArgs=True, - searchInSiblings=False) - assert lookupResult is not None # we create symbols all the way, so that can't happen - symbols = list(lookupResult.symbols) + return Symbol( + parent=parent_symbol, + identOrOp=ident_or_op, + templateParams=template_params, + templateArgs=template_args, + declaration=None, + docname=None, + line=None, + ) + + lookup_result = self._symbol_lookup( + nested_name, + template_decls, + on_missing_qualified_symbol, + strict_template_param_arg_lists=True, + ancestor_lookup_type=None, + template_shorthand=False, + match_self=False, + recurse_in_anon=False, + correct_primary_template_args=True, + search_in_siblings=False, + ) + # we create symbols all the way, so that can't happen + assert lookup_result is not None + symbols = list(lookup_result.symbols) if len(symbols) == 0: if Symbol.debug_lookup: - Symbol.debug_print("_add_symbols, result, no symbol:") + 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(f"location: {docname}:{line}") + Symbol.debug_print('template_params:', lookup_result.templateParams) + Symbol.debug_print('ident_or_op: ', lookup_result.identOrOp) + Symbol.debug_print('template_args: ', lookup_result.templateArgs) + Symbol.debug_print('declaration: ', declaration) + Symbol.debug_print(f'location: {docname}:{line}') Symbol.debug_indent -= 1 - symbol = Symbol(parent=lookupResult.parentSymbol, - identOrOp=lookupResult.identOrOp, - templateParams=lookupResult.templateParams, - templateArgs=lookupResult.templateArgs, - declaration=declaration, - docname=docname, line=line) + symbol = Symbol( + parent=lookup_result.parentSymbol, + identOrOp=lookup_result.identOrOp, + templateParams=lookup_result.templateParams, + templateArgs=lookup_result.templateArgs, + declaration=declaration, + docname=docname, + line=line, + ) if Symbol.debug_lookup: Symbol.debug_indent -= 2 return symbol if Symbol.debug_lookup: - Symbol.debug_print("_add_symbols, result, symbols:") + Symbol.debug_print('_add_symbols, result, symbols:') Symbol.debug_indent += 1 - Symbol.debug_print("number symbols:", len(symbols)) + Symbol.debug_print('number symbols:', len(symbols)) Symbol.debug_indent -= 1 if not declaration: if Symbol.debug_lookup: - Symbol.debug_print("no declaration") + Symbol.debug_print('no declaration') Symbol.debug_indent -= 2 # good, just a scope creation # TODO: what if we have more than one symbol? return symbols[0] - noDecl = [] - withDecl = [] - dupDecl = [] + no_decl = [] + with_decl = [] + dup_decl = [] for s in symbols: if s.declaration is None: - noDecl.append(s) + no_decl.append(s) elif s.isRedeclaration: - dupDecl.append(s) + dup_decl.append(s) else: - withDecl.append(s) + with_decl.append(s) if Symbol.debug_lookup: - Symbol.debug_print("#noDecl: ", len(noDecl)) - Symbol.debug_print("#withDecl:", len(withDecl)) - Symbol.debug_print("#dupDecl: ", len(dupDecl)) + Symbol.debug_print('#no_decl: ', len(no_decl)) + Symbol.debug_print('#with_decl:', len(with_decl)) + Symbol.debug_print('#dup_decl: ', len(dup_decl)) # With partial builds we may start with a large symbol tree stripped of declarations. - # Essentially any combination of noDecl, withDecl, and dupDecls seems possible. + # Essentially any combination of no_decl, with_decl, and dup_decls seems possible. # TODO: make partial builds fully work. What should happen when the primary symbol gets # deleted, and other duplicates exist? The full document should probably be rebuild. # First check if one of those with a declaration matches. # If it's a function, we need to compare IDs, # otherwise there should be only one symbol with a declaration. - def makeCandSymbol() -> Symbol: + def make_cand_symbol() -> Symbol: if Symbol.debug_lookup: - Symbol.debug_print("begin: creating candidate symbol") - symbol = Symbol(parent=lookupResult.parentSymbol, - identOrOp=lookupResult.identOrOp, - templateParams=lookupResult.templateParams, - templateArgs=lookupResult.templateArgs, - declaration=declaration, - docname=docname, line=line) + Symbol.debug_print('begin: creating candidate symbol') + symbol = Symbol( + parent=lookup_result.parentSymbol, + identOrOp=lookup_result.identOrOp, + templateParams=lookup_result.templateParams, + templateArgs=lookup_result.templateArgs, + declaration=declaration, + docname=docname, + line=line, + ) if Symbol.debug_lookup: - Symbol.debug_print("end: creating candidate symbol") + Symbol.debug_print('end: creating candidate symbol') return symbol - if len(withDecl) == 0: - candSymbol = None + + if len(with_decl) == 0: + cand_symbol = None else: - candSymbol = makeCandSymbol() + cand_symbol = make_cand_symbol() - def handleDuplicateDeclaration(symbol: Symbol, candSymbol: Symbol) -> None: + def handle_duplicate_declaration( + symbol: Symbol, cand_symbol: Symbol + ) -> None: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("redeclaration") + 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. # This will probably result in a duplicate id warning. - candSymbol.isRedeclaration = True + cand_symbol.isRedeclaration = True raise _DuplicateSymbolError(symbol, declaration) - if declaration.objectType != "function": - assert len(withDecl) <= 1 - handleDuplicateDeclaration(withDecl[0], candSymbol) + if declaration.objectType != 'function': + assert len(with_decl) <= 1 + handle_duplicate_declaration(with_decl[0], cand_symbol) # (not reachable) # a function, so compare IDs - candId = declaration.get_newest_id() + cand_id = declaration.get_newest_id() if Symbol.debug_lookup: - Symbol.debug_print("candId:", candId) - for symbol in withDecl: + Symbol.debug_print('cand_id:', cand_id) + for symbol in with_decl: # but all existing must be functions as well, # otherwise we declare it to be a duplicate if symbol.declaration.objectType != 'function': - handleDuplicateDeclaration(symbol, candSymbol) + handle_duplicate_declaration(symbol, cand_symbol) # (not reachable) - oldId = symbol.declaration.get_newest_id() + old_id = symbol.declaration.get_newest_id() if Symbol.debug_lookup: - Symbol.debug_print("oldId: ", oldId) - if candId == oldId: - handleDuplicateDeclaration(symbol, candSymbol) + Symbol.debug_print('old_id: ', old_id) + if cand_id == old_id: + handle_duplicate_declaration(symbol, cand_symbol) # (not reachable) # no candidate symbol found with matching ID # if there is an empty symbol, fill that one - if len(noDecl) == 0: + if len(no_decl) == 0: if Symbol.debug_lookup: - Symbol.debug_print("no match, no empty") - if candSymbol is not None: - Symbol.debug_print("result is already created candSymbol") + Symbol.debug_print('no match, no empty') + if cand_symbol is not None: + Symbol.debug_print('result is already created cand_symbol') else: - Symbol.debug_print("result is makeCandSymbol()") + Symbol.debug_print('result is make_cand_symbol()') Symbol.debug_indent -= 2 - if candSymbol is not None: - return candSymbol + if cand_symbol is not None: + return cand_symbol else: - return makeCandSymbol() + return make_cand_symbol() else: if Symbol.debug_lookup: Symbol.debug_print( - "no match, but fill an empty declaration, candSybmol is not None?:", - candSymbol is not None, + 'no match, but fill an empty declaration, cand_sybmol is not None?:', + cand_symbol is not None, ) Symbol.debug_indent -= 2 - if candSymbol is not None: - candSymbol.remove() - # assert len(noDecl) == 1 + if cand_symbol is not None: + cand_symbol.remove() + # assert len(no_decl) == 1 # TODO: enable assertion when we at some point find out how to do cleanup # for now, just take the first one, it should work fine ... right? - symbol = noDecl[0] + symbol = no_decl[0] # If someone first opened the scope, and then later # declares it, e.g, # .. namespace:: Test @@ -710,103 +797,116 @@ def handleDuplicateDeclaration(symbol: Symbol, candSymbol: Symbol) -> None: symbol._fill_empty(declaration, docname, line) return symbol - def merge_with(self, other: Symbol, docnames: list[str], - env: BuildEnvironment) -> None: + 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:") + Symbol.debug_print('merge_with:') assert other is not None - def unconditionalAdd(self: Symbol, otherChild: Symbol) -> None: + def unconditional_add(self: Symbol, other_child: Symbol) -> None: # TODO: hmm, should we prune by docnames? - self._children.append(otherChild) - otherChild.parent = self - otherChild._assert_invariants() + self._children.append(other_child) + other_child.parent = self + other_child._assert_invariants() if Symbol.debug_lookup: Symbol.debug_indent += 1 - for otherChild in other._children: + for other_child in other._children: if Symbol.debug_lookup: - Symbol.debug_print("otherChild:\n", otherChild.to_string(Symbol.debug_indent)) + Symbol.debug_print( + 'other_child:\n', other_child.to_string(Symbol.debug_indent) + ) Symbol.debug_indent += 1 - if otherChild.isRedeclaration: - unconditionalAdd(self, otherChild) + if other_child.isRedeclaration: + unconditional_add(self, other_child) if Symbol.debug_lookup: - Symbol.debug_print("isRedeclaration") + Symbol.debug_print('is_redeclaration') Symbol.debug_indent -= 1 continue - candiateIter = self._find_named_symbols( - identOrOp=otherChild.identOrOp, - templateParams=otherChild.templateParams, - templateArgs=otherChild.templateArgs, - templateShorthand=False, matchSelf=False, - recurseInAnon=False, correctPrimaryTemplateArgs=False, - searchInSiblings=False) - candidates = list(candiateIter) + candiate_iter = self._find_named_symbols( + ident_or_op=other_child.identOrOp, + template_params=other_child.templateParams, + template_args=other_child.templateArgs, + template_shorthand=False, + match_self=False, + recurse_in_anon=False, + correct_primary_template_args=False, + search_in_siblings=False, + ) + candidates = list(candiate_iter) if Symbol.debug_lookup: - Symbol.debug_print("raw candidate symbols:", len(candidates)) + Symbol.debug_print('raw candidate symbols:', len(candidates)) symbols = [s for s in candidates if not s.isRedeclaration] if Symbol.debug_lookup: - Symbol.debug_print("non-duplicate candidate symbols:", len(symbols)) + Symbol.debug_print('non-duplicate candidate symbols:', len(symbols)) if len(symbols) == 0: - unconditionalAdd(self, otherChild) + unconditional_add(self, other_child) if Symbol.debug_lookup: Symbol.debug_indent -= 1 continue - ourChild = None - if otherChild.declaration is None: + our_child = None + if other_child.declaration is None: if Symbol.debug_lookup: - Symbol.debug_print("no declaration in other child") - ourChild = symbols[0] + Symbol.debug_print('no declaration in other child') + our_child = symbols[0] else: - queryId = otherChild.declaration.get_newest_id() + query_id = other_child.declaration.get_newest_id() if Symbol.debug_lookup: - Symbol.debug_print("queryId: ", queryId) + Symbol.debug_print('query_id: ', query_id) for symbol in symbols: if symbol.declaration is None: if Symbol.debug_lookup: - Symbol.debug_print("empty candidate") + Symbol.debug_print('empty candidate') # if in the end we have non-matching, but have an empty one, # then just continue with that - ourChild = symbol + our_child = symbol continue - candId = symbol.declaration.get_newest_id() + cand_id = symbol.declaration.get_newest_id() if Symbol.debug_lookup: - Symbol.debug_print("candidate:", candId) - if candId == queryId: - ourChild = symbol + Symbol.debug_print('candidate:', cand_id) + if cand_id == query_id: + our_child = symbol break if Symbol.debug_lookup: Symbol.debug_indent -= 1 - if ourChild is None: - unconditionalAdd(self, otherChild) + if our_child is None: + unconditional_add(self, other_child) continue - if otherChild.declaration and otherChild.docname in docnames: - if not ourChild.declaration: - ourChild._fill_empty(otherChild.declaration, - otherChild.docname, otherChild.line) - elif ourChild.docname != otherChild.docname: - name = str(ourChild.declaration) - msg = __("Duplicate C++ declaration, also defined at %s:%s.\n" - "Declaration is '.. cpp:%s:: %s'.") + if other_child.declaration and other_child.docname in docnames: + if not our_child.declaration: + our_child._fill_empty( + other_child.declaration, other_child.docname, other_child.line + ) + elif our_child.docname != other_child.docname: + name = str(our_child.declaration) + msg = __( + 'Duplicate C++ declaration, also defined at %s:%s.\n' + "Declaration is '.. cpp:%s:: %s'." + ) logger.warning( msg, - ourChild.docname, - ourChild.line, - ourChild.declaration.directiveType, + our_child.docname, + our_child.line, + our_child.declaration.directiveType, name, - location=(otherChild.docname, otherChild.line), + location=(other_child.docname, other_child.line), ) else: - if (otherChild.declaration.objectType == - ourChild.declaration.objectType and - otherChild.declaration.objectType in - {'templateParam', 'functionParam'} and - ourChild.parent.declaration == otherChild.parent.declaration): - # `ourChild` was just created during merging by the call + our_object_type = our_child.declaration.objectType + other_object_type = other_child.declaration.objectType + our_child_parent_decl = our_child.parent.declaration + other_child_parent_decl = other_child.parent.declaration + if ( + other_object_type == our_object_type + and other_object_type in {'templateParam', 'functionParam'} + and our_child_parent_decl == other_child_parent_decl + ): + # `our_child` was just created during merging by the call # to `_fill_empty` on the parent and can be ignored. pass else: @@ -814,70 +914,82 @@ def unconditionalAdd(self: Symbol, otherChild: Symbol) -> None: # This can apparently happen, it should be safe to # just ignore it, right? # Hmm, only on duplicate declarations, right? - msg = "Internal C++ domain error during symbol merging.\n" - msg += "ourChild:\n" + ourChild.to_string(1) - msg += "\notherChild:\n" + otherChild.to_string(1) - logger.warning(msg, location=otherChild.docname) - ourChild.merge_with(otherChild, docnames, env) + msg = 'Internal C++ domain error during symbol merging.\n' + msg += 'our_child:\n' + our_child.to_string(1) + msg += '\nother_child:\n' + other_child.to_string(1) + logger.warning(msg, location=other_child.docname) + our_child.merge_with(other_child, docnames, env) if Symbol.debug_lookup: Symbol.debug_indent -= 2 - def add_name(self, nestedName: ASTNestedName, - templatePrefix: ASTTemplateDeclarationPrefix | None = None) -> Symbol: + def add_name( + self, + nestedName: ASTNestedName, + templatePrefix: ASTTemplateDeclarationPrefix | None = None, + ) -> Symbol: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("add_name:") + Symbol.debug_print('add_name:') if templatePrefix: - templateDecls = templatePrefix.templates + template_decls = templatePrefix.templates else: - templateDecls = [] - res = self._add_symbols(nestedName, templateDecls, - declaration=None, docname=None, line=None) + template_decls = [] + res = self._add_symbols( + nestedName, template_decls, declaration=None, docname=None, line=None + ) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res - def add_declaration(self, declaration: ASTDeclaration, - docname: str, line: int) -> Symbol: + def add_declaration( + self, declaration: ASTDeclaration, docname: str, line: int + ) -> Symbol: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("add_declaration:") + Symbol.debug_print('add_declaration:') assert declaration is not None assert docname is not None assert line is not None - nestedName = declaration.name + nested_name = declaration.name if declaration.templatePrefix: - templateDecls = declaration.templatePrefix.templates + template_decls = declaration.templatePrefix.templates else: - templateDecls = [] - res = self._add_symbols(nestedName, templateDecls, declaration, docname, line) + template_decls = [] + res = self._add_symbols(nested_name, template_decls, declaration, docname, line) if Symbol.debug_lookup: Symbol.debug_indent -= 1 return res - def find_identifier(self, identOrOp: ASTIdentifier | ASTOperator, - matchSelf: bool, recurseInAnon: bool, searchInSiblings: bool, - ) -> Symbol | None: + def find_identifier( + self, + identOrOp: ASTIdentifier | ASTOperator, + matchSelf: bool, + recurseInAnon: bool, + searchInSiblings: bool, + ) -> Symbol | None: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("find_identifier:") + 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) - logger.debug(self.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('identOrOp: ', identOrOp) + Symbol.debug_print('matchSelf: ', matchSelf) + Symbol.debug_print('recurseInAnon: ', recurseInAnon) + Symbol.debug_print('searchInSiblings:', searchInSiblings) + logger.debug(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:") - logger.debug(current.to_string(Symbol.debug_indent + 1), end="") + Symbol.debug_print('trying:') + logger.debug(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 + if recurseInAnon: + children: Iterable[Symbol] = current.children_recurse_anon + else: + children = current._children for s in children: if s.identOrOp == identOrOp: return s @@ -889,10 +1001,10 @@ def find_identifier(self, identOrOp: ASTIdentifier | ASTOperator, def direct_lookup(self, key: LookupKey) -> Symbol: if Symbol.debug_lookup: Symbol.debug_indent += 1 - Symbol.debug_print("direct_lookup:") + Symbol.debug_print('direct_lookup:') Symbol.debug_indent += 1 s = self - for name, templateParams, id_ in key.data: + for name, template_params, id_ in key.data: if id_ is not None: res = None for cand in s._children: @@ -903,22 +1015,25 @@ def direct_lookup(self, key: LookupKey) -> Symbol: 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) + ident_or_op = name.identOrOp + template_args = name.templateArgs + s = s._find_first_named_symbol( + ident_or_op, + template_params, + template_args, + template_shorthand=False, + match_self=False, + recurse_in_anon=False, + correct_primary_template_args=False, + ) if Symbol.debug_lookup: - Symbol.debug_print("name: ", name) - Symbol.debug_print("templateParams:", templateParams) - Symbol.debug_print("id: ", id_) + Symbol.debug_print('name: ', name) + Symbol.debug_print('template_params:', template_params) + Symbol.debug_print('id: ', id_) if s is not None: - logger.debug(s.to_string(Symbol.debug_indent + 1), end="") + logger.debug(s.to_string(Symbol.debug_indent + 1), end='') else: - Symbol.debug_print("not found") + Symbol.debug_print('not found') if s is None: if Symbol.debug_lookup: Symbol.debug_indent -= 2 @@ -942,68 +1057,78 @@ def find_name( # 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_print('find_name:') Symbol.debug_indent += 1 - Symbol.debug_print("self:") - logger.debug(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) + Symbol.debug_print('self:') + logger.debug(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: ASTIdentifier | ASTOperator, - templateParams: Any, - templateArgs: ASTTemplateArgs) -> Symbol | None: + def on_missing_qualified_symbol( + parent_symbol: Symbol, + ident_or_op: ASTIdentifier | ASTOperator, + template_params: Any, + template_args: ASTTemplateArgs, + ) -> Symbol | None: # TODO: Maybe search without template args? - # Though, the correctPrimaryTemplateArgs does + # Though, the correct_primary_template_args 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': + if parent_symbol.declaration is not None: + if parent_symbol.declaration.objectType == 'templateParam': raise QualifiedSymbolIsTemplateParam return None try: - lookupResult = self._symbol_lookup(nestedName, templateDecls, - onMissingQualifiedSymbol, - strictTemplateParamArgLists=False, - ancestorLookupType=typ, - templateShorthand=templateShorthand, - matchSelf=matchSelf, - recurseInAnon=recurseInAnon, - correctPrimaryTemplateArgs=False, - searchInSiblings=searchInSiblings) + lookup_result = self._symbol_lookup( + nestedName, + templateDecls, + on_missing_qualified_symbol, + strict_template_param_arg_lists=False, + ancestor_lookup_type=typ, + template_shorthand=templateShorthand, + match_self=matchSelf, + recurse_in_anon=recurseInAnon, + correct_primary_template_args=False, + search_in_siblings=searchInSiblings, + ) except QualifiedSymbolIsTemplateParam: - return None, "templateParamInQualified" + return None, 'templateParamInQualified' - if lookupResult is None: + if lookup_result is None: # if it was a part of the qualification that could not be found if Symbol.debug_lookup: Symbol.debug_indent -= 2 return None, None - res = list(lookupResult.symbols) + res = list(lookup_result.symbols) if len(res) != 0: 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" + if lookup_result.parentSymbol.declaration is not None: + if lookup_result.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) + symbol = lookup_result.parentSymbol._find_first_named_symbol( + lookup_result.identOrOp, + None, + None, + template_shorthand=templateShorthand, + match_self=matchSelf, + recurse_in_anon=recurseInAnon, + correct_primary_template_args=False, + ) if Symbol.debug_lookup: Symbol.debug_indent -= 2 if symbol is not None: @@ -1011,58 +1136,71 @@ def onMissingQualifiedSymbol(parentSymbol: Symbol, else: return None, None - def find_declaration(self, declaration: ASTDeclaration, typ: str, templateShorthand: bool, - matchSelf: bool, recurseInAnon: bool) -> Symbol | None: + def find_declaration( + self, + declaration: ASTDeclaration, + typ: str, + templateShorthand: bool, + matchSelf: bool, + recurseInAnon: bool, + ) -> Symbol | None: # 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 + Symbol.debug_print('find_declaration:') + nested_name = declaration.name if declaration.templatePrefix: - templateDecls = declaration.templatePrefix.templates + template_decls = declaration.templatePrefix.templates else: - templateDecls = [] - - def onMissingQualifiedSymbol(parentSymbol: Symbol, - identOrOp: ASTIdentifier | ASTOperator, - templateParams: Any, - templateArgs: ASTTemplateArgs) -> Symbol | None: + template_decls = [] + + def on_missing_qualified_symbol( + parent_symbol: Symbol, + ident_or_op: ASTIdentifier | ASTOperator, + template_params: Any, + template_args: ASTTemplateArgs, + ) -> Symbol | None: return None - lookupResult = self._symbol_lookup(nestedName, templateDecls, - onMissingQualifiedSymbol, - strictTemplateParamArgLists=False, - ancestorLookupType=typ, - templateShorthand=templateShorthand, - matchSelf=matchSelf, - recurseInAnon=recurseInAnon, - correctPrimaryTemplateArgs=False, - searchInSiblings=False) + lookup_result = self._symbol_lookup( + nested_name, + template_decls, + on_missing_qualified_symbol, + strict_template_param_arg_lists=False, + ancestor_lookup_type=typ, + template_shorthand=templateShorthand, + match_self=matchSelf, + recurse_in_anon=recurseInAnon, + correct_primary_template_args=False, + search_in_siblings=False, + ) if Symbol.debug_lookup: Symbol.debug_indent -= 1 - if lookupResult is None: + if lookup_result is None: return None - symbols = list(lookupResult.symbols) + symbols = list(lookup_result.symbols) if len(symbols) == 0: return None - querySymbol = Symbol(parent=lookupResult.parentSymbol, - identOrOp=lookupResult.identOrOp, - templateParams=lookupResult.templateParams, - templateArgs=lookupResult.templateArgs, - declaration=declaration, - docname='fakeDocnameForQuery', - line=42) - queryId = declaration.get_newest_id() + query_symbol = Symbol( + parent=lookup_result.parentSymbol, + identOrOp=lookup_result.identOrOp, + templateParams=lookup_result.templateParams, + templateArgs=lookup_result.templateArgs, + declaration=declaration, + docname='fakeDocnameForQuery', + line=42, + ) + query_id = declaration.get_newest_id() for symbol in symbols: if symbol.declaration is None: continue - candId = symbol.declaration.get_newest_id() - if candId == queryId: - querySymbol.remove() + cand_id = symbol.declaration.get_newest_id() + if cand_id == query_id: + query_symbol.remove() return symbol - querySymbol.remove() + query_symbol.remove() return None def to_string(self, indent: int) -> str: @@ -1081,10 +1219,10 @@ def to_string(self, indent: int) -> str: if self.templateArgs: res.append(str(self.templateArgs)) if self.declaration: - res.append(": ") + res.append(': ') if self.isRedeclaration: res.append('!!duplicate!! ') - res.append("{" + self.declaration.objectType + "} ") + res.append('{' + self.declaration.objectType + '} ') res.append(str(self.declaration)) if self.docname: res.append('\t(')