2
0

sq_libclang.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. #ifdef WITH_LIBCLANG
  2. #include "squirrel.h"
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include "sqstdblobimpl.h"
  7. #include "dynamic_library.h"
  8. #include <clang-c/Index.h>
  9. #include <clang-c/Platform.h>
  10. /*SquiLu
  11. local dynamic_functions = [
  12. ["CXIndex", "clang_createIndex",
  13. @"int excludeDeclarationsFromPCH, int displayDiagnostics"],
  14. ["void", "clang_disposeIndex", "CXIndex index"],
  15. ["CXTranslationUnit", "clang_parseTranslationUnit",
  16. @"CXIndex CIdx,
  17. const char *source_filename,
  18. const char *const *command_line_args,
  19. int num_command_line_args,
  20. struct CXUnsavedFile *unsaved_files,
  21. unsigned num_unsaved_files,
  22. unsigned options"],
  23. ["CXCursor", "clang_getTranslationUnitCursor", "CXTranslationUnit"],
  24. ["void", "clang_disposeTranslationUnit", "CXTranslationUnit"],
  25. ["unsigned", "clang_visitChildren",
  26. @"CXCursor parent,
  27. CXCursorVisitor visitor,
  28. CXClientData client_data"],
  29. ["enum CXCursorKind", "clang_getCursorKind", "CXCursor"],
  30. ["CXType", "clang_getCursorType", "CXCursor"],
  31. ["CXString", "clang_getCursorSpelling", "CXCursor"],
  32. ["CXString", "clang_getTypeSpelling", "CXType CT"],
  33. ["CXString", "clang_getCursorKindSpelling", "enum CXCursorKind"],
  34. ["CXCursor", "clang_getCursorReferenced", "CXCursor"],
  35. ["const char *", "clang_getCString", "CXString string"],
  36. ["void", "clang_disposeString", "CXString str"],
  37. ["CXSourceLocation", "clang_getCursorLocation", "CXCursor"],
  38. ["void", "clang_getPresumedLocation",
  39. @"CXSourceLocation location,
  40. CXString *filename,
  41. unsigned *line,
  42. unsigned *column"],
  43. ["enum CXLinkageKind", "clang_getCursorLinkage", "CXCursor"],
  44. ["CXType", "clang_getResultType", "CXType"],
  45. ];
  46. function write_dynamic_functions_declaration(){
  47. foreach(k,v in dynamic_functions) {
  48. putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
  49. putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
  50. }
  51. }
  52. function write_dynamic_functions_load(){
  53. foreach(k,v in dynamic_functions){
  54. putsnl("dl" + v[1] + " = (" + v[1] + "_t) dynamicLib.dlsym(\"" + v[1] + "\");");
  55. putsnl("if(!dl" + v[1] + ") return false;");
  56. }
  57. }
  58. SquiLu*/
  59. static DynamicLibrary dynamicLib;
  60. //@write_dynamic_functions_declaration();
  61. // generated-code:begin
  62. typedef CXIndex (*clang_createIndex_t)(int excludeDeclarationsFromPCH, int displayDiagnostics);
  63. static clang_createIndex_t dlclang_createIndex = 0;
  64. typedef void (*clang_disposeIndex_t)(CXIndex index);
  65. static clang_disposeIndex_t dlclang_disposeIndex = 0;
  66. typedef CXTranslationUnit (*clang_parseTranslationUnit_t)(CXIndex CIdx,
  67. const char *source_filename,
  68. const char *const *command_line_args,
  69. int num_command_line_args,
  70. struct CXUnsavedFile *unsaved_files,
  71. unsigned num_unsaved_files,
  72. unsigned options);
  73. static clang_parseTranslationUnit_t dlclang_parseTranslationUnit = 0;
  74. typedef CXCursor (*clang_getTranslationUnitCursor_t)(CXTranslationUnit);
  75. static clang_getTranslationUnitCursor_t dlclang_getTranslationUnitCursor = 0;
  76. typedef void (*clang_disposeTranslationUnit_t)(CXTranslationUnit);
  77. static clang_disposeTranslationUnit_t dlclang_disposeTranslationUnit = 0;
  78. typedef unsigned (*clang_visitChildren_t)(CXCursor parent,
  79. CXCursorVisitor visitor,
  80. CXClientData client_data);
  81. static clang_visitChildren_t dlclang_visitChildren = 0;
  82. typedef enum CXCursorKind (*clang_getCursorKind_t)(CXCursor);
  83. static clang_getCursorKind_t dlclang_getCursorKind = 0;
  84. typedef CXType (*clang_getCursorType_t)(CXCursor);
  85. static clang_getCursorType_t dlclang_getCursorType = 0;
  86. typedef CXString (*clang_getCursorSpelling_t)(CXCursor);
  87. static clang_getCursorSpelling_t dlclang_getCursorSpelling = 0;
  88. typedef CXString (*clang_getTypeSpelling_t)(CXType CT);
  89. static clang_getTypeSpelling_t dlclang_getTypeSpelling = 0;
  90. typedef CXString (*clang_getCursorKindSpelling_t)(enum CXCursorKind);
  91. static clang_getCursorKindSpelling_t dlclang_getCursorKindSpelling = 0;
  92. typedef CXCursor (*clang_getCursorReferenced_t)(CXCursor);
  93. static clang_getCursorReferenced_t dlclang_getCursorReferenced = 0;
  94. typedef const char * (*clang_getCString_t)(CXString string);
  95. static clang_getCString_t dlclang_getCString = 0;
  96. typedef void (*clang_disposeString_t)(CXString str);
  97. static clang_disposeString_t dlclang_disposeString = 0;
  98. typedef CXSourceLocation (*clang_getCursorLocation_t)(CXCursor);
  99. static clang_getCursorLocation_t dlclang_getCursorLocation = 0;
  100. typedef void (*clang_getPresumedLocation_t)(CXSourceLocation location,
  101. CXString *filename,
  102. unsigned *line,
  103. unsigned *column);
  104. static clang_getPresumedLocation_t dlclang_getPresumedLocation = 0;
  105. typedef enum CXLinkageKind (*clang_getCursorLinkage_t)(CXCursor);
  106. static clang_getCursorLinkage_t dlclang_getCursorLinkage = 0;
  107. typedef CXType (*clang_getResultType_t)(CXType);
  108. static clang_getResultType_t dlclang_getResultType = 0;
  109. // generated-code:end
  110. static const char *dynamicLibName = DYNLIB_FOR_OS(libclang);
  111. static bool load_dynamicLib()
  112. {
  113. if(dlclang_createIndex) return true;
  114. if(dynamicLib.open(dynamicLibName))
  115. {
  116. //@write_dynamic_functions_load();
  117. // generated-code:begin
  118. dlclang_createIndex = (clang_createIndex_t) dynamicLib.dlsym("clang_createIndex");
  119. if(!dlclang_createIndex) return false;
  120. dlclang_disposeIndex = (clang_disposeIndex_t) dynamicLib.dlsym("clang_disposeIndex");
  121. if(!dlclang_disposeIndex) return false;
  122. dlclang_parseTranslationUnit = (clang_parseTranslationUnit_t) dynamicLib.dlsym("clang_parseTranslationUnit");
  123. if(!dlclang_parseTranslationUnit) return false;
  124. dlclang_getTranslationUnitCursor = (clang_getTranslationUnitCursor_t) dynamicLib.dlsym("clang_getTranslationUnitCursor");
  125. if(!dlclang_getTranslationUnitCursor) return false;
  126. dlclang_disposeTranslationUnit = (clang_disposeTranslationUnit_t) dynamicLib.dlsym("clang_disposeTranslationUnit");
  127. if(!dlclang_disposeTranslationUnit) return false;
  128. dlclang_visitChildren = (clang_visitChildren_t) dynamicLib.dlsym("clang_visitChildren");
  129. if(!dlclang_visitChildren) return false;
  130. dlclang_getCursorKind = (clang_getCursorKind_t) dynamicLib.dlsym("clang_getCursorKind");
  131. if(!dlclang_getCursorKind) return false;
  132. dlclang_getCursorType = (clang_getCursorType_t) dynamicLib.dlsym("clang_getCursorType");
  133. if(!dlclang_getCursorType) return false;
  134. dlclang_getCursorSpelling = (clang_getCursorSpelling_t) dynamicLib.dlsym("clang_getCursorSpelling");
  135. if(!dlclang_getCursorSpelling) return false;
  136. dlclang_getTypeSpelling = (clang_getTypeSpelling_t) dynamicLib.dlsym("clang_getTypeSpelling");
  137. if(!dlclang_getTypeSpelling) return false;
  138. dlclang_getCursorKindSpelling = (clang_getCursorKindSpelling_t) dynamicLib.dlsym("clang_getCursorKindSpelling");
  139. if(!dlclang_getCursorKindSpelling) return false;
  140. dlclang_getCursorReferenced = (clang_getCursorReferenced_t) dynamicLib.dlsym("clang_getCursorReferenced");
  141. if(!dlclang_getCursorReferenced) return false;
  142. dlclang_getCString = (clang_getCString_t) dynamicLib.dlsym("clang_getCString");
  143. if(!dlclang_getCString) return false;
  144. dlclang_disposeString = (clang_disposeString_t) dynamicLib.dlsym("clang_disposeString");
  145. if(!dlclang_disposeString) return false;
  146. dlclang_getCursorLocation = (clang_getCursorLocation_t) dynamicLib.dlsym("clang_getCursorLocation");
  147. if(!dlclang_getCursorLocation) return false;
  148. dlclang_getPresumedLocation = (clang_getPresumedLocation_t) dynamicLib.dlsym("clang_getPresumedLocation");
  149. if(!dlclang_getPresumedLocation) return false;
  150. dlclang_getCursorLinkage = (clang_getCursorLinkage_t) dynamicLib.dlsym("clang_getCursorLinkage");
  151. if(!dlclang_getCursorLinkage) return false;
  152. dlclang_getResultType = (clang_getResultType_t) dynamicLib.dlsym("clang_getResultType");
  153. if(!dlclang_getResultType) return false;
  154. // generated-code:end
  155. return true;
  156. }
  157. return false;
  158. }
  159. ////////////////////////////////////////////////////////////////////////////////
  160. static const SQChar *LibClang_TAG = _SC("LibClang");
  161. struct MyLibClang {
  162. CXIndex index;
  163. int depth;
  164. const char *file_name;
  165. char *function_name;
  166. unsigned int prev_line, prev_column;
  167. unsigned int line, column;
  168. HSQUIRRELVM v;
  169. HSQOBJECT visitor_cb;
  170. HSQOBJECT visitor_udata;
  171. };
  172. static SQRESULT get_libclang_instance(HSQUIRRELVM v, SQInteger idx, MyLibClang **self){
  173. SQRESULT _rc_;
  174. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)LibClang_TAG)) < 0) return _rc_;
  175. if(!*self) return sq_throwerror(v, _SC("libclang is closed"));
  176. return _rc_;
  177. }
  178. #define GET_libclang_INSTANCE_AT(idx) \
  179. MyLibClang *self=NULL; \
  180. if((_rc_ = get_libclang_instance(v,idx,&self)) < 0) return _rc_;
  181. #define GET_libclang_INSTANCE() GET_libclang_INSTANCE_AT(1)
  182. static void release_visitor_cb(MyLibClang *self)
  183. {
  184. sq_release(self->v, &self->visitor_cb);
  185. sq_resetobject(&self->visitor_cb);
  186. }
  187. static SQRESULT sq_libclang_releasehook(SQUserPointer p, SQInteger size, void */*ep*/)
  188. {
  189. MyLibClang *self = ((MyLibClang *)p);
  190. if (self)
  191. {
  192. if(self->index)
  193. {
  194. dlclang_disposeIndex(self->index);
  195. }
  196. release_visitor_cb(self);
  197. sq_free(self, sizeof(MyLibClang));
  198. }
  199. return 0;
  200. }
  201. static SQRESULT sq_libclang_constructor(HSQUIRRELVM v)
  202. {
  203. //SQ_FUNC_VARS_NO_TOP(v);
  204. if(!load_dynamicLib()) return sq_throwerror(v, _SC("Failed to load libclang !"));
  205. MyLibClang *self = (MyLibClang *)sq_malloc(sizeof(MyLibClang));
  206. memset(self, 0, sizeof(MyLibClang));
  207. self->v = v;
  208. self->index = dlclang_createIndex(0, 0);
  209. sq_setinstanceup(v, 1, self);
  210. sq_setreleasehook(v,1, sq_libclang_releasehook);
  211. return 1;
  212. }
  213. static SQRESULT sq_libclang_close(HSQUIRRELVM v){
  214. SQ_FUNC_VARS_NO_TOP(v);
  215. GET_libclang_INSTANCE();
  216. sq_libclang_releasehook(self, sizeof(MyLibClang), v);
  217. sq_setinstanceup(v, 1, 0); //next calls will fail with "libclang is closed"
  218. return 0;
  219. }
  220. static void call_visitor_cb(MyLibClang *self, const SQChar *sig, ...)
  221. {
  222. HSQUIRRELVM v = self->v;
  223. int top = sq_gettop(v);
  224. sq_pushobject(v, self->visitor_cb);
  225. //sq_pushroottable(v);
  226. //sq_pushobject(v, self->busy_udata);
  227. va_list vl;
  228. va_start(vl, sig);
  229. /*SQRESULT rc =*/ sq_call_va_vl(v, SQFalse, -1, NULL, 0, sig, vl);
  230. va_end(vl);
  231. sq_settop(v, top);
  232. }
  233. static enum CXChildVisitResult
  234. functionDeclVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
  235. {
  236. MyLibClang *cvu = (MyLibClang*) client_data;
  237. enum CXCursorKind kind = dlclang_getCursorKind(cursor);
  238. CXType type = dlclang_getCursorType(cursor);
  239. CXString type_spelling;
  240. //CXString type_kind_spelling;
  241. CXString name;
  242. if (kind == CXCursor_ParmDecl){
  243. name = dlclang_getCursorSpelling(cursor);
  244. type_spelling = dlclang_getTypeSpelling(type);
  245. //db_add_funcparam(cvu->db, cvu->function_name, dlclang_getCString(name), dlclang_getCString(type_spelling), type.kind);
  246. call_visitor_cb(cvu, "ssiisssi",
  247. "FuncParam",
  248. cvu->file_name,
  249. cvu->line,
  250. cvu->column,
  251. cvu->function_name,
  252. dlclang_getCString(name),
  253. dlclang_getCString(type_spelling),
  254. type.kind);
  255. dlclang_disposeString(name);
  256. dlclang_disposeString(type_spelling);
  257. }
  258. return CXChildVisit_Continue;
  259. }
  260. static enum CXChildVisitResult
  261. cursorVisitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
  262. {
  263. MyLibClang *cvu = (MyLibClang*) client_data;
  264. enum CXCursorKind kind = dlclang_getCursorKind(cursor);
  265. CXString name = dlclang_getCursorSpelling(cursor);
  266. enum CXChildVisitResult ret = CXChildVisit_Recurse;
  267. CXString filename;
  268. unsigned int line, column;
  269. CXSourceLocation location = dlclang_getCursorLocation(cursor);
  270. dlclang_getPresumedLocation(location, &filename, &line, &column);
  271. cvu->file_name = dlclang_getCString(filename);
  272. cvu->line = line;
  273. cvu->column = column;
  274. //sqlite_int64 file_id = db_add_funcfile(cvu->db, dlclang_getCString(filename));
  275. //call_visitor_cb(cvu, "ss", "FuncFile", dlclang_getCString(filename));
  276. if (kind == CXCursor_FunctionDecl) {
  277. enum CXLinkageKind lk = dlclang_getCursorLinkage(cursor);
  278. CXType type = dlclang_getCursorType(cursor);
  279. CXString type_spelling = dlclang_getTypeSpelling(type);
  280. CXType rtype = dlclang_getResultType(type);
  281. CXString rtype_spelling = dlclang_getTypeSpelling(rtype);
  282. free(cvu->function_name);
  283. cvu->function_name = strdup(dlclang_getCString(name));
  284. cvu->prev_line = line;
  285. cvu->prev_column = column;
  286. //db_add_funcdecl(cvu->db, cvu->function_name, dlclang_getCString(type_spelling),
  287. // dlclang_getCString(rtype_spelling), lk, file_id, line, column);
  288. call_visitor_cb(cvu, "ssiisssi",
  289. "FuncDecl",
  290. cvu->file_name,
  291. cvu->line,
  292. cvu->column,
  293. cvu->function_name,
  294. dlclang_getCString(type_spelling),
  295. dlclang_getCString(rtype_spelling),
  296. lk);
  297. dlclang_visitChildren(cursor, *functionDeclVisitor, cvu);
  298. dlclang_disposeString(type_spelling);
  299. dlclang_disposeString(rtype_spelling);
  300. } else if (kind == CXCursor_CallExpr) {
  301. //CXType type = clang_getCursorType(cursor);
  302. //CXString type_spelling = clang_getTypeSpelling(type);
  303. //printf("%s\n", type_spelling);
  304. //db_add_funccall(cvu->db, cvu->function_name, dlclang_getCString(name), file_id, line, column);
  305. CXCursor to_func_file_cursor = dlclang_getCursorReferenced(cursor);
  306. CXString to_func_filename;
  307. unsigned int to_func_line, to_func_column;
  308. CXSourceLocation to_func_location = dlclang_getCursorLocation(to_func_file_cursor);
  309. dlclang_getPresumedLocation(to_func_location, &to_func_filename, &to_func_line, &to_func_column);
  310. call_visitor_cb(cvu, "ssiisiisiis",
  311. "CallExpr",
  312. cvu->file_name,
  313. line,
  314. column,
  315. cvu->function_name, //from function
  316. cvu->prev_line,
  317. cvu->prev_column,
  318. dlclang_getCString(to_func_filename),
  319. to_func_line,
  320. to_func_column,
  321. dlclang_getCString(name)); //to function
  322. dlclang_disposeString(to_func_filename);
  323. ret = CXChildVisit_Continue;
  324. }
  325. dlclang_disposeString(name);
  326. dlclang_disposeString(filename);
  327. return ret;
  328. }
  329. static SQRESULT sq_libclang_parseTranslationUnit(HSQUIRRELVM v){
  330. SQ_FUNC_VARS(v);
  331. GET_libclang_INSTANCE();
  332. if(sq_gettype(v, 2) != OT_CLOSURE)
  333. return sq_throwerror(v, _SC("invalid fisrt parameter expected closure"));
  334. SQ_GET_STRING(v, 3, fname);
  335. release_visitor_cb(self);
  336. sq_getstackobj(v, 2, &self->visitor_cb);
  337. sq_addref(v, &self->visitor_cb);
  338. const char *cl_argsDefault[] = {"-I."};
  339. const char **cl_args = cl_argsDefault;
  340. int cl_argNum = 1;
  341. int rc = 0;
  342. const int cl_arg_start = 4;
  343. bool has_extra_params = _top_ >= cl_arg_start;
  344. if(has_extra_params)
  345. {
  346. //create cl_args with extra parameters
  347. cl_argNum = _top_ - (cl_arg_start -1);
  348. cl_args = (const char **)sq_malloc(sizeof(char*) * cl_argNum);
  349. for(int i=cl_arg_start; i <= _top_; ++i)
  350. {
  351. const SQChar *p;
  352. if(sq_gettype(v, i) == OT_STRING)
  353. {
  354. rc = sq_getstring(v, i, &p);
  355. }
  356. else
  357. {
  358. rc = sq_throwerror(v, _SC("not a string parameter at %d"), i);
  359. goto cleanup;
  360. }
  361. cl_args[i-cl_arg_start] = p;
  362. }
  363. }
  364. CXTranslationUnit TU;
  365. CXCursor rootCursor;
  366. TU = dlclang_parseTranslationUnit(self->index, fname,
  367. cl_args, cl_argNum, 0, 0, CXTranslationUnit_Incomplete);
  368. if (TU == NULL) {
  369. rc = sq_throwerror(v, _SC("clang_parseTranslationUnit for %s failed\n"), fname);
  370. goto cleanup;
  371. }
  372. rootCursor = dlclang_getTranslationUnitCursor(TU);
  373. dlclang_visitChildren(rootCursor, cursorVisitor, self);
  374. dlclang_disposeTranslationUnit(TU);
  375. cleanup:
  376. if(has_extra_params)
  377. {
  378. sq_free(cl_args, sizeof(char*) * cl_argNum);
  379. }
  380. return rc;
  381. }
  382. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_libclang_##name,nparams,tycheck}
  383. static SQRegFunction sq_libclang_methods[] =
  384. {
  385. _DECL_FUNC(constructor, 1, _SC("x")),
  386. _DECL_FUNC(close, 1, _SC("x")),
  387. _DECL_FUNC(parseTranslationUnit, -3, _SC("xcs")),
  388. {0,0}
  389. };
  390. #undef _DECL_FUNC
  391. #ifdef __cplusplus
  392. extern "C" {
  393. #endif
  394. SQRESULT sqext_register_libclang(HSQUIRRELVM v)
  395. {
  396. sq_pushstring(v,LibClang_TAG,-1);
  397. sq_newclass(v,SQFalse);
  398. sq_settypetag(v,-1,(void*)LibClang_TAG);
  399. sq_insert_reg_funcs(v, sq_libclang_methods);
  400. sq_newslot(v,-3,SQTrue);
  401. return 0;
  402. }
  403. #ifdef __cplusplus
  404. }
  405. #endif
  406. #endif // WITH_LIBCLANG