sq_libclang.cpp 15 KB

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