#!/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()