c-index-test.c 92 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905
  1. /* c-index-test.c */
  2. #include "clang-c/Index.h"
  3. #include <ctype.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. /******************************************************************************/
  9. /* Utility functions. */
  10. /******************************************************************************/
  11. #ifdef _MSC_VER
  12. char *basename(const char* path)
  13. {
  14. char* base1 = (char*)strrchr(path, '/');
  15. char* base2 = (char*)strrchr(path, '\\');
  16. if (base1 && base2)
  17. return((base1 > base2) ? base1 + 1 : base2 + 1);
  18. else if (base1)
  19. return(base1 + 1);
  20. else if (base2)
  21. return(base2 + 1);
  22. return((char*)path);
  23. }
  24. #else
  25. extern char *basename(const char *);
  26. #endif
  27. /** \brief Return the default parsing options. */
  28. static unsigned getDefaultParsingOptions() {
  29. unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
  30. if (getenv("CINDEXTEST_EDITING"))
  31. options |= clang_defaultEditingTranslationUnitOptions();
  32. if (getenv("CINDEXTEST_COMPLETION_CACHING"))
  33. options |= CXTranslationUnit_CacheCompletionResults;
  34. if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
  35. options &= ~CXTranslationUnit_CacheCompletionResults;
  36. if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
  37. options |= CXTranslationUnit_SkipFunctionBodies;
  38. return options;
  39. }
  40. static int checkForErrors(CXTranslationUnit TU);
  41. static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
  42. unsigned end_line, unsigned end_column) {
  43. fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
  44. end_line, end_column);
  45. }
  46. static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
  47. CXTranslationUnit *TU) {
  48. *TU = clang_createTranslationUnit(Idx, file);
  49. if (!*TU) {
  50. fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
  51. return 0;
  52. }
  53. return 1;
  54. }
  55. void free_remapped_files(struct CXUnsavedFile *unsaved_files,
  56. int num_unsaved_files) {
  57. int i;
  58. for (i = 0; i != num_unsaved_files; ++i) {
  59. free((char *)unsaved_files[i].Filename);
  60. free((char *)unsaved_files[i].Contents);
  61. }
  62. free(unsaved_files);
  63. }
  64. int parse_remapped_files(int argc, const char **argv, int start_arg,
  65. struct CXUnsavedFile **unsaved_files,
  66. int *num_unsaved_files) {
  67. int i;
  68. int arg;
  69. int prefix_len = strlen("-remap-file=");
  70. *unsaved_files = 0;
  71. *num_unsaved_files = 0;
  72. /* Count the number of remapped files. */
  73. for (arg = start_arg; arg < argc; ++arg) {
  74. if (strncmp(argv[arg], "-remap-file=", prefix_len))
  75. break;
  76. ++*num_unsaved_files;
  77. }
  78. if (*num_unsaved_files == 0)
  79. return 0;
  80. *unsaved_files
  81. = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
  82. *num_unsaved_files);
  83. for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
  84. struct CXUnsavedFile *unsaved = *unsaved_files + i;
  85. const char *arg_string = argv[arg] + prefix_len;
  86. int filename_len;
  87. char *filename;
  88. char *contents;
  89. FILE *to_file;
  90. const char *semi = strchr(arg_string, ';');
  91. if (!semi) {
  92. fprintf(stderr,
  93. "error: -remap-file=from;to argument is missing semicolon\n");
  94. free_remapped_files(*unsaved_files, i);
  95. *unsaved_files = 0;
  96. *num_unsaved_files = 0;
  97. return -1;
  98. }
  99. /* Open the file that we're remapping to. */
  100. to_file = fopen(semi + 1, "rb");
  101. if (!to_file) {
  102. fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
  103. semi + 1);
  104. free_remapped_files(*unsaved_files, i);
  105. *unsaved_files = 0;
  106. *num_unsaved_files = 0;
  107. return -1;
  108. }
  109. /* Determine the length of the file we're remapping to. */
  110. fseek(to_file, 0, SEEK_END);
  111. unsaved->Length = ftell(to_file);
  112. fseek(to_file, 0, SEEK_SET);
  113. /* Read the contents of the file we're remapping to. */
  114. contents = (char *)malloc(unsaved->Length + 1);
  115. if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
  116. fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
  117. (feof(to_file) ? "EOF" : "error"), semi + 1);
  118. fclose(to_file);
  119. free_remapped_files(*unsaved_files, i);
  120. *unsaved_files = 0;
  121. *num_unsaved_files = 0;
  122. return -1;
  123. }
  124. contents[unsaved->Length] = 0;
  125. unsaved->Contents = contents;
  126. /* Close the file. */
  127. fclose(to_file);
  128. /* Copy the file name that we're remapping from. */
  129. filename_len = semi - arg_string;
  130. filename = (char *)malloc(filename_len + 1);
  131. memcpy(filename, arg_string, filename_len);
  132. filename[filename_len] = 0;
  133. unsaved->Filename = filename;
  134. }
  135. return 0;
  136. }
  137. /******************************************************************************/
  138. /* Pretty-printing. */
  139. /******************************************************************************/
  140. static void PrintRange(CXSourceRange R, const char *str) {
  141. CXFile begin_file, end_file;
  142. unsigned begin_line, begin_column, end_line, end_column;
  143. clang_getSpellingLocation(clang_getRangeStart(R),
  144. &begin_file, &begin_line, &begin_column, 0);
  145. clang_getSpellingLocation(clang_getRangeEnd(R),
  146. &end_file, &end_line, &end_column, 0);
  147. if (!begin_file || !end_file)
  148. return;
  149. if (str)
  150. printf(" %s=", str);
  151. PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
  152. }
  153. int want_display_name = 0;
  154. static void printVersion(const char *Prefix, CXVersion Version) {
  155. if (Version.Major < 0)
  156. return;
  157. printf("%s%d", Prefix, Version.Major);
  158. if (Version.Minor < 0)
  159. return;
  160. printf(".%d", Version.Minor);
  161. if (Version.Subminor < 0)
  162. return;
  163. printf(".%d", Version.Subminor);
  164. }
  165. static void PrintCursor(CXCursor Cursor) {
  166. CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
  167. if (clang_isInvalid(Cursor.kind)) {
  168. CXString ks = clang_getCursorKindSpelling(Cursor.kind);
  169. printf("Invalid Cursor => %s", clang_getCString(ks));
  170. clang_disposeString(ks);
  171. }
  172. else {
  173. CXString string, ks;
  174. CXCursor Referenced;
  175. unsigned line, column;
  176. CXCursor SpecializationOf;
  177. CXCursor *overridden;
  178. unsigned num_overridden;
  179. unsigned RefNameRangeNr;
  180. CXSourceRange CursorExtent;
  181. CXSourceRange RefNameRange;
  182. int AlwaysUnavailable;
  183. int AlwaysDeprecated;
  184. CXString UnavailableMessage;
  185. CXString DeprecatedMessage;
  186. CXPlatformAvailability PlatformAvailability[2];
  187. int NumPlatformAvailability;
  188. int I;
  189. CXString Comment;
  190. const char *CommentCString;
  191. ks = clang_getCursorKindSpelling(Cursor.kind);
  192. string = want_display_name? clang_getCursorDisplayName(Cursor)
  193. : clang_getCursorSpelling(Cursor);
  194. printf("%s=%s", clang_getCString(ks),
  195. clang_getCString(string));
  196. clang_disposeString(ks);
  197. clang_disposeString(string);
  198. Referenced = clang_getCursorReferenced(Cursor);
  199. if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
  200. if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) {
  201. unsigned I, N = clang_getNumOverloadedDecls(Referenced);
  202. printf("[");
  203. for (I = 0; I != N; ++I) {
  204. CXCursor Ovl = clang_getOverloadedDecl(Referenced, I);
  205. CXSourceLocation Loc;
  206. if (I)
  207. printf(", ");
  208. Loc = clang_getCursorLocation(Ovl);
  209. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  210. printf("%d:%d", line, column);
  211. }
  212. printf("]");
  213. } else {
  214. CXSourceLocation Loc = clang_getCursorLocation(Referenced);
  215. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  216. printf(":%d:%d", line, column);
  217. }
  218. }
  219. if (clang_isCursorDefinition(Cursor))
  220. printf(" (Definition)");
  221. switch (clang_getCursorAvailability(Cursor)) {
  222. case CXAvailability_Available:
  223. break;
  224. case CXAvailability_Deprecated:
  225. printf(" (deprecated)");
  226. break;
  227. case CXAvailability_NotAvailable:
  228. printf(" (unavailable)");
  229. break;
  230. case CXAvailability_NotAccessible:
  231. printf(" (inaccessible)");
  232. break;
  233. }
  234. NumPlatformAvailability
  235. = clang_getCursorPlatformAvailability(Cursor,
  236. &AlwaysDeprecated,
  237. &DeprecatedMessage,
  238. &AlwaysUnavailable,
  239. &UnavailableMessage,
  240. PlatformAvailability, 2);
  241. if (AlwaysUnavailable) {
  242. printf(" (always unavailable: \"%s\")",
  243. clang_getCString(UnavailableMessage));
  244. } else if (AlwaysDeprecated) {
  245. printf(" (always deprecated: \"%s\")",
  246. clang_getCString(DeprecatedMessage));
  247. } else {
  248. for (I = 0; I != NumPlatformAvailability; ++I) {
  249. if (I >= 2)
  250. break;
  251. printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
  252. if (PlatformAvailability[I].Unavailable)
  253. printf(", unavailable");
  254. else {
  255. printVersion(", introduced=", PlatformAvailability[I].Introduced);
  256. printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
  257. printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
  258. }
  259. if (clang_getCString(PlatformAvailability[I].Message)[0])
  260. printf(", message=\"%s\"",
  261. clang_getCString(PlatformAvailability[I].Message));
  262. printf(")");
  263. }
  264. }
  265. for (I = 0; I != NumPlatformAvailability; ++I) {
  266. if (I >= 2)
  267. break;
  268. clang_disposeCXPlatformAvailability(PlatformAvailability + I);
  269. }
  270. clang_disposeString(DeprecatedMessage);
  271. clang_disposeString(UnavailableMessage);
  272. if (clang_CXXMethod_isStatic(Cursor))
  273. printf(" (static)");
  274. if (clang_CXXMethod_isVirtual(Cursor))
  275. printf(" (virtual)");
  276. if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
  277. CXType T =
  278. clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
  279. CXString S = clang_getTypeKindSpelling(T.kind);
  280. printf(" [IBOutletCollection=%s]", clang_getCString(S));
  281. clang_disposeString(S);
  282. }
  283. if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
  284. enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
  285. unsigned isVirtual = clang_isVirtualBase(Cursor);
  286. const char *accessStr = 0;
  287. switch (access) {
  288. case CX_CXXInvalidAccessSpecifier:
  289. accessStr = "invalid"; break;
  290. case CX_CXXPublic:
  291. accessStr = "public"; break;
  292. case CX_CXXProtected:
  293. accessStr = "protected"; break;
  294. case CX_CXXPrivate:
  295. accessStr = "private"; break;
  296. }
  297. printf(" [access=%s isVirtual=%s]", accessStr,
  298. isVirtual ? "true" : "false");
  299. }
  300. SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
  301. if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
  302. CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
  303. CXString Name = clang_getCursorSpelling(SpecializationOf);
  304. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  305. printf(" [Specialization of %s:%d:%d]",
  306. clang_getCString(Name), line, column);
  307. clang_disposeString(Name);
  308. }
  309. clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
  310. if (num_overridden) {
  311. unsigned I;
  312. printf(" [Overrides ");
  313. for (I = 0; I != num_overridden; ++I) {
  314. CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
  315. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  316. if (I)
  317. printf(", ");
  318. printf("@%d:%d", line, column);
  319. }
  320. printf("]");
  321. clang_disposeOverriddenCursors(overridden);
  322. }
  323. if (Cursor.kind == CXCursor_InclusionDirective) {
  324. CXFile File = clang_getIncludedFile(Cursor);
  325. CXString Included = clang_getFileName(File);
  326. printf(" (%s)", clang_getCString(Included));
  327. clang_disposeString(Included);
  328. if (clang_isFileMultipleIncludeGuarded(TU, File))
  329. printf(" [multi-include guarded]");
  330. }
  331. CursorExtent = clang_getCursorExtent(Cursor);
  332. RefNameRange = clang_getCursorReferenceNameRange(Cursor,
  333. CXNameRange_WantQualifier
  334. | CXNameRange_WantSinglePiece
  335. | CXNameRange_WantTemplateArgs,
  336. 0);
  337. if (!clang_equalRanges(CursorExtent, RefNameRange))
  338. PrintRange(RefNameRange, "SingleRefName");
  339. for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
  340. RefNameRange = clang_getCursorReferenceNameRange(Cursor,
  341. CXNameRange_WantQualifier
  342. | CXNameRange_WantTemplateArgs,
  343. RefNameRangeNr);
  344. if (clang_equalRanges(clang_getNullRange(), RefNameRange))
  345. break;
  346. if (!clang_equalRanges(CursorExtent, RefNameRange))
  347. PrintRange(RefNameRange, "RefName");
  348. }
  349. Comment = clang_Cursor_getRawCommentText(Cursor);
  350. CommentCString = clang_getCString(Comment);
  351. if (CommentCString != NULL && CommentCString[0] != '\0') {
  352. printf(" Comment=[");
  353. for ( ; *CommentCString; ++CommentCString) {
  354. if (*CommentCString != '\n')
  355. putchar(*CommentCString);
  356. else
  357. printf("\\n");
  358. }
  359. printf("]");
  360. PrintRange(clang_Cursor_getCommentRange(Cursor), "CommentRange");
  361. }
  362. clang_disposeString(Comment);
  363. }
  364. }
  365. static const char* GetCursorSource(CXCursor Cursor) {
  366. CXSourceLocation Loc = clang_getCursorLocation(Cursor);
  367. CXString source;
  368. CXFile file;
  369. clang_getExpansionLocation(Loc, &file, 0, 0, 0);
  370. source = clang_getFileName(file);
  371. if (!clang_getCString(source)) {
  372. clang_disposeString(source);
  373. return "<invalid loc>";
  374. }
  375. else {
  376. const char *b = basename(clang_getCString(source));
  377. clang_disposeString(source);
  378. return b;
  379. }
  380. }
  381. /******************************************************************************/
  382. /* Callbacks. */
  383. /******************************************************************************/
  384. typedef void (*PostVisitTU)(CXTranslationUnit);
  385. void PrintDiagnostic(CXDiagnostic Diagnostic) {
  386. FILE *out = stderr;
  387. CXFile file;
  388. CXString Msg;
  389. unsigned display_opts = CXDiagnostic_DisplaySourceLocation
  390. | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
  391. | CXDiagnostic_DisplayOption;
  392. unsigned i, num_fixits;
  393. if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
  394. return;
  395. Msg = clang_formatDiagnostic(Diagnostic, display_opts);
  396. fprintf(stderr, "%s\n", clang_getCString(Msg));
  397. clang_disposeString(Msg);
  398. clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
  399. &file, 0, 0, 0);
  400. if (!file)
  401. return;
  402. num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
  403. fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
  404. for (i = 0; i != num_fixits; ++i) {
  405. CXSourceRange range;
  406. CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
  407. CXSourceLocation start = clang_getRangeStart(range);
  408. CXSourceLocation end = clang_getRangeEnd(range);
  409. unsigned start_line, start_column, end_line, end_column;
  410. CXFile start_file, end_file;
  411. clang_getSpellingLocation(start, &start_file, &start_line,
  412. &start_column, 0);
  413. clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
  414. if (clang_equalLocations(start, end)) {
  415. /* Insertion. */
  416. if (start_file == file)
  417. fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
  418. clang_getCString(insertion_text), start_line, start_column);
  419. } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
  420. /* Removal. */
  421. if (start_file == file && end_file == file) {
  422. fprintf(out, "FIX-IT: Remove ");
  423. PrintExtent(out, start_line, start_column, end_line, end_column);
  424. fprintf(out, "\n");
  425. }
  426. } else {
  427. /* Replacement. */
  428. if (start_file == end_file) {
  429. fprintf(out, "FIX-IT: Replace ");
  430. PrintExtent(out, start_line, start_column, end_line, end_column);
  431. fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
  432. }
  433. break;
  434. }
  435. clang_disposeString(insertion_text);
  436. }
  437. }
  438. void PrintDiagnosticSet(CXDiagnosticSet Set) {
  439. int i = 0, n = clang_getNumDiagnosticsInSet(Set);
  440. for ( ; i != n ; ++i) {
  441. CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
  442. CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
  443. PrintDiagnostic(Diag);
  444. if (ChildDiags)
  445. PrintDiagnosticSet(ChildDiags);
  446. }
  447. }
  448. void PrintDiagnostics(CXTranslationUnit TU) {
  449. CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
  450. PrintDiagnosticSet(TUSet);
  451. clang_disposeDiagnosticSet(TUSet);
  452. }
  453. void PrintMemoryUsage(CXTranslationUnit TU) {
  454. unsigned long total = 0;
  455. unsigned i = 0;
  456. CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
  457. fprintf(stderr, "Memory usage:\n");
  458. for (i = 0 ; i != usage.numEntries; ++i) {
  459. const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
  460. unsigned long amount = usage.entries[i].amount;
  461. total += amount;
  462. fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
  463. ((double) amount)/(1024*1024));
  464. }
  465. fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
  466. ((double) total)/(1024*1024));
  467. clang_disposeCXTUResourceUsage(usage);
  468. }
  469. /******************************************************************************/
  470. /* Logic for testing traversal. */
  471. /******************************************************************************/
  472. static const char *FileCheckPrefix = "CHECK";
  473. static void PrintCursorExtent(CXCursor C) {
  474. CXSourceRange extent = clang_getCursorExtent(C);
  475. PrintRange(extent, "Extent");
  476. }
  477. /* Data used by all of the visitors. */
  478. typedef struct {
  479. CXTranslationUnit TU;
  480. enum CXCursorKind *Filter;
  481. } VisitorData;
  482. enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
  483. CXCursor Parent,
  484. CXClientData ClientData) {
  485. VisitorData *Data = (VisitorData *)ClientData;
  486. if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
  487. CXSourceLocation Loc = clang_getCursorLocation(Cursor);
  488. unsigned line, column;
  489. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  490. printf("// %s: %s:%d:%d: ", FileCheckPrefix,
  491. GetCursorSource(Cursor), line, column);
  492. PrintCursor(Cursor);
  493. PrintCursorExtent(Cursor);
  494. printf("\n");
  495. return CXChildVisit_Recurse;
  496. }
  497. return CXChildVisit_Continue;
  498. }
  499. static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
  500. CXCursor Parent,
  501. CXClientData ClientData) {
  502. const char *startBuf, *endBuf;
  503. unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
  504. CXCursor Ref;
  505. VisitorData *Data = (VisitorData *)ClientData;
  506. if (Cursor.kind != CXCursor_FunctionDecl ||
  507. !clang_isCursorDefinition(Cursor))
  508. return CXChildVisit_Continue;
  509. clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
  510. &startLine, &startColumn,
  511. &endLine, &endColumn);
  512. /* Probe the entire body, looking for both decls and refs. */
  513. curLine = startLine;
  514. curColumn = startColumn;
  515. while (startBuf < endBuf) {
  516. CXSourceLocation Loc;
  517. CXFile file;
  518. CXString source;
  519. if (*startBuf == '\n') {
  520. startBuf++;
  521. curLine++;
  522. curColumn = 1;
  523. } else if (*startBuf != '\t')
  524. curColumn++;
  525. Loc = clang_getCursorLocation(Cursor);
  526. clang_getSpellingLocation(Loc, &file, 0, 0, 0);
  527. source = clang_getFileName(file);
  528. if (clang_getCString(source)) {
  529. CXSourceLocation RefLoc
  530. = clang_getLocation(Data->TU, file, curLine, curColumn);
  531. Ref = clang_getCursor(Data->TU, RefLoc);
  532. if (Ref.kind == CXCursor_NoDeclFound) {
  533. /* Nothing found here; that's fine. */
  534. } else if (Ref.kind != CXCursor_FunctionDecl) {
  535. printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
  536. curLine, curColumn);
  537. PrintCursor(Ref);
  538. printf("\n");
  539. }
  540. }
  541. clang_disposeString(source);
  542. startBuf++;
  543. }
  544. return CXChildVisit_Continue;
  545. }
  546. /******************************************************************************/
  547. /* USR testing. */
  548. /******************************************************************************/
  549. enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
  550. CXClientData ClientData) {
  551. VisitorData *Data = (VisitorData *)ClientData;
  552. if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
  553. CXString USR = clang_getCursorUSR(C);
  554. const char *cstr = clang_getCString(USR);
  555. if (!cstr || cstr[0] == '\0') {
  556. clang_disposeString(USR);
  557. return CXChildVisit_Recurse;
  558. }
  559. printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
  560. PrintCursorExtent(C);
  561. printf("\n");
  562. clang_disposeString(USR);
  563. return CXChildVisit_Recurse;
  564. }
  565. return CXChildVisit_Continue;
  566. }
  567. /******************************************************************************/
  568. /* Inclusion stack testing. */
  569. /******************************************************************************/
  570. void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
  571. unsigned includeStackLen, CXClientData data) {
  572. unsigned i;
  573. CXString fname;
  574. fname = clang_getFileName(includedFile);
  575. printf("file: %s\nincluded by:\n", clang_getCString(fname));
  576. clang_disposeString(fname);
  577. for (i = 0; i < includeStackLen; ++i) {
  578. CXFile includingFile;
  579. unsigned line, column;
  580. clang_getSpellingLocation(includeStack[i], &includingFile, &line,
  581. &column, 0);
  582. fname = clang_getFileName(includingFile);
  583. printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
  584. clang_disposeString(fname);
  585. }
  586. printf("\n");
  587. }
  588. void PrintInclusionStack(CXTranslationUnit TU) {
  589. clang_getInclusions(TU, InclusionVisitor, NULL);
  590. }
  591. /******************************************************************************/
  592. /* Linkage testing. */
  593. /******************************************************************************/
  594. static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
  595. CXClientData d) {
  596. const char *linkage = 0;
  597. if (clang_isInvalid(clang_getCursorKind(cursor)))
  598. return CXChildVisit_Recurse;
  599. switch (clang_getCursorLinkage(cursor)) {
  600. case CXLinkage_Invalid: break;
  601. case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
  602. case CXLinkage_Internal: linkage = "Internal"; break;
  603. case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
  604. case CXLinkage_External: linkage = "External"; break;
  605. }
  606. if (linkage) {
  607. PrintCursor(cursor);
  608. printf("linkage=%s\n", linkage);
  609. }
  610. return CXChildVisit_Recurse;
  611. }
  612. /******************************************************************************/
  613. /* Typekind testing. */
  614. /******************************************************************************/
  615. static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p,
  616. CXClientData d) {
  617. if (!clang_isInvalid(clang_getCursorKind(cursor))) {
  618. CXType T = clang_getCursorType(cursor);
  619. CXString S = clang_getTypeKindSpelling(T.kind);
  620. PrintCursor(cursor);
  621. printf(" typekind=%s", clang_getCString(S));
  622. if (clang_isConstQualifiedType(T))
  623. printf(" const");
  624. if (clang_isVolatileQualifiedType(T))
  625. printf(" volatile");
  626. if (clang_isRestrictQualifiedType(T))
  627. printf(" restrict");
  628. clang_disposeString(S);
  629. /* Print the canonical type if it is different. */
  630. {
  631. CXType CT = clang_getCanonicalType(T);
  632. if (!clang_equalTypes(T, CT)) {
  633. CXString CS = clang_getTypeKindSpelling(CT.kind);
  634. printf(" [canonical=%s]", clang_getCString(CS));
  635. clang_disposeString(CS);
  636. }
  637. }
  638. /* Print the return type if it exists. */
  639. {
  640. CXType RT = clang_getCursorResultType(cursor);
  641. if (RT.kind != CXType_Invalid) {
  642. CXString RS = clang_getTypeKindSpelling(RT.kind);
  643. printf(" [result=%s]", clang_getCString(RS));
  644. clang_disposeString(RS);
  645. }
  646. }
  647. /* Print the argument types if they exist. */
  648. {
  649. int numArgs = clang_Cursor_getNumArguments(cursor);
  650. if (numArgs != -1 && numArgs != 0) {
  651. int i;
  652. printf(" [args=");
  653. for (i = 0; i < numArgs; ++i) {
  654. CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
  655. if (T.kind != CXType_Invalid) {
  656. CXString S = clang_getTypeKindSpelling(T.kind);
  657. printf(" %s", clang_getCString(S));
  658. clang_disposeString(S);
  659. }
  660. }
  661. printf("]");
  662. }
  663. }
  664. /* Print if this is a non-POD type. */
  665. printf(" [isPOD=%d]", clang_isPODType(T));
  666. printf("\n");
  667. }
  668. return CXChildVisit_Recurse;
  669. }
  670. /******************************************************************************/
  671. /* Loading ASTs/source. */
  672. /******************************************************************************/
  673. static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
  674. const char *filter, const char *prefix,
  675. CXCursorVisitor Visitor,
  676. PostVisitTU PV) {
  677. if (prefix)
  678. FileCheckPrefix = prefix;
  679. if (Visitor) {
  680. enum CXCursorKind K = CXCursor_NotImplemented;
  681. enum CXCursorKind *ck = &K;
  682. VisitorData Data;
  683. /* Perform some simple filtering. */
  684. if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
  685. else if (!strcmp(filter, "all-display") ||
  686. !strcmp(filter, "local-display")) {
  687. ck = NULL;
  688. want_display_name = 1;
  689. }
  690. else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
  691. else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
  692. else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
  693. else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
  694. else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
  695. else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
  696. else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
  697. else {
  698. fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
  699. return 1;
  700. }
  701. Data.TU = TU;
  702. Data.Filter = ck;
  703. clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
  704. }
  705. if (PV)
  706. PV(TU);
  707. PrintDiagnostics(TU);
  708. if (checkForErrors(TU) != 0) {
  709. clang_disposeTranslationUnit(TU);
  710. return -1;
  711. }
  712. clang_disposeTranslationUnit(TU);
  713. return 0;
  714. }
  715. int perform_test_load_tu(const char *file, const char *filter,
  716. const char *prefix, CXCursorVisitor Visitor,
  717. PostVisitTU PV) {
  718. CXIndex Idx;
  719. CXTranslationUnit TU;
  720. int result;
  721. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  722. !strcmp(filter, "local") ? 1 : 0,
  723. /* displayDiagnosics=*/1);
  724. if (!CreateTranslationUnit(Idx, file, &TU)) {
  725. clang_disposeIndex(Idx);
  726. return 1;
  727. }
  728. result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV);
  729. clang_disposeIndex(Idx);
  730. return result;
  731. }
  732. int perform_test_load_source(int argc, const char **argv,
  733. const char *filter, CXCursorVisitor Visitor,
  734. PostVisitTU PV) {
  735. CXIndex Idx;
  736. CXTranslationUnit TU;
  737. struct CXUnsavedFile *unsaved_files = 0;
  738. int num_unsaved_files = 0;
  739. int result;
  740. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  741. (!strcmp(filter, "local") ||
  742. !strcmp(filter, "local-display"))? 1 : 0,
  743. /* displayDiagnosics=*/0);
  744. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  745. clang_disposeIndex(Idx);
  746. return -1;
  747. }
  748. TU = clang_parseTranslationUnit(Idx, 0,
  749. argv + num_unsaved_files,
  750. argc - num_unsaved_files,
  751. unsaved_files, num_unsaved_files,
  752. getDefaultParsingOptions());
  753. if (!TU) {
  754. fprintf(stderr, "Unable to load translation unit!\n");
  755. free_remapped_files(unsaved_files, num_unsaved_files);
  756. clang_disposeIndex(Idx);
  757. return 1;
  758. }
  759. result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
  760. free_remapped_files(unsaved_files, num_unsaved_files);
  761. clang_disposeIndex(Idx);
  762. return result;
  763. }
  764. int perform_test_reparse_source(int argc, const char **argv, int trials,
  765. const char *filter, CXCursorVisitor Visitor,
  766. PostVisitTU PV) {
  767. CXIndex Idx;
  768. CXTranslationUnit TU;
  769. struct CXUnsavedFile *unsaved_files = 0;
  770. int num_unsaved_files = 0;
  771. int result;
  772. int trial;
  773. int remap_after_trial = 0;
  774. char *endptr = 0;
  775. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  776. !strcmp(filter, "local") ? 1 : 0,
  777. /* displayDiagnosics=*/0);
  778. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  779. clang_disposeIndex(Idx);
  780. return -1;
  781. }
  782. /* Load the initial translation unit -- we do this without honoring remapped
  783. * files, so that we have a way to test results after changing the source. */
  784. TU = clang_parseTranslationUnit(Idx, 0,
  785. argv + num_unsaved_files,
  786. argc - num_unsaved_files,
  787. 0, 0, getDefaultParsingOptions());
  788. if (!TU) {
  789. fprintf(stderr, "Unable to load translation unit!\n");
  790. free_remapped_files(unsaved_files, num_unsaved_files);
  791. clang_disposeIndex(Idx);
  792. return 1;
  793. }
  794. if (checkForErrors(TU) != 0)
  795. return -1;
  796. if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
  797. remap_after_trial =
  798. strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
  799. }
  800. for (trial = 0; trial < trials; ++trial) {
  801. if (clang_reparseTranslationUnit(TU,
  802. trial >= remap_after_trial ? num_unsaved_files : 0,
  803. trial >= remap_after_trial ? unsaved_files : 0,
  804. clang_defaultReparseOptions(TU))) {
  805. fprintf(stderr, "Unable to reparse translation unit!\n");
  806. clang_disposeTranslationUnit(TU);
  807. free_remapped_files(unsaved_files, num_unsaved_files);
  808. clang_disposeIndex(Idx);
  809. return -1;
  810. }
  811. if (checkForErrors(TU) != 0)
  812. return -1;
  813. }
  814. result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
  815. free_remapped_files(unsaved_files, num_unsaved_files);
  816. clang_disposeIndex(Idx);
  817. return result;
  818. }
  819. /******************************************************************************/
  820. /* Logic for testing clang_getCursor(). */
  821. /******************************************************************************/
  822. static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
  823. unsigned start_line, unsigned start_col,
  824. unsigned end_line, unsigned end_col,
  825. const char *prefix) {
  826. printf("// %s: ", FileCheckPrefix);
  827. if (prefix)
  828. printf("-%s", prefix);
  829. PrintExtent(stdout, start_line, start_col, end_line, end_col);
  830. printf(" ");
  831. PrintCursor(cursor);
  832. printf("\n");
  833. }
  834. static int perform_file_scan(const char *ast_file, const char *source_file,
  835. const char *prefix) {
  836. CXIndex Idx;
  837. CXTranslationUnit TU;
  838. FILE *fp;
  839. CXCursor prevCursor = clang_getNullCursor();
  840. CXFile file;
  841. unsigned line = 1, col = 1;
  842. unsigned start_line = 1, start_col = 1;
  843. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  844. /* displayDiagnosics=*/1))) {
  845. fprintf(stderr, "Could not create Index\n");
  846. return 1;
  847. }
  848. if (!CreateTranslationUnit(Idx, ast_file, &TU))
  849. return 1;
  850. if ((fp = fopen(source_file, "r")) == NULL) {
  851. fprintf(stderr, "Could not open '%s'\n", source_file);
  852. return 1;
  853. }
  854. file = clang_getFile(TU, source_file);
  855. for (;;) {
  856. CXCursor cursor;
  857. int c = fgetc(fp);
  858. if (c == '\n') {
  859. ++line;
  860. col = 1;
  861. } else
  862. ++col;
  863. /* Check the cursor at this position, and dump the previous one if we have
  864. * found something new.
  865. */
  866. cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
  867. if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
  868. prevCursor.kind != CXCursor_InvalidFile) {
  869. print_cursor_file_scan(TU, prevCursor, start_line, start_col,
  870. line, col, prefix);
  871. start_line = line;
  872. start_col = col;
  873. }
  874. if (c == EOF)
  875. break;
  876. prevCursor = cursor;
  877. }
  878. fclose(fp);
  879. clang_disposeTranslationUnit(TU);
  880. clang_disposeIndex(Idx);
  881. return 0;
  882. }
  883. /******************************************************************************/
  884. /* Logic for testing clang code completion. */
  885. /******************************************************************************/
  886. /* Parse file:line:column from the input string. Returns 0 on success, non-zero
  887. on failure. If successful, the pointer *filename will contain newly-allocated
  888. memory (that will be owned by the caller) to store the file name. */
  889. int parse_file_line_column(const char *input, char **filename, unsigned *line,
  890. unsigned *column, unsigned *second_line,
  891. unsigned *second_column) {
  892. /* Find the second colon. */
  893. const char *last_colon = strrchr(input, ':');
  894. unsigned values[4], i;
  895. unsigned num_values = (second_line && second_column)? 4 : 2;
  896. char *endptr = 0;
  897. if (!last_colon || last_colon == input) {
  898. if (num_values == 4)
  899. fprintf(stderr, "could not parse filename:line:column:line:column in "
  900. "'%s'\n", input);
  901. else
  902. fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
  903. return 1;
  904. }
  905. for (i = 0; i != num_values; ++i) {
  906. const char *prev_colon;
  907. /* Parse the next line or column. */
  908. values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
  909. if (*endptr != 0 && *endptr != ':') {
  910. fprintf(stderr, "could not parse %s in '%s'\n",
  911. (i % 2 ? "column" : "line"), input);
  912. return 1;
  913. }
  914. if (i + 1 == num_values)
  915. break;
  916. /* Find the previous colon. */
  917. prev_colon = last_colon - 1;
  918. while (prev_colon != input && *prev_colon != ':')
  919. --prev_colon;
  920. if (prev_colon == input) {
  921. fprintf(stderr, "could not parse %s in '%s'\n",
  922. (i % 2 == 0? "column" : "line"), input);
  923. return 1;
  924. }
  925. last_colon = prev_colon;
  926. }
  927. *line = values[0];
  928. *column = values[1];
  929. if (second_line && second_column) {
  930. *second_line = values[2];
  931. *second_column = values[3];
  932. }
  933. /* Copy the file name. */
  934. *filename = (char*)malloc(last_colon - input + 1);
  935. memcpy(*filename, input, last_colon - input);
  936. (*filename)[last_colon - input] = 0;
  937. return 0;
  938. }
  939. const char *
  940. clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
  941. switch (Kind) {
  942. case CXCompletionChunk_Optional: return "Optional";
  943. case CXCompletionChunk_TypedText: return "TypedText";
  944. case CXCompletionChunk_Text: return "Text";
  945. case CXCompletionChunk_Placeholder: return "Placeholder";
  946. case CXCompletionChunk_Informative: return "Informative";
  947. case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
  948. case CXCompletionChunk_LeftParen: return "LeftParen";
  949. case CXCompletionChunk_RightParen: return "RightParen";
  950. case CXCompletionChunk_LeftBracket: return "LeftBracket";
  951. case CXCompletionChunk_RightBracket: return "RightBracket";
  952. case CXCompletionChunk_LeftBrace: return "LeftBrace";
  953. case CXCompletionChunk_RightBrace: return "RightBrace";
  954. case CXCompletionChunk_LeftAngle: return "LeftAngle";
  955. case CXCompletionChunk_RightAngle: return "RightAngle";
  956. case CXCompletionChunk_Comma: return "Comma";
  957. case CXCompletionChunk_ResultType: return "ResultType";
  958. case CXCompletionChunk_Colon: return "Colon";
  959. case CXCompletionChunk_SemiColon: return "SemiColon";
  960. case CXCompletionChunk_Equal: return "Equal";
  961. case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
  962. case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
  963. }
  964. return "Unknown";
  965. }
  966. static int checkForErrors(CXTranslationUnit TU) {
  967. unsigned Num, i;
  968. CXDiagnostic Diag;
  969. CXString DiagStr;
  970. if (!getenv("CINDEXTEST_FAILONERROR"))
  971. return 0;
  972. Num = clang_getNumDiagnostics(TU);
  973. for (i = 0; i != Num; ++i) {
  974. Diag = clang_getDiagnostic(TU, i);
  975. if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
  976. DiagStr = clang_formatDiagnostic(Diag,
  977. clang_defaultDiagnosticDisplayOptions());
  978. fprintf(stderr, "%s\n", clang_getCString(DiagStr));
  979. clang_disposeString(DiagStr);
  980. clang_disposeDiagnostic(Diag);
  981. return -1;
  982. }
  983. clang_disposeDiagnostic(Diag);
  984. }
  985. return 0;
  986. }
  987. void print_completion_string(CXCompletionString completion_string, FILE *file) {
  988. int I, N;
  989. N = clang_getNumCompletionChunks(completion_string);
  990. for (I = 0; I != N; ++I) {
  991. CXString text;
  992. const char *cstr;
  993. enum CXCompletionChunkKind Kind
  994. = clang_getCompletionChunkKind(completion_string, I);
  995. if (Kind == CXCompletionChunk_Optional) {
  996. fprintf(file, "{Optional ");
  997. print_completion_string(
  998. clang_getCompletionChunkCompletionString(completion_string, I),
  999. file);
  1000. fprintf(file, "}");
  1001. continue;
  1002. }
  1003. if (Kind == CXCompletionChunk_VerticalSpace) {
  1004. fprintf(file, "{VerticalSpace }");
  1005. continue;
  1006. }
  1007. text = clang_getCompletionChunkText(completion_string, I);
  1008. cstr = clang_getCString(text);
  1009. fprintf(file, "{%s %s}",
  1010. clang_getCompletionChunkKindSpelling(Kind),
  1011. cstr ? cstr : "");
  1012. clang_disposeString(text);
  1013. }
  1014. }
  1015. void print_completion_result(CXCompletionResult *completion_result,
  1016. CXClientData client_data) {
  1017. FILE *file = (FILE *)client_data;
  1018. CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
  1019. unsigned annotationCount;
  1020. enum CXCursorKind ParentKind;
  1021. CXString ParentName;
  1022. fprintf(file, "%s:", clang_getCString(ks));
  1023. clang_disposeString(ks);
  1024. print_completion_string(completion_result->CompletionString, file);
  1025. fprintf(file, " (%u)",
  1026. clang_getCompletionPriority(completion_result->CompletionString));
  1027. switch (clang_getCompletionAvailability(completion_result->CompletionString)){
  1028. case CXAvailability_Available:
  1029. break;
  1030. case CXAvailability_Deprecated:
  1031. fprintf(file, " (deprecated)");
  1032. break;
  1033. case CXAvailability_NotAvailable:
  1034. fprintf(file, " (unavailable)");
  1035. break;
  1036. case CXAvailability_NotAccessible:
  1037. fprintf(file, " (inaccessible)");
  1038. break;
  1039. }
  1040. annotationCount = clang_getCompletionNumAnnotations(
  1041. completion_result->CompletionString);
  1042. if (annotationCount) {
  1043. unsigned i;
  1044. fprintf(file, " (");
  1045. for (i = 0; i < annotationCount; ++i) {
  1046. if (i != 0)
  1047. fprintf(file, ", ");
  1048. fprintf(file, "\"%s\"",
  1049. clang_getCString(clang_getCompletionAnnotation(
  1050. completion_result->CompletionString, i)));
  1051. }
  1052. fprintf(file, ")");
  1053. }
  1054. if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
  1055. ParentName = clang_getCompletionParent(completion_result->CompletionString,
  1056. &ParentKind);
  1057. if (ParentKind != CXCursor_NotImplemented) {
  1058. CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
  1059. fprintf(file, " (parent: %s '%s')",
  1060. clang_getCString(KindSpelling),
  1061. clang_getCString(ParentName));
  1062. clang_disposeString(KindSpelling);
  1063. }
  1064. clang_disposeString(ParentName);
  1065. }
  1066. fprintf(file, "\n");
  1067. }
  1068. void print_completion_contexts(unsigned long long contexts, FILE *file) {
  1069. fprintf(file, "Completion contexts:\n");
  1070. if (contexts == CXCompletionContext_Unknown) {
  1071. fprintf(file, "Unknown\n");
  1072. }
  1073. if (contexts & CXCompletionContext_AnyType) {
  1074. fprintf(file, "Any type\n");
  1075. }
  1076. if (contexts & CXCompletionContext_AnyValue) {
  1077. fprintf(file, "Any value\n");
  1078. }
  1079. if (contexts & CXCompletionContext_ObjCObjectValue) {
  1080. fprintf(file, "Objective-C object value\n");
  1081. }
  1082. if (contexts & CXCompletionContext_ObjCSelectorValue) {
  1083. fprintf(file, "Objective-C selector value\n");
  1084. }
  1085. if (contexts & CXCompletionContext_CXXClassTypeValue) {
  1086. fprintf(file, "C++ class type value\n");
  1087. }
  1088. if (contexts & CXCompletionContext_DotMemberAccess) {
  1089. fprintf(file, "Dot member access\n");
  1090. }
  1091. if (contexts & CXCompletionContext_ArrowMemberAccess) {
  1092. fprintf(file, "Arrow member access\n");
  1093. }
  1094. if (contexts & CXCompletionContext_ObjCPropertyAccess) {
  1095. fprintf(file, "Objective-C property access\n");
  1096. }
  1097. if (contexts & CXCompletionContext_EnumTag) {
  1098. fprintf(file, "Enum tag\n");
  1099. }
  1100. if (contexts & CXCompletionContext_UnionTag) {
  1101. fprintf(file, "Union tag\n");
  1102. }
  1103. if (contexts & CXCompletionContext_StructTag) {
  1104. fprintf(file, "Struct tag\n");
  1105. }
  1106. if (contexts & CXCompletionContext_ClassTag) {
  1107. fprintf(file, "Class name\n");
  1108. }
  1109. if (contexts & CXCompletionContext_Namespace) {
  1110. fprintf(file, "Namespace or namespace alias\n");
  1111. }
  1112. if (contexts & CXCompletionContext_NestedNameSpecifier) {
  1113. fprintf(file, "Nested name specifier\n");
  1114. }
  1115. if (contexts & CXCompletionContext_ObjCInterface) {
  1116. fprintf(file, "Objective-C interface\n");
  1117. }
  1118. if (contexts & CXCompletionContext_ObjCProtocol) {
  1119. fprintf(file, "Objective-C protocol\n");
  1120. }
  1121. if (contexts & CXCompletionContext_ObjCCategory) {
  1122. fprintf(file, "Objective-C category\n");
  1123. }
  1124. if (contexts & CXCompletionContext_ObjCInstanceMessage) {
  1125. fprintf(file, "Objective-C instance method\n");
  1126. }
  1127. if (contexts & CXCompletionContext_ObjCClassMessage) {
  1128. fprintf(file, "Objective-C class method\n");
  1129. }
  1130. if (contexts & CXCompletionContext_ObjCSelectorName) {
  1131. fprintf(file, "Objective-C selector name\n");
  1132. }
  1133. if (contexts & CXCompletionContext_MacroName) {
  1134. fprintf(file, "Macro name\n");
  1135. }
  1136. if (contexts & CXCompletionContext_NaturalLanguage) {
  1137. fprintf(file, "Natural language\n");
  1138. }
  1139. }
  1140. int my_stricmp(const char *s1, const char *s2) {
  1141. while (*s1 && *s2) {
  1142. int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
  1143. if (c1 < c2)
  1144. return -1;
  1145. else if (c1 > c2)
  1146. return 1;
  1147. ++s1;
  1148. ++s2;
  1149. }
  1150. if (*s1)
  1151. return 1;
  1152. else if (*s2)
  1153. return -1;
  1154. return 0;
  1155. }
  1156. int perform_code_completion(int argc, const char **argv, int timing_only) {
  1157. const char *input = argv[1];
  1158. char *filename = 0;
  1159. unsigned line;
  1160. unsigned column;
  1161. CXIndex CIdx;
  1162. int errorCode;
  1163. struct CXUnsavedFile *unsaved_files = 0;
  1164. int num_unsaved_files = 0;
  1165. CXCodeCompleteResults *results = 0;
  1166. CXTranslationUnit TU = 0;
  1167. unsigned I, Repeats = 1;
  1168. unsigned completionOptions = clang_defaultCodeCompleteOptions();
  1169. if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
  1170. completionOptions |= CXCodeComplete_IncludeCodePatterns;
  1171. if (timing_only)
  1172. input += strlen("-code-completion-timing=");
  1173. else
  1174. input += strlen("-code-completion-at=");
  1175. if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
  1176. 0, 0)))
  1177. return errorCode;
  1178. if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
  1179. return -1;
  1180. CIdx = clang_createIndex(0, 0);
  1181. if (getenv("CINDEXTEST_EDITING"))
  1182. Repeats = 5;
  1183. TU = clang_parseTranslationUnit(CIdx, 0,
  1184. argv + num_unsaved_files + 2,
  1185. argc - num_unsaved_files - 2,
  1186. 0, 0, getDefaultParsingOptions());
  1187. if (!TU) {
  1188. fprintf(stderr, "Unable to load translation unit!\n");
  1189. return 1;
  1190. }
  1191. if (clang_reparseTranslationUnit(TU, 0, 0, clang_defaultReparseOptions(TU))) {
  1192. fprintf(stderr, "Unable to reparse translation init!\n");
  1193. return 1;
  1194. }
  1195. for (I = 0; I != Repeats; ++I) {
  1196. results = clang_codeCompleteAt(TU, filename, line, column,
  1197. unsaved_files, num_unsaved_files,
  1198. completionOptions);
  1199. if (!results) {
  1200. fprintf(stderr, "Unable to perform code completion!\n");
  1201. return 1;
  1202. }
  1203. if (I != Repeats-1)
  1204. clang_disposeCodeCompleteResults(results);
  1205. }
  1206. if (results) {
  1207. unsigned i, n = results->NumResults, containerIsIncomplete = 0;
  1208. unsigned long long contexts;
  1209. enum CXCursorKind containerKind;
  1210. CXString objCSelector;
  1211. const char *selectorString;
  1212. if (!timing_only) {
  1213. /* Sort the code-completion results based on the typed text. */
  1214. clang_sortCodeCompletionResults(results->Results, results->NumResults);
  1215. for (i = 0; i != n; ++i)
  1216. print_completion_result(results->Results + i, stdout);
  1217. }
  1218. n = clang_codeCompleteGetNumDiagnostics(results);
  1219. for (i = 0; i != n; ++i) {
  1220. CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
  1221. PrintDiagnostic(diag);
  1222. clang_disposeDiagnostic(diag);
  1223. }
  1224. contexts = clang_codeCompleteGetContexts(results);
  1225. print_completion_contexts(contexts, stdout);
  1226. containerKind = clang_codeCompleteGetContainerKind(results,
  1227. &containerIsIncomplete);
  1228. if (containerKind != CXCursor_InvalidCode) {
  1229. /* We have found a container */
  1230. CXString containerUSR, containerKindSpelling;
  1231. containerKindSpelling = clang_getCursorKindSpelling(containerKind);
  1232. printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
  1233. clang_disposeString(containerKindSpelling);
  1234. if (containerIsIncomplete) {
  1235. printf("Container is incomplete\n");
  1236. }
  1237. else {
  1238. printf("Container is complete\n");
  1239. }
  1240. containerUSR = clang_codeCompleteGetContainerUSR(results);
  1241. printf("Container USR: %s\n", clang_getCString(containerUSR));
  1242. clang_disposeString(containerUSR);
  1243. }
  1244. objCSelector = clang_codeCompleteGetObjCSelector(results);
  1245. selectorString = clang_getCString(objCSelector);
  1246. if (selectorString && strlen(selectorString) > 0) {
  1247. printf("Objective-C selector: %s\n", selectorString);
  1248. }
  1249. clang_disposeString(objCSelector);
  1250. clang_disposeCodeCompleteResults(results);
  1251. }
  1252. clang_disposeTranslationUnit(TU);
  1253. clang_disposeIndex(CIdx);
  1254. free(filename);
  1255. free_remapped_files(unsaved_files, num_unsaved_files);
  1256. return 0;
  1257. }
  1258. typedef struct {
  1259. char *filename;
  1260. unsigned line;
  1261. unsigned column;
  1262. } CursorSourceLocation;
  1263. static int inspect_cursor_at(int argc, const char **argv) {
  1264. CXIndex CIdx;
  1265. int errorCode;
  1266. struct CXUnsavedFile *unsaved_files = 0;
  1267. int num_unsaved_files = 0;
  1268. CXTranslationUnit TU;
  1269. CXCursor Cursor;
  1270. CursorSourceLocation *Locations = 0;
  1271. unsigned NumLocations = 0, Loc;
  1272. unsigned Repeats = 1;
  1273. unsigned I;
  1274. /* Count the number of locations. */
  1275. while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
  1276. ++NumLocations;
  1277. /* Parse the locations. */
  1278. assert(NumLocations > 0 && "Unable to count locations?");
  1279. Locations = (CursorSourceLocation *)malloc(
  1280. NumLocations * sizeof(CursorSourceLocation));
  1281. for (Loc = 0; Loc < NumLocations; ++Loc) {
  1282. const char *input = argv[Loc + 1] + strlen("-cursor-at=");
  1283. if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
  1284. &Locations[Loc].line,
  1285. &Locations[Loc].column, 0, 0)))
  1286. return errorCode;
  1287. }
  1288. if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
  1289. &num_unsaved_files))
  1290. return -1;
  1291. if (getenv("CINDEXTEST_EDITING"))
  1292. Repeats = 5;
  1293. /* Parse the translation unit. When we're testing clang_getCursor() after
  1294. reparsing, don't remap unsaved files until the second parse. */
  1295. CIdx = clang_createIndex(1, 1);
  1296. TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
  1297. argv + num_unsaved_files + 1 + NumLocations,
  1298. argc - num_unsaved_files - 2 - NumLocations,
  1299. unsaved_files,
  1300. Repeats > 1? 0 : num_unsaved_files,
  1301. getDefaultParsingOptions());
  1302. if (!TU) {
  1303. fprintf(stderr, "unable to parse input\n");
  1304. return -1;
  1305. }
  1306. if (checkForErrors(TU) != 0)
  1307. return -1;
  1308. for (I = 0; I != Repeats; ++I) {
  1309. if (Repeats > 1 &&
  1310. clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  1311. clang_defaultReparseOptions(TU))) {
  1312. clang_disposeTranslationUnit(TU);
  1313. return 1;
  1314. }
  1315. if (checkForErrors(TU) != 0)
  1316. return -1;
  1317. for (Loc = 0; Loc < NumLocations; ++Loc) {
  1318. CXFile file = clang_getFile(TU, Locations[Loc].filename);
  1319. if (!file)
  1320. continue;
  1321. Cursor = clang_getCursor(TU,
  1322. clang_getLocation(TU, file, Locations[Loc].line,
  1323. Locations[Loc].column));
  1324. if (checkForErrors(TU) != 0)
  1325. return -1;
  1326. if (I + 1 == Repeats) {
  1327. CXCompletionString completionString = clang_getCursorCompletionString(
  1328. Cursor);
  1329. CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
  1330. CXString Spelling;
  1331. const char *cspell;
  1332. unsigned line, column;
  1333. clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
  1334. printf("%d:%d ", line, column);
  1335. PrintCursor(Cursor);
  1336. PrintCursorExtent(Cursor);
  1337. Spelling = clang_getCursorSpelling(Cursor);
  1338. cspell = clang_getCString(Spelling);
  1339. if (cspell && strlen(cspell) != 0) {
  1340. unsigned pieceIndex;
  1341. printf(" Spelling=%s (", cspell);
  1342. for (pieceIndex = 0; ; ++pieceIndex) {
  1343. CXSourceRange range =
  1344. clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
  1345. if (clang_Range_isNull(range))
  1346. break;
  1347. PrintRange(range, 0);
  1348. }
  1349. printf(")");
  1350. }
  1351. clang_disposeString(Spelling);
  1352. if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
  1353. printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
  1354. if (completionString != NULL) {
  1355. printf("\nCompletion string: ");
  1356. print_completion_string(completionString, stdout);
  1357. }
  1358. printf("\n");
  1359. free(Locations[Loc].filename);
  1360. }
  1361. }
  1362. }
  1363. PrintDiagnostics(TU);
  1364. clang_disposeTranslationUnit(TU);
  1365. clang_disposeIndex(CIdx);
  1366. free(Locations);
  1367. free_remapped_files(unsaved_files, num_unsaved_files);
  1368. return 0;
  1369. }
  1370. static enum CXVisitorResult findFileRefsVisit(void *context,
  1371. CXCursor cursor, CXSourceRange range) {
  1372. if (clang_Range_isNull(range))
  1373. return CXVisit_Continue;
  1374. PrintCursor(cursor);
  1375. PrintRange(range, "");
  1376. printf("\n");
  1377. return CXVisit_Continue;
  1378. }
  1379. static int find_file_refs_at(int argc, const char **argv) {
  1380. CXIndex CIdx;
  1381. int errorCode;
  1382. struct CXUnsavedFile *unsaved_files = 0;
  1383. int num_unsaved_files = 0;
  1384. CXTranslationUnit TU;
  1385. CXCursor Cursor;
  1386. CursorSourceLocation *Locations = 0;
  1387. unsigned NumLocations = 0, Loc;
  1388. unsigned Repeats = 1;
  1389. unsigned I;
  1390. /* Count the number of locations. */
  1391. while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
  1392. ++NumLocations;
  1393. /* Parse the locations. */
  1394. assert(NumLocations > 0 && "Unable to count locations?");
  1395. Locations = (CursorSourceLocation *)malloc(
  1396. NumLocations * sizeof(CursorSourceLocation));
  1397. for (Loc = 0; Loc < NumLocations; ++Loc) {
  1398. const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
  1399. if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
  1400. &Locations[Loc].line,
  1401. &Locations[Loc].column, 0, 0)))
  1402. return errorCode;
  1403. }
  1404. if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
  1405. &num_unsaved_files))
  1406. return -1;
  1407. if (getenv("CINDEXTEST_EDITING"))
  1408. Repeats = 5;
  1409. /* Parse the translation unit. When we're testing clang_getCursor() after
  1410. reparsing, don't remap unsaved files until the second parse. */
  1411. CIdx = clang_createIndex(1, 1);
  1412. TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
  1413. argv + num_unsaved_files + 1 + NumLocations,
  1414. argc - num_unsaved_files - 2 - NumLocations,
  1415. unsaved_files,
  1416. Repeats > 1? 0 : num_unsaved_files,
  1417. getDefaultParsingOptions());
  1418. if (!TU) {
  1419. fprintf(stderr, "unable to parse input\n");
  1420. return -1;
  1421. }
  1422. if (checkForErrors(TU) != 0)
  1423. return -1;
  1424. for (I = 0; I != Repeats; ++I) {
  1425. if (Repeats > 1 &&
  1426. clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  1427. clang_defaultReparseOptions(TU))) {
  1428. clang_disposeTranslationUnit(TU);
  1429. return 1;
  1430. }
  1431. if (checkForErrors(TU) != 0)
  1432. return -1;
  1433. for (Loc = 0; Loc < NumLocations; ++Loc) {
  1434. CXFile file = clang_getFile(TU, Locations[Loc].filename);
  1435. if (!file)
  1436. continue;
  1437. Cursor = clang_getCursor(TU,
  1438. clang_getLocation(TU, file, Locations[Loc].line,
  1439. Locations[Loc].column));
  1440. if (checkForErrors(TU) != 0)
  1441. return -1;
  1442. if (I + 1 == Repeats) {
  1443. CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
  1444. PrintCursor(Cursor);
  1445. printf("\n");
  1446. clang_findReferencesInFile(Cursor, file, visitor);
  1447. free(Locations[Loc].filename);
  1448. if (checkForErrors(TU) != 0)
  1449. return -1;
  1450. }
  1451. }
  1452. }
  1453. PrintDiagnostics(TU);
  1454. clang_disposeTranslationUnit(TU);
  1455. clang_disposeIndex(CIdx);
  1456. free(Locations);
  1457. free_remapped_files(unsaved_files, num_unsaved_files);
  1458. return 0;
  1459. }
  1460. typedef struct {
  1461. const char *check_prefix;
  1462. int first_check_printed;
  1463. int fail_for_error;
  1464. int abort;
  1465. const char *main_filename;
  1466. } IndexData;
  1467. static void printCheck(IndexData *data) {
  1468. if (data->check_prefix) {
  1469. if (data->first_check_printed) {
  1470. printf("// %s-NEXT: ", data->check_prefix);
  1471. } else {
  1472. printf("// %s : ", data->check_prefix);
  1473. data->first_check_printed = 1;
  1474. }
  1475. }
  1476. }
  1477. static void printCXIndexFile(CXIdxClientFile file) {
  1478. CXString filename = clang_getFileName((CXFile)file);
  1479. printf("%s", clang_getCString(filename));
  1480. clang_disposeString(filename);
  1481. }
  1482. static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
  1483. IndexData *index_data;
  1484. CXString filename;
  1485. const char *cname;
  1486. CXIdxClientFile file;
  1487. unsigned line, column;
  1488. int isMainFile;
  1489. index_data = (IndexData *)client_data;
  1490. clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
  1491. if (line == 0) {
  1492. printf("<null loc>");
  1493. return;
  1494. }
  1495. if (!file) {
  1496. printf("<no idxfile>");
  1497. return;
  1498. }
  1499. filename = clang_getFileName((CXFile)file);
  1500. cname = clang_getCString(filename);
  1501. if (strcmp(cname, index_data->main_filename) == 0)
  1502. isMainFile = 1;
  1503. else
  1504. isMainFile = 0;
  1505. clang_disposeString(filename);
  1506. if (!isMainFile) {
  1507. printCXIndexFile(file);
  1508. printf(":");
  1509. }
  1510. printf("%d:%d", line, column);
  1511. }
  1512. static unsigned digitCount(unsigned val) {
  1513. unsigned c = 1;
  1514. while (1) {
  1515. if (val < 10)
  1516. return c;
  1517. ++c;
  1518. val /= 10;
  1519. }
  1520. }
  1521. static CXIdxClientContainer makeClientContainer(const CXIdxEntityInfo *info,
  1522. CXIdxLoc loc) {
  1523. const char *name;
  1524. char *newStr;
  1525. CXIdxClientFile file;
  1526. unsigned line, column;
  1527. name = info->name;
  1528. if (!name)
  1529. name = "<anon-tag>";
  1530. clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
  1531. /* FIXME: free these.*/
  1532. newStr = (char *)malloc(strlen(name) +
  1533. digitCount(line) + digitCount(column) + 3);
  1534. sprintf(newStr, "%s:%d:%d", name, line, column);
  1535. return (CXIdxClientContainer)newStr;
  1536. }
  1537. static void printCXIndexContainer(const CXIdxContainerInfo *info) {
  1538. CXIdxClientContainer container;
  1539. container = clang_index_getClientContainer(info);
  1540. if (!container)
  1541. printf("[<<NULL>>]");
  1542. else
  1543. printf("[%s]", (const char *)container);
  1544. }
  1545. static const char *getEntityKindString(CXIdxEntityKind kind) {
  1546. switch (kind) {
  1547. case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
  1548. case CXIdxEntity_Typedef: return "typedef";
  1549. case CXIdxEntity_Function: return "function";
  1550. case CXIdxEntity_Variable: return "variable";
  1551. case CXIdxEntity_Field: return "field";
  1552. case CXIdxEntity_EnumConstant: return "enumerator";
  1553. case CXIdxEntity_ObjCClass: return "objc-class";
  1554. case CXIdxEntity_ObjCProtocol: return "objc-protocol";
  1555. case CXIdxEntity_ObjCCategory: return "objc-category";
  1556. case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
  1557. case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
  1558. case CXIdxEntity_ObjCProperty: return "objc-property";
  1559. case CXIdxEntity_ObjCIvar: return "objc-ivar";
  1560. case CXIdxEntity_Enum: return "enum";
  1561. case CXIdxEntity_Struct: return "struct";
  1562. case CXIdxEntity_Union: return "union";
  1563. case CXIdxEntity_CXXClass: return "c++-class";
  1564. case CXIdxEntity_CXXNamespace: return "namespace";
  1565. case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
  1566. case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
  1567. case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
  1568. case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
  1569. case CXIdxEntity_CXXConstructor: return "constructor";
  1570. case CXIdxEntity_CXXDestructor: return "destructor";
  1571. case CXIdxEntity_CXXConversionFunction: return "conversion-func";
  1572. case CXIdxEntity_CXXTypeAlias: return "type-alias";
  1573. }
  1574. assert(0 && "Garbage entity kind");
  1575. return 0;
  1576. }
  1577. static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
  1578. switch (kind) {
  1579. case CXIdxEntity_NonTemplate: return "";
  1580. case CXIdxEntity_Template: return "-template";
  1581. case CXIdxEntity_TemplatePartialSpecialization:
  1582. return "-template-partial-spec";
  1583. case CXIdxEntity_TemplateSpecialization: return "-template-spec";
  1584. }
  1585. assert(0 && "Garbage entity kind");
  1586. return 0;
  1587. }
  1588. static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
  1589. switch (kind) {
  1590. case CXIdxEntityLang_None: return "<none>";
  1591. case CXIdxEntityLang_C: return "C";
  1592. case CXIdxEntityLang_ObjC: return "ObjC";
  1593. case CXIdxEntityLang_CXX: return "C++";
  1594. }
  1595. assert(0 && "Garbage language kind");
  1596. return 0;
  1597. }
  1598. static void printEntityInfo(const char *cb,
  1599. CXClientData client_data,
  1600. const CXIdxEntityInfo *info) {
  1601. const char *name;
  1602. IndexData *index_data;
  1603. unsigned i;
  1604. index_data = (IndexData *)client_data;
  1605. printCheck(index_data);
  1606. if (!info) {
  1607. printf("%s: <<NULL>>", cb);
  1608. return;
  1609. }
  1610. name = info->name;
  1611. if (!name)
  1612. name = "<anon-tag>";
  1613. printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
  1614. getEntityTemplateKindString(info->templateKind));
  1615. printf(" | name: %s", name);
  1616. printf(" | USR: %s", info->USR);
  1617. printf(" | lang: %s", getEntityLanguageString(info->lang));
  1618. for (i = 0; i != info->numAttributes; ++i) {
  1619. const CXIdxAttrInfo *Attr = info->attributes[i];
  1620. printf(" <attribute>: ");
  1621. PrintCursor(Attr->cursor);
  1622. }
  1623. }
  1624. static void printBaseClassInfo(CXClientData client_data,
  1625. const CXIdxBaseClassInfo *info) {
  1626. printEntityInfo(" <base>", client_data, info->base);
  1627. printf(" | cursor: ");
  1628. PrintCursor(info->cursor);
  1629. printf(" | loc: ");
  1630. printCXIndexLoc(info->loc, client_data);
  1631. }
  1632. static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
  1633. CXClientData client_data) {
  1634. unsigned i;
  1635. for (i = 0; i < ProtoInfo->numProtocols; ++i) {
  1636. printEntityInfo(" <protocol>", client_data,
  1637. ProtoInfo->protocols[i]->protocol);
  1638. printf(" | cursor: ");
  1639. PrintCursor(ProtoInfo->protocols[i]->cursor);
  1640. printf(" | loc: ");
  1641. printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
  1642. printf("\n");
  1643. }
  1644. }
  1645. static void index_diagnostic(CXClientData client_data,
  1646. CXDiagnosticSet diagSet, void *reserved) {
  1647. CXString str;
  1648. const char *cstr;
  1649. unsigned numDiags, i;
  1650. CXDiagnostic diag;
  1651. IndexData *index_data;
  1652. index_data = (IndexData *)client_data;
  1653. printCheck(index_data);
  1654. numDiags = clang_getNumDiagnosticsInSet(diagSet);
  1655. for (i = 0; i != numDiags; ++i) {
  1656. diag = clang_getDiagnosticInSet(diagSet, i);
  1657. str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
  1658. cstr = clang_getCString(str);
  1659. printf("[diagnostic]: %s\n", cstr);
  1660. clang_disposeString(str);
  1661. if (getenv("CINDEXTEST_FAILONERROR") &&
  1662. clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
  1663. index_data->fail_for_error = 1;
  1664. }
  1665. }
  1666. }
  1667. static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
  1668. CXFile file, void *reserved) {
  1669. IndexData *index_data;
  1670. CXString filename;
  1671. index_data = (IndexData *)client_data;
  1672. printCheck(index_data);
  1673. filename = clang_getFileName(file);
  1674. index_data->main_filename = clang_getCString(filename);
  1675. clang_disposeString(filename);
  1676. printf("[enteredMainFile]: ");
  1677. printCXIndexFile((CXIdxClientFile)file);
  1678. printf("\n");
  1679. return (CXIdxClientFile)file;
  1680. }
  1681. static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
  1682. const CXIdxIncludedFileInfo *info) {
  1683. IndexData *index_data;
  1684. index_data = (IndexData *)client_data;
  1685. printCheck(index_data);
  1686. printf("[ppIncludedFile]: ");
  1687. printCXIndexFile((CXIdxClientFile)info->file);
  1688. printf(" | name: \"%s\"", info->filename);
  1689. printf(" | hash loc: ");
  1690. printCXIndexLoc(info->hashLoc, client_data);
  1691. printf(" | isImport: %d | isAngled: %d\n", info->isImport, info->isAngled);
  1692. return (CXIdxClientFile)info->file;
  1693. }
  1694. static CXIdxClientContainer index_startedTranslationUnit(CXClientData client_data,
  1695. void *reserved) {
  1696. IndexData *index_data;
  1697. index_data = (IndexData *)client_data;
  1698. printCheck(index_data);
  1699. printf("[startedTranslationUnit]\n");
  1700. return (CXIdxClientContainer)"TU";
  1701. }
  1702. static void index_indexDeclaration(CXClientData client_data,
  1703. const CXIdxDeclInfo *info) {
  1704. IndexData *index_data;
  1705. const CXIdxObjCCategoryDeclInfo *CatInfo;
  1706. const CXIdxObjCInterfaceDeclInfo *InterInfo;
  1707. const CXIdxObjCProtocolRefListInfo *ProtoInfo;
  1708. const CXIdxObjCPropertyDeclInfo *PropInfo;
  1709. const CXIdxCXXClassDeclInfo *CXXClassInfo;
  1710. unsigned i;
  1711. index_data = (IndexData *)client_data;
  1712. printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
  1713. printf(" | cursor: ");
  1714. PrintCursor(info->cursor);
  1715. printf(" | loc: ");
  1716. printCXIndexLoc(info->loc, client_data);
  1717. printf(" | semantic-container: ");
  1718. printCXIndexContainer(info->semanticContainer);
  1719. printf(" | lexical-container: ");
  1720. printCXIndexContainer(info->lexicalContainer);
  1721. printf(" | isRedecl: %d", info->isRedeclaration);
  1722. printf(" | isDef: %d", info->isDefinition);
  1723. printf(" | isContainer: %d", info->isContainer);
  1724. printf(" | isImplicit: %d\n", info->isImplicit);
  1725. for (i = 0; i != info->numAttributes; ++i) {
  1726. const CXIdxAttrInfo *Attr = info->attributes[i];
  1727. printf(" <attribute>: ");
  1728. PrintCursor(Attr->cursor);
  1729. printf("\n");
  1730. }
  1731. if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
  1732. const char *kindName = 0;
  1733. CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
  1734. switch (K) {
  1735. case CXIdxObjCContainer_ForwardRef:
  1736. kindName = "forward-ref"; break;
  1737. case CXIdxObjCContainer_Interface:
  1738. kindName = "interface"; break;
  1739. case CXIdxObjCContainer_Implementation:
  1740. kindName = "implementation"; break;
  1741. }
  1742. printCheck(index_data);
  1743. printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
  1744. }
  1745. if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
  1746. printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
  1747. CatInfo->objcClass);
  1748. printf(" | cursor: ");
  1749. PrintCursor(CatInfo->classCursor);
  1750. printf(" | loc: ");
  1751. printCXIndexLoc(CatInfo->classLoc, client_data);
  1752. printf("\n");
  1753. }
  1754. if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
  1755. if (InterInfo->superInfo) {
  1756. printBaseClassInfo(client_data, InterInfo->superInfo);
  1757. printf("\n");
  1758. }
  1759. }
  1760. if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
  1761. printProtocolList(ProtoInfo, client_data);
  1762. }
  1763. if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
  1764. if (PropInfo->getter) {
  1765. printEntityInfo(" <getter>", client_data, PropInfo->getter);
  1766. printf("\n");
  1767. }
  1768. if (PropInfo->setter) {
  1769. printEntityInfo(" <setter>", client_data, PropInfo->setter);
  1770. printf("\n");
  1771. }
  1772. }
  1773. if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
  1774. for (i = 0; i != CXXClassInfo->numBases; ++i) {
  1775. printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
  1776. printf("\n");
  1777. }
  1778. }
  1779. if (info->declAsContainer)
  1780. clang_index_setClientContainer(info->declAsContainer,
  1781. makeClientContainer(info->entityInfo, info->loc));
  1782. }
  1783. static void index_indexEntityReference(CXClientData client_data,
  1784. const CXIdxEntityRefInfo *info) {
  1785. printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity);
  1786. printf(" | cursor: ");
  1787. PrintCursor(info->cursor);
  1788. printf(" | loc: ");
  1789. printCXIndexLoc(info->loc, client_data);
  1790. printEntityInfo(" | <parent>:", client_data, info->parentEntity);
  1791. printf(" | container: ");
  1792. printCXIndexContainer(info->container);
  1793. printf(" | refkind: ");
  1794. switch (info->kind) {
  1795. case CXIdxEntityRef_Direct: printf("direct"); break;
  1796. case CXIdxEntityRef_Implicit: printf("implicit"); break;
  1797. }
  1798. printf("\n");
  1799. }
  1800. static int index_abortQuery(CXClientData client_data, void *reserved) {
  1801. IndexData *index_data;
  1802. index_data = (IndexData *)client_data;
  1803. return index_data->abort;
  1804. }
  1805. static IndexerCallbacks IndexCB = {
  1806. index_abortQuery,
  1807. index_diagnostic,
  1808. index_enteredMainFile,
  1809. index_ppIncludedFile,
  1810. 0, /*importedASTFile*/
  1811. index_startedTranslationUnit,
  1812. index_indexDeclaration,
  1813. index_indexEntityReference
  1814. };
  1815. static unsigned getIndexOptions(void) {
  1816. unsigned index_opts;
  1817. index_opts = 0;
  1818. if (getenv("CINDEXTEST_SUPPRESSREFS"))
  1819. index_opts |= CXIndexOpt_SuppressRedundantRefs;
  1820. if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
  1821. index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
  1822. return index_opts;
  1823. }
  1824. static int index_file(int argc, const char **argv) {
  1825. const char *check_prefix;
  1826. CXIndex Idx;
  1827. CXIndexAction idxAction;
  1828. IndexData index_data;
  1829. unsigned index_opts;
  1830. int result;
  1831. check_prefix = 0;
  1832. if (argc > 0) {
  1833. if (strstr(argv[0], "-check-prefix=") == argv[0]) {
  1834. check_prefix = argv[0] + strlen("-check-prefix=");
  1835. ++argv;
  1836. --argc;
  1837. }
  1838. }
  1839. if (argc == 0) {
  1840. fprintf(stderr, "no compiler arguments\n");
  1841. return -1;
  1842. }
  1843. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  1844. /* displayDiagnosics=*/1))) {
  1845. fprintf(stderr, "Could not create Index\n");
  1846. return 1;
  1847. }
  1848. idxAction = 0;
  1849. result = 1;
  1850. index_data.check_prefix = check_prefix;
  1851. index_data.first_check_printed = 0;
  1852. index_data.fail_for_error = 0;
  1853. index_data.abort = 0;
  1854. index_opts = getIndexOptions();
  1855. idxAction = clang_IndexAction_create(Idx);
  1856. result = clang_indexSourceFile(idxAction, &index_data,
  1857. &IndexCB,sizeof(IndexCB), index_opts,
  1858. 0, argv, argc, 0, 0, 0, 0);
  1859. if (index_data.fail_for_error)
  1860. result = -1;
  1861. clang_IndexAction_dispose(idxAction);
  1862. clang_disposeIndex(Idx);
  1863. return result;
  1864. }
  1865. static int index_tu(int argc, const char **argv) {
  1866. CXIndex Idx;
  1867. CXIndexAction idxAction;
  1868. CXTranslationUnit TU;
  1869. const char *check_prefix;
  1870. IndexData index_data;
  1871. unsigned index_opts;
  1872. int result;
  1873. check_prefix = 0;
  1874. if (argc > 0) {
  1875. if (strstr(argv[0], "-check-prefix=") == argv[0]) {
  1876. check_prefix = argv[0] + strlen("-check-prefix=");
  1877. ++argv;
  1878. --argc;
  1879. }
  1880. }
  1881. if (argc == 0) {
  1882. fprintf(stderr, "no ast file\n");
  1883. return -1;
  1884. }
  1885. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  1886. /* displayDiagnosics=*/1))) {
  1887. fprintf(stderr, "Could not create Index\n");
  1888. return 1;
  1889. }
  1890. idxAction = 0;
  1891. result = 1;
  1892. if (!CreateTranslationUnit(Idx, argv[0], &TU))
  1893. goto finished;
  1894. index_data.check_prefix = check_prefix;
  1895. index_data.first_check_printed = 0;
  1896. index_data.fail_for_error = 0;
  1897. index_data.abort = 0;
  1898. index_opts = getIndexOptions();
  1899. idxAction = clang_IndexAction_create(Idx);
  1900. result = clang_indexTranslationUnit(idxAction, &index_data,
  1901. &IndexCB,sizeof(IndexCB),
  1902. index_opts, TU);
  1903. if (index_data.fail_for_error)
  1904. goto finished;
  1905. finished:
  1906. clang_IndexAction_dispose(idxAction);
  1907. clang_disposeIndex(Idx);
  1908. return result;
  1909. }
  1910. int perform_token_annotation(int argc, const char **argv) {
  1911. const char *input = argv[1];
  1912. char *filename = 0;
  1913. unsigned line, second_line;
  1914. unsigned column, second_column;
  1915. CXIndex CIdx;
  1916. CXTranslationUnit TU = 0;
  1917. int errorCode;
  1918. struct CXUnsavedFile *unsaved_files = 0;
  1919. int num_unsaved_files = 0;
  1920. CXToken *tokens;
  1921. unsigned num_tokens;
  1922. CXSourceRange range;
  1923. CXSourceLocation startLoc, endLoc;
  1924. CXFile file = 0;
  1925. CXCursor *cursors = 0;
  1926. unsigned i;
  1927. input += strlen("-test-annotate-tokens=");
  1928. if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
  1929. &second_line, &second_column)))
  1930. return errorCode;
  1931. if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
  1932. return -1;
  1933. CIdx = clang_createIndex(0, 1);
  1934. TU = clang_parseTranslationUnit(CIdx, argv[argc - 1],
  1935. argv + num_unsaved_files + 2,
  1936. argc - num_unsaved_files - 3,
  1937. unsaved_files,
  1938. num_unsaved_files,
  1939. getDefaultParsingOptions());
  1940. if (!TU) {
  1941. fprintf(stderr, "unable to parse input\n");
  1942. clang_disposeIndex(CIdx);
  1943. free(filename);
  1944. free_remapped_files(unsaved_files, num_unsaved_files);
  1945. return -1;
  1946. }
  1947. errorCode = 0;
  1948. if (checkForErrors(TU) != 0)
  1949. return -1;
  1950. if (getenv("CINDEXTEST_EDITING")) {
  1951. for (i = 0; i < 5; ++i) {
  1952. if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  1953. clang_defaultReparseOptions(TU))) {
  1954. fprintf(stderr, "Unable to reparse translation unit!\n");
  1955. errorCode = -1;
  1956. goto teardown;
  1957. }
  1958. }
  1959. }
  1960. if (checkForErrors(TU) != 0) {
  1961. errorCode = -1;
  1962. goto teardown;
  1963. }
  1964. file = clang_getFile(TU, filename);
  1965. if (!file) {
  1966. fprintf(stderr, "file %s is not in this translation unit\n", filename);
  1967. errorCode = -1;
  1968. goto teardown;
  1969. }
  1970. startLoc = clang_getLocation(TU, file, line, column);
  1971. if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
  1972. fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
  1973. column);
  1974. errorCode = -1;
  1975. goto teardown;
  1976. }
  1977. endLoc = clang_getLocation(TU, file, second_line, second_column);
  1978. if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
  1979. fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
  1980. second_line, second_column);
  1981. errorCode = -1;
  1982. goto teardown;
  1983. }
  1984. range = clang_getRange(startLoc, endLoc);
  1985. clang_tokenize(TU, range, &tokens, &num_tokens);
  1986. if (checkForErrors(TU) != 0) {
  1987. errorCode = -1;
  1988. goto teardown;
  1989. }
  1990. cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
  1991. clang_annotateTokens(TU, tokens, num_tokens, cursors);
  1992. if (checkForErrors(TU) != 0) {
  1993. errorCode = -1;
  1994. goto teardown;
  1995. }
  1996. for (i = 0; i != num_tokens; ++i) {
  1997. const char *kind = "<unknown>";
  1998. CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
  1999. CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
  2000. unsigned start_line, start_column, end_line, end_column;
  2001. switch (clang_getTokenKind(tokens[i])) {
  2002. case CXToken_Punctuation: kind = "Punctuation"; break;
  2003. case CXToken_Keyword: kind = "Keyword"; break;
  2004. case CXToken_Identifier: kind = "Identifier"; break;
  2005. case CXToken_Literal: kind = "Literal"; break;
  2006. case CXToken_Comment: kind = "Comment"; break;
  2007. }
  2008. clang_getSpellingLocation(clang_getRangeStart(extent),
  2009. 0, &start_line, &start_column, 0);
  2010. clang_getSpellingLocation(clang_getRangeEnd(extent),
  2011. 0, &end_line, &end_column, 0);
  2012. printf("%s: \"%s\" ", kind, clang_getCString(spelling));
  2013. clang_disposeString(spelling);
  2014. PrintExtent(stdout, start_line, start_column, end_line, end_column);
  2015. if (!clang_isInvalid(cursors[i].kind)) {
  2016. printf(" ");
  2017. PrintCursor(cursors[i]);
  2018. }
  2019. printf("\n");
  2020. }
  2021. free(cursors);
  2022. clang_disposeTokens(TU, tokens, num_tokens);
  2023. teardown:
  2024. PrintDiagnostics(TU);
  2025. clang_disposeTranslationUnit(TU);
  2026. clang_disposeIndex(CIdx);
  2027. free(filename);
  2028. free_remapped_files(unsaved_files, num_unsaved_files);
  2029. return errorCode;
  2030. }
  2031. /******************************************************************************/
  2032. /* USR printing. */
  2033. /******************************************************************************/
  2034. static int insufficient_usr(const char *kind, const char *usage) {
  2035. fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
  2036. return 1;
  2037. }
  2038. static unsigned isUSR(const char *s) {
  2039. return s[0] == 'c' && s[1] == ':';
  2040. }
  2041. static int not_usr(const char *s, const char *arg) {
  2042. fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
  2043. return 1;
  2044. }
  2045. static void print_usr(CXString usr) {
  2046. const char *s = clang_getCString(usr);
  2047. printf("%s\n", s);
  2048. clang_disposeString(usr);
  2049. }
  2050. static void display_usrs() {
  2051. fprintf(stderr, "-print-usrs options:\n"
  2052. " ObjCCategory <class name> <category name>\n"
  2053. " ObjCClass <class name>\n"
  2054. " ObjCIvar <ivar name> <class USR>\n"
  2055. " ObjCMethod <selector> [0=class method|1=instance method] "
  2056. "<class USR>\n"
  2057. " ObjCProperty <property name> <class USR>\n"
  2058. " ObjCProtocol <protocol name>\n");
  2059. }
  2060. int print_usrs(const char **I, const char **E) {
  2061. while (I != E) {
  2062. const char *kind = *I;
  2063. unsigned len = strlen(kind);
  2064. switch (len) {
  2065. case 8:
  2066. if (memcmp(kind, "ObjCIvar", 8) == 0) {
  2067. if (I + 2 >= E)
  2068. return insufficient_usr(kind, "<ivar name> <class USR>");
  2069. if (!isUSR(I[2]))
  2070. return not_usr("<class USR>", I[2]);
  2071. else {
  2072. CXString x;
  2073. x.data = (void*) I[2];
  2074. x.private_flags = 0;
  2075. print_usr(clang_constructUSR_ObjCIvar(I[1], x));
  2076. }
  2077. I += 3;
  2078. continue;
  2079. }
  2080. break;
  2081. case 9:
  2082. if (memcmp(kind, "ObjCClass", 9) == 0) {
  2083. if (I + 1 >= E)
  2084. return insufficient_usr(kind, "<class name>");
  2085. print_usr(clang_constructUSR_ObjCClass(I[1]));
  2086. I += 2;
  2087. continue;
  2088. }
  2089. break;
  2090. case 10:
  2091. if (memcmp(kind, "ObjCMethod", 10) == 0) {
  2092. if (I + 3 >= E)
  2093. return insufficient_usr(kind, "<method selector> "
  2094. "[0=class method|1=instance method] <class USR>");
  2095. if (!isUSR(I[3]))
  2096. return not_usr("<class USR>", I[3]);
  2097. else {
  2098. CXString x;
  2099. x.data = (void*) I[3];
  2100. x.private_flags = 0;
  2101. print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
  2102. }
  2103. I += 4;
  2104. continue;
  2105. }
  2106. break;
  2107. case 12:
  2108. if (memcmp(kind, "ObjCCategory", 12) == 0) {
  2109. if (I + 2 >= E)
  2110. return insufficient_usr(kind, "<class name> <category name>");
  2111. print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
  2112. I += 3;
  2113. continue;
  2114. }
  2115. if (memcmp(kind, "ObjCProtocol", 12) == 0) {
  2116. if (I + 1 >= E)
  2117. return insufficient_usr(kind, "<protocol name>");
  2118. print_usr(clang_constructUSR_ObjCProtocol(I[1]));
  2119. I += 2;
  2120. continue;
  2121. }
  2122. if (memcmp(kind, "ObjCProperty", 12) == 0) {
  2123. if (I + 2 >= E)
  2124. return insufficient_usr(kind, "<property name> <class USR>");
  2125. if (!isUSR(I[2]))
  2126. return not_usr("<class USR>", I[2]);
  2127. else {
  2128. CXString x;
  2129. x.data = (void*) I[2];
  2130. x.private_flags = 0;
  2131. print_usr(clang_constructUSR_ObjCProperty(I[1], x));
  2132. }
  2133. I += 3;
  2134. continue;
  2135. }
  2136. break;
  2137. default:
  2138. break;
  2139. }
  2140. break;
  2141. }
  2142. if (I != E) {
  2143. fprintf(stderr, "Invalid USR kind: %s\n", *I);
  2144. display_usrs();
  2145. return 1;
  2146. }
  2147. return 0;
  2148. }
  2149. int print_usrs_file(const char *file_name) {
  2150. char line[2048];
  2151. const char *args[128];
  2152. unsigned numChars = 0;
  2153. FILE *fp = fopen(file_name, "r");
  2154. if (!fp) {
  2155. fprintf(stderr, "error: cannot open '%s'\n", file_name);
  2156. return 1;
  2157. }
  2158. /* This code is not really all that safe, but it works fine for testing. */
  2159. while (!feof(fp)) {
  2160. char c = fgetc(fp);
  2161. if (c == '\n') {
  2162. unsigned i = 0;
  2163. const char *s = 0;
  2164. if (numChars == 0)
  2165. continue;
  2166. line[numChars] = '\0';
  2167. numChars = 0;
  2168. if (line[0] == '/' && line[1] == '/')
  2169. continue;
  2170. s = strtok(line, " ");
  2171. while (s) {
  2172. args[i] = s;
  2173. ++i;
  2174. s = strtok(0, " ");
  2175. }
  2176. if (print_usrs(&args[0], &args[i]))
  2177. return 1;
  2178. }
  2179. else
  2180. line[numChars++] = c;
  2181. }
  2182. fclose(fp);
  2183. return 0;
  2184. }
  2185. /******************************************************************************/
  2186. /* Command line processing. */
  2187. /******************************************************************************/
  2188. int write_pch_file(const char *filename, int argc, const char *argv[]) {
  2189. CXIndex Idx;
  2190. CXTranslationUnit TU;
  2191. struct CXUnsavedFile *unsaved_files = 0;
  2192. int num_unsaved_files = 0;
  2193. int result = 0;
  2194. Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1);
  2195. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  2196. clang_disposeIndex(Idx);
  2197. return -1;
  2198. }
  2199. TU = clang_parseTranslationUnit(Idx, 0,
  2200. argv + num_unsaved_files,
  2201. argc - num_unsaved_files,
  2202. unsaved_files,
  2203. num_unsaved_files,
  2204. CXTranslationUnit_Incomplete);
  2205. if (!TU) {
  2206. fprintf(stderr, "Unable to load translation unit!\n");
  2207. free_remapped_files(unsaved_files, num_unsaved_files);
  2208. clang_disposeIndex(Idx);
  2209. return 1;
  2210. }
  2211. switch (clang_saveTranslationUnit(TU, filename,
  2212. clang_defaultSaveOptions(TU))) {
  2213. case CXSaveError_None:
  2214. break;
  2215. case CXSaveError_TranslationErrors:
  2216. fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
  2217. filename);
  2218. result = 2;
  2219. break;
  2220. case CXSaveError_InvalidTU:
  2221. fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
  2222. filename);
  2223. result = 3;
  2224. break;
  2225. case CXSaveError_Unknown:
  2226. default:
  2227. fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
  2228. result = 1;
  2229. break;
  2230. }
  2231. clang_disposeTranslationUnit(TU);
  2232. free_remapped_files(unsaved_files, num_unsaved_files);
  2233. clang_disposeIndex(Idx);
  2234. return result;
  2235. }
  2236. /******************************************************************************/
  2237. /* Serialized diagnostics. */
  2238. /******************************************************************************/
  2239. static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
  2240. switch (error) {
  2241. case CXLoadDiag_CannotLoad: return "Cannot Load File";
  2242. case CXLoadDiag_None: break;
  2243. case CXLoadDiag_Unknown: return "Unknown";
  2244. case CXLoadDiag_InvalidFile: return "Invalid File";
  2245. }
  2246. return "None";
  2247. }
  2248. static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
  2249. switch (severity) {
  2250. case CXDiagnostic_Note: return "note";
  2251. case CXDiagnostic_Error: return "error";
  2252. case CXDiagnostic_Fatal: return "fatal";
  2253. case CXDiagnostic_Ignored: return "ignored";
  2254. case CXDiagnostic_Warning: return "warning";
  2255. }
  2256. return "unknown";
  2257. }
  2258. static void printIndent(unsigned indent) {
  2259. if (indent == 0)
  2260. return;
  2261. fprintf(stderr, "+");
  2262. --indent;
  2263. while (indent > 0) {
  2264. fprintf(stderr, "-");
  2265. --indent;
  2266. }
  2267. }
  2268. static void printLocation(CXSourceLocation L) {
  2269. CXFile File;
  2270. CXString FileName;
  2271. unsigned line, column, offset;
  2272. clang_getExpansionLocation(L, &File, &line, &column, &offset);
  2273. FileName = clang_getFileName(File);
  2274. fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
  2275. clang_disposeString(FileName);
  2276. }
  2277. static void printRanges(CXDiagnostic D, unsigned indent) {
  2278. unsigned i, n = clang_getDiagnosticNumRanges(D);
  2279. for (i = 0; i < n; ++i) {
  2280. CXSourceLocation Start, End;
  2281. CXSourceRange SR = clang_getDiagnosticRange(D, i);
  2282. Start = clang_getRangeStart(SR);
  2283. End = clang_getRangeEnd(SR);
  2284. printIndent(indent);
  2285. fprintf(stderr, "Range: ");
  2286. printLocation(Start);
  2287. fprintf(stderr, " ");
  2288. printLocation(End);
  2289. fprintf(stderr, "\n");
  2290. }
  2291. }
  2292. static void printFixIts(CXDiagnostic D, unsigned indent) {
  2293. unsigned i, n = clang_getDiagnosticNumFixIts(D);
  2294. fprintf(stderr, "Number FIXITs = %d\n", n);
  2295. for (i = 0 ; i < n; ++i) {
  2296. CXSourceRange ReplacementRange;
  2297. CXString text;
  2298. text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
  2299. printIndent(indent);
  2300. fprintf(stderr, "FIXIT: (");
  2301. printLocation(clang_getRangeStart(ReplacementRange));
  2302. fprintf(stderr, " - ");
  2303. printLocation(clang_getRangeEnd(ReplacementRange));
  2304. fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
  2305. clang_disposeString(text);
  2306. }
  2307. }
  2308. static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
  2309. unsigned i, n;
  2310. if (!Diags)
  2311. return;
  2312. n = clang_getNumDiagnosticsInSet(Diags);
  2313. for (i = 0; i < n; ++i) {
  2314. CXSourceLocation DiagLoc;
  2315. CXDiagnostic D;
  2316. CXFile File;
  2317. CXString FileName, DiagSpelling, DiagOption, DiagCat;
  2318. unsigned line, column, offset;
  2319. const char *DiagOptionStr = 0, *DiagCatStr = 0;
  2320. D = clang_getDiagnosticInSet(Diags, i);
  2321. DiagLoc = clang_getDiagnosticLocation(D);
  2322. clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
  2323. FileName = clang_getFileName(File);
  2324. DiagSpelling = clang_getDiagnosticSpelling(D);
  2325. printIndent(indent);
  2326. fprintf(stderr, "%s:%d:%d: %s: %s",
  2327. clang_getCString(FileName),
  2328. line,
  2329. column,
  2330. getSeverityString(clang_getDiagnosticSeverity(D)),
  2331. clang_getCString(DiagSpelling));
  2332. DiagOption = clang_getDiagnosticOption(D, 0);
  2333. DiagOptionStr = clang_getCString(DiagOption);
  2334. if (DiagOptionStr) {
  2335. fprintf(stderr, " [%s]", DiagOptionStr);
  2336. }
  2337. DiagCat = clang_getDiagnosticCategoryText(D);
  2338. DiagCatStr = clang_getCString(DiagCat);
  2339. if (DiagCatStr) {
  2340. fprintf(stderr, " [%s]", DiagCatStr);
  2341. }
  2342. fprintf(stderr, "\n");
  2343. printRanges(D, indent);
  2344. printFixIts(D, indent);
  2345. /* Print subdiagnostics. */
  2346. printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
  2347. clang_disposeString(FileName);
  2348. clang_disposeString(DiagSpelling);
  2349. clang_disposeString(DiagOption);
  2350. }
  2351. }
  2352. static int read_diagnostics(const char *filename) {
  2353. enum CXLoadDiag_Error error;
  2354. CXString errorString;
  2355. CXDiagnosticSet Diags = 0;
  2356. Diags = clang_loadDiagnostics(filename, &error, &errorString);
  2357. if (!Diags) {
  2358. fprintf(stderr, "Trouble deserializing file (%s): %s\n",
  2359. getDiagnosticCodeStr(error),
  2360. clang_getCString(errorString));
  2361. clang_disposeString(errorString);
  2362. return 1;
  2363. }
  2364. printDiagnosticSet(Diags, 0);
  2365. fprintf(stderr, "Number of diagnostics: %d\n",
  2366. clang_getNumDiagnosticsInSet(Diags));
  2367. clang_disposeDiagnosticSet(Diags);
  2368. return 0;
  2369. }
  2370. /******************************************************************************/
  2371. /* Command line processing. */
  2372. /******************************************************************************/
  2373. static CXCursorVisitor GetVisitor(const char *s) {
  2374. if (s[0] == '\0')
  2375. return FilteredPrintingVisitor;
  2376. if (strcmp(s, "-usrs") == 0)
  2377. return USRVisitor;
  2378. if (strncmp(s, "-memory-usage", 13) == 0)
  2379. return GetVisitor(s + 13);
  2380. return NULL;
  2381. }
  2382. static void print_usage(void) {
  2383. fprintf(stderr,
  2384. "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
  2385. " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
  2386. " c-index-test -cursor-at=<site> <compiler arguments>\n"
  2387. " c-index-test -file-refs-at=<site> <compiler arguments>\n"
  2388. " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
  2389. " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
  2390. " c-index-test -test-file-scan <AST file> <source file> "
  2391. "[FileCheck prefix]\n");
  2392. fprintf(stderr,
  2393. " c-index-test -test-load-tu <AST file> <symbol filter> "
  2394. "[FileCheck prefix]\n"
  2395. " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
  2396. "[FileCheck prefix]\n"
  2397. " c-index-test -test-load-source <symbol filter> {<args>}*\n");
  2398. fprintf(stderr,
  2399. " c-index-test -test-load-source-memory-usage "
  2400. "<symbol filter> {<args>}*\n"
  2401. " c-index-test -test-load-source-reparse <trials> <symbol filter> "
  2402. " {<args>}*\n"
  2403. " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
  2404. " c-index-test -test-load-source-usrs-memory-usage "
  2405. "<symbol filter> {<args>}*\n"
  2406. " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
  2407. " c-index-test -test-inclusion-stack-source {<args>}*\n"
  2408. " c-index-test -test-inclusion-stack-tu <AST file>\n");
  2409. fprintf(stderr,
  2410. " c-index-test -test-print-linkage-source {<args>}*\n"
  2411. " c-index-test -test-print-typekind {<args>}*\n"
  2412. " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
  2413. " c-index-test -print-usr-file <file>\n"
  2414. " c-index-test -write-pch <file> <compiler arguments>\n");
  2415. fprintf(stderr,
  2416. " c-index-test -read-diagnostics <file>\n\n");
  2417. fprintf(stderr,
  2418. " <symbol filter> values:\n%s",
  2419. " all - load all symbols, including those from PCH\n"
  2420. " local - load all symbols except those in PCH\n"
  2421. " category - only load ObjC categories (non-PCH)\n"
  2422. " interface - only load ObjC interfaces (non-PCH)\n"
  2423. " protocol - only load ObjC protocols (non-PCH)\n"
  2424. " function - only load functions (non-PCH)\n"
  2425. " typedef - only load typdefs (non-PCH)\n"
  2426. " scan-function - scan function bodies (non-PCH)\n\n");
  2427. }
  2428. /***/
  2429. int cindextest_main(int argc, const char **argv) {
  2430. clang_enableStackTraces();
  2431. if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
  2432. return read_diagnostics(argv[2]);
  2433. if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
  2434. return perform_code_completion(argc, argv, 0);
  2435. if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
  2436. return perform_code_completion(argc, argv, 1);
  2437. if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
  2438. return inspect_cursor_at(argc, argv);
  2439. if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
  2440. return find_file_refs_at(argc, argv);
  2441. if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
  2442. return index_file(argc - 2, argv + 2);
  2443. if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
  2444. return index_tu(argc - 2, argv + 2);
  2445. else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
  2446. CXCursorVisitor I = GetVisitor(argv[1] + 13);
  2447. if (I)
  2448. return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
  2449. NULL);
  2450. }
  2451. else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
  2452. CXCursorVisitor I = GetVisitor(argv[1] + 25);
  2453. if (I) {
  2454. int trials = atoi(argv[2]);
  2455. return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
  2456. NULL);
  2457. }
  2458. }
  2459. else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
  2460. CXCursorVisitor I = GetVisitor(argv[1] + 17);
  2461. PostVisitTU postVisit = 0;
  2462. if (strstr(argv[1], "-memory-usage"))
  2463. postVisit = PrintMemoryUsage;
  2464. if (I)
  2465. return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
  2466. postVisit);
  2467. }
  2468. else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
  2469. return perform_file_scan(argv[2], argv[3],
  2470. argc >= 5 ? argv[4] : 0);
  2471. else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
  2472. return perform_token_annotation(argc, argv);
  2473. else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
  2474. return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
  2475. PrintInclusionStack);
  2476. else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
  2477. return perform_test_load_tu(argv[2], "all", NULL, NULL,
  2478. PrintInclusionStack);
  2479. else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
  2480. return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
  2481. NULL);
  2482. else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0)
  2483. return perform_test_load_source(argc - 2, argv + 2, "all",
  2484. PrintTypeKind, 0);
  2485. else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
  2486. if (argc > 2)
  2487. return print_usrs(argv + 2, argv + argc);
  2488. else {
  2489. display_usrs();
  2490. return 1;
  2491. }
  2492. }
  2493. else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
  2494. return print_usrs_file(argv[2]);
  2495. else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
  2496. return write_pch_file(argv[2], argc - 3, argv + 3);
  2497. print_usage();
  2498. return 1;
  2499. }
  2500. /***/
  2501. /* We intentionally run in a separate thread to ensure we at least minimal
  2502. * testing of a multithreaded environment (for example, having a reduced stack
  2503. * size). */
  2504. typedef struct thread_info {
  2505. int argc;
  2506. const char **argv;
  2507. int result;
  2508. } thread_info;
  2509. void thread_runner(void *client_data_v) {
  2510. thread_info *client_data = client_data_v;
  2511. client_data->result = cindextest_main(client_data->argc, client_data->argv);
  2512. #ifdef __CYGWIN__
  2513. fflush(stdout); /* stdout is not flushed on Cygwin. */
  2514. #endif
  2515. }
  2516. int main(int argc, const char **argv) {
  2517. thread_info client_data;
  2518. if (getenv("CINDEXTEST_NOTHREADS"))
  2519. return cindextest_main(argc, argv);
  2520. client_data.argc = argc;
  2521. client_data.argv = argv;
  2522. clang_executeOnThread(thread_runner, &client_data, 0);
  2523. return client_data.result;
  2524. }