/
autocmt.py
129 lines (107 loc) · 3.4 KB
/
autocmt.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env python
class DocBlockInfo:
def __init__(self, name, args):
self._name = name
self._args = args
@property
def name(self):
return self._name
@property
def args(self):
return self._args
class DocBlockComment:
def __init__(self, line, comment):
self._line = line
self._comment = comment
@property
def line(self):
return self._line
@property
def comment(self):
return self._comment
def doc_block_comment(info):
result = "/****************************************************************\n\n"
result = result + "\tFUNCTION: %s\n\n" %(info.name)
result = result + "\tARGUMENTS: \n"
for arg in info.args:
result = result + "\t\t%s - \n" % (arg)
result = result + "\n"
result = result + "\tRETURNS: \n\n"
result = result + "\tNOTES: \n"
result = result + "****************************************************************/\n"
return result
def is_commentable(node):
"""True if the function/method is to be documented according to
the standards of CSCI 241"""
from clang.cindex import CursorKind
kind = node.kind
return node.is_definition() and (kind == CursorKind.CXX_METHOD or kind == CursorKind.CONSTRUCTOR or kind == CursorKind.DESTRUCTOR or kind == CursorKind.FUNCTION_DECL)
def get_commentable_cursors(node):
"""Get all cursors for which is_commentable is true"""
cursors = []
kind = node.kind
if is_commentable(node):
cursors.append(node)
for child in node.get_children():
for n in get_commentable_cursors(child):
cursors.append(n)
return cursors
def get_doc_block_info(cursor):
"""Get the documentation box comment with the line in a DocBlockInfo"""
parentScope = cursor.semantic_parent.spelling or ""
if parentScope != "":
parentScope = parentScope + "::"
# Get the names of each argument
args = [arg.spelling for arg in cursor.get_arguments()]
const = str()
# To do
if cursor.type.is_const_qualified():
const = " const"
return DocBlockInfo(parentScope + cursor.spelling + const, args)
def get_doc_comments(cursor, sourceFileName):
docCmts = []
for node in get_commentable_cursors(cursor):
# Only use functions defined in the current file
if node.location.file.name == sourceFileName:
commentInfo = get_doc_block_info(node)
docCmts.append(DocBlockComment(node.location.line, doc_block_comment(commentInfo)))
return docCmts
def source_with_doc_blocks(fileName, docBlocks):
lines = []
result = str();
# Get all lines in the file
with open(fileName, "r") as file:
lines = file.readlines()
# Insert block comments in their respective lines
offset = 0
for comment in docBlocks:
lines.insert(comment.line - 1 + offset, comment.comment)
offset = offset + 1
return "".join(["%s" % (s) for s in lines]);
def usage():
print("Usage: autocmt.py [-o] sourcefile")
def main():
import sys
from clang.cindex import Index, Config
from io import open
# TODO: Don't hard code the clang library path
Config.set_library_path("/usr/lib/llvm-3.3/lib")
if len(sys.argv) == 1 or len(sys.argv) > 3:
usage()
sys.exit(1)
cppFile = str()
overwrite = False
if "-o" in sys.argv:
overwrite = True
cppFile = sys.argv[len(sys.argv) - 1]
index = Index.create()
transUnit = index.parse(cppFile)
docBlocks = get_doc_comments(transUnit.cursor, cppFile)
source = source_with_doc_blocks(cppFile, docBlocks)
if overwrite:
with open(cppFile, "w") as file:
file.write(unicode(source))
else:
sys.stdout.write(unicode(source))
if __name__ == '__main__':
main()