aboutsummaryrefslogtreecommitdiff
path: root/tools/highlevel_c.py
blob: cb75044ba2fe09a0b6c3119fdaab289e20a9a1ef (plain)
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
#!/usr/bin/env python3

import os
import sys
import json
import clang.cindex

def find_child_of_kind(node, kind):
    if node.kind == kind:
        return node
    for child in node.get_children():
        found_type = find_child_of_kind(child, kind)
        if found_type:
            return found_type

def get_types_from_annotation(annotation):
    return [t.replace(" ", "") for t in annotation.split(",")]

def parse_call_expr(call_expr):
    if call_expr.spelling == "hash_map_get" or call_expr.spelling == "hash_map_insert":
        args = list(call_expr.get_arguments())

        # First arg
        self_obj = next(args[0].get_children(), None)
        self_obj_def = self_obj.get_definition()
        annotation = next(self_obj_def.get_children(), None)
        if not annotation or annotation.kind != clang.cindex.CursorKind.ANNOTATE_ATTR:
            print("WARNING: Hash map at %s is not annotated" % args[0].location)
            return

        (hash_map_key_type, hash_map_value_type) = get_types_from_annotation(annotation.spelling)
        hash_map_value_type = hash_map_value_type + "*"

        # Second arg
        #key_arg_type = args[1].type.spelling.replace(" ", "")
        #if key_arg_type != hash_map_key_type:
        #    print("Error: Incorrect usage of %s key argument found at %s." % (call_expr.spelling, args[1].location))
        #    print("  Argument variable is of type %s, but the HashMap expects a value of type %s" % (key_arg_type, hash_map_key_type))

        # Third arg
        value_obj = next(args[2].get_children(), None)
        value_arg_type = value_obj.type.spelling.replace(" ", "")

        if value_arg_type != hash_map_value_type:
            print("ERROR: Incorrect usage of %s value argument found at %s." % (call_expr.spelling, args[2].location))
            print("  Argument variable is of type %s, but the HashMap expects a value of type %s" % (value_arg_type, hash_map_value_type))
        #print("def: %s, loc: %s" % (self_obj.get_definition(), self_obj.get_definition().location))

def parse(node):
    if node.kind == clang.cindex.CursorKind.CALL_EXPR:
        parse_call_expr(node)
    for child in node.get_children():
        parse(child)

def compile_commands_get_files(compile_commands_filepath):
    files = []
    with open(compile_commands_filepath) as json_file:
        data = json.load(json_file)
        for obj in data:
            filepath = os.path.join(obj["directory"], obj["file"])
            files.append(filepath)
    return files

def main():
    script_path = os.path.realpath(sys.argv[0])
    script_dir = os.path.dirname(script_path)

    compile_commands_file = os.path.join(script_dir, "..", "compile_commands.json")
    if not os.path.isfile(compile_commands_file):
        print("compile_commands.json file is missing! You need to compile amalgam before running this script")
        exit(1)

    idx = clang.cindex.Index.create()
    for filepath in compile_commands_get_files(compile_commands_file):
        #print("Parsing file: %s" % filepath)
        tu = idx.parse(filepath, args=['-std=c89'], options=0)
        parse(tu.cursor)

if __name__ == "__main__":
    main()