def _result(comment, cursor=None, fmt=docstr.Type.TEXT, nest=0, name=None, ttype=None, args=None, compat=None): # FIXME: docstr.generate changes the number of lines in output. This impacts # the error reporting via meta['line']. Adjust meta to take this into # account. doc = docstr.generate(text=comment.spelling, fmt=fmt, name=name, ttype=ttype, args=args, transform=compat) doc = docstr.nest(doc, nest) meta = {'line': comment.extent.start.line} if cursor: meta['cursor.kind'] = cursor.kind, meta['cursor.displayname'] = cursor.displayname, meta['cursor.spelling'] = cursor.spelling return [(doc, meta)]
def _recursive_parse(comments, cursor, nest, compat): comment = comments[cursor.hash] name = cursor.spelling ttype = cursor.type.spelling if cursor.kind == CursorKind.MACRO_DEFINITION: # FIXME: check args against comment args = _get_macro_args(cursor) fmt = docstr.Type.MACRO if args is None else docstr.Type.MACRO_FUNC return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=name, args=args, compat=compat) elif cursor.kind == CursorKind.VAR_DECL: fmt = docstr.Type.VAR return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=name, ttype=ttype, compat=compat) elif cursor.kind == CursorKind.TYPEDEF_DECL: # FIXME: function pointers typedefs. fmt = docstr.Type.TYPE return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=ttype, compat=compat) elif cursor.kind in [ CursorKind.STRUCT_DECL, CursorKind.UNION_DECL, CursorKind.ENUM_DECL ]: # FIXME: # Handle cases where variables are instantiated on type declaration, # including anonymous cases. Idea is that if there is a variable # instantiation, the documentation should be applied to the variable if # the structure is anonymous or to the type otherwise. # # Due to the new recursiveness of the parser, fixing this here, _should_ # handle all cases (struct, union, enum). # FIXME: Handle anonymous enumerators. fmt = docstr.Type.TYPE result = _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=ttype, compat=compat) nest += 1 for c in cursor.get_children(): if c.hash in comments: result.extend(_recursive_parse(comments, c, nest, compat)) return result elif cursor.kind == CursorKind.ENUM_CONSTANT_DECL: fmt = docstr.Type.ENUM_VAL return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=name, compat=compat) elif cursor.kind == CursorKind.FIELD_DECL: fmt = docstr.Type.MEMBER return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=name, ttype=ttype, compat=compat) elif cursor.kind == CursorKind.FUNCTION_DECL: # FIXME: check args against comment # FIXME: children may contain extra stuff if the return type is a # typedef, for example args = [] for c in cursor.get_children(): if c.kind == CursorKind.PARM_DECL: args.append('{ttype} {arg}'.format(ttype=c.type.spelling, arg=c.spelling)) if cursor.type.is_function_variadic(): args.append('...') fmt = docstr.Type.FUNC ttype = cursor.result_type.spelling return _result(comment, cursor=cursor, fmt=fmt, nest=nest, name=name, ttype=ttype, args=args, compat=compat) # FIXME: If we reach here, nothing matched. This is a warning or even error # and it should be logged, but it should also return an empty list so that # it doesn't break. I.e. the parser needs to pass warnings and errors to the # Sphinx extension instead of polluting the generated output. fmt = docstr.Type.TEXT text = 'warning: unhandled cursor {kind} {name}\n'.format( kind=str(cursor.kind), name=cursor.spelling) doc = docstr.generate(text=text, fmt=fmt) meta = { 'line': comment.extent.start.line, 'cursor.kind': cursor.kind, 'cursor.displayname': cursor.displayname, 'cursor.spelling': cursor.spelling } return [(doc, meta)]