class Search: Record = Struct.define('Record', node=None, s='', id=0) def __init__(self, tree): self.records = [] self.suffixes = [] self.db = [] for node in tree.root.descendants(): if not node._refid is None: self.make_index(node) def make_index(self, node): name = node.qid.lower() r = Search.Record(node=node, s=name, id=len(self.records)) self.records.append(r) for i in range(len(name) - 3): suffix = name[i:] # Determine where to insert the suffix idx = bisect.bisect_left(self.suffixes, suffix) if idx != len(self.suffixes) and self.suffixes[idx] == suffix: self.db[idx].append((r.id, i)) else: self.suffixes.insert(idx, suffix) self.db.insert(idx, [(r.id, i)])
class Example(list): Item = Struct.define('Item', text='', classes=None) def append(self, text, classes=None): if isinstance(classes, basestring): classes = [classes] list.append(self, Example.Item(text=text, classes=classes))
class RangeMap(Sorted): Item = Struct.define('Item', obj=None, start=0, end=0) def __init__(self): super(RangeMap, self).__init__(key=lambda x: x.start) self.stack = [] def push(self, obj, start): self.stack.append(RangeMap.Item(obj=obj, start=start, end=start)) def pop(self, end): item = self.stack.pop() item.end = end self.insert(item) def insert(self, item, start=None, end=None): if not isinstance(item, RangeMap.Item): item = RangeMap.Item(obj=item, start=start, end=end) self.insert_right(item) def find(self, i): # Finds object for which i falls in the range of that object idx = bisect.bisect_right(self.keys, i) # Go back up until falls within end while idx > 0: idx -= 1 o = self[idx] if i <= o.end: return o.obj return None
class Report: Coverage = Struct.define('Coverage', name='', documented=[], undocumented=[]) def __init__(self, tree, options): self.tree = tree self.options = options def indent(self, elem, level=0): i = "\n" + " " * level if len(elem): if not elem.text or not elem.text.strip(): elem.text = i + " " for e in elem: self.indent(e, level + 1) if not e.tail or not e.tail.strip(): e.tail = i + " " if not e.tail or not e.tail.strip(): e.tail = i else: if level and (not elem.tail or not elem.tail.strip()): elem.tail = i def make_location(self, loc): elem = ElementTree.Element('location') if self.options.basedir: start = self.options.basedir else: start = os.curdir elem.set('file', os.path.relpath(str(loc.file), start)) elem.set('line', str(loc.line)) elem.set('column', str(loc.column)) return elem def arguments(self, root): elem = ElementTree.Element('arguments') root.append(elem) for node in self.tree.all_nodes: if not isinstance(node, nodes.Function): continue if node.access == cindex.CXXAccessSpecifier.PRIVATE: continue if node.comment is None: continue # Check documented arguments notdocumented = [] misspelled = [] cm = node.comment argnames = {} for name in node.argument_names: argnames[name] = False for k in cm.params: if self._is_undocumented_comment(cm.params[k]): continue if k in argnames: argnames[k] = True else: misspelled.append(k) for k in argnames: if not argnames[k]: notdocumented.append(k) if node.return_type.typename != 'void' and not hasattr( cm, 'returns'): missingret = True elif hasattr(cm, 'returns') and self._is_undocumented_comment( cm.returns): missingret = True else: missingret = False if len(notdocumented) > 0 or len(misspelled) > 0 or missingret: e = ElementTree.Element('function') e.set('id', node.qid) e.set('name', node.name) for loc in node.comment_locations: e.append(self.make_location(loc)) if missingret: ee = ElementTree.Element('undocumented-return') e.append(ee) for ndoc in notdocumented: ee = ElementTree.Element('undocumented') ee.set('name', ndoc) e.append(ee) for mis in misspelled: ee = ElementTree.Element('misspelled') ee.set('name', mis) e.append(ee) elem.append(e) def _is_undocumented_comment(self, cm): return not bool(cm) def coverage(self, root): pertype = {} for node in self.tree.all_nodes: cname = node.__class__.__name__ if node.access == cindex.CXXAccessSpecifier.PRIVATE: continue if not cname in pertype: pertype[cname] = Report.Coverage(name=cname.lower()) if not self._is_undocumented_comment(node.comment): pertype[cname].documented.append(node) else: pertype[cname].undocumented.append(node) cov = ElementTree.Element('coverage') root.append(cov) for item in pertype.values(): elem = ElementTree.Element('type') elem.set('name', item.name) elem.set('documented', str(len(item.documented))) elem.set('undocumented', str(len(item.undocumented))) item.undocumented.sort(key=lambda x: x.qid) for undoc in item.undocumented: e = ElementTree.Element('undocumented') e.set('id', undoc.qid) e.set('name', undoc.name) for loc in undoc.comment_locations: e.append(self.make_location(loc)) elem.append(e) cov.append(elem) def references(self, root): elem = ElementTree.Element('references') root.append(elem) for node in self.tree.all_nodes: if node.comment is None: continue ee = None for name in node.comment.docstrings: cm = getattr(node.comment, name) if not isinstance(cm, dict): cm = {None: cm} for k in cm: en = None for component in cm[k].components: if isinstance(component, Comment.UnresolvedReference): if ee is None: ee = ElementTree.Element(node.classname) ee.set('name', node.name) ee.set('id', node.qid) for loc in node.comment_locations: ee.append(self.make_location(loc)) elem.append(ee) if en is None: en = ElementTree.Element('doctype') en.set('name', name) if not k is None: en.set('component', k) ee.append(en) er = ElementTree.Element('ref') er.set('name', component.orig) en.append(er) def generate(self, filename): root = ElementTree.Element('report') root.set('id', filename) root.set('title', 'Documention generator') doc = ElementTree.Element('doc') doc.text = """ This page provides a documentation coverage report. Any undocumented symbols are reported here together with the location of where you should document them. This report contains the following sections: 1. [Coverage](#{0}/coverage): The documented symbols coverage. 2. [Arguments](#{0}/arguments): Errors about undocumented, misspelled function arguments and return values. 3. [References](#{0}/references): Unresolved cross references. """.format(filename) root.append(doc) self.coverage(root) self.arguments(root) self.references(root) return root