libclang.nut 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. function libclangParse2sqlite(dbname, source_file_name, ...)
  2. {
  3. auto db = SQLite3(dbname);
  4. db.exec_dml([==[
  5. CREATE TABLE IF NOT EXISTS function_file (
  6. id INTEGER PRIMARY KEY,
  7. file_name VARCHAR UNIQUE NOT NULL
  8. );
  9. ]==]);
  10. db.exec_dml([==[
  11. CREATE TABLE IF NOT EXISTS function_declaration (
  12. id INTEGER PRIMARY KEY,
  13. name VARCHAR NOT NULL,
  14. ftype VARCHAR NOT NULL,
  15. return_type VARCHAR NOT NULL,
  16. linkage_type INTEGER,
  17. file_id INTEGER NOT NULL REFERENCES function_file(id),
  18. line INTEGER,
  19. col INTEGER,
  20. UNIQUE(file_id, name, line, col)
  21. );
  22. ]==]);
  23. db.exec_dml([==[
  24. CREATE INDEX IF NOT EXISTS function_declaration_name_file_idx ON function_declaration(name, file_id);
  25. ]==]);
  26. db.exec_dml([==[
  27. CREATE TABLE IF NOT EXISTS function_param (
  28. id INTEGER PRIMARY KEY,
  29. function_id INTEGER NOT NULL REFERENCES function_declaration(id),
  30. name VARCHAR,
  31. type VARCHAR NOT NULL,
  32. kind_id INTEGER,
  33. UNIQUE(function_id, name)
  34. );
  35. ]==]);
  36. db.exec_dml([==[
  37. CREATE TABLE IF NOT EXISTS function_calling (
  38. id INTEGER PRIMARY KEY,
  39. caller_id INTEGER NOT NULL REFERENCES function_declaration(id),
  40. callee_id INTEGER NOT NULL REFERENCES function_declaration(id),
  41. file_id INTEGER NOT NULL REFERENCES function_file(id),
  42. line INTEGER,
  43. col INTEGER,
  44. UNIQUE(file_id, caller_id, callee_id, line, col)
  45. );
  46. ]==]);
  47. db.exec_dml([==[
  48. CREATE INDEX IF NOT EXISTS function_calling_caller_idx ON function_calling(caller_id);
  49. CREATE INDEX IF NOT EXISTS function_calling_callee_idx ON function_calling(callee_id);
  50. ]==]);
  51. auto stmt_get_file_id = db.prepare("SELECT id FROM function_file WHERE file_name = ?;");
  52. auto stmt_get_func_decl_id = db.prepare("SELECT id FROM function_declaration WHERE file_id = ? AND name=? AND line=? AND col=?;");
  53. auto stmt_insert_file = db.prepare("INSERT OR IGNORE INTO function_file (file_name) VALUES (?);");
  54. auto stmt_insert_function = db.prepare("INSERT OR IGNORE INTO function_declaration (name, ftype, return_type, linkage_type, file_id, line, col) VALUES (?, ?, ?, ?, ?, ?, ?);");
  55. auto stmt_insert_call = db.prepare("INSERT OR IGNORE INTO function_calling (caller_id, callee_id, file_id, line, col) VALUES (?, ?, ?, ?, ?);");
  56. auto stmt_insert_param = db.prepare("INSERT OR IGNORE INTO function_param (function_id, name, type, kind_id) VALUES (?, ?, ?, ?);");
  57. local function cleanBackwardPath(path)
  58. {
  59. while(path.find("/../") > 0)
  60. {
  61. path = path.gsub("/[^/.]+/%.%.", "");
  62. }
  63. return path;
  64. }
  65. local function add_funcfile(file_name)
  66. {
  67. local id = null;
  68. file_name = cleanBackwardPath(file_name);
  69. stmt_get_file_id.bind(1, file_name);
  70. if (stmt_get_file_id.next_row()) {
  71. id = stmt_get_file_id.col(0);
  72. }
  73. stmt_get_file_id.reset();
  74. if(id) {
  75. return id;
  76. }
  77. stmt_insert_file.bind(1, file_name);
  78. local rc = stmt_insert_file.step();
  79. if (rc != db.SQLITE_DONE) {
  80. print("Can't insert: %d : %s\n", rc, db.errmsg());
  81. os.exit(-1);
  82. }
  83. stmt_insert_file.reset();
  84. return db.last_row_id();
  85. }
  86. local function add_funcdecl(file_name, line, col, func_name, func_type, return_type, linkage_type)
  87. {
  88. local file_id = add_funcfile(file_name);
  89. stmt_insert_function.bind(1, func_name);
  90. stmt_insert_function.bind(2, func_type);
  91. stmt_insert_function.bind(3, return_type);
  92. stmt_insert_function.bind(4, linkage_type);
  93. stmt_insert_function.bind(5, file_id);
  94. stmt_insert_function.bind(6, line);
  95. stmt_insert_function.bind(7, col);
  96. local rc = stmt_insert_function.step();
  97. if (rc != db.SQLITE_DONE) {
  98. print("Can't insert: %d : %s\n", rc, db.errmsg());
  99. os.exit(-1);
  100. }
  101. stmt_insert_function.reset();
  102. }
  103. local function get_func_decl_id(file_id, func_name, line, col)
  104. {
  105. local id = null;
  106. stmt_get_func_decl_id.bind(1, file_id);
  107. stmt_get_func_decl_id.bind(2, func_name);
  108. stmt_get_func_decl_id.bind(3, line);
  109. stmt_get_func_decl_id.bind(4, col);
  110. if (stmt_get_func_decl_id.next_row()) {
  111. id = stmt_get_func_decl_id.col(0);
  112. }
  113. stmt_get_func_decl_id.reset();
  114. return id;
  115. }
  116. local function add_funcparam(file_name, line, col, func_name, param_name, param_type, type_kind)
  117. {
  118. local file_id = add_funcfile(file_name);
  119. local func_id = get_func_decl_id(file_id, func_name, line, col);
  120. stmt_insert_param.bind(1, func_id);
  121. stmt_insert_param.bind(2, param_name);
  122. stmt_insert_param.bind(3, param_type);
  123. stmt_insert_param.bind(4, type_kind);
  124. local rc = stmt_insert_param.step();
  125. if (rc != db.SQLITE_DONE) {
  126. print("Can't insert: %d : %s\n", rc, db.errmsg());
  127. os.exit(-1);
  128. }
  129. stmt_insert_param.reset();
  130. }
  131. local function add_funccall(file_name, line, col, from_func, from_line, from_col, to_func_file, to_func_line, to_func_col, to_func)
  132. {
  133. local file_id = add_funcfile(file_name);
  134. local from_func_id = get_func_decl_id(file_id, from_func, from_line, from_col);
  135. local to_file_id = add_funcfile(to_func_file);
  136. local to_func_id = get_func_decl_id(to_file_id, to_func, to_func_line, to_func_col);
  137. stmt_insert_call.bind(1, from_func_id);
  138. stmt_insert_call.bind(2, to_func_id);
  139. stmt_insert_call.bind(3, file_id);
  140. stmt_insert_call.bind(4, line);
  141. stmt_insert_call.bind(5, col);
  142. local rc = stmt_insert_call.step();
  143. if (rc != db.SQLITE_DONE) {
  144. print("Can't insert: %d : %s\n", rc, db.errmsg());
  145. os.exit(-1);
  146. }
  147. stmt_insert_call.reset();
  148. }
  149. db.exec_dml("BEGIN;");
  150. auto libclang = new LibClang();
  151. local function libclangVisitor(...)
  152. {
  153. //print("Hello!");
  154. //print(vargv.join("\t"));
  155. //try
  156. {
  157. local vtype = vargv[0];
  158. switch(vtype)
  159. {
  160. case "CallExpr":
  161. //vtype, file_name, line, col, from_func, from_line, from_col, to_func_file, to_func_line, to_func_col, to_func
  162. add_funccall(vargv[1], vargv[2], vargv[3], vargv[4], vargv[5], vargv[6], vargv[7], vargv[8], vargv[9], vargv[10]);
  163. break;
  164. case "FuncDecl":
  165. //vtype, file_name, line, col, func_name, func_type, return_type, linkage_type
  166. add_funcdecl(vargv[1], vargv[2], vargv[3], vargv[4], vargv[5], vargv[6], vargv[7]);
  167. break;
  168. case "FuncParam":
  169. //vtype, file_name, line, col, func_name, param_name, param_type, type_kind
  170. add_funcparam(vargv[1], vargv[2], vargv[3], vargv[4], vargv[5], vargv[6], vargv[7]);
  171. break;
  172. }
  173. }
  174. //catch(e)
  175. {
  176. //print(e);
  177. }
  178. }
  179. //libclang.parseTranslationUnit(libclangVisitor, source_file_name, "-I.", "-I/home/mingo/local/clang-3.6/include");
  180. auto call_args = [libclang, libclangVisitor, source_file_name];
  181. foreach(p in vargv)
  182. {
  183. call_args.append(p);
  184. }
  185. libclang.parseTranslationUnit.acall(call_args);
  186. libclang.close();
  187. db.exec_dml([==[
  188. CREATE VIEW IF NOT EXISTS "function_calling_list_view" AS
  189. SELECT
  190. a."id",
  191. d.name AS caller,
  192. c.name AS callee,
  193. b.file_name,
  194. a."line",
  195. a."col",
  196. a."caller_id",
  197. a."callee_id",
  198. a."file_id"
  199. FROM "function_calling" AS a
  200. LEFT JOIN "function_file" AS b ON a."file_id" = b."id"
  201. LEFT JOIN "function_declaration" AS c ON a."callee_id" = c."id"
  202. LEFT JOIN "function_declaration" AS d ON a."caller_id" = d."id";
  203. CREATE VIEW IF NOT EXISTS "function_declaration_list_view" AS
  204. SELECT
  205. a."id",
  206. a."name",
  207. a."ftype",
  208. a."return_type",
  209. a."linkage_type",
  210. b.file_name,
  211. a."line",
  212. a."col",
  213. a."file_id"
  214. FROM "function_declaration" AS a
  215. LEFT JOIN "function_file" AS b ON a."file_id" = b."id";
  216. CREATE VIEW IF NOT EXISTS "function_param_list_view" AS
  217. SELECT
  218. a."id",
  219. b."name" AS function_name,
  220. a."name" AS param_name,
  221. a."type",
  222. a."kind_id",
  223. a."function_id"
  224. FROM "function_param" AS a
  225. LEFT JOIN "function_declaration" AS b ON a."function_id" = b."id";
  226. CREATE VIEW IF NOT EXISTS function_calling_count_view AS
  227. SELECT b.id, b.name, COUNT(*) AS calls, c.file_name
  228. FROM function_calling a
  229. LEFT JOIN function_declaration b
  230. ON a.callee_id = b.id
  231. LEFT JOIN function_file c
  232. ON b.file_id = c.id
  233. GROUP BY a.callee_id
  234. ORDER BY 3 DESC, 2 ASC;
  235. ]==]);
  236. /*
  237. db.exec_dml([==[
  238. CREATE VIEW IF NOT EXISTS functions_of_interest_view AS
  239. WITH
  240. source_file AS(
  241. SELECT id FROM function_file WHERE file_name = 'SOURCE_FILE_NAME'
  242. )
  243. SELECT caller_id as fid FROM function_calling a, source_file as b WHERE a.file_id = b.id
  244. UNION
  245. SELECT callee_id as fid FROM function_calling a, source_file as b WHERE a.file_id = b.id
  246. UNION
  247. SELECT a.id as fid FROM function_declaration a, source_file as b WHERE a.file_id = b.id;
  248. ]==].gsub("SOURCE_FILE_NAME", source_file_name));
  249. db.exec_dml([==[
  250. -- remove function parameter not in use
  251. DELETE FROM function_param
  252. WHERE function_id NOT IN(
  253. SELECT fid FROM functions_of_interest_view
  254. );
  255. -- remove functio_declaration not in use
  256. DELETE FROM function_declaration
  257. WHERE id NOT IN(
  258. SELECT fid FROM functions_of_interest_view
  259. );
  260. -- remove function_file not in use
  261. DELETE FROM function_file
  262. WHERE id NOT IN(
  263. SELECT DISTINCT file_id FROM function_declaration
  264. );
  265. ]==]);
  266. */
  267. db.exec_dml("COMMIT;");
  268. stmt_insert_param.finalize();
  269. stmt_insert_call.finalize();
  270. stmt_insert_function.finalize();
  271. stmt_get_func_decl_id.finalize();
  272. stmt_insert_file.finalize();
  273. stmt_get_file_id.finalize();
  274. db.close();
  275. }
  276. //libclangParse2sqlite("c2sqlite.db", "c2sqlite.c", "-I.", "-I/home/mingo/local/clang-3.6/include");