def run(self) -> List[Node]: name = self.arguments[0] try: project_info = self.project_info_factory.create_project_info(self.options) except ProjectError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) finder_filter = self.filter_factory.create_compound_finder_filter(name, self.kind) # TODO: find a more specific type for the Doxygen nodes matches = [] # type: List[Any] finder.filter_(finder_filter, matches) if len(matches) == 0: warning = create_warning(project_info, self.state, self.lineno, name=name, kind=self.kind) return warning.warn('doxygen{kind}: Cannot find class "{name}" {tail}') target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_class_filter(name, self.options) mask_factory = NullMaskFactory() return self.render(matches[0], project_info, filter_, target_handler, mask_factory, self.directive_args)
def run(self) -> List[Node]: try: namespace, name = self.arguments[0].rsplit("::", 1) except ValueError: namespace, name = "", self.arguments[0] try: project_info = self.project_info_factory.create_project_info( self.options) except ProjectError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) finder_filter = self.create_finder_filter(namespace, name) # TODO: find a more specific type for the Doxygen nodes matches = [] # type: List[Any] finder.filter_(finder_filter, matches) if len(matches) == 0: display_name = "%s::%s" % (namespace, name) if namespace else name warning = create_warning(project_info, self.state, self.lineno, kind=self.kind, display_name=display_name) return warning.warn( 'doxygen{kind}: Cannot find {kind} "{display_name}" {tail}') target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_outline_filter(self.options) node_stack = matches[0] mask_factory = NullMaskFactory() return self.render(node_stack, project_info, filter_, target_handler, mask_factory, self.directive_args)
def handle_contents(self, project_info): try: finder = self.finder_factory.create_finder(project_info) except ParserError as e: return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno, True) except FileIOError as e: return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno) data_object = finder.root() target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_index_filter(self.options) object_renderer = SphinxRenderer( self.parser_factory.app, project_info, [data_object], self.state, self.state.document, target_handler, self.parser_factory.create_compound_parser(project_info), filter_, ) mask_factory = NullMaskFactory() context = RenderContext([data_object, RootDataObject()], mask_factory, self.directive_args) try: node_list = object_renderer.render(context.node_stack[0], context) except ParserError as e: return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno, True) except FileIOError as e: return format_parser_error(self.name, e.error, e.filename, self.state, self.lineno) return node_list
def run(self) -> List[Node]: # Separate possible arguments (delimited by a "(") from the namespace::name match = re.match(r"([^(]*)(.*)", self.arguments[0]) assert match is not None # TODO: this is probably not appropriate, for now it fixes typing namespaced_function, args = match.group(1), match.group(2) # Split the namespace and the function name try: (namespace, function_name) = namespaced_function.rsplit("::", 1) except ValueError: (namespace, function_name) = "", namespaced_function try: project_info = self.project_info_factory.create_project_info( self.options) except ProjectError as e: warning = create_warning(None, self.state, self.lineno) return warning.warn('doxygenfunction: %s' % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = create_warning(None, self.state, self.lineno) return warning.warn('doxygenfunction: %s' % e) # Extract arguments from the function name. args = self.parse_args(args) finder_filter = self.filter_factory.create_function_finder_filter( namespace, function_name) # TODO: find a more specific type for the Doxygen nodes matches = [] # type: List[Any] finder.filter_(finder_filter, matches) # Create it ahead of time as it is cheap and it is ugly to declare it for both exception # clauses below warning = create_warning(project_info, self.state, self.lineno, namespace='%s::' % namespace if namespace else '', function=function_name, args=', '.join(args)) try: node_stack = self.resolve_function(matches, args, project_info) except NoMatchingFunctionError: return warning.warn( 'doxygenfunction: Cannot find function "{namespace}{function}" ' '{tail}') except UnableToResolveFunctionError as error: message = 'doxygenfunction: Unable to resolve multiple matches for function ' \ '"{namespace}{function}" with arguments ({args}) {tail}.\n' \ 'Potential matches:\n' # We want to create a string for the console output and a set of docutils nodes # for rendering into the final output. We handle the final output as a literal string # with a txt based list of the options. literal_text = '' # TODO: We're cheating here with the set() as signatures has repeating entries for some # reason (failures in the matcher_stack code) so we consolidate them by shoving them in # a set to remove duplicates. Should be fixed! signatures = '' for i, entry in enumerate(sorted(set(error.signatures))): if i: literal_text += '\n' # Replace new lines with a new line & enough spacing to reach the appropriate # alignment for our simple plain text list literal_text += '- %s' % entry.replace('\n', '\n ') signatures += ' - %s\n' % entry.replace('\n', '\n ') block = nodes.literal_block('', '', nodes.Text(literal_text)) formatted_message = warning.format(message) warning_nodes = [ nodes.paragraph("", "", nodes.Text(formatted_message)), block ] result = warning.warn(message, rendered_nodes=warning_nodes, unformatted_suffix=signatures) return result target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_outline_filter(self.options) return self.render(node_stack, project_info, filter_, target_handler, NullMaskFactory(), self.directive_args)
def run(self) -> List[Node]: name = self.arguments[0] try: project_info = self.project_info_factory.create_project_info( self.options) except ProjectError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = create_warning(None, self.state, self.lineno, kind=self.kind) return warning.warn('doxygen{kind}: %s' % e) finder_filter = self.filter_factory.create_finder_filter( self.kind, name) # TODO: find a more specific type for the Doxygen nodes matches = [] # type: List[Any] finder.filter_(finder_filter, matches) # It shouldn't be possible to have too many matches as namespaces & groups in their nature # are merged together if there are multiple declarations, so we only check for no matches if not matches: warning = create_warning(project_info, self.state, self.lineno, name=name, kind=self.kind) return warning.warn( 'doxygen{kind}: Cannot find namespace "{name}" {tail}') if 'content-only' in self.options: # Unpack the single entry in the matches list (node_stack, ) = matches filter_ = self.filter_factory.create_content_filter( self.kind, self.options) # Having found the compound node for the namespace or group in the index we want to grab # the contents of it which match the filter contents_finder = self.finder_factory.create_finder_from_root( node_stack[0], project_info) # TODO: find a more specific type for the Doxygen nodes contents = [] # type: List[Any] contents_finder.filter_(filter_, contents) # Replaces matches with our new starting points matches = contents target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_render_filter( self.kind, self.options) node_list = [] for node_stack in matches: object_renderer = SphinxRenderer( self.parser_factory.app, project_info, node_stack, self.state, self.state.document, target_handler, self.parser_factory.create_compound_parser(project_info), filter_) mask_factory = NullMaskFactory() context = RenderContext(node_stack, mask_factory, self.directive_args) node_list.extend( object_renderer.render(context.node_stack[0], context)) return node_list
def run(self) -> List[Node]: # Separate possible arguments (delimited by a "(") from the namespace::name match = re.match(r"([^(]*)(.*)", self.arguments[0]) assert match is not None # TODO: this is probably not appropriate, for now it fixes typing namespaced_function, args = match.group(1), match.group(2) # Split the namespace and the function name try: (namespace, function_name) = namespaced_function.rsplit("::", 1) except ValueError: (namespace, function_name) = "", namespaced_function try: project_info = self.project_info_factory.create_project_info(self.options) except ProjectError as e: warning = create_warning(None, self.state, self.lineno) return warning.warn('doxygenfunction: %s' % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = create_warning(None, self.state, self.lineno) return warning.warn('doxygenfunction: %s' % e) # Extract arguments from the function name. args = self._parse_args(args) finder_filter = self.filter_factory.create_function_and_all_friend_finder_filter( namespace, function_name) # TODO: find a more specific type for the Doxygen nodes matchesAll = [] # type: List[Any] finder.filter_(finder_filter, matchesAll) matches = [] for m in matchesAll: # only take functions and friend functions # ignore friend classes node = m[0] if node.kind == 'friend' and not node.argsstring: continue matches.append(m) # Create it ahead of time as it is cheap and it is ugly to declare it for both exception # clauses below warning = create_warning( project_info, self.state, self.lineno, namespace='%s::' % namespace if namespace else '', function=function_name, args=str(args) ) try: node_stack = self._resolve_function(matches, args, project_info) except NoMatchingFunctionError: return warning.warn('doxygenfunction: Cannot find function "{namespace}{function}" ' '{tail}') except UnableToResolveFunctionError as error: message = 'doxygenfunction: Unable to resolve function ' \ '"{namespace}{function}" with arguments {args} {tail}.\n' \ 'Potential matches:\n' text = '' for i, entry in enumerate(sorted(error.signatures)): text += '- %s\n' % entry block = nodes.literal_block('', '', nodes.Text(text)) formatted_message = warning.format(message) warning_nodes = [ nodes.paragraph("", "", nodes.Text(formatted_message)), block ] result = warning.warn(message, rendered_nodes=warning_nodes, unformatted_suffix=text) return result target_handler = create_target_handler(self.options, project_info, self.state.document) filter_ = self.filter_factory.create_outline_filter(self.options) return self.render(node_stack, project_info, filter_, target_handler, NullMaskFactory(), self.directive_args)
def run(self) -> List[Node]: # Extract namespace, function name, and parameters # Regex explanation: # 1. (?:<something>::)? # Optional namespace prefix, including template arguments if a specialization. # The <something> is group 1: # 1. [^:(<]+, basically an identifier # definitely not a scope operator, ::, or template argument list, < # 2. (?:::[^:(<]+)*, (?:<stuff>) for anon match group, # so a namespace delimiter and then another identifier # 3. ::, another namespace delimiter before the function name # 2. ([^(]+), group 2, the function name, whatever remains after the optional prefix, # until a (. # 3. (.*), group 3, the parameters. # Note: for template argument lists, the spacing is important for the Doxygen lookup. # TODO: we should really do this parsing differently, e.g., using the Sphinx C++ domain. # TODO: the Doxygen lookup should not be whitespace sensitive. match = re.match(r"(?:([^:(<]+(?:::[^:(<]+)*)::)?([^(]+)(.*)", self.arguments[0]) assert match is not None # TODO: this is probably not appropriate, for now it fixes typing namespace = (match.group(1) or "").strip() function_name = match.group(2).strip() argsStr = match.group(3) try: project_info = self.project_info_factory.create_project_info( self.options) except ProjectError as e: warning = self.create_warning(None) return warning.warn("doxygenfunction: %s" % e) try: finder = self.finder_factory.create_finder(project_info) except MTimeError as e: warning = self.create_warning(None) return warning.warn("doxygenfunction: %s" % e) # Extract arguments from the function name. try: args = self._parse_args(argsStr) except cpp.DefinitionError as e: return self.create_warning( project_info, namespace="%s::" % namespace if namespace else "", function=function_name, args=argsStr, 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) # TODO: find a more specific type for the Doxygen nodes matchesAll: List[Any] = [] finder.filter_(finder_filter, matchesAll) matches = [] for m in matchesAll: # only take functions and friend functions # ignore friend classes node = m[0] if node.kind == "friend" and not node.argsstring: continue matches.append(m) # Create it ahead of time as it is cheap and it is ugly to declare it for both exception # clauses below warning = self.create_warning( project_info, namespace="%s::" % namespace if namespace else "", function=function_name, args=str(args), ) try: node_stack = self._resolve_function(matches, args, project_info) except _NoMatchingFunctionError: return warning.warn( 'doxygenfunction: Cannot find function "{namespace}{function}" ' "{tail}") except _UnableToResolveFunctionError as error: message = ( "doxygenfunction: Unable to resolve function " '"{namespace}{function}" with arguments {args} {tail}.\n' "Potential matches:\n") text = "" for i, entry in enumerate(sorted(error.signatures)): text += "- %s\n" % entry block = nodes.literal_block("", "", nodes.Text(text)) formatted_message = warning.format(message) warning_nodes = [ nodes.paragraph("", "", nodes.Text(formatted_message)), block ] 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) return self.render( node_stack, project_info, filter_, target_handler, NullMaskFactory(), self.directive_args, )