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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
#!/usr/bin/env python3
from collections import OrderedDict
from sets import Set
from shutil import copyfile
import argparse
import json
import os
import pprint
import re
import subprocess
def normalize(dict_var):
for k, v in dict_var.items():
if isinstance(v, OrderedDict):
normalize(v)
elif isinstance(v, list):
for e in v:
if isinstance(e, OrderedDict):
normalize(e)
elif type(v) is unicode:
st = v.encode('utf-8')
if re.match(r"0x[0-9A-Fa-f]+", v):
dict_var[k] = u'0x{{.*}}'
elif os.path.isfile(v):
dict_var[k] = u'{{.*}}'
else:
splits = (v.split(u' '))
out_splits = []
for split in splits:
inner_splits = split.rsplit(u':',2)
if os.path.isfile(inner_splits[0]):
out_splits.append(
u'{{.*}}:%s:%s'
%(inner_splits[1],
inner_splits[2]))
continue
out_splits.append(split)
dict_var[k] = ' '.join(out_splits)
def filter_json(dict_var, filters, out):
for k, v in dict_var.items():
if type(v) is unicode:
st = v.encode('utf-8')
if st in filters:
out.append(dict_var)
break
elif isinstance(v, OrderedDict):
filter_json(v, filters, out)
elif isinstance(v, list):
for e in v:
if isinstance(e, OrderedDict):
filter_json(e, filters, out)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--clang", help="The clang binary (could be a relative or absolute path)",
action="store", required=True)
parser.add_argument("--opts", help="other options",
action="store", default='', type=str)
parser.add_argument("--source", help="the source file. Command used to generate the json will be of the format <clang> -cc1 -ast-dump=json <opts> <source>",
action="store", required=True)
parser.add_argument("--filters", help="comma separated list of AST filters. Ex: --filters=TypedefDecl,BuiltinType",
action="store", default='')
args = parser.parse_args()
if not args.source:
print("Specify the source file to give to clang.")
return -1
clang_binary = os.path.abspath(args.clang)
if not os.path.isfile(clang_binary):
print("clang binary specified not present.")
return -1
options = args.opts.split(' ')
filters = Set(args.filters.split(',')) if args.filters else Set([])
note = "// NOTE: CHECK lines have been autogenerated by " \
"gen_ast_dump_json_test.py"
if (args.filters):
note += "\n// using --filters=" + args.filters
cmd = [clang_binary, "-cc1"]
cmd.extend(options)
using_ast_dump_filter = 'ast-dump-filter' in args.opts
cmd.extend(["-ast-dump=json", args.source])
try:
json_str = subprocess.check_output(cmd)
except Exception as ex:
print("The clang command failed with %s" % ex)
return -1
out_asts = []
if using_ast_dump_filter:
splits = re.split('Dumping .*:\n', json_str)
if len(splits) > 1:
for split in splits[1:]:
j = json.loads(split.decode('utf-8'), object_pairs_hook=OrderedDict)
normalize(j)
out_asts.append(j)
else:
j = json.loads(json_str.decode('utf-8'), object_pairs_hook=OrderedDict)
normalize(j)
if len(filters) == 0:
out_asts.append(j)
else:
#assert using_ast_dump_filter is False,\
# "Does not support using compiler's ast-dump-filter "\
# "and the tool's filter option at the same time yet."
filter_json(j, filters, out_asts)
partition = args.source.rpartition('.')
dest_path = '%s-json%s%s' % (partition[0], partition[1], partition[2])
print("Writing json appended source file to %s." %(dest_path))
copyfile(args.source, dest_path)
with open(dest_path, "a") as f:
f.write("\n" + note + "\n")
for out_ast in out_asts:
append_str = json.dumps(out_ast, indent=1, ensure_ascii=False)
out_str = '\n\n'
index = 0
for append_line in append_str.splitlines()[2:]:
if index == 0:
out_str += '// CHECK: %s\n' %(append_line)
index += 1
else:
out_str += '// CHECK-NEXT: %s\n' %(append_line)
f.write(out_str)
return 0
if __name__ == '__main__':
main()
|