-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathast_helpers.py
executable file
·111 lines (87 loc) · 3.04 KB
/
ast_helpers.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
#!/usr/bin/env python3
import clang.cindex
from clang.cindex import CursorKind, TranslationUnit
from collections import defaultdict
import pdb
import sys
def get_translation_unit( fname, cmd_args ):
index = clang.cindex.Index.create()
options = TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD
args = [
'-x', cmd_args.language,
'-std=' + cmd_args.standard,
]
if cmd_args.include_path:
for path in cmd_args.include_path.split( ',' ):
args.append( '-I' )
args.append( path )
if cmd_args.clang_flags:
for flag in cmd_args.clang_flags.split( ' ' ):
args.append( flag )
print( fname )
try:
tu = index.parse( fname, options=options, args=args )
except Exception as e:
print( "\nFailed to parse {}".format( fname ) )
if cmd_args.verbose:
print( "Clang arguments: \n\t{}".format( '\n\t'.join( args ) ) )
tu = None
if tu is not None and tu.diagnostics:
print( "\nParsing errors for {}".format( fname ) )
for diag in tu.diagnostics:
print( "\t{}".format( str( diag ) ) )
if cmd_args.verbose:
print( "Clang arguments: {}".format( ' '.join( args ) ) )
return tu
def dump_ast( node, output_func, depth=0 ):
"""
dump the ast for easy human consumption
"""
indent = " " * depth
output_func( "%s%s: %s" % ( indent, str( node.kind ), str( node.displayname ) ) )
if node.kind in [CursorKind.DECL_REF_EXPR, CursorKind.VAR_DECL]:
#pdb.set_trace()
pass
if node.kind == CursorKind.BINARY_OPERATOR:
#pdb.set_trace()
pass
if node.displayname == 'stop_hunting(int)':
#pdb.set_trace()
pass
for child in node.get_children():
dump_ast( child, output_func, depth + 2 )
def get_human_name( node ):
"""
Given a declaration, find its fully qualified name (with class and
namespaces and compilation unit) and make it human readable
"""
node = node.referenced
res = "{0} ({1},{2})".format(
node.displayname,
node.location.line,
node.location.column )
node = node.semantic_parent
while node:
if node.kind == CursorKind.UNEXPOSED_DECL:
res = "(#include)" + "::" + res
else:
res = str(node.displayname) + "::" + res
node = node.semantic_parent
return res
def get_qualifiers( node ):
"""
Given a declaration, return all its qualifiers
This includes quaifiers on overridden cursors.
"""
res = set()
for child in node.get_children():
if child.kind == CursorKind.ANNOTATE_ATTR:
if child.displayname.startswith("funqual::"):
res.add(child.displayname[9:])
for overridden_cursor in node.get_overridden_cursors():
res |= get_qualifiers( overridden_cursor )
return res
def is_function_pointer( cursor ):
return '(*)' in cursor.type.spelling
if __name__ == '__main__':
dump_ast(get_translation_unit(sys.argv[1]).cursor, print)