From eb465789f89ad6d37117714192fe733d487ff745 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Wed, 16 Jun 2021 18:06:29 +0200 Subject: [PATCH 1/2] Handle parsing errors from the C++ domain --- breathe/directives/function.py | 21 +++++++++++++++++++- breathe/renderer/sphinxrenderer.py | 32 ++++++++++++++++++------------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/breathe/directives/function.py b/breathe/directives/function.py index eda57157..cc6eaad1 100644 --- a/breathe/directives/function.py +++ b/breathe/directives/function.py @@ -70,7 +70,18 @@ def run(self) -> List[Node]: return warning.warn('doxygenfunction: %s' % e) # Extract arguments from the function name. - args = self._parse_args(args) + try: + args = self._parse_args(args) + except cpp.DefinitionError as e: + return self.create_warning( + project_info, + namespace='%s::' % namespace if namespace else '', + function=function_name, + args=str(args), + cpperror=str(e) + ).warn('doxygenfunction: Unable to resolve function ' + '"{namespace}{function}" with arguments "{args}".\n' + 'Could not parse arguments. Parsing eror is\n{cpperror}') finder_filter = self.filter_factory.create_function_and_all_friend_finder_filter( namespace, function_name) @@ -118,6 +129,12 @@ def run(self) -> List[Node]: result = warning.warn(message, rendered_nodes=warning_nodes, unformatted_suffix=text) return result + except cpp.DefinitionError as error: + warning.context['cpperror'] = str(error) + return warning.warn( + 'doxygenfunction: Unable to resolve function ' + '"{namespace}{function}" with arguments "{args}".\n' + 'Candidate function could not be parsed. Parsing error is\n{cpperror}') target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_outline_filter(self.options) @@ -126,6 +143,7 @@ def run(self) -> List[Node]: self.directive_args) def _parse_args(self, function_description: str) -> Optional[cpp.ASTParametersQualifiers]: + # Note: the caller must catch cpp.DefinitionError if function_description == '': return None @@ -216,6 +234,7 @@ def _resolve_function(self, matches, args: Optional[cpp.ASTParametersQualifiers] _match_args = match.group(2) # Parse the text to find the arguments + # This one should succeed as it came from _create_function_signature match_args = self._parse_args(_match_args) # Match them against the arg spec diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 656ef1e8..6f949863 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -2067,8 +2067,8 @@ def visit_friendclass(self, node) -> List[Node]: signode += nodes.Text(node.name) return [desc] - def visit_param(self, node: compound.paramTypeSub, *, - insertDeclNameByParsing: bool = False) -> List[Node]: + def visit_templateparam(self, node: compound.paramTypeSub, *, + insertDeclNameByParsing: bool = False) -> List[Node]: nodelist = [] # Parameter type @@ -2096,15 +2096,22 @@ def visit_param(self, node: compound.paramTypeSub, *, ''.join(n.astext() for n in nodelist), location=self.state.state_machine.get_source_and_line(), config=self.app.config) - ast = parser._parse_type(named='single', outer='templateParam') - assert ast.name is None - nn = cpp.ASTNestedName( - names=[cpp.ASTNestedNameElement(cpp.ASTIdentifier(node.declname), None)], - templates=[False], rooted=False) - ast.name = nn - # the actual nodes don't matter, as it is astext()-ed later - nodelist = [nodes.Text(str(ast))] - appendDeclName = False + try: + # we really should use _parse_template_paramter() + # but setting a name there is non-trivial, so we use type + ast = parser._parse_type(named='single', outer='templateParam') + assert ast.name is None + nn = cpp.ASTNestedName( + names=[cpp.ASTNestedNameElement( + cpp.ASTIdentifier(node.declname), None)], + templates=[False], rooted=False) + ast.name = nn + # the actual nodes don't matter, as it is astext()-ed later + nodelist = [nodes.Text(str(ast))] + appendDeclName = False + except cpp.DefinitionError: + # happens with "typename ...Args", so for now, just append + pass if appendDeclName: if nodelist: @@ -2134,7 +2141,7 @@ def visit_templateparamlist(self, node: compound.templateparamlistTypeSub) -> Li for i, item in enumerate(node.param): if i: nodelist.append(nodes.Text(", ")) - nodelist.extend(self.visit_param(item, insertDeclNameByParsing=True)) + nodelist.extend(self.visit_templateparam(item, insertDeclNameByParsing=True)) self.output_defname = True return nodelist @@ -2273,7 +2280,6 @@ def dispatch_memberdef(self, node) -> List[Node]: "compoundref": visit_compoundref, "mixedcontainer": visit_mixedcontainer, "description": visit_description, - "param": visit_param, "templateparamlist": visit_templateparamlist, "docparamlist": visit_docparamlist, "docxrefsect": visit_docxrefsect, From d5b1b13accc9cc118e4356c02d3d7d8acf4fd916 Mon Sep 17 00:00:00 2001 From: Jakob Lykke Andersen Date: Thu, 5 Aug 2021 16:31:10 +0200 Subject: [PATCH 2/2] Fix typo Co-authored-by: Bruce Merry <1963944+bmerry@users.noreply.github.com> --- breathe/renderer/sphinxrenderer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/breathe/renderer/sphinxrenderer.py b/breathe/renderer/sphinxrenderer.py index 6f949863..443f8499 100644 --- a/breathe/renderer/sphinxrenderer.py +++ b/breathe/renderer/sphinxrenderer.py @@ -2097,7 +2097,7 @@ def visit_templateparam(self, node: compound.paramTypeSub, *, location=self.state.state_machine.get_source_and_line(), config=self.app.config) try: - # we really should use _parse_template_paramter() + # we really should use _parse_template_parameter() # but setting a name there is non-trivial, so we use type ast = parser._parse_type(named='single', outer='templateParam') assert ast.name is None