c-index-test.c 141 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459
  1. /* c-index-test.c */
  2. #include "clang/Config/config.h"
  3. #include "clang-c/Index.h"
  4. #include "clang-c/CXCompilationDatabase.h"
  5. #include "clang-c/BuildSystem.h"
  6. #include "clang-c/Documentation.h"
  7. #include <ctype.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #ifdef CLANG_HAVE_LIBXML
  13. #include <libxml/parser.h>
  14. #include <libxml/relaxng.h>
  15. #include <libxml/xmlerror.h>
  16. #endif
  17. #ifdef _WIN32
  18. # include <direct.h>
  19. #else
  20. # include <unistd.h>
  21. #endif
  22. extern int indextest_core_main(int argc, const char **argv);
  23. /******************************************************************************/
  24. /* Utility functions. */
  25. /******************************************************************************/
  26. #ifdef _MSC_VER
  27. char *basename(const char* path)
  28. {
  29. char* base1 = (char*)strrchr(path, '/');
  30. char* base2 = (char*)strrchr(path, '\\');
  31. if (base1 && base2)
  32. return((base1 > base2) ? base1 + 1 : base2 + 1);
  33. else if (base1)
  34. return(base1 + 1);
  35. else if (base2)
  36. return(base2 + 1);
  37. return((char*)path);
  38. }
  39. char *dirname(char* path)
  40. {
  41. char* base1 = (char*)strrchr(path, '/');
  42. char* base2 = (char*)strrchr(path, '\\');
  43. if (base1 && base2)
  44. if (base1 > base2)
  45. *base1 = 0;
  46. else
  47. *base2 = 0;
  48. else if (base1)
  49. *base1 = 0;
  50. else if (base2)
  51. *base2 = 0;
  52. return path;
  53. }
  54. #else
  55. extern char *basename(const char *);
  56. extern char *dirname(char *);
  57. #endif
  58. /** \brief Return the default parsing options. */
  59. static unsigned getDefaultParsingOptions() {
  60. unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
  61. if (getenv("CINDEXTEST_EDITING"))
  62. options |= clang_defaultEditingTranslationUnitOptions();
  63. if (getenv("CINDEXTEST_COMPLETION_CACHING"))
  64. options |= CXTranslationUnit_CacheCompletionResults;
  65. if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
  66. options &= ~CXTranslationUnit_CacheCompletionResults;
  67. if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
  68. options |= CXTranslationUnit_SkipFunctionBodies;
  69. if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
  70. options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
  71. if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
  72. options |= CXTranslationUnit_CreatePreambleOnFirstParse;
  73. if (getenv("CINDEXTEST_KEEP_GOING"))
  74. options |= CXTranslationUnit_KeepGoing;
  75. return options;
  76. }
  77. /** \brief Returns 0 in case of success, non-zero in case of a failure. */
  78. static int checkForErrors(CXTranslationUnit TU);
  79. static void describeLibclangFailure(enum CXErrorCode Err) {
  80. switch (Err) {
  81. case CXError_Success:
  82. fprintf(stderr, "Success\n");
  83. return;
  84. case CXError_Failure:
  85. fprintf(stderr, "Failure (no details available)\n");
  86. return;
  87. case CXError_Crashed:
  88. fprintf(stderr, "Failure: libclang crashed\n");
  89. return;
  90. case CXError_InvalidArguments:
  91. fprintf(stderr, "Failure: invalid arguments passed to a libclang routine\n");
  92. return;
  93. case CXError_ASTReadError:
  94. fprintf(stderr, "Failure: AST deserialization error occurred\n");
  95. return;
  96. }
  97. }
  98. static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
  99. unsigned end_line, unsigned end_column) {
  100. fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
  101. end_line, end_column);
  102. }
  103. static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
  104. CXTranslationUnit *TU) {
  105. enum CXErrorCode Err = clang_createTranslationUnit2(Idx, file, TU);
  106. if (Err != CXError_Success) {
  107. fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
  108. describeLibclangFailure(Err);
  109. *TU = 0;
  110. return 0;
  111. }
  112. return 1;
  113. }
  114. void free_remapped_files(struct CXUnsavedFile *unsaved_files,
  115. int num_unsaved_files) {
  116. int i;
  117. for (i = 0; i != num_unsaved_files; ++i) {
  118. free((char *)unsaved_files[i].Filename);
  119. free((char *)unsaved_files[i].Contents);
  120. }
  121. free(unsaved_files);
  122. }
  123. static int parse_remapped_files_with_opt(const char *opt_name,
  124. int argc, const char **argv,
  125. int start_arg,
  126. struct CXUnsavedFile **unsaved_files,
  127. int *num_unsaved_files) {
  128. int i;
  129. int arg;
  130. int prefix_len = strlen(opt_name);
  131. int arg_indices[20];
  132. *unsaved_files = 0;
  133. *num_unsaved_files = 0;
  134. /* Count the number of remapped files. */
  135. for (arg = start_arg; arg < argc; ++arg) {
  136. if (strncmp(argv[arg], opt_name, prefix_len))
  137. continue;
  138. assert(*num_unsaved_files < (int)(sizeof(arg_indices)/sizeof(int)));
  139. arg_indices[*num_unsaved_files] = arg;
  140. ++*num_unsaved_files;
  141. }
  142. if (*num_unsaved_files == 0)
  143. return 0;
  144. *unsaved_files
  145. = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
  146. *num_unsaved_files);
  147. for (i = 0; i != *num_unsaved_files; ++i) {
  148. struct CXUnsavedFile *unsaved = *unsaved_files + i;
  149. const char *arg_string = argv[arg_indices[i]] + prefix_len;
  150. int filename_len;
  151. char *filename;
  152. char *contents;
  153. FILE *to_file;
  154. const char *sep = strchr(arg_string, ',');
  155. if (!sep) {
  156. fprintf(stderr,
  157. "error: %sfrom:to argument is missing comma\n", opt_name);
  158. free_remapped_files(*unsaved_files, i);
  159. *unsaved_files = 0;
  160. *num_unsaved_files = 0;
  161. return -1;
  162. }
  163. /* Open the file that we're remapping to. */
  164. to_file = fopen(sep + 1, "rb");
  165. if (!to_file) {
  166. fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
  167. sep + 1);
  168. free_remapped_files(*unsaved_files, i);
  169. *unsaved_files = 0;
  170. *num_unsaved_files = 0;
  171. return -1;
  172. }
  173. /* Determine the length of the file we're remapping to. */
  174. fseek(to_file, 0, SEEK_END);
  175. unsaved->Length = ftell(to_file);
  176. fseek(to_file, 0, SEEK_SET);
  177. /* Read the contents of the file we're remapping to. */
  178. contents = (char *)malloc(unsaved->Length + 1);
  179. if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
  180. fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
  181. (feof(to_file) ? "EOF" : "error"), sep + 1);
  182. fclose(to_file);
  183. free_remapped_files(*unsaved_files, i);
  184. free(contents);
  185. *unsaved_files = 0;
  186. *num_unsaved_files = 0;
  187. return -1;
  188. }
  189. contents[unsaved->Length] = 0;
  190. unsaved->Contents = contents;
  191. /* Close the file. */
  192. fclose(to_file);
  193. /* Copy the file name that we're remapping from. */
  194. filename_len = sep - arg_string;
  195. filename = (char *)malloc(filename_len + 1);
  196. memcpy(filename, arg_string, filename_len);
  197. filename[filename_len] = 0;
  198. unsaved->Filename = filename;
  199. }
  200. return 0;
  201. }
  202. static int parse_remapped_files(int argc, const char **argv, int start_arg,
  203. struct CXUnsavedFile **unsaved_files,
  204. int *num_unsaved_files) {
  205. return parse_remapped_files_with_opt("-remap-file=", argc, argv, start_arg,
  206. unsaved_files, num_unsaved_files);
  207. }
  208. static int parse_remapped_files_with_try(int try_idx,
  209. int argc, const char **argv,
  210. int start_arg,
  211. struct CXUnsavedFile **unsaved_files,
  212. int *num_unsaved_files) {
  213. struct CXUnsavedFile *unsaved_files_no_try_idx;
  214. int num_unsaved_files_no_try_idx;
  215. struct CXUnsavedFile *unsaved_files_try_idx;
  216. int num_unsaved_files_try_idx;
  217. int ret;
  218. char opt_name[32];
  219. ret = parse_remapped_files(argc, argv, start_arg,
  220. &unsaved_files_no_try_idx, &num_unsaved_files_no_try_idx);
  221. if (ret)
  222. return ret;
  223. sprintf(opt_name, "-remap-file-%d=", try_idx);
  224. ret = parse_remapped_files_with_opt(opt_name, argc, argv, start_arg,
  225. &unsaved_files_try_idx, &num_unsaved_files_try_idx);
  226. if (ret)
  227. return ret;
  228. if (num_unsaved_files_no_try_idx == 0) {
  229. *unsaved_files = unsaved_files_try_idx;
  230. *num_unsaved_files = num_unsaved_files_try_idx;
  231. return 0;
  232. }
  233. if (num_unsaved_files_try_idx == 0) {
  234. *unsaved_files = unsaved_files_no_try_idx;
  235. *num_unsaved_files = num_unsaved_files_no_try_idx;
  236. return 0;
  237. }
  238. *num_unsaved_files = num_unsaved_files_no_try_idx + num_unsaved_files_try_idx;
  239. *unsaved_files
  240. = (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
  241. sizeof(struct CXUnsavedFile) *
  242. *num_unsaved_files);
  243. memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
  244. unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
  245. num_unsaved_files_try_idx);
  246. free(unsaved_files_try_idx);
  247. return 0;
  248. }
  249. static const char *parse_comments_schema(int argc, const char **argv) {
  250. const char *CommentsSchemaArg = "-comments-xml-schema=";
  251. const char *CommentSchemaFile = NULL;
  252. if (argc == 0)
  253. return CommentSchemaFile;
  254. if (!strncmp(argv[0], CommentsSchemaArg, strlen(CommentsSchemaArg)))
  255. CommentSchemaFile = argv[0] + strlen(CommentsSchemaArg);
  256. return CommentSchemaFile;
  257. }
  258. /******************************************************************************/
  259. /* Pretty-printing. */
  260. /******************************************************************************/
  261. static const char *FileCheckPrefix = "CHECK";
  262. static void PrintCString(const char *CStr) {
  263. if (CStr != NULL && CStr[0] != '\0') {
  264. for ( ; *CStr; ++CStr) {
  265. const char C = *CStr;
  266. switch (C) {
  267. case '\n': printf("\\n"); break;
  268. case '\r': printf("\\r"); break;
  269. case '\t': printf("\\t"); break;
  270. case '\v': printf("\\v"); break;
  271. case '\f': printf("\\f"); break;
  272. default: putchar(C); break;
  273. }
  274. }
  275. }
  276. }
  277. static void PrintCStringWithPrefix(const char *Prefix, const char *CStr) {
  278. printf(" %s=[", Prefix);
  279. PrintCString(CStr);
  280. printf("]");
  281. }
  282. static void PrintCXStringAndDispose(CXString Str) {
  283. PrintCString(clang_getCString(Str));
  284. clang_disposeString(Str);
  285. }
  286. static void PrintCXStringWithPrefix(const char *Prefix, CXString Str) {
  287. PrintCStringWithPrefix(Prefix, clang_getCString(Str));
  288. }
  289. static void PrintCXStringWithPrefixAndDispose(const char *Prefix,
  290. CXString Str) {
  291. PrintCStringWithPrefix(Prefix, clang_getCString(Str));
  292. clang_disposeString(Str);
  293. }
  294. static void PrintRange(CXSourceRange R, const char *str) {
  295. CXFile begin_file, end_file;
  296. unsigned begin_line, begin_column, end_line, end_column;
  297. clang_getSpellingLocation(clang_getRangeStart(R),
  298. &begin_file, &begin_line, &begin_column, 0);
  299. clang_getSpellingLocation(clang_getRangeEnd(R),
  300. &end_file, &end_line, &end_column, 0);
  301. if (!begin_file || !end_file)
  302. return;
  303. if (str)
  304. printf(" %s=", str);
  305. PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
  306. }
  307. int want_display_name = 0;
  308. static void printVersion(const char *Prefix, CXVersion Version) {
  309. if (Version.Major < 0)
  310. return;
  311. printf("%s%d", Prefix, Version.Major);
  312. if (Version.Minor < 0)
  313. return;
  314. printf(".%d", Version.Minor);
  315. if (Version.Subminor < 0)
  316. return;
  317. printf(".%d", Version.Subminor);
  318. }
  319. struct CommentASTDumpingContext {
  320. int IndentLevel;
  321. };
  322. static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
  323. CXComment Comment) {
  324. unsigned i;
  325. unsigned e;
  326. enum CXCommentKind Kind = clang_Comment_getKind(Comment);
  327. Ctx->IndentLevel++;
  328. for (i = 0, e = Ctx->IndentLevel; i != e; ++i)
  329. printf(" ");
  330. printf("(");
  331. switch (Kind) {
  332. case CXComment_Null:
  333. printf("CXComment_Null");
  334. break;
  335. case CXComment_Text:
  336. printf("CXComment_Text");
  337. PrintCXStringWithPrefixAndDispose("Text",
  338. clang_TextComment_getText(Comment));
  339. if (clang_Comment_isWhitespace(Comment))
  340. printf(" IsWhitespace");
  341. if (clang_InlineContentComment_hasTrailingNewline(Comment))
  342. printf(" HasTrailingNewline");
  343. break;
  344. case CXComment_InlineCommand:
  345. printf("CXComment_InlineCommand");
  346. PrintCXStringWithPrefixAndDispose(
  347. "CommandName",
  348. clang_InlineCommandComment_getCommandName(Comment));
  349. switch (clang_InlineCommandComment_getRenderKind(Comment)) {
  350. case CXCommentInlineCommandRenderKind_Normal:
  351. printf(" RenderNormal");
  352. break;
  353. case CXCommentInlineCommandRenderKind_Bold:
  354. printf(" RenderBold");
  355. break;
  356. case CXCommentInlineCommandRenderKind_Monospaced:
  357. printf(" RenderMonospaced");
  358. break;
  359. case CXCommentInlineCommandRenderKind_Emphasized:
  360. printf(" RenderEmphasized");
  361. break;
  362. }
  363. for (i = 0, e = clang_InlineCommandComment_getNumArgs(Comment);
  364. i != e; ++i) {
  365. printf(" Arg[%u]=", i);
  366. PrintCXStringAndDispose(
  367. clang_InlineCommandComment_getArgText(Comment, i));
  368. }
  369. if (clang_InlineContentComment_hasTrailingNewline(Comment))
  370. printf(" HasTrailingNewline");
  371. break;
  372. case CXComment_HTMLStartTag: {
  373. unsigned NumAttrs;
  374. printf("CXComment_HTMLStartTag");
  375. PrintCXStringWithPrefixAndDispose(
  376. "Name",
  377. clang_HTMLTagComment_getTagName(Comment));
  378. NumAttrs = clang_HTMLStartTag_getNumAttrs(Comment);
  379. if (NumAttrs != 0) {
  380. printf(" Attrs:");
  381. for (i = 0; i != NumAttrs; ++i) {
  382. printf(" ");
  383. PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment, i));
  384. printf("=");
  385. PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment, i));
  386. }
  387. }
  388. if (clang_HTMLStartTagComment_isSelfClosing(Comment))
  389. printf(" SelfClosing");
  390. if (clang_InlineContentComment_hasTrailingNewline(Comment))
  391. printf(" HasTrailingNewline");
  392. break;
  393. }
  394. case CXComment_HTMLEndTag:
  395. printf("CXComment_HTMLEndTag");
  396. PrintCXStringWithPrefixAndDispose(
  397. "Name",
  398. clang_HTMLTagComment_getTagName(Comment));
  399. if (clang_InlineContentComment_hasTrailingNewline(Comment))
  400. printf(" HasTrailingNewline");
  401. break;
  402. case CXComment_Paragraph:
  403. printf("CXComment_Paragraph");
  404. if (clang_Comment_isWhitespace(Comment))
  405. printf(" IsWhitespace");
  406. break;
  407. case CXComment_BlockCommand:
  408. printf("CXComment_BlockCommand");
  409. PrintCXStringWithPrefixAndDispose(
  410. "CommandName",
  411. clang_BlockCommandComment_getCommandName(Comment));
  412. for (i = 0, e = clang_BlockCommandComment_getNumArgs(Comment);
  413. i != e; ++i) {
  414. printf(" Arg[%u]=", i);
  415. PrintCXStringAndDispose(
  416. clang_BlockCommandComment_getArgText(Comment, i));
  417. }
  418. break;
  419. case CXComment_ParamCommand:
  420. printf("CXComment_ParamCommand");
  421. switch (clang_ParamCommandComment_getDirection(Comment)) {
  422. case CXCommentParamPassDirection_In:
  423. printf(" in");
  424. break;
  425. case CXCommentParamPassDirection_Out:
  426. printf(" out");
  427. break;
  428. case CXCommentParamPassDirection_InOut:
  429. printf(" in,out");
  430. break;
  431. }
  432. if (clang_ParamCommandComment_isDirectionExplicit(Comment))
  433. printf(" explicitly");
  434. else
  435. printf(" implicitly");
  436. PrintCXStringWithPrefixAndDispose(
  437. "ParamName",
  438. clang_ParamCommandComment_getParamName(Comment));
  439. if (clang_ParamCommandComment_isParamIndexValid(Comment))
  440. printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment));
  441. else
  442. printf(" ParamIndex=Invalid");
  443. break;
  444. case CXComment_TParamCommand:
  445. printf("CXComment_TParamCommand");
  446. PrintCXStringWithPrefixAndDispose(
  447. "ParamName",
  448. clang_TParamCommandComment_getParamName(Comment));
  449. if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
  450. printf(" ParamPosition={");
  451. for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
  452. i != e; ++i) {
  453. printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
  454. if (i != e - 1)
  455. printf(", ");
  456. }
  457. printf("}");
  458. } else
  459. printf(" ParamPosition=Invalid");
  460. break;
  461. case CXComment_VerbatimBlockCommand:
  462. printf("CXComment_VerbatimBlockCommand");
  463. PrintCXStringWithPrefixAndDispose(
  464. "CommandName",
  465. clang_BlockCommandComment_getCommandName(Comment));
  466. break;
  467. case CXComment_VerbatimBlockLine:
  468. printf("CXComment_VerbatimBlockLine");
  469. PrintCXStringWithPrefixAndDispose(
  470. "Text",
  471. clang_VerbatimBlockLineComment_getText(Comment));
  472. break;
  473. case CXComment_VerbatimLine:
  474. printf("CXComment_VerbatimLine");
  475. PrintCXStringWithPrefixAndDispose(
  476. "Text",
  477. clang_VerbatimLineComment_getText(Comment));
  478. break;
  479. case CXComment_FullComment:
  480. printf("CXComment_FullComment");
  481. break;
  482. }
  483. if (Kind != CXComment_Null) {
  484. const unsigned NumChildren = clang_Comment_getNumChildren(Comment);
  485. unsigned i;
  486. for (i = 0; i != NumChildren; ++i) {
  487. printf("\n// %s: ", FileCheckPrefix);
  488. DumpCXCommentInternal(Ctx, clang_Comment_getChild(Comment, i));
  489. }
  490. }
  491. printf(")");
  492. Ctx->IndentLevel--;
  493. }
  494. static void DumpCXComment(CXComment Comment) {
  495. struct CommentASTDumpingContext Ctx;
  496. Ctx.IndentLevel = 1;
  497. printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix, FileCheckPrefix);
  498. DumpCXCommentInternal(&Ctx, Comment);
  499. printf("]");
  500. }
  501. static void ValidateCommentXML(const char *Str, const char *CommentSchemaFile) {
  502. #ifdef CLANG_HAVE_LIBXML
  503. xmlRelaxNGParserCtxtPtr RNGParser;
  504. xmlRelaxNGPtr Schema;
  505. xmlDocPtr Doc;
  506. xmlRelaxNGValidCtxtPtr ValidationCtxt;
  507. int status;
  508. if (!CommentSchemaFile)
  509. return;
  510. RNGParser = xmlRelaxNGNewParserCtxt(CommentSchemaFile);
  511. if (!RNGParser) {
  512. printf(" libXMLError");
  513. return;
  514. }
  515. Schema = xmlRelaxNGParse(RNGParser);
  516. Doc = xmlParseDoc((const xmlChar *) Str);
  517. if (!Doc) {
  518. xmlErrorPtr Error = xmlGetLastError();
  519. printf(" CommentXMLInvalid [not well-formed XML: %s]", Error->message);
  520. return;
  521. }
  522. ValidationCtxt = xmlRelaxNGNewValidCtxt(Schema);
  523. status = xmlRelaxNGValidateDoc(ValidationCtxt, Doc);
  524. if (!status)
  525. printf(" CommentXMLValid");
  526. else if (status > 0) {
  527. xmlErrorPtr Error = xmlGetLastError();
  528. printf(" CommentXMLInvalid [not vaild XML: %s]", Error->message);
  529. } else
  530. printf(" libXMLError");
  531. xmlRelaxNGFreeValidCtxt(ValidationCtxt);
  532. xmlFreeDoc(Doc);
  533. xmlRelaxNGFree(Schema);
  534. xmlRelaxNGFreeParserCtxt(RNGParser);
  535. #endif
  536. }
  537. static void PrintCursorComments(CXCursor Cursor,
  538. const char *CommentSchemaFile) {
  539. {
  540. CXString RawComment;
  541. const char *RawCommentCString;
  542. CXString BriefComment;
  543. const char *BriefCommentCString;
  544. RawComment = clang_Cursor_getRawCommentText(Cursor);
  545. RawCommentCString = clang_getCString(RawComment);
  546. if (RawCommentCString != NULL && RawCommentCString[0] != '\0') {
  547. PrintCStringWithPrefix("RawComment", RawCommentCString);
  548. PrintRange(clang_Cursor_getCommentRange(Cursor), "RawCommentRange");
  549. BriefComment = clang_Cursor_getBriefCommentText(Cursor);
  550. BriefCommentCString = clang_getCString(BriefComment);
  551. if (BriefCommentCString != NULL && BriefCommentCString[0] != '\0')
  552. PrintCStringWithPrefix("BriefComment", BriefCommentCString);
  553. clang_disposeString(BriefComment);
  554. }
  555. clang_disposeString(RawComment);
  556. }
  557. {
  558. CXComment Comment = clang_Cursor_getParsedComment(Cursor);
  559. if (clang_Comment_getKind(Comment) != CXComment_Null) {
  560. PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
  561. clang_FullComment_getAsHTML(Comment));
  562. {
  563. CXString XML;
  564. XML = clang_FullComment_getAsXML(Comment);
  565. PrintCXStringWithPrefix("FullCommentAsXML", XML);
  566. ValidateCommentXML(clang_getCString(XML), CommentSchemaFile);
  567. clang_disposeString(XML);
  568. }
  569. DumpCXComment(Comment);
  570. }
  571. }
  572. }
  573. typedef struct {
  574. unsigned line;
  575. unsigned col;
  576. } LineCol;
  577. static int lineCol_cmp(const void *p1, const void *p2) {
  578. const LineCol *lhs = p1;
  579. const LineCol *rhs = p2;
  580. if (lhs->line != rhs->line)
  581. return (int)lhs->line - (int)rhs->line;
  582. return (int)lhs->col - (int)rhs->col;
  583. }
  584. static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
  585. CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
  586. if (clang_isInvalid(Cursor.kind)) {
  587. CXString ks = clang_getCursorKindSpelling(Cursor.kind);
  588. printf("Invalid Cursor => %s", clang_getCString(ks));
  589. clang_disposeString(ks);
  590. }
  591. else {
  592. CXString string, ks;
  593. CXCursor Referenced;
  594. unsigned line, column;
  595. CXCursor SpecializationOf;
  596. CXCursor *overridden;
  597. unsigned num_overridden;
  598. unsigned RefNameRangeNr;
  599. CXSourceRange CursorExtent;
  600. CXSourceRange RefNameRange;
  601. int AlwaysUnavailable;
  602. int AlwaysDeprecated;
  603. CXString UnavailableMessage;
  604. CXString DeprecatedMessage;
  605. CXPlatformAvailability PlatformAvailability[2];
  606. int NumPlatformAvailability;
  607. int I;
  608. ks = clang_getCursorKindSpelling(Cursor.kind);
  609. string = want_display_name? clang_getCursorDisplayName(Cursor)
  610. : clang_getCursorSpelling(Cursor);
  611. printf("%s=%s", clang_getCString(ks),
  612. clang_getCString(string));
  613. clang_disposeString(ks);
  614. clang_disposeString(string);
  615. Referenced = clang_getCursorReferenced(Cursor);
  616. if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
  617. if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) {
  618. unsigned I, N = clang_getNumOverloadedDecls(Referenced);
  619. printf("[");
  620. for (I = 0; I != N; ++I) {
  621. CXCursor Ovl = clang_getOverloadedDecl(Referenced, I);
  622. CXSourceLocation Loc;
  623. if (I)
  624. printf(", ");
  625. Loc = clang_getCursorLocation(Ovl);
  626. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  627. printf("%d:%d", line, column);
  628. }
  629. printf("]");
  630. } else {
  631. CXSourceLocation Loc = clang_getCursorLocation(Referenced);
  632. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  633. printf(":%d:%d", line, column);
  634. }
  635. }
  636. if (clang_isCursorDefinition(Cursor))
  637. printf(" (Definition)");
  638. switch (clang_getCursorAvailability(Cursor)) {
  639. case CXAvailability_Available:
  640. break;
  641. case CXAvailability_Deprecated:
  642. printf(" (deprecated)");
  643. break;
  644. case CXAvailability_NotAvailable:
  645. printf(" (unavailable)");
  646. break;
  647. case CXAvailability_NotAccessible:
  648. printf(" (inaccessible)");
  649. break;
  650. }
  651. NumPlatformAvailability
  652. = clang_getCursorPlatformAvailability(Cursor,
  653. &AlwaysDeprecated,
  654. &DeprecatedMessage,
  655. &AlwaysUnavailable,
  656. &UnavailableMessage,
  657. PlatformAvailability, 2);
  658. if (AlwaysUnavailable) {
  659. printf(" (always unavailable: \"%s\")",
  660. clang_getCString(UnavailableMessage));
  661. } else if (AlwaysDeprecated) {
  662. printf(" (always deprecated: \"%s\")",
  663. clang_getCString(DeprecatedMessage));
  664. } else {
  665. for (I = 0; I != NumPlatformAvailability; ++I) {
  666. if (I >= 2)
  667. break;
  668. printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
  669. if (PlatformAvailability[I].Unavailable)
  670. printf(", unavailable");
  671. else {
  672. printVersion(", introduced=", PlatformAvailability[I].Introduced);
  673. printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
  674. printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
  675. }
  676. if (clang_getCString(PlatformAvailability[I].Message)[0])
  677. printf(", message=\"%s\"",
  678. clang_getCString(PlatformAvailability[I].Message));
  679. printf(")");
  680. }
  681. }
  682. for (I = 0; I != NumPlatformAvailability; ++I) {
  683. if (I >= 2)
  684. break;
  685. clang_disposeCXPlatformAvailability(PlatformAvailability + I);
  686. }
  687. clang_disposeString(DeprecatedMessage);
  688. clang_disposeString(UnavailableMessage);
  689. if (clang_CXXField_isMutable(Cursor))
  690. printf(" (mutable)");
  691. if (clang_CXXMethod_isStatic(Cursor))
  692. printf(" (static)");
  693. if (clang_CXXMethod_isVirtual(Cursor))
  694. printf(" (virtual)");
  695. if (clang_CXXMethod_isConst(Cursor))
  696. printf(" (const)");
  697. if (clang_CXXMethod_isPureVirtual(Cursor))
  698. printf(" (pure)");
  699. if (clang_Cursor_isVariadic(Cursor))
  700. printf(" (variadic)");
  701. if (clang_Cursor_isObjCOptional(Cursor))
  702. printf(" (@optional)");
  703. if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
  704. CXType T =
  705. clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
  706. CXString S = clang_getTypeKindSpelling(T.kind);
  707. printf(" [IBOutletCollection=%s]", clang_getCString(S));
  708. clang_disposeString(S);
  709. }
  710. if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
  711. enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
  712. unsigned isVirtual = clang_isVirtualBase(Cursor);
  713. const char *accessStr = 0;
  714. switch (access) {
  715. case CX_CXXInvalidAccessSpecifier:
  716. accessStr = "invalid"; break;
  717. case CX_CXXPublic:
  718. accessStr = "public"; break;
  719. case CX_CXXProtected:
  720. accessStr = "protected"; break;
  721. case CX_CXXPrivate:
  722. accessStr = "private"; break;
  723. }
  724. printf(" [access=%s isVirtual=%s]", accessStr,
  725. isVirtual ? "true" : "false");
  726. }
  727. SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
  728. if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
  729. CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
  730. CXString Name = clang_getCursorSpelling(SpecializationOf);
  731. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  732. printf(" [Specialization of %s:%d:%d]",
  733. clang_getCString(Name), line, column);
  734. clang_disposeString(Name);
  735. if (Cursor.kind == CXCursor_FunctionDecl) {
  736. /* Collect the template parameter kinds from the base template. */
  737. unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
  738. unsigned I;
  739. for (I = 0; I < NumTemplateArgs; I++) {
  740. enum CXTemplateArgumentKind TAK =
  741. clang_Cursor_getTemplateArgumentKind(Cursor, I);
  742. switch(TAK) {
  743. case CXTemplateArgumentKind_Type:
  744. {
  745. CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
  746. CXString S = clang_getTypeSpelling(T);
  747. printf(" [Template arg %d: kind: %d, type: %s]",
  748. I, TAK, clang_getCString(S));
  749. clang_disposeString(S);
  750. }
  751. break;
  752. case CXTemplateArgumentKind_Integral:
  753. printf(" [Template arg %d: kind: %d, intval: %lld]",
  754. I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
  755. break;
  756. default:
  757. printf(" [Template arg %d: kind: %d]\n", I, TAK);
  758. }
  759. }
  760. }
  761. }
  762. clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
  763. if (num_overridden) {
  764. unsigned I;
  765. LineCol lineCols[50];
  766. assert(num_overridden <= 50);
  767. printf(" [Overrides ");
  768. for (I = 0; I != num_overridden; ++I) {
  769. CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
  770. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  771. lineCols[I].line = line;
  772. lineCols[I].col = column;
  773. }
  774. /* Make the order of the override list deterministic. */
  775. qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
  776. for (I = 0; I != num_overridden; ++I) {
  777. if (I)
  778. printf(", ");
  779. printf("@%d:%d", lineCols[I].line, lineCols[I].col);
  780. }
  781. printf("]");
  782. clang_disposeOverriddenCursors(overridden);
  783. }
  784. if (Cursor.kind == CXCursor_InclusionDirective) {
  785. CXFile File = clang_getIncludedFile(Cursor);
  786. CXString Included = clang_getFileName(File);
  787. printf(" (%s)", clang_getCString(Included));
  788. clang_disposeString(Included);
  789. if (clang_isFileMultipleIncludeGuarded(TU, File))
  790. printf(" [multi-include guarded]");
  791. }
  792. CursorExtent = clang_getCursorExtent(Cursor);
  793. RefNameRange = clang_getCursorReferenceNameRange(Cursor,
  794. CXNameRange_WantQualifier
  795. | CXNameRange_WantSinglePiece
  796. | CXNameRange_WantTemplateArgs,
  797. 0);
  798. if (!clang_equalRanges(CursorExtent, RefNameRange))
  799. PrintRange(RefNameRange, "SingleRefName");
  800. for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
  801. RefNameRange = clang_getCursorReferenceNameRange(Cursor,
  802. CXNameRange_WantQualifier
  803. | CXNameRange_WantTemplateArgs,
  804. RefNameRangeNr);
  805. if (clang_equalRanges(clang_getNullRange(), RefNameRange))
  806. break;
  807. if (!clang_equalRanges(CursorExtent, RefNameRange))
  808. PrintRange(RefNameRange, "RefName");
  809. }
  810. PrintCursorComments(Cursor, CommentSchemaFile);
  811. {
  812. unsigned PropAttrs = clang_Cursor_getObjCPropertyAttributes(Cursor, 0);
  813. if (PropAttrs != CXObjCPropertyAttr_noattr) {
  814. printf(" [");
  815. #define PRINT_PROP_ATTR(A) \
  816. if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
  817. PRINT_PROP_ATTR(readonly);
  818. PRINT_PROP_ATTR(getter);
  819. PRINT_PROP_ATTR(assign);
  820. PRINT_PROP_ATTR(readwrite);
  821. PRINT_PROP_ATTR(retain);
  822. PRINT_PROP_ATTR(copy);
  823. PRINT_PROP_ATTR(nonatomic);
  824. PRINT_PROP_ATTR(setter);
  825. PRINT_PROP_ATTR(atomic);
  826. PRINT_PROP_ATTR(weak);
  827. PRINT_PROP_ATTR(strong);
  828. PRINT_PROP_ATTR(unsafe_unretained);
  829. printf("]");
  830. }
  831. }
  832. {
  833. unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
  834. if (QT != CXObjCDeclQualifier_None) {
  835. printf(" [");
  836. #define PRINT_OBJC_QUAL(A) \
  837. if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
  838. PRINT_OBJC_QUAL(In);
  839. PRINT_OBJC_QUAL(Inout);
  840. PRINT_OBJC_QUAL(Out);
  841. PRINT_OBJC_QUAL(Bycopy);
  842. PRINT_OBJC_QUAL(Byref);
  843. PRINT_OBJC_QUAL(Oneway);
  844. printf("]");
  845. }
  846. }
  847. }
  848. }
  849. static const char* GetCursorSource(CXCursor Cursor) {
  850. CXSourceLocation Loc = clang_getCursorLocation(Cursor);
  851. CXString source;
  852. CXFile file;
  853. clang_getExpansionLocation(Loc, &file, 0, 0, 0);
  854. source = clang_getFileName(file);
  855. if (!clang_getCString(source)) {
  856. clang_disposeString(source);
  857. return "<invalid loc>";
  858. }
  859. else {
  860. const char *b = basename(clang_getCString(source));
  861. clang_disposeString(source);
  862. return b;
  863. }
  864. }
  865. /******************************************************************************/
  866. /* Callbacks. */
  867. /******************************************************************************/
  868. typedef void (*PostVisitTU)(CXTranslationUnit);
  869. void PrintDiagnostic(CXDiagnostic Diagnostic) {
  870. FILE *out = stderr;
  871. CXFile file;
  872. CXString Msg;
  873. unsigned display_opts = CXDiagnostic_DisplaySourceLocation
  874. | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
  875. | CXDiagnostic_DisplayOption;
  876. unsigned i, num_fixits;
  877. if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
  878. return;
  879. Msg = clang_formatDiagnostic(Diagnostic, display_opts);
  880. fprintf(stderr, "%s\n", clang_getCString(Msg));
  881. clang_disposeString(Msg);
  882. clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
  883. &file, 0, 0, 0);
  884. if (!file)
  885. return;
  886. num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
  887. fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
  888. for (i = 0; i != num_fixits; ++i) {
  889. CXSourceRange range;
  890. CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
  891. CXSourceLocation start = clang_getRangeStart(range);
  892. CXSourceLocation end = clang_getRangeEnd(range);
  893. unsigned start_line, start_column, end_line, end_column;
  894. CXFile start_file, end_file;
  895. clang_getSpellingLocation(start, &start_file, &start_line,
  896. &start_column, 0);
  897. clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
  898. if (clang_equalLocations(start, end)) {
  899. /* Insertion. */
  900. if (start_file == file)
  901. fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
  902. clang_getCString(insertion_text), start_line, start_column);
  903. } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
  904. /* Removal. */
  905. if (start_file == file && end_file == file) {
  906. fprintf(out, "FIX-IT: Remove ");
  907. PrintExtent(out, start_line, start_column, end_line, end_column);
  908. fprintf(out, "\n");
  909. }
  910. } else {
  911. /* Replacement. */
  912. if (start_file == end_file) {
  913. fprintf(out, "FIX-IT: Replace ");
  914. PrintExtent(out, start_line, start_column, end_line, end_column);
  915. fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
  916. }
  917. }
  918. clang_disposeString(insertion_text);
  919. }
  920. }
  921. void PrintDiagnosticSet(CXDiagnosticSet Set) {
  922. int i = 0, n = clang_getNumDiagnosticsInSet(Set);
  923. for ( ; i != n ; ++i) {
  924. CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
  925. CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
  926. PrintDiagnostic(Diag);
  927. if (ChildDiags)
  928. PrintDiagnosticSet(ChildDiags);
  929. }
  930. }
  931. void PrintDiagnostics(CXTranslationUnit TU) {
  932. CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
  933. PrintDiagnosticSet(TUSet);
  934. clang_disposeDiagnosticSet(TUSet);
  935. }
  936. void PrintMemoryUsage(CXTranslationUnit TU) {
  937. unsigned long total = 0;
  938. unsigned i = 0;
  939. CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
  940. fprintf(stderr, "Memory usage:\n");
  941. for (i = 0 ; i != usage.numEntries; ++i) {
  942. const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
  943. unsigned long amount = usage.entries[i].amount;
  944. total += amount;
  945. fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
  946. ((double) amount)/(1024*1024));
  947. }
  948. fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
  949. ((double) total)/(1024*1024));
  950. clang_disposeCXTUResourceUsage(usage);
  951. }
  952. /******************************************************************************/
  953. /* Logic for testing traversal. */
  954. /******************************************************************************/
  955. static void PrintCursorExtent(CXCursor C) {
  956. CXSourceRange extent = clang_getCursorExtent(C);
  957. PrintRange(extent, "Extent");
  958. }
  959. /* Data used by the visitors. */
  960. typedef struct {
  961. CXTranslationUnit TU;
  962. enum CXCursorKind *Filter;
  963. const char *CommentSchemaFile;
  964. } VisitorData;
  965. enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
  966. CXCursor Parent,
  967. CXClientData ClientData) {
  968. VisitorData *Data = (VisitorData *)ClientData;
  969. if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
  970. CXSourceLocation Loc = clang_getCursorLocation(Cursor);
  971. unsigned line, column;
  972. clang_getSpellingLocation(Loc, 0, &line, &column, 0);
  973. printf("// %s: %s:%d:%d: ", FileCheckPrefix,
  974. GetCursorSource(Cursor), line, column);
  975. PrintCursor(Cursor, Data->CommentSchemaFile);
  976. PrintCursorExtent(Cursor);
  977. if (clang_isDeclaration(Cursor.kind)) {
  978. enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
  979. const char *accessStr = 0;
  980. switch (access) {
  981. case CX_CXXInvalidAccessSpecifier: break;
  982. case CX_CXXPublic:
  983. accessStr = "public"; break;
  984. case CX_CXXProtected:
  985. accessStr = "protected"; break;
  986. case CX_CXXPrivate:
  987. accessStr = "private"; break;
  988. }
  989. if (accessStr)
  990. printf(" [access=%s]", accessStr);
  991. }
  992. printf("\n");
  993. return CXChildVisit_Recurse;
  994. }
  995. return CXChildVisit_Continue;
  996. }
  997. static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
  998. CXCursor Parent,
  999. CXClientData ClientData) {
  1000. const char *startBuf, *endBuf;
  1001. unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
  1002. CXCursor Ref;
  1003. VisitorData *Data = (VisitorData *)ClientData;
  1004. if (Cursor.kind != CXCursor_FunctionDecl ||
  1005. !clang_isCursorDefinition(Cursor))
  1006. return CXChildVisit_Continue;
  1007. clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
  1008. &startLine, &startColumn,
  1009. &endLine, &endColumn);
  1010. /* Probe the entire body, looking for both decls and refs. */
  1011. curLine = startLine;
  1012. curColumn = startColumn;
  1013. while (startBuf < endBuf) {
  1014. CXSourceLocation Loc;
  1015. CXFile file;
  1016. CXString source;
  1017. if (*startBuf == '\n') {
  1018. startBuf++;
  1019. curLine++;
  1020. curColumn = 1;
  1021. } else if (*startBuf != '\t')
  1022. curColumn++;
  1023. Loc = clang_getCursorLocation(Cursor);
  1024. clang_getSpellingLocation(Loc, &file, 0, 0, 0);
  1025. source = clang_getFileName(file);
  1026. if (clang_getCString(source)) {
  1027. CXSourceLocation RefLoc
  1028. = clang_getLocation(Data->TU, file, curLine, curColumn);
  1029. Ref = clang_getCursor(Data->TU, RefLoc);
  1030. if (Ref.kind == CXCursor_NoDeclFound) {
  1031. /* Nothing found here; that's fine. */
  1032. } else if (Ref.kind != CXCursor_FunctionDecl) {
  1033. printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
  1034. curLine, curColumn);
  1035. PrintCursor(Ref, Data->CommentSchemaFile);
  1036. printf("\n");
  1037. }
  1038. }
  1039. clang_disposeString(source);
  1040. startBuf++;
  1041. }
  1042. return CXChildVisit_Continue;
  1043. }
  1044. /******************************************************************************/
  1045. /* USR testing. */
  1046. /******************************************************************************/
  1047. enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
  1048. CXClientData ClientData) {
  1049. VisitorData *Data = (VisitorData *)ClientData;
  1050. if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
  1051. CXString USR = clang_getCursorUSR(C);
  1052. const char *cstr = clang_getCString(USR);
  1053. if (!cstr || cstr[0] == '\0') {
  1054. clang_disposeString(USR);
  1055. return CXChildVisit_Recurse;
  1056. }
  1057. printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
  1058. PrintCursorExtent(C);
  1059. printf("\n");
  1060. clang_disposeString(USR);
  1061. return CXChildVisit_Recurse;
  1062. }
  1063. return CXChildVisit_Continue;
  1064. }
  1065. /******************************************************************************/
  1066. /* Inclusion stack testing. */
  1067. /******************************************************************************/
  1068. void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
  1069. unsigned includeStackLen, CXClientData data) {
  1070. unsigned i;
  1071. CXString fname;
  1072. fname = clang_getFileName(includedFile);
  1073. printf("file: %s\nincluded by:\n", clang_getCString(fname));
  1074. clang_disposeString(fname);
  1075. for (i = 0; i < includeStackLen; ++i) {
  1076. CXFile includingFile;
  1077. unsigned line, column;
  1078. clang_getSpellingLocation(includeStack[i], &includingFile, &line,
  1079. &column, 0);
  1080. fname = clang_getFileName(includingFile);
  1081. printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
  1082. clang_disposeString(fname);
  1083. }
  1084. printf("\n");
  1085. }
  1086. void PrintInclusionStack(CXTranslationUnit TU) {
  1087. clang_getInclusions(TU, InclusionVisitor, NULL);
  1088. }
  1089. /******************************************************************************/
  1090. /* Linkage testing. */
  1091. /******************************************************************************/
  1092. static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
  1093. CXClientData d) {
  1094. const char *linkage = 0;
  1095. if (clang_isInvalid(clang_getCursorKind(cursor)))
  1096. return CXChildVisit_Recurse;
  1097. switch (clang_getCursorLinkage(cursor)) {
  1098. case CXLinkage_Invalid: break;
  1099. case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
  1100. case CXLinkage_Internal: linkage = "Internal"; break;
  1101. case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
  1102. case CXLinkage_External: linkage = "External"; break;
  1103. }
  1104. if (linkage) {
  1105. PrintCursor(cursor, NULL);
  1106. printf("linkage=%s\n", linkage);
  1107. }
  1108. return CXChildVisit_Recurse;
  1109. }
  1110. /******************************************************************************/
  1111. /* Visibility testing. */
  1112. /******************************************************************************/
  1113. static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p,
  1114. CXClientData d) {
  1115. const char *visibility = 0;
  1116. if (clang_isInvalid(clang_getCursorKind(cursor)))
  1117. return CXChildVisit_Recurse;
  1118. switch (clang_getCursorVisibility(cursor)) {
  1119. case CXVisibility_Invalid: break;
  1120. case CXVisibility_Hidden: visibility = "Hidden"; break;
  1121. case CXVisibility_Protected: visibility = "Protected"; break;
  1122. case CXVisibility_Default: visibility = "Default"; break;
  1123. }
  1124. if (visibility) {
  1125. PrintCursor(cursor, NULL);
  1126. printf("visibility=%s\n", visibility);
  1127. }
  1128. return CXChildVisit_Recurse;
  1129. }
  1130. /******************************************************************************/
  1131. /* Typekind testing. */
  1132. /******************************************************************************/
  1133. static void PrintTypeAndTypeKind(CXType T, const char *Format) {
  1134. CXString TypeSpelling, TypeKindSpelling;
  1135. TypeSpelling = clang_getTypeSpelling(T);
  1136. TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
  1137. printf(Format,
  1138. clang_getCString(TypeSpelling),
  1139. clang_getCString(TypeKindSpelling));
  1140. clang_disposeString(TypeSpelling);
  1141. clang_disposeString(TypeKindSpelling);
  1142. }
  1143. static enum CXVisitorResult FieldVisitor(CXCursor C,
  1144. CXClientData client_data) {
  1145. (*(int *) client_data)+=1;
  1146. return CXVisit_Continue;
  1147. }
  1148. static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
  1149. CXClientData d) {
  1150. if (!clang_isInvalid(clang_getCursorKind(cursor))) {
  1151. CXType T = clang_getCursorType(cursor);
  1152. enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
  1153. PrintCursor(cursor, NULL);
  1154. PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
  1155. if (clang_isConstQualifiedType(T))
  1156. printf(" const");
  1157. if (clang_isVolatileQualifiedType(T))
  1158. printf(" volatile");
  1159. if (clang_isRestrictQualifiedType(T))
  1160. printf(" restrict");
  1161. if (RQ == CXRefQualifier_LValue)
  1162. printf(" lvalue-ref-qualifier");
  1163. if (RQ == CXRefQualifier_RValue)
  1164. printf(" rvalue-ref-qualifier");
  1165. /* Print the canonical type if it is different. */
  1166. {
  1167. CXType CT = clang_getCanonicalType(T);
  1168. if (!clang_equalTypes(T, CT)) {
  1169. PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
  1170. }
  1171. }
  1172. /* Print the return type if it exists. */
  1173. {
  1174. CXType RT = clang_getCursorResultType(cursor);
  1175. if (RT.kind != CXType_Invalid) {
  1176. PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
  1177. }
  1178. }
  1179. /* Print the argument types if they exist. */
  1180. {
  1181. int NumArgs = clang_Cursor_getNumArguments(cursor);
  1182. if (NumArgs != -1 && NumArgs != 0) {
  1183. int i;
  1184. printf(" [args=");
  1185. for (i = 0; i < NumArgs; ++i) {
  1186. CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
  1187. if (T.kind != CXType_Invalid) {
  1188. PrintTypeAndTypeKind(T, " [%s] [%s]");
  1189. }
  1190. }
  1191. printf("]");
  1192. }
  1193. }
  1194. /* Print the template argument types if they exist. */
  1195. {
  1196. int NumTArgs = clang_Type_getNumTemplateArguments(T);
  1197. if (NumTArgs != -1 && NumTArgs != 0) {
  1198. int i;
  1199. printf(" [templateargs/%d=", NumTArgs);
  1200. for (i = 0; i < NumTArgs; ++i) {
  1201. CXType TArg = clang_Type_getTemplateArgumentAsType(T, i);
  1202. if (TArg.kind != CXType_Invalid) {
  1203. PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
  1204. }
  1205. }
  1206. printf("]");
  1207. }
  1208. }
  1209. /* Print if this is a non-POD type. */
  1210. printf(" [isPOD=%d]", clang_isPODType(T));
  1211. /* Print the pointee type. */
  1212. {
  1213. CXType PT = clang_getPointeeType(T);
  1214. if (PT.kind != CXType_Invalid) {
  1215. PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
  1216. }
  1217. }
  1218. /* Print the number of fields if they exist. */
  1219. {
  1220. int numFields = 0;
  1221. if (clang_Type_visitFields(T, FieldVisitor, &numFields)){
  1222. if (numFields != 0) {
  1223. printf(" [nbFields=%d]", numFields);
  1224. }
  1225. /* Print if it is an anonymous record. */
  1226. {
  1227. unsigned isAnon = clang_Cursor_isAnonymous(cursor);
  1228. if (isAnon != 0) {
  1229. printf(" [isAnon=%d]", isAnon);
  1230. }
  1231. }
  1232. }
  1233. }
  1234. printf("\n");
  1235. }
  1236. return CXChildVisit_Recurse;
  1237. }
  1238. static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
  1239. CXClientData d) {
  1240. CXType T;
  1241. enum CXCursorKind K = clang_getCursorKind(cursor);
  1242. if (clang_isInvalid(K))
  1243. return CXChildVisit_Recurse;
  1244. T = clang_getCursorType(cursor);
  1245. PrintCursor(cursor, NULL);
  1246. PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
  1247. /* Print the type sizeof if applicable. */
  1248. {
  1249. long long Size = clang_Type_getSizeOf(T);
  1250. if (Size >= 0 || Size < -1 ) {
  1251. printf(" [sizeof=%lld]", Size);
  1252. }
  1253. }
  1254. /* Print the type alignof if applicable. */
  1255. {
  1256. long long Align = clang_Type_getAlignOf(T);
  1257. if (Align >= 0 || Align < -1) {
  1258. printf(" [alignof=%lld]", Align);
  1259. }
  1260. }
  1261. /* Print the record field offset if applicable. */
  1262. {
  1263. CXString FieldSpelling = clang_getCursorSpelling(cursor);
  1264. const char *FieldName = clang_getCString(FieldSpelling);
  1265. /* recurse to get the first parent record that is not anonymous. */
  1266. CXCursor Parent, Record;
  1267. unsigned RecordIsAnonymous = 0;
  1268. if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
  1269. Record = Parent = p;
  1270. do {
  1271. Record = Parent;
  1272. Parent = clang_getCursorSemanticParent(Record);
  1273. RecordIsAnonymous = clang_Cursor_isAnonymous(Record);
  1274. /* Recurse as long as the parent is a CXType_Record and the Record
  1275. is anonymous */
  1276. } while ( clang_getCursorType(Parent).kind == CXType_Record &&
  1277. RecordIsAnonymous > 0);
  1278. {
  1279. long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record),
  1280. FieldName);
  1281. long long Offset2 = clang_Cursor_getOffsetOfField(cursor);
  1282. if (Offset == Offset2){
  1283. printf(" [offsetof=%lld]", Offset);
  1284. } else {
  1285. /* Offsets will be different in anonymous records. */
  1286. printf(" [offsetof=%lld/%lld]", Offset, Offset2);
  1287. }
  1288. }
  1289. }
  1290. clang_disposeString(FieldSpelling);
  1291. }
  1292. /* Print if its a bitfield */
  1293. {
  1294. int IsBitfield = clang_Cursor_isBitField(cursor);
  1295. if (IsBitfield)
  1296. printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
  1297. }
  1298. printf("\n");
  1299. return CXChildVisit_Recurse;
  1300. }
  1301. /******************************************************************************/
  1302. /* Mangling testing. */
  1303. /******************************************************************************/
  1304. static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p,
  1305. CXClientData d) {
  1306. CXString MangledName;
  1307. if (clang_isUnexposed(clang_getCursorKind(cursor)))
  1308. return CXChildVisit_Recurse;
  1309. PrintCursor(cursor, NULL);
  1310. MangledName = clang_Cursor_getMangling(cursor);
  1311. printf(" [mangled=%s]\n", clang_getCString(MangledName));
  1312. clang_disposeString(MangledName);
  1313. return CXChildVisit_Continue;
  1314. }
  1315. static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
  1316. CXClientData d) {
  1317. unsigned I, E;
  1318. CXStringSet *Manglings = NULL;
  1319. if (clang_isUnexposed(clang_getCursorKind(cursor)))
  1320. return CXChildVisit_Recurse;
  1321. if (!clang_isDeclaration(clang_getCursorKind(cursor)))
  1322. return CXChildVisit_Recurse;
  1323. if (clang_getCursorKind(cursor) == CXCursor_ParmDecl)
  1324. return CXChildVisit_Continue;
  1325. PrintCursor(cursor, NULL);
  1326. Manglings = clang_Cursor_getCXXManglings(cursor);
  1327. for (I = 0, E = Manglings->Count; I < E; ++I)
  1328. printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
  1329. clang_disposeStringSet(Manglings);
  1330. printf("\n");
  1331. return CXChildVisit_Recurse;
  1332. }
  1333. /******************************************************************************/
  1334. /* Bitwidth testing. */
  1335. /******************************************************************************/
  1336. static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
  1337. CXClientData d) {
  1338. int Bitwidth;
  1339. if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
  1340. return CXChildVisit_Recurse;
  1341. Bitwidth = clang_getFieldDeclBitWidth(cursor);
  1342. if (Bitwidth >= 0) {
  1343. PrintCursor(cursor, NULL);
  1344. printf(" bitwidth=%d\n", Bitwidth);
  1345. }
  1346. return CXChildVisit_Recurse;
  1347. }
  1348. /******************************************************************************/
  1349. /* Type declaration testing */
  1350. /******************************************************************************/
  1351. static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
  1352. CXClientData d) {
  1353. CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
  1354. if (clang_isDeclaration(typeDeclaration.kind)) {
  1355. PrintCursor(cursor, NULL);
  1356. PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
  1357. }
  1358. return CXChildVisit_Recurse;
  1359. }
  1360. /******************************************************************************/
  1361. /* Loading ASTs/source. */
  1362. /******************************************************************************/
  1363. static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
  1364. const char *filter, const char *prefix,
  1365. CXCursorVisitor Visitor,
  1366. PostVisitTU PV,
  1367. const char *CommentSchemaFile) {
  1368. if (prefix)
  1369. FileCheckPrefix = prefix;
  1370. if (Visitor) {
  1371. enum CXCursorKind K = CXCursor_NotImplemented;
  1372. enum CXCursorKind *ck = &K;
  1373. VisitorData Data;
  1374. /* Perform some simple filtering. */
  1375. if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
  1376. else if (!strcmp(filter, "all-display") ||
  1377. !strcmp(filter, "local-display")) {
  1378. ck = NULL;
  1379. want_display_name = 1;
  1380. }
  1381. else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
  1382. else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
  1383. else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
  1384. else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
  1385. else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
  1386. else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
  1387. else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
  1388. else {
  1389. fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
  1390. return 1;
  1391. }
  1392. Data.TU = TU;
  1393. Data.Filter = ck;
  1394. Data.CommentSchemaFile = CommentSchemaFile;
  1395. clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
  1396. }
  1397. if (PV)
  1398. PV(TU);
  1399. PrintDiagnostics(TU);
  1400. if (checkForErrors(TU) != 0) {
  1401. clang_disposeTranslationUnit(TU);
  1402. return -1;
  1403. }
  1404. clang_disposeTranslationUnit(TU);
  1405. return 0;
  1406. }
  1407. int perform_test_load_tu(const char *file, const char *filter,
  1408. const char *prefix, CXCursorVisitor Visitor,
  1409. PostVisitTU PV) {
  1410. CXIndex Idx;
  1411. CXTranslationUnit TU;
  1412. int result;
  1413. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  1414. !strcmp(filter, "local") ? 1 : 0,
  1415. /* displayDiagnostics=*/1);
  1416. if (!CreateTranslationUnit(Idx, file, &TU)) {
  1417. clang_disposeIndex(Idx);
  1418. return 1;
  1419. }
  1420. result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
  1421. clang_disposeIndex(Idx);
  1422. return result;
  1423. }
  1424. int perform_test_load_source(int argc, const char **argv,
  1425. const char *filter, CXCursorVisitor Visitor,
  1426. PostVisitTU PV) {
  1427. CXIndex Idx;
  1428. CXTranslationUnit TU;
  1429. const char *CommentSchemaFile;
  1430. struct CXUnsavedFile *unsaved_files = 0;
  1431. int num_unsaved_files = 0;
  1432. enum CXErrorCode Err;
  1433. int result;
  1434. unsigned Repeats = 0;
  1435. unsigned I;
  1436. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  1437. (!strcmp(filter, "local") ||
  1438. !strcmp(filter, "local-display"))? 1 : 0,
  1439. /* displayDiagnostics=*/1);
  1440. if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
  1441. argc--;
  1442. argv++;
  1443. }
  1444. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  1445. clang_disposeIndex(Idx);
  1446. return -1;
  1447. }
  1448. if (getenv("CINDEXTEST_EDITING"))
  1449. Repeats = 5;
  1450. Err = clang_parseTranslationUnit2(Idx, 0,
  1451. argv + num_unsaved_files,
  1452. argc - num_unsaved_files,
  1453. unsaved_files, num_unsaved_files,
  1454. getDefaultParsingOptions(), &TU);
  1455. if (Err != CXError_Success) {
  1456. fprintf(stderr, "Unable to load translation unit!\n");
  1457. describeLibclangFailure(Err);
  1458. free_remapped_files(unsaved_files, num_unsaved_files);
  1459. clang_disposeIndex(Idx);
  1460. return 1;
  1461. }
  1462. for (I = 0; I != Repeats; ++I) {
  1463. if (checkForErrors(TU) != 0)
  1464. return -1;
  1465. if (Repeats > 1) {
  1466. Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  1467. clang_defaultReparseOptions(TU));
  1468. if (Err != CXError_Success) {
  1469. describeLibclangFailure(Err);
  1470. free_remapped_files(unsaved_files, num_unsaved_files);
  1471. clang_disposeIndex(Idx);
  1472. return 1;
  1473. }
  1474. }
  1475. }
  1476. result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
  1477. CommentSchemaFile);
  1478. free_remapped_files(unsaved_files, num_unsaved_files);
  1479. clang_disposeIndex(Idx);
  1480. return result;
  1481. }
  1482. int perform_test_reparse_source(int argc, const char **argv, int trials,
  1483. const char *filter, CXCursorVisitor Visitor,
  1484. PostVisitTU PV) {
  1485. CXIndex Idx;
  1486. CXTranslationUnit TU;
  1487. struct CXUnsavedFile *unsaved_files = 0;
  1488. int num_unsaved_files = 0;
  1489. int compiler_arg_idx = 0;
  1490. enum CXErrorCode Err;
  1491. int result, i;
  1492. int trial;
  1493. int remap_after_trial = 0;
  1494. char *endptr = 0;
  1495. Idx = clang_createIndex(/* excludeDeclsFromPCH */
  1496. !strcmp(filter, "local") ? 1 : 0,
  1497. /* displayDiagnostics=*/1);
  1498. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  1499. clang_disposeIndex(Idx);
  1500. return -1;
  1501. }
  1502. for (i = 0; i < argc; ++i) {
  1503. if (strcmp(argv[i], "--") == 0)
  1504. break;
  1505. }
  1506. if (i < argc)
  1507. compiler_arg_idx = i+1;
  1508. if (num_unsaved_files > compiler_arg_idx)
  1509. compiler_arg_idx = num_unsaved_files;
  1510. /* Load the initial translation unit -- we do this without honoring remapped
  1511. * files, so that we have a way to test results after changing the source. */
  1512. Err = clang_parseTranslationUnit2(Idx, 0,
  1513. argv + compiler_arg_idx,
  1514. argc - compiler_arg_idx,
  1515. 0, 0, getDefaultParsingOptions(), &TU);
  1516. if (Err != CXError_Success) {
  1517. fprintf(stderr, "Unable to load translation unit!\n");
  1518. describeLibclangFailure(Err);
  1519. free_remapped_files(unsaved_files, num_unsaved_files);
  1520. clang_disposeIndex(Idx);
  1521. return 1;
  1522. }
  1523. if (checkForErrors(TU) != 0)
  1524. return -1;
  1525. if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
  1526. remap_after_trial =
  1527. strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
  1528. }
  1529. for (trial = 0; trial < trials; ++trial) {
  1530. free_remapped_files(unsaved_files, num_unsaved_files);
  1531. if (parse_remapped_files_with_try(trial, argc, argv, 0,
  1532. &unsaved_files, &num_unsaved_files)) {
  1533. clang_disposeTranslationUnit(TU);
  1534. clang_disposeIndex(Idx);
  1535. return -1;
  1536. }
  1537. Err = clang_reparseTranslationUnit(
  1538. TU,
  1539. trial >= remap_after_trial ? num_unsaved_files : 0,
  1540. trial >= remap_after_trial ? unsaved_files : 0,
  1541. clang_defaultReparseOptions(TU));
  1542. if (Err != CXError_Success) {
  1543. fprintf(stderr, "Unable to reparse translation unit!\n");
  1544. describeLibclangFailure(Err);
  1545. clang_disposeTranslationUnit(TU);
  1546. free_remapped_files(unsaved_files, num_unsaved_files);
  1547. clang_disposeIndex(Idx);
  1548. return -1;
  1549. }
  1550. if (checkForErrors(TU) != 0)
  1551. return -1;
  1552. }
  1553. result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
  1554. free_remapped_files(unsaved_files, num_unsaved_files);
  1555. clang_disposeIndex(Idx);
  1556. return result;
  1557. }
  1558. /******************************************************************************/
  1559. /* Logic for testing clang_getCursor(). */
  1560. /******************************************************************************/
  1561. static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
  1562. unsigned start_line, unsigned start_col,
  1563. unsigned end_line, unsigned end_col,
  1564. const char *prefix) {
  1565. printf("// %s: ", FileCheckPrefix);
  1566. if (prefix)
  1567. printf("-%s", prefix);
  1568. PrintExtent(stdout, start_line, start_col, end_line, end_col);
  1569. printf(" ");
  1570. PrintCursor(cursor, NULL);
  1571. printf("\n");
  1572. }
  1573. static int perform_file_scan(const char *ast_file, const char *source_file,
  1574. const char *prefix) {
  1575. CXIndex Idx;
  1576. CXTranslationUnit TU;
  1577. FILE *fp;
  1578. CXCursor prevCursor = clang_getNullCursor();
  1579. CXFile file;
  1580. unsigned line = 1, col = 1;
  1581. unsigned start_line = 1, start_col = 1;
  1582. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  1583. /* displayDiagnostics=*/1))) {
  1584. fprintf(stderr, "Could not create Index\n");
  1585. return 1;
  1586. }
  1587. if (!CreateTranslationUnit(Idx, ast_file, &TU))
  1588. return 1;
  1589. if ((fp = fopen(source_file, "r")) == NULL) {
  1590. fprintf(stderr, "Could not open '%s'\n", source_file);
  1591. clang_disposeTranslationUnit(TU);
  1592. return 1;
  1593. }
  1594. file = clang_getFile(TU, source_file);
  1595. for (;;) {
  1596. CXCursor cursor;
  1597. int c = fgetc(fp);
  1598. if (c == '\n') {
  1599. ++line;
  1600. col = 1;
  1601. } else
  1602. ++col;
  1603. /* Check the cursor at this position, and dump the previous one if we have
  1604. * found something new.
  1605. */
  1606. cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
  1607. if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
  1608. prevCursor.kind != CXCursor_InvalidFile) {
  1609. print_cursor_file_scan(TU, prevCursor, start_line, start_col,
  1610. line, col, prefix);
  1611. start_line = line;
  1612. start_col = col;
  1613. }
  1614. if (c == EOF)
  1615. break;
  1616. prevCursor = cursor;
  1617. }
  1618. fclose(fp);
  1619. clang_disposeTranslationUnit(TU);
  1620. clang_disposeIndex(Idx);
  1621. return 0;
  1622. }
  1623. /******************************************************************************/
  1624. /* Logic for testing clang code completion. */
  1625. /******************************************************************************/
  1626. /* Parse file:line:column from the input string. Returns 0 on success, non-zero
  1627. on failure. If successful, the pointer *filename will contain newly-allocated
  1628. memory (that will be owned by the caller) to store the file name. */
  1629. int parse_file_line_column(const char *input, char **filename, unsigned *line,
  1630. unsigned *column, unsigned *second_line,
  1631. unsigned *second_column) {
  1632. /* Find the second colon. */
  1633. const char *last_colon = strrchr(input, ':');
  1634. unsigned values[4], i;
  1635. unsigned num_values = (second_line && second_column)? 4 : 2;
  1636. char *endptr = 0;
  1637. if (!last_colon || last_colon == input) {
  1638. if (num_values == 4)
  1639. fprintf(stderr, "could not parse filename:line:column:line:column in "
  1640. "'%s'\n", input);
  1641. else
  1642. fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
  1643. return 1;
  1644. }
  1645. for (i = 0; i != num_values; ++i) {
  1646. const char *prev_colon;
  1647. /* Parse the next line or column. */
  1648. values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
  1649. if (*endptr != 0 && *endptr != ':') {
  1650. fprintf(stderr, "could not parse %s in '%s'\n",
  1651. (i % 2 ? "column" : "line"), input);
  1652. return 1;
  1653. }
  1654. if (i + 1 == num_values)
  1655. break;
  1656. /* Find the previous colon. */
  1657. prev_colon = last_colon - 1;
  1658. while (prev_colon != input && *prev_colon != ':')
  1659. --prev_colon;
  1660. if (prev_colon == input) {
  1661. fprintf(stderr, "could not parse %s in '%s'\n",
  1662. (i % 2 == 0? "column" : "line"), input);
  1663. return 1;
  1664. }
  1665. last_colon = prev_colon;
  1666. }
  1667. *line = values[0];
  1668. *column = values[1];
  1669. if (second_line && second_column) {
  1670. *second_line = values[2];
  1671. *second_column = values[3];
  1672. }
  1673. /* Copy the file name. */
  1674. *filename = (char*)malloc(last_colon - input + 1);
  1675. memcpy(*filename, input, last_colon - input);
  1676. (*filename)[last_colon - input] = 0;
  1677. return 0;
  1678. }
  1679. const char *
  1680. clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
  1681. switch (Kind) {
  1682. case CXCompletionChunk_Optional: return "Optional";
  1683. case CXCompletionChunk_TypedText: return "TypedText";
  1684. case CXCompletionChunk_Text: return "Text";
  1685. case CXCompletionChunk_Placeholder: return "Placeholder";
  1686. case CXCompletionChunk_Informative: return "Informative";
  1687. case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
  1688. case CXCompletionChunk_LeftParen: return "LeftParen";
  1689. case CXCompletionChunk_RightParen: return "RightParen";
  1690. case CXCompletionChunk_LeftBracket: return "LeftBracket";
  1691. case CXCompletionChunk_RightBracket: return "RightBracket";
  1692. case CXCompletionChunk_LeftBrace: return "LeftBrace";
  1693. case CXCompletionChunk_RightBrace: return "RightBrace";
  1694. case CXCompletionChunk_LeftAngle: return "LeftAngle";
  1695. case CXCompletionChunk_RightAngle: return "RightAngle";
  1696. case CXCompletionChunk_Comma: return "Comma";
  1697. case CXCompletionChunk_ResultType: return "ResultType";
  1698. case CXCompletionChunk_Colon: return "Colon";
  1699. case CXCompletionChunk_SemiColon: return "SemiColon";
  1700. case CXCompletionChunk_Equal: return "Equal";
  1701. case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
  1702. case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
  1703. }
  1704. return "Unknown";
  1705. }
  1706. static int checkForErrors(CXTranslationUnit TU) {
  1707. unsigned Num, i;
  1708. CXDiagnostic Diag;
  1709. CXString DiagStr;
  1710. if (!getenv("CINDEXTEST_FAILONERROR"))
  1711. return 0;
  1712. Num = clang_getNumDiagnostics(TU);
  1713. for (i = 0; i != Num; ++i) {
  1714. Diag = clang_getDiagnostic(TU, i);
  1715. if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
  1716. DiagStr = clang_formatDiagnostic(Diag,
  1717. clang_defaultDiagnosticDisplayOptions());
  1718. fprintf(stderr, "%s\n", clang_getCString(DiagStr));
  1719. clang_disposeString(DiagStr);
  1720. clang_disposeDiagnostic(Diag);
  1721. return -1;
  1722. }
  1723. clang_disposeDiagnostic(Diag);
  1724. }
  1725. return 0;
  1726. }
  1727. static void print_completion_string(CXCompletionString completion_string,
  1728. FILE *file) {
  1729. int I, N;
  1730. N = clang_getNumCompletionChunks(completion_string);
  1731. for (I = 0; I != N; ++I) {
  1732. CXString text;
  1733. const char *cstr;
  1734. enum CXCompletionChunkKind Kind
  1735. = clang_getCompletionChunkKind(completion_string, I);
  1736. if (Kind == CXCompletionChunk_Optional) {
  1737. fprintf(file, "{Optional ");
  1738. print_completion_string(
  1739. clang_getCompletionChunkCompletionString(completion_string, I),
  1740. file);
  1741. fprintf(file, "}");
  1742. continue;
  1743. }
  1744. if (Kind == CXCompletionChunk_VerticalSpace) {
  1745. fprintf(file, "{VerticalSpace }");
  1746. continue;
  1747. }
  1748. text = clang_getCompletionChunkText(completion_string, I);
  1749. cstr = clang_getCString(text);
  1750. fprintf(file, "{%s %s}",
  1751. clang_getCompletionChunkKindSpelling(Kind),
  1752. cstr ? cstr : "");
  1753. clang_disposeString(text);
  1754. }
  1755. }
  1756. static void print_completion_result(CXCompletionResult *completion_result,
  1757. FILE *file) {
  1758. CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
  1759. unsigned annotationCount;
  1760. enum CXCursorKind ParentKind;
  1761. CXString ParentName;
  1762. CXString BriefComment;
  1763. const char *BriefCommentCString;
  1764. fprintf(file, "%s:", clang_getCString(ks));
  1765. clang_disposeString(ks);
  1766. print_completion_string(completion_result->CompletionString, file);
  1767. fprintf(file, " (%u)",
  1768. clang_getCompletionPriority(completion_result->CompletionString));
  1769. switch (clang_getCompletionAvailability(completion_result->CompletionString)){
  1770. case CXAvailability_Available:
  1771. break;
  1772. case CXAvailability_Deprecated:
  1773. fprintf(file, " (deprecated)");
  1774. break;
  1775. case CXAvailability_NotAvailable:
  1776. fprintf(file, " (unavailable)");
  1777. break;
  1778. case CXAvailability_NotAccessible:
  1779. fprintf(file, " (inaccessible)");
  1780. break;
  1781. }
  1782. annotationCount = clang_getCompletionNumAnnotations(
  1783. completion_result->CompletionString);
  1784. if (annotationCount) {
  1785. unsigned i;
  1786. fprintf(file, " (");
  1787. for (i = 0; i < annotationCount; ++i) {
  1788. if (i != 0)
  1789. fprintf(file, ", ");
  1790. fprintf(file, "\"%s\"",
  1791. clang_getCString(clang_getCompletionAnnotation(
  1792. completion_result->CompletionString, i)));
  1793. }
  1794. fprintf(file, ")");
  1795. }
  1796. if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
  1797. ParentName = clang_getCompletionParent(completion_result->CompletionString,
  1798. &ParentKind);
  1799. if (ParentKind != CXCursor_NotImplemented) {
  1800. CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
  1801. fprintf(file, " (parent: %s '%s')",
  1802. clang_getCString(KindSpelling),
  1803. clang_getCString(ParentName));
  1804. clang_disposeString(KindSpelling);
  1805. }
  1806. clang_disposeString(ParentName);
  1807. }
  1808. BriefComment = clang_getCompletionBriefComment(
  1809. completion_result->CompletionString);
  1810. BriefCommentCString = clang_getCString(BriefComment);
  1811. if (BriefCommentCString && *BriefCommentCString != '\0') {
  1812. fprintf(file, "(brief comment: %s)", BriefCommentCString);
  1813. }
  1814. clang_disposeString(BriefComment);
  1815. fprintf(file, "\n");
  1816. }
  1817. void print_completion_contexts(unsigned long long contexts, FILE *file) {
  1818. fprintf(file, "Completion contexts:\n");
  1819. if (contexts == CXCompletionContext_Unknown) {
  1820. fprintf(file, "Unknown\n");
  1821. }
  1822. if (contexts & CXCompletionContext_AnyType) {
  1823. fprintf(file, "Any type\n");
  1824. }
  1825. if (contexts & CXCompletionContext_AnyValue) {
  1826. fprintf(file, "Any value\n");
  1827. }
  1828. if (contexts & CXCompletionContext_ObjCObjectValue) {
  1829. fprintf(file, "Objective-C object value\n");
  1830. }
  1831. if (contexts & CXCompletionContext_ObjCSelectorValue) {
  1832. fprintf(file, "Objective-C selector value\n");
  1833. }
  1834. if (contexts & CXCompletionContext_CXXClassTypeValue) {
  1835. fprintf(file, "C++ class type value\n");
  1836. }
  1837. if (contexts & CXCompletionContext_DotMemberAccess) {
  1838. fprintf(file, "Dot member access\n");
  1839. }
  1840. if (contexts & CXCompletionContext_ArrowMemberAccess) {
  1841. fprintf(file, "Arrow member access\n");
  1842. }
  1843. if (contexts & CXCompletionContext_ObjCPropertyAccess) {
  1844. fprintf(file, "Objective-C property access\n");
  1845. }
  1846. if (contexts & CXCompletionContext_EnumTag) {
  1847. fprintf(file, "Enum tag\n");
  1848. }
  1849. if (contexts & CXCompletionContext_UnionTag) {
  1850. fprintf(file, "Union tag\n");
  1851. }
  1852. if (contexts & CXCompletionContext_StructTag) {
  1853. fprintf(file, "Struct tag\n");
  1854. }
  1855. if (contexts & CXCompletionContext_ClassTag) {
  1856. fprintf(file, "Class name\n");
  1857. }
  1858. if (contexts & CXCompletionContext_Namespace) {
  1859. fprintf(file, "Namespace or namespace alias\n");
  1860. }
  1861. if (contexts & CXCompletionContext_NestedNameSpecifier) {
  1862. fprintf(file, "Nested name specifier\n");
  1863. }
  1864. if (contexts & CXCompletionContext_ObjCInterface) {
  1865. fprintf(file, "Objective-C interface\n");
  1866. }
  1867. if (contexts & CXCompletionContext_ObjCProtocol) {
  1868. fprintf(file, "Objective-C protocol\n");
  1869. }
  1870. if (contexts & CXCompletionContext_ObjCCategory) {
  1871. fprintf(file, "Objective-C category\n");
  1872. }
  1873. if (contexts & CXCompletionContext_ObjCInstanceMessage) {
  1874. fprintf(file, "Objective-C instance method\n");
  1875. }
  1876. if (contexts & CXCompletionContext_ObjCClassMessage) {
  1877. fprintf(file, "Objective-C class method\n");
  1878. }
  1879. if (contexts & CXCompletionContext_ObjCSelectorName) {
  1880. fprintf(file, "Objective-C selector name\n");
  1881. }
  1882. if (contexts & CXCompletionContext_MacroName) {
  1883. fprintf(file, "Macro name\n");
  1884. }
  1885. if (contexts & CXCompletionContext_NaturalLanguage) {
  1886. fprintf(file, "Natural language\n");
  1887. }
  1888. }
  1889. int my_stricmp(const char *s1, const char *s2) {
  1890. while (*s1 && *s2) {
  1891. int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
  1892. if (c1 < c2)
  1893. return -1;
  1894. else if (c1 > c2)
  1895. return 1;
  1896. ++s1;
  1897. ++s2;
  1898. }
  1899. if (*s1)
  1900. return 1;
  1901. else if (*s2)
  1902. return -1;
  1903. return 0;
  1904. }
  1905. int perform_code_completion(int argc, const char **argv, int timing_only) {
  1906. const char *input = argv[1];
  1907. char *filename = 0;
  1908. unsigned line;
  1909. unsigned column;
  1910. CXIndex CIdx;
  1911. int errorCode;
  1912. struct CXUnsavedFile *unsaved_files = 0;
  1913. int num_unsaved_files = 0;
  1914. CXCodeCompleteResults *results = 0;
  1915. enum CXErrorCode Err;
  1916. CXTranslationUnit TU;
  1917. unsigned I, Repeats = 1;
  1918. unsigned completionOptions = clang_defaultCodeCompleteOptions();
  1919. if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
  1920. completionOptions |= CXCodeComplete_IncludeCodePatterns;
  1921. if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
  1922. completionOptions |= CXCodeComplete_IncludeBriefComments;
  1923. if (timing_only)
  1924. input += strlen("-code-completion-timing=");
  1925. else
  1926. input += strlen("-code-completion-at=");
  1927. if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
  1928. 0, 0)))
  1929. return errorCode;
  1930. if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
  1931. return -1;
  1932. CIdx = clang_createIndex(0, 0);
  1933. if (getenv("CINDEXTEST_EDITING"))
  1934. Repeats = 5;
  1935. Err = clang_parseTranslationUnit2(CIdx, 0,
  1936. argv + num_unsaved_files + 2,
  1937. argc - num_unsaved_files - 2,
  1938. 0, 0, getDefaultParsingOptions(), &TU);
  1939. if (Err != CXError_Success) {
  1940. fprintf(stderr, "Unable to load translation unit!\n");
  1941. describeLibclangFailure(Err);
  1942. return 1;
  1943. }
  1944. Err = clang_reparseTranslationUnit(TU, 0, 0,
  1945. clang_defaultReparseOptions(TU));
  1946. if (Err != CXError_Success) {
  1947. fprintf(stderr, "Unable to reparse translation unit!\n");
  1948. describeLibclangFailure(Err);
  1949. clang_disposeTranslationUnit(TU);
  1950. return 1;
  1951. }
  1952. for (I = 0; I != Repeats; ++I) {
  1953. results = clang_codeCompleteAt(TU, filename, line, column,
  1954. unsaved_files, num_unsaved_files,
  1955. completionOptions);
  1956. if (!results) {
  1957. fprintf(stderr, "Unable to perform code completion!\n");
  1958. return 1;
  1959. }
  1960. if (I != Repeats-1)
  1961. clang_disposeCodeCompleteResults(results);
  1962. }
  1963. if (results) {
  1964. unsigned i, n = results->NumResults, containerIsIncomplete = 0;
  1965. unsigned long long contexts;
  1966. enum CXCursorKind containerKind;
  1967. CXString objCSelector;
  1968. const char *selectorString;
  1969. if (!timing_only) {
  1970. /* Sort the code-completion results based on the typed text. */
  1971. clang_sortCodeCompletionResults(results->Results, results->NumResults);
  1972. for (i = 0; i != n; ++i)
  1973. print_completion_result(results->Results + i, stdout);
  1974. }
  1975. n = clang_codeCompleteGetNumDiagnostics(results);
  1976. for (i = 0; i != n; ++i) {
  1977. CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
  1978. PrintDiagnostic(diag);
  1979. clang_disposeDiagnostic(diag);
  1980. }
  1981. contexts = clang_codeCompleteGetContexts(results);
  1982. print_completion_contexts(contexts, stdout);
  1983. containerKind = clang_codeCompleteGetContainerKind(results,
  1984. &containerIsIncomplete);
  1985. if (containerKind != CXCursor_InvalidCode) {
  1986. /* We have found a container */
  1987. CXString containerUSR, containerKindSpelling;
  1988. containerKindSpelling = clang_getCursorKindSpelling(containerKind);
  1989. printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
  1990. clang_disposeString(containerKindSpelling);
  1991. if (containerIsIncomplete) {
  1992. printf("Container is incomplete\n");
  1993. }
  1994. else {
  1995. printf("Container is complete\n");
  1996. }
  1997. containerUSR = clang_codeCompleteGetContainerUSR(results);
  1998. printf("Container USR: %s\n", clang_getCString(containerUSR));
  1999. clang_disposeString(containerUSR);
  2000. }
  2001. objCSelector = clang_codeCompleteGetObjCSelector(results);
  2002. selectorString = clang_getCString(objCSelector);
  2003. if (selectorString && strlen(selectorString) > 0) {
  2004. printf("Objective-C selector: %s\n", selectorString);
  2005. }
  2006. clang_disposeString(objCSelector);
  2007. clang_disposeCodeCompleteResults(results);
  2008. }
  2009. clang_disposeTranslationUnit(TU);
  2010. clang_disposeIndex(CIdx);
  2011. free(filename);
  2012. free_remapped_files(unsaved_files, num_unsaved_files);
  2013. return 0;
  2014. }
  2015. typedef struct {
  2016. char *filename;
  2017. unsigned line;
  2018. unsigned column;
  2019. } CursorSourceLocation;
  2020. typedef void (*cursor_handler_t)(CXCursor cursor);
  2021. static int inspect_cursor_at(int argc, const char **argv,
  2022. const char *locations_flag,
  2023. cursor_handler_t handler) {
  2024. CXIndex CIdx;
  2025. int errorCode;
  2026. struct CXUnsavedFile *unsaved_files = 0;
  2027. int num_unsaved_files = 0;
  2028. enum CXErrorCode Err;
  2029. CXTranslationUnit TU;
  2030. CXCursor Cursor;
  2031. CursorSourceLocation *Locations = 0;
  2032. unsigned NumLocations = 0, Loc;
  2033. unsigned Repeats = 1;
  2034. unsigned I;
  2035. /* Count the number of locations. */
  2036. while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
  2037. ++NumLocations;
  2038. /* Parse the locations. */
  2039. assert(NumLocations > 0 && "Unable to count locations?");
  2040. Locations = (CursorSourceLocation *)malloc(
  2041. NumLocations * sizeof(CursorSourceLocation));
  2042. for (Loc = 0; Loc < NumLocations; ++Loc) {
  2043. const char *input = argv[Loc + 1] + strlen(locations_flag);
  2044. if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
  2045. &Locations[Loc].line,
  2046. &Locations[Loc].column, 0, 0)))
  2047. return errorCode;
  2048. }
  2049. if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
  2050. &num_unsaved_files))
  2051. return -1;
  2052. if (getenv("CINDEXTEST_EDITING"))
  2053. Repeats = 5;
  2054. /* Parse the translation unit. When we're testing clang_getCursor() after
  2055. reparsing, don't remap unsaved files until the second parse. */
  2056. CIdx = clang_createIndex(1, 1);
  2057. Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
  2058. argv + num_unsaved_files + 1 + NumLocations,
  2059. argc - num_unsaved_files - 2 - NumLocations,
  2060. unsaved_files,
  2061. Repeats > 1? 0 : num_unsaved_files,
  2062. getDefaultParsingOptions(), &TU);
  2063. if (Err != CXError_Success) {
  2064. fprintf(stderr, "unable to parse input\n");
  2065. describeLibclangFailure(Err);
  2066. return -1;
  2067. }
  2068. if (checkForErrors(TU) != 0)
  2069. return -1;
  2070. for (I = 0; I != Repeats; ++I) {
  2071. if (Repeats > 1) {
  2072. Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  2073. clang_defaultReparseOptions(TU));
  2074. if (Err != CXError_Success) {
  2075. describeLibclangFailure(Err);
  2076. clang_disposeTranslationUnit(TU);
  2077. return 1;
  2078. }
  2079. }
  2080. if (checkForErrors(TU) != 0)
  2081. return -1;
  2082. for (Loc = 0; Loc < NumLocations; ++Loc) {
  2083. CXFile file = clang_getFile(TU, Locations[Loc].filename);
  2084. if (!file)
  2085. continue;
  2086. Cursor = clang_getCursor(TU,
  2087. clang_getLocation(TU, file, Locations[Loc].line,
  2088. Locations[Loc].column));
  2089. if (checkForErrors(TU) != 0)
  2090. return -1;
  2091. if (I + 1 == Repeats) {
  2092. handler(Cursor);
  2093. free(Locations[Loc].filename);
  2094. }
  2095. }
  2096. }
  2097. PrintDiagnostics(TU);
  2098. clang_disposeTranslationUnit(TU);
  2099. clang_disposeIndex(CIdx);
  2100. free(Locations);
  2101. free_remapped_files(unsaved_files, num_unsaved_files);
  2102. return 0;
  2103. }
  2104. static void inspect_print_cursor(CXCursor Cursor) {
  2105. CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
  2106. CXCompletionString completionString = clang_getCursorCompletionString(
  2107. Cursor);
  2108. CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
  2109. CXString Spelling;
  2110. const char *cspell;
  2111. unsigned line, column;
  2112. clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
  2113. printf("%d:%d ", line, column);
  2114. PrintCursor(Cursor, NULL);
  2115. PrintCursorExtent(Cursor);
  2116. Spelling = clang_getCursorSpelling(Cursor);
  2117. cspell = clang_getCString(Spelling);
  2118. if (cspell && strlen(cspell) != 0) {
  2119. unsigned pieceIndex;
  2120. printf(" Spelling=%s (", cspell);
  2121. for (pieceIndex = 0; ; ++pieceIndex) {
  2122. CXSourceRange range =
  2123. clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
  2124. if (clang_Range_isNull(range))
  2125. break;
  2126. PrintRange(range, 0);
  2127. }
  2128. printf(")");
  2129. }
  2130. clang_disposeString(Spelling);
  2131. if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
  2132. printf(" Selector index=%d",
  2133. clang_Cursor_getObjCSelectorIndex(Cursor));
  2134. if (clang_Cursor_isDynamicCall(Cursor))
  2135. printf(" Dynamic-call");
  2136. if (Cursor.kind == CXCursor_ObjCMessageExpr) {
  2137. CXType T = clang_Cursor_getReceiverType(Cursor);
  2138. CXString S = clang_getTypeKindSpelling(T.kind);
  2139. printf(" Receiver-type=%s", clang_getCString(S));
  2140. clang_disposeString(S);
  2141. }
  2142. {
  2143. CXModule mod = clang_Cursor_getModule(Cursor);
  2144. CXFile astFile;
  2145. CXString name, astFilename;
  2146. unsigned i, numHeaders;
  2147. if (mod) {
  2148. astFile = clang_Module_getASTFile(mod);
  2149. astFilename = clang_getFileName(astFile);
  2150. name = clang_Module_getFullName(mod);
  2151. numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
  2152. printf(" ModuleName=%s (%s) system=%d Headers(%d):",
  2153. clang_getCString(name), clang_getCString(astFilename),
  2154. clang_Module_isSystem(mod), numHeaders);
  2155. clang_disposeString(name);
  2156. clang_disposeString(astFilename);
  2157. for (i = 0; i < numHeaders; ++i) {
  2158. CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
  2159. CXString filename = clang_getFileName(file);
  2160. printf("\n%s", clang_getCString(filename));
  2161. clang_disposeString(filename);
  2162. }
  2163. }
  2164. }
  2165. if (completionString != NULL) {
  2166. printf("\nCompletion string: ");
  2167. print_completion_string(completionString, stdout);
  2168. }
  2169. printf("\n");
  2170. }
  2171. static void display_evaluate_results(CXEvalResult result) {
  2172. switch (clang_EvalResult_getKind(result)) {
  2173. case CXEval_Int:
  2174. {
  2175. int val = clang_EvalResult_getAsInt(result);
  2176. printf("Kind: Int , Value: %d", val);
  2177. break;
  2178. }
  2179. case CXEval_Float:
  2180. {
  2181. double val = clang_EvalResult_getAsDouble(result);
  2182. printf("Kind: Float , Value: %f", val);
  2183. break;
  2184. }
  2185. case CXEval_ObjCStrLiteral:
  2186. {
  2187. const char* str = clang_EvalResult_getAsStr(result);
  2188. printf("Kind: ObjCString , Value: %s", str);
  2189. break;
  2190. }
  2191. case CXEval_StrLiteral:
  2192. {
  2193. const char* str = clang_EvalResult_getAsStr(result);
  2194. printf("Kind: CString , Value: %s", str);
  2195. break;
  2196. }
  2197. case CXEval_CFStr:
  2198. {
  2199. const char* str = clang_EvalResult_getAsStr(result);
  2200. printf("Kind: CFString , Value: %s", str);
  2201. break;
  2202. }
  2203. default:
  2204. printf("Unexposed");
  2205. break;
  2206. }
  2207. }
  2208. static void inspect_evaluate_cursor(CXCursor Cursor) {
  2209. CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
  2210. CXString Spelling;
  2211. const char *cspell;
  2212. unsigned line, column;
  2213. CXEvalResult ER;
  2214. clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
  2215. printf("%d:%d ", line, column);
  2216. PrintCursor(Cursor, NULL);
  2217. PrintCursorExtent(Cursor);
  2218. Spelling = clang_getCursorSpelling(Cursor);
  2219. cspell = clang_getCString(Spelling);
  2220. if (cspell && strlen(cspell) != 0) {
  2221. unsigned pieceIndex;
  2222. printf(" Spelling=%s (", cspell);
  2223. for (pieceIndex = 0; ; ++pieceIndex) {
  2224. CXSourceRange range =
  2225. clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
  2226. if (clang_Range_isNull(range))
  2227. break;
  2228. PrintRange(range, 0);
  2229. }
  2230. printf(")");
  2231. }
  2232. clang_disposeString(Spelling);
  2233. ER = clang_Cursor_Evaluate(Cursor);
  2234. if (!ER) {
  2235. printf("Not Evaluatable");
  2236. } else {
  2237. display_evaluate_results(ER);
  2238. clang_EvalResult_dispose(ER);
  2239. }
  2240. printf("\n");
  2241. }
  2242. static void inspect_macroinfo_cursor(CXCursor Cursor) {
  2243. CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
  2244. CXString Spelling;
  2245. const char *cspell;
  2246. unsigned line, column;
  2247. clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
  2248. printf("%d:%d ", line, column);
  2249. PrintCursor(Cursor, NULL);
  2250. PrintCursorExtent(Cursor);
  2251. Spelling = clang_getCursorSpelling(Cursor);
  2252. cspell = clang_getCString(Spelling);
  2253. if (cspell && strlen(cspell) != 0) {
  2254. unsigned pieceIndex;
  2255. printf(" Spelling=%s (", cspell);
  2256. for (pieceIndex = 0; ; ++pieceIndex) {
  2257. CXSourceRange range =
  2258. clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
  2259. if (clang_Range_isNull(range))
  2260. break;
  2261. PrintRange(range, 0);
  2262. }
  2263. printf(")");
  2264. }
  2265. clang_disposeString(Spelling);
  2266. if (clang_Cursor_isMacroBuiltin(Cursor)) {
  2267. printf("[builtin macro]");
  2268. } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
  2269. printf("[function macro]");
  2270. }
  2271. printf("\n");
  2272. }
  2273. static enum CXVisitorResult findFileRefsVisit(void *context,
  2274. CXCursor cursor, CXSourceRange range) {
  2275. if (clang_Range_isNull(range))
  2276. return CXVisit_Continue;
  2277. PrintCursor(cursor, NULL);
  2278. PrintRange(range, "");
  2279. printf("\n");
  2280. return CXVisit_Continue;
  2281. }
  2282. static int find_file_refs_at(int argc, const char **argv) {
  2283. CXIndex CIdx;
  2284. int errorCode;
  2285. struct CXUnsavedFile *unsaved_files = 0;
  2286. int num_unsaved_files = 0;
  2287. enum CXErrorCode Err;
  2288. CXTranslationUnit TU;
  2289. CXCursor Cursor;
  2290. CursorSourceLocation *Locations = 0;
  2291. unsigned NumLocations = 0, Loc;
  2292. unsigned Repeats = 1;
  2293. unsigned I;
  2294. /* Count the number of locations. */
  2295. while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
  2296. ++NumLocations;
  2297. /* Parse the locations. */
  2298. assert(NumLocations > 0 && "Unable to count locations?");
  2299. Locations = (CursorSourceLocation *)malloc(
  2300. NumLocations * sizeof(CursorSourceLocation));
  2301. for (Loc = 0; Loc < NumLocations; ++Loc) {
  2302. const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
  2303. if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
  2304. &Locations[Loc].line,
  2305. &Locations[Loc].column, 0, 0)))
  2306. return errorCode;
  2307. }
  2308. if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
  2309. &num_unsaved_files))
  2310. return -1;
  2311. if (getenv("CINDEXTEST_EDITING"))
  2312. Repeats = 5;
  2313. /* Parse the translation unit. When we're testing clang_getCursor() after
  2314. reparsing, don't remap unsaved files until the second parse. */
  2315. CIdx = clang_createIndex(1, 1);
  2316. Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
  2317. argv + num_unsaved_files + 1 + NumLocations,
  2318. argc - num_unsaved_files - 2 - NumLocations,
  2319. unsaved_files,
  2320. Repeats > 1? 0 : num_unsaved_files,
  2321. getDefaultParsingOptions(), &TU);
  2322. if (Err != CXError_Success) {
  2323. fprintf(stderr, "unable to parse input\n");
  2324. describeLibclangFailure(Err);
  2325. clang_disposeTranslationUnit(TU);
  2326. return -1;
  2327. }
  2328. if (checkForErrors(TU) != 0)
  2329. return -1;
  2330. for (I = 0; I != Repeats; ++I) {
  2331. if (Repeats > 1) {
  2332. Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  2333. clang_defaultReparseOptions(TU));
  2334. if (Err != CXError_Success) {
  2335. describeLibclangFailure(Err);
  2336. clang_disposeTranslationUnit(TU);
  2337. return 1;
  2338. }
  2339. }
  2340. if (checkForErrors(TU) != 0)
  2341. return -1;
  2342. for (Loc = 0; Loc < NumLocations; ++Loc) {
  2343. CXFile file = clang_getFile(TU, Locations[Loc].filename);
  2344. if (!file)
  2345. continue;
  2346. Cursor = clang_getCursor(TU,
  2347. clang_getLocation(TU, file, Locations[Loc].line,
  2348. Locations[Loc].column));
  2349. if (checkForErrors(TU) != 0)
  2350. return -1;
  2351. if (I + 1 == Repeats) {
  2352. CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
  2353. PrintCursor(Cursor, NULL);
  2354. printf("\n");
  2355. clang_findReferencesInFile(Cursor, file, visitor);
  2356. free(Locations[Loc].filename);
  2357. if (checkForErrors(TU) != 0)
  2358. return -1;
  2359. }
  2360. }
  2361. }
  2362. PrintDiagnostics(TU);
  2363. clang_disposeTranslationUnit(TU);
  2364. clang_disposeIndex(CIdx);
  2365. free(Locations);
  2366. free_remapped_files(unsaved_files, num_unsaved_files);
  2367. return 0;
  2368. }
  2369. static enum CXVisitorResult findFileIncludesVisit(void *context,
  2370. CXCursor cursor, CXSourceRange range) {
  2371. PrintCursor(cursor, NULL);
  2372. PrintRange(range, "");
  2373. printf("\n");
  2374. return CXVisit_Continue;
  2375. }
  2376. static int find_file_includes_in(int argc, const char **argv) {
  2377. CXIndex CIdx;
  2378. struct CXUnsavedFile *unsaved_files = 0;
  2379. int num_unsaved_files = 0;
  2380. enum CXErrorCode Err;
  2381. CXTranslationUnit TU;
  2382. const char **Filenames = 0;
  2383. unsigned NumFilenames = 0;
  2384. unsigned Repeats = 1;
  2385. unsigned I, FI;
  2386. /* Count the number of locations. */
  2387. while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
  2388. ++NumFilenames;
  2389. /* Parse the locations. */
  2390. assert(NumFilenames > 0 && "Unable to count filenames?");
  2391. Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
  2392. for (I = 0; I < NumFilenames; ++I) {
  2393. const char *input = argv[I + 1] + strlen("-file-includes-in=");
  2394. /* Copy the file name. */
  2395. Filenames[I] = input;
  2396. }
  2397. if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
  2398. &num_unsaved_files))
  2399. return -1;
  2400. if (getenv("CINDEXTEST_EDITING"))
  2401. Repeats = 2;
  2402. /* Parse the translation unit. When we're testing clang_getCursor() after
  2403. reparsing, don't remap unsaved files until the second parse. */
  2404. CIdx = clang_createIndex(1, 1);
  2405. Err = clang_parseTranslationUnit2(
  2406. CIdx, argv[argc - 1],
  2407. argv + num_unsaved_files + 1 + NumFilenames,
  2408. argc - num_unsaved_files - 2 - NumFilenames,
  2409. unsaved_files,
  2410. Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU);
  2411. if (Err != CXError_Success) {
  2412. fprintf(stderr, "unable to parse input\n");
  2413. describeLibclangFailure(Err);
  2414. clang_disposeTranslationUnit(TU);
  2415. return -1;
  2416. }
  2417. if (checkForErrors(TU) != 0)
  2418. return -1;
  2419. for (I = 0; I != Repeats; ++I) {
  2420. if (Repeats > 1) {
  2421. Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  2422. clang_defaultReparseOptions(TU));
  2423. if (Err != CXError_Success) {
  2424. describeLibclangFailure(Err);
  2425. clang_disposeTranslationUnit(TU);
  2426. return 1;
  2427. }
  2428. }
  2429. if (checkForErrors(TU) != 0)
  2430. return -1;
  2431. for (FI = 0; FI < NumFilenames; ++FI) {
  2432. CXFile file = clang_getFile(TU, Filenames[FI]);
  2433. if (!file)
  2434. continue;
  2435. if (checkForErrors(TU) != 0)
  2436. return -1;
  2437. if (I + 1 == Repeats) {
  2438. CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
  2439. clang_findIncludesInFile(TU, file, visitor);
  2440. if (checkForErrors(TU) != 0)
  2441. return -1;
  2442. }
  2443. }
  2444. }
  2445. PrintDiagnostics(TU);
  2446. clang_disposeTranslationUnit(TU);
  2447. clang_disposeIndex(CIdx);
  2448. free((void *)Filenames);
  2449. free_remapped_files(unsaved_files, num_unsaved_files);
  2450. return 0;
  2451. }
  2452. #define MAX_IMPORTED_ASTFILES 200
  2453. typedef struct {
  2454. char **filenames;
  2455. unsigned num_files;
  2456. } ImportedASTFilesData;
  2457. static ImportedASTFilesData *importedASTs_create() {
  2458. ImportedASTFilesData *p;
  2459. p = malloc(sizeof(ImportedASTFilesData));
  2460. p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
  2461. p->num_files = 0;
  2462. return p;
  2463. }
  2464. static void importedASTs_dispose(ImportedASTFilesData *p) {
  2465. unsigned i;
  2466. if (!p)
  2467. return;
  2468. for (i = 0; i < p->num_files; ++i)
  2469. free(p->filenames[i]);
  2470. free(p->filenames);
  2471. free(p);
  2472. }
  2473. static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
  2474. unsigned i;
  2475. assert(p && file);
  2476. for (i = 0; i < p->num_files; ++i)
  2477. if (strcmp(file, p->filenames[i]) == 0)
  2478. return;
  2479. assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
  2480. p->filenames[p->num_files++] = strdup(file);
  2481. }
  2482. typedef struct IndexDataStringList_ {
  2483. struct IndexDataStringList_ *next;
  2484. char data[1]; /* Dynamically sized. */
  2485. } IndexDataStringList;
  2486. typedef struct {
  2487. const char *check_prefix;
  2488. int first_check_printed;
  2489. int fail_for_error;
  2490. int abort;
  2491. const char *main_filename;
  2492. ImportedASTFilesData *importedASTs;
  2493. IndexDataStringList *strings;
  2494. CXTranslationUnit TU;
  2495. } IndexData;
  2496. static void free_client_data(IndexData *index_data) {
  2497. IndexDataStringList *node = index_data->strings;
  2498. while (node) {
  2499. IndexDataStringList *next = node->next;
  2500. free(node);
  2501. node = next;
  2502. }
  2503. index_data->strings = NULL;
  2504. }
  2505. static void printCheck(IndexData *data) {
  2506. if (data->check_prefix) {
  2507. if (data->first_check_printed) {
  2508. printf("// %s-NEXT: ", data->check_prefix);
  2509. } else {
  2510. printf("// %s : ", data->check_prefix);
  2511. data->first_check_printed = 1;
  2512. }
  2513. }
  2514. }
  2515. static void printCXIndexFile(CXIdxClientFile file) {
  2516. CXString filename = clang_getFileName((CXFile)file);
  2517. printf("%s", clang_getCString(filename));
  2518. clang_disposeString(filename);
  2519. }
  2520. static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
  2521. IndexData *index_data;
  2522. CXString filename;
  2523. const char *cname;
  2524. CXIdxClientFile file;
  2525. unsigned line, column;
  2526. int isMainFile;
  2527. index_data = (IndexData *)client_data;
  2528. clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
  2529. if (line == 0) {
  2530. printf("<invalid>");
  2531. return;
  2532. }
  2533. if (!file) {
  2534. printf("<no idxfile>");
  2535. return;
  2536. }
  2537. filename = clang_getFileName((CXFile)file);
  2538. cname = clang_getCString(filename);
  2539. if (strcmp(cname, index_data->main_filename) == 0)
  2540. isMainFile = 1;
  2541. else
  2542. isMainFile = 0;
  2543. clang_disposeString(filename);
  2544. if (!isMainFile) {
  2545. printCXIndexFile(file);
  2546. printf(":");
  2547. }
  2548. printf("%d:%d", line, column);
  2549. }
  2550. static unsigned digitCount(unsigned val) {
  2551. unsigned c = 1;
  2552. while (1) {
  2553. if (val < 10)
  2554. return c;
  2555. ++c;
  2556. val /= 10;
  2557. }
  2558. }
  2559. static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
  2560. const CXIdxEntityInfo *info,
  2561. CXIdxLoc loc) {
  2562. IndexData *index_data;
  2563. IndexDataStringList *node;
  2564. const char *name;
  2565. char *newStr;
  2566. CXIdxClientFile file;
  2567. unsigned line, column;
  2568. name = info->name;
  2569. if (!name)
  2570. name = "<anon-tag>";
  2571. clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
  2572. node =
  2573. (IndexDataStringList *)malloc(sizeof(IndexDataStringList) + strlen(name) +
  2574. digitCount(line) + digitCount(column) + 2);
  2575. newStr = node->data;
  2576. sprintf(newStr, "%s:%d:%d", name, line, column);
  2577. /* Remember string so it can be freed later. */
  2578. index_data = (IndexData *)client_data;
  2579. node->next = index_data->strings;
  2580. index_data->strings = node;
  2581. return (CXIdxClientContainer)newStr;
  2582. }
  2583. static void printCXIndexContainer(const CXIdxContainerInfo *info) {
  2584. CXIdxClientContainer container;
  2585. container = clang_index_getClientContainer(info);
  2586. if (!container)
  2587. printf("[<<NULL>>]");
  2588. else
  2589. printf("[%s]", (const char *)container);
  2590. }
  2591. static const char *getEntityKindString(CXIdxEntityKind kind) {
  2592. switch (kind) {
  2593. case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
  2594. case CXIdxEntity_Typedef: return "typedef";
  2595. case CXIdxEntity_Function: return "function";
  2596. case CXIdxEntity_Variable: return "variable";
  2597. case CXIdxEntity_Field: return "field";
  2598. case CXIdxEntity_EnumConstant: return "enumerator";
  2599. case CXIdxEntity_ObjCClass: return "objc-class";
  2600. case CXIdxEntity_ObjCProtocol: return "objc-protocol";
  2601. case CXIdxEntity_ObjCCategory: return "objc-category";
  2602. case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
  2603. case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
  2604. case CXIdxEntity_ObjCProperty: return "objc-property";
  2605. case CXIdxEntity_ObjCIvar: return "objc-ivar";
  2606. case CXIdxEntity_Enum: return "enum";
  2607. case CXIdxEntity_Struct: return "struct";
  2608. case CXIdxEntity_Union: return "union";
  2609. case CXIdxEntity_CXXClass: return "c++-class";
  2610. case CXIdxEntity_CXXNamespace: return "namespace";
  2611. case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
  2612. case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
  2613. case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
  2614. case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
  2615. case CXIdxEntity_CXXConstructor: return "constructor";
  2616. case CXIdxEntity_CXXDestructor: return "destructor";
  2617. case CXIdxEntity_CXXConversionFunction: return "conversion-func";
  2618. case CXIdxEntity_CXXTypeAlias: return "type-alias";
  2619. case CXIdxEntity_CXXInterface: return "c++-__interface";
  2620. }
  2621. assert(0 && "Garbage entity kind");
  2622. return 0;
  2623. }
  2624. static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
  2625. switch (kind) {
  2626. case CXIdxEntity_NonTemplate: return "";
  2627. case CXIdxEntity_Template: return "-template";
  2628. case CXIdxEntity_TemplatePartialSpecialization:
  2629. return "-template-partial-spec";
  2630. case CXIdxEntity_TemplateSpecialization: return "-template-spec";
  2631. }
  2632. assert(0 && "Garbage entity kind");
  2633. return 0;
  2634. }
  2635. static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
  2636. switch (kind) {
  2637. case CXIdxEntityLang_None: return "<none>";
  2638. case CXIdxEntityLang_C: return "C";
  2639. case CXIdxEntityLang_ObjC: return "ObjC";
  2640. case CXIdxEntityLang_CXX: return "C++";
  2641. }
  2642. assert(0 && "Garbage language kind");
  2643. return 0;
  2644. }
  2645. static void printEntityInfo(const char *cb,
  2646. CXClientData client_data,
  2647. const CXIdxEntityInfo *info) {
  2648. const char *name;
  2649. IndexData *index_data;
  2650. unsigned i;
  2651. index_data = (IndexData *)client_data;
  2652. printCheck(index_data);
  2653. if (!info) {
  2654. printf("%s: <<NULL>>", cb);
  2655. return;
  2656. }
  2657. name = info->name;
  2658. if (!name)
  2659. name = "<anon-tag>";
  2660. printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
  2661. getEntityTemplateKindString(info->templateKind));
  2662. printf(" | name: %s", name);
  2663. printf(" | USR: %s", info->USR);
  2664. printf(" | lang: %s", getEntityLanguageString(info->lang));
  2665. for (i = 0; i != info->numAttributes; ++i) {
  2666. const CXIdxAttrInfo *Attr = info->attributes[i];
  2667. printf(" <attribute>: ");
  2668. PrintCursor(Attr->cursor, NULL);
  2669. }
  2670. }
  2671. static void printBaseClassInfo(CXClientData client_data,
  2672. const CXIdxBaseClassInfo *info) {
  2673. printEntityInfo(" <base>", client_data, info->base);
  2674. printf(" | cursor: ");
  2675. PrintCursor(info->cursor, NULL);
  2676. printf(" | loc: ");
  2677. printCXIndexLoc(info->loc, client_data);
  2678. }
  2679. static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
  2680. CXClientData client_data) {
  2681. unsigned i;
  2682. for (i = 0; i < ProtoInfo->numProtocols; ++i) {
  2683. printEntityInfo(" <protocol>", client_data,
  2684. ProtoInfo->protocols[i]->protocol);
  2685. printf(" | cursor: ");
  2686. PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
  2687. printf(" | loc: ");
  2688. printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
  2689. printf("\n");
  2690. }
  2691. }
  2692. static void index_diagnostic(CXClientData client_data,
  2693. CXDiagnosticSet diagSet, void *reserved) {
  2694. CXString str;
  2695. const char *cstr;
  2696. unsigned numDiags, i;
  2697. CXDiagnostic diag;
  2698. IndexData *index_data;
  2699. index_data = (IndexData *)client_data;
  2700. printCheck(index_data);
  2701. numDiags = clang_getNumDiagnosticsInSet(diagSet);
  2702. for (i = 0; i != numDiags; ++i) {
  2703. diag = clang_getDiagnosticInSet(diagSet, i);
  2704. str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
  2705. cstr = clang_getCString(str);
  2706. printf("[diagnostic]: %s\n", cstr);
  2707. clang_disposeString(str);
  2708. if (getenv("CINDEXTEST_FAILONERROR") &&
  2709. clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
  2710. index_data->fail_for_error = 1;
  2711. }
  2712. }
  2713. }
  2714. static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
  2715. CXFile file, void *reserved) {
  2716. IndexData *index_data;
  2717. CXString filename;
  2718. index_data = (IndexData *)client_data;
  2719. printCheck(index_data);
  2720. filename = clang_getFileName(file);
  2721. index_data->main_filename = clang_getCString(filename);
  2722. clang_disposeString(filename);
  2723. printf("[enteredMainFile]: ");
  2724. printCXIndexFile((CXIdxClientFile)file);
  2725. printf("\n");
  2726. return (CXIdxClientFile)file;
  2727. }
  2728. static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
  2729. const CXIdxIncludedFileInfo *info) {
  2730. IndexData *index_data;
  2731. CXModule Mod;
  2732. index_data = (IndexData *)client_data;
  2733. printCheck(index_data);
  2734. printf("[ppIncludedFile]: ");
  2735. printCXIndexFile((CXIdxClientFile)info->file);
  2736. printf(" | name: \"%s\"", info->filename);
  2737. printf(" | hash loc: ");
  2738. printCXIndexLoc(info->hashLoc, client_data);
  2739. printf(" | isImport: %d | isAngled: %d | isModule: %d",
  2740. info->isImport, info->isAngled, info->isModuleImport);
  2741. Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
  2742. if (Mod) {
  2743. CXString str = clang_Module_getFullName(Mod);
  2744. const char *cstr = clang_getCString(str);
  2745. printf(" | module: %s", cstr);
  2746. clang_disposeString(str);
  2747. }
  2748. printf("\n");
  2749. return (CXIdxClientFile)info->file;
  2750. }
  2751. static CXIdxClientFile index_importedASTFile(CXClientData client_data,
  2752. const CXIdxImportedASTFileInfo *info) {
  2753. IndexData *index_data;
  2754. index_data = (IndexData *)client_data;
  2755. printCheck(index_data);
  2756. if (index_data->importedASTs) {
  2757. CXString filename = clang_getFileName(info->file);
  2758. importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
  2759. clang_disposeString(filename);
  2760. }
  2761. printf("[importedASTFile]: ");
  2762. printCXIndexFile((CXIdxClientFile)info->file);
  2763. if (info->module) {
  2764. CXString name = clang_Module_getFullName(info->module);
  2765. printf(" | loc: ");
  2766. printCXIndexLoc(info->loc, client_data);
  2767. printf(" | name: \"%s\"", clang_getCString(name));
  2768. printf(" | isImplicit: %d\n", info->isImplicit);
  2769. clang_disposeString(name);
  2770. } else {
  2771. /* PCH file, the rest are not relevant. */
  2772. printf("\n");
  2773. }
  2774. return (CXIdxClientFile)info->file;
  2775. }
  2776. static CXIdxClientContainer
  2777. index_startedTranslationUnit(CXClientData client_data, void *reserved) {
  2778. IndexData *index_data;
  2779. index_data = (IndexData *)client_data;
  2780. printCheck(index_data);
  2781. printf("[startedTranslationUnit]\n");
  2782. return (CXIdxClientContainer)"TU";
  2783. }
  2784. static void index_indexDeclaration(CXClientData client_data,
  2785. const CXIdxDeclInfo *info) {
  2786. IndexData *index_data;
  2787. const CXIdxObjCCategoryDeclInfo *CatInfo;
  2788. const CXIdxObjCInterfaceDeclInfo *InterInfo;
  2789. const CXIdxObjCProtocolRefListInfo *ProtoInfo;
  2790. const CXIdxObjCPropertyDeclInfo *PropInfo;
  2791. const CXIdxCXXClassDeclInfo *CXXClassInfo;
  2792. unsigned i;
  2793. index_data = (IndexData *)client_data;
  2794. printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
  2795. printf(" | cursor: ");
  2796. PrintCursor(info->cursor, NULL);
  2797. printf(" | loc: ");
  2798. printCXIndexLoc(info->loc, client_data);
  2799. printf(" | semantic-container: ");
  2800. printCXIndexContainer(info->semanticContainer);
  2801. printf(" | lexical-container: ");
  2802. printCXIndexContainer(info->lexicalContainer);
  2803. printf(" | isRedecl: %d", info->isRedeclaration);
  2804. printf(" | isDef: %d", info->isDefinition);
  2805. if (info->flags & CXIdxDeclFlag_Skipped) {
  2806. assert(!info->isContainer);
  2807. printf(" | isContainer: skipped");
  2808. } else {
  2809. printf(" | isContainer: %d", info->isContainer);
  2810. }
  2811. printf(" | isImplicit: %d\n", info->isImplicit);
  2812. for (i = 0; i != info->numAttributes; ++i) {
  2813. const CXIdxAttrInfo *Attr = info->attributes[i];
  2814. printf(" <attribute>: ");
  2815. PrintCursor(Attr->cursor, NULL);
  2816. printf("\n");
  2817. }
  2818. if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
  2819. const char *kindName = 0;
  2820. CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
  2821. switch (K) {
  2822. case CXIdxObjCContainer_ForwardRef:
  2823. kindName = "forward-ref"; break;
  2824. case CXIdxObjCContainer_Interface:
  2825. kindName = "interface"; break;
  2826. case CXIdxObjCContainer_Implementation:
  2827. kindName = "implementation"; break;
  2828. }
  2829. printCheck(index_data);
  2830. printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
  2831. }
  2832. if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
  2833. printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
  2834. CatInfo->objcClass);
  2835. printf(" | cursor: ");
  2836. PrintCursor(CatInfo->classCursor, NULL);
  2837. printf(" | loc: ");
  2838. printCXIndexLoc(CatInfo->classLoc, client_data);
  2839. printf("\n");
  2840. }
  2841. if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
  2842. if (InterInfo->superInfo) {
  2843. printBaseClassInfo(client_data, InterInfo->superInfo);
  2844. printf("\n");
  2845. }
  2846. }
  2847. if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
  2848. printProtocolList(ProtoInfo, client_data);
  2849. }
  2850. if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
  2851. if (PropInfo->getter) {
  2852. printEntityInfo(" <getter>", client_data, PropInfo->getter);
  2853. printf("\n");
  2854. }
  2855. if (PropInfo->setter) {
  2856. printEntityInfo(" <setter>", client_data, PropInfo->setter);
  2857. printf("\n");
  2858. }
  2859. }
  2860. if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
  2861. for (i = 0; i != CXXClassInfo->numBases; ++i) {
  2862. printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
  2863. printf("\n");
  2864. }
  2865. }
  2866. if (info->declAsContainer)
  2867. clang_index_setClientContainer(
  2868. info->declAsContainer,
  2869. makeClientContainer(client_data, info->entityInfo, info->loc));
  2870. }
  2871. static void index_indexEntityReference(CXClientData client_data,
  2872. const CXIdxEntityRefInfo *info) {
  2873. printEntityInfo("[indexEntityReference]", client_data,
  2874. info->referencedEntity);
  2875. printf(" | cursor: ");
  2876. PrintCursor(info->cursor, NULL);
  2877. printf(" | loc: ");
  2878. printCXIndexLoc(info->loc, client_data);
  2879. printEntityInfo(" | <parent>:", client_data, info->parentEntity);
  2880. printf(" | container: ");
  2881. printCXIndexContainer(info->container);
  2882. printf(" | refkind: ");
  2883. switch (info->kind) {
  2884. case CXIdxEntityRef_Direct: printf("direct"); break;
  2885. case CXIdxEntityRef_Implicit: printf("implicit"); break;
  2886. }
  2887. printf("\n");
  2888. }
  2889. static int index_abortQuery(CXClientData client_data, void *reserved) {
  2890. IndexData *index_data;
  2891. index_data = (IndexData *)client_data;
  2892. return index_data->abort;
  2893. }
  2894. static IndexerCallbacks IndexCB = {
  2895. index_abortQuery,
  2896. index_diagnostic,
  2897. index_enteredMainFile,
  2898. index_ppIncludedFile,
  2899. index_importedASTFile,
  2900. index_startedTranslationUnit,
  2901. index_indexDeclaration,
  2902. index_indexEntityReference
  2903. };
  2904. static unsigned getIndexOptions(void) {
  2905. unsigned index_opts;
  2906. index_opts = 0;
  2907. if (getenv("CINDEXTEST_SUPPRESSREFS"))
  2908. index_opts |= CXIndexOpt_SuppressRedundantRefs;
  2909. if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
  2910. index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
  2911. if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
  2912. index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
  2913. return index_opts;
  2914. }
  2915. static int index_compile_args(int num_args, const char **args,
  2916. CXIndexAction idxAction,
  2917. ImportedASTFilesData *importedASTs,
  2918. const char *check_prefix) {
  2919. IndexData index_data;
  2920. unsigned index_opts;
  2921. int result;
  2922. if (num_args == 0) {
  2923. fprintf(stderr, "no compiler arguments\n");
  2924. return -1;
  2925. }
  2926. index_data.check_prefix = check_prefix;
  2927. index_data.first_check_printed = 0;
  2928. index_data.fail_for_error = 0;
  2929. index_data.abort = 0;
  2930. index_data.main_filename = "";
  2931. index_data.importedASTs = importedASTs;
  2932. index_data.strings = NULL;
  2933. index_data.TU = NULL;
  2934. index_opts = getIndexOptions();
  2935. result = clang_indexSourceFile(idxAction, &index_data,
  2936. &IndexCB,sizeof(IndexCB), index_opts,
  2937. 0, args, num_args, 0, 0, 0,
  2938. getDefaultParsingOptions());
  2939. if (result != CXError_Success)
  2940. describeLibclangFailure(result);
  2941. if (index_data.fail_for_error)
  2942. result = -1;
  2943. free_client_data(&index_data);
  2944. return result;
  2945. }
  2946. static int index_ast_file(const char *ast_file,
  2947. CXIndex Idx,
  2948. CXIndexAction idxAction,
  2949. ImportedASTFilesData *importedASTs,
  2950. const char *check_prefix) {
  2951. CXTranslationUnit TU;
  2952. IndexData index_data;
  2953. unsigned index_opts;
  2954. int result;
  2955. if (!CreateTranslationUnit(Idx, ast_file, &TU))
  2956. return -1;
  2957. index_data.check_prefix = check_prefix;
  2958. index_data.first_check_printed = 0;
  2959. index_data.fail_for_error = 0;
  2960. index_data.abort = 0;
  2961. index_data.main_filename = "";
  2962. index_data.importedASTs = importedASTs;
  2963. index_data.strings = NULL;
  2964. index_data.TU = TU;
  2965. index_opts = getIndexOptions();
  2966. result = clang_indexTranslationUnit(idxAction, &index_data,
  2967. &IndexCB,sizeof(IndexCB),
  2968. index_opts, TU);
  2969. if (index_data.fail_for_error)
  2970. result = -1;
  2971. clang_disposeTranslationUnit(TU);
  2972. free_client_data(&index_data);
  2973. return result;
  2974. }
  2975. static int index_file(int argc, const char **argv, int full) {
  2976. const char *check_prefix;
  2977. CXIndex Idx;
  2978. CXIndexAction idxAction;
  2979. ImportedASTFilesData *importedASTs;
  2980. int result;
  2981. check_prefix = 0;
  2982. if (argc > 0) {
  2983. if (strstr(argv[0], "-check-prefix=") == argv[0]) {
  2984. check_prefix = argv[0] + strlen("-check-prefix=");
  2985. ++argv;
  2986. --argc;
  2987. }
  2988. }
  2989. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  2990. /* displayDiagnostics=*/1))) {
  2991. fprintf(stderr, "Could not create Index\n");
  2992. return 1;
  2993. }
  2994. idxAction = clang_IndexAction_create(Idx);
  2995. importedASTs = 0;
  2996. if (full)
  2997. importedASTs = importedASTs_create();
  2998. result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
  2999. if (result != 0)
  3000. goto finished;
  3001. if (full) {
  3002. unsigned i;
  3003. for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
  3004. result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
  3005. importedASTs, check_prefix);
  3006. }
  3007. }
  3008. finished:
  3009. importedASTs_dispose(importedASTs);
  3010. clang_IndexAction_dispose(idxAction);
  3011. clang_disposeIndex(Idx);
  3012. return result;
  3013. }
  3014. static int index_tu(int argc, const char **argv) {
  3015. const char *check_prefix;
  3016. CXIndex Idx;
  3017. CXIndexAction idxAction;
  3018. int result;
  3019. check_prefix = 0;
  3020. if (argc > 0) {
  3021. if (strstr(argv[0], "-check-prefix=") == argv[0]) {
  3022. check_prefix = argv[0] + strlen("-check-prefix=");
  3023. ++argv;
  3024. --argc;
  3025. }
  3026. }
  3027. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  3028. /* displayDiagnostics=*/1))) {
  3029. fprintf(stderr, "Could not create Index\n");
  3030. return 1;
  3031. }
  3032. idxAction = clang_IndexAction_create(Idx);
  3033. result = index_ast_file(argv[0], Idx, idxAction,
  3034. /*importedASTs=*/0, check_prefix);
  3035. clang_IndexAction_dispose(idxAction);
  3036. clang_disposeIndex(Idx);
  3037. return result;
  3038. }
  3039. static int index_compile_db(int argc, const char **argv) {
  3040. const char *check_prefix;
  3041. CXIndex Idx;
  3042. CXIndexAction idxAction;
  3043. int errorCode = 0;
  3044. check_prefix = 0;
  3045. if (argc > 0) {
  3046. if (strstr(argv[0], "-check-prefix=") == argv[0]) {
  3047. check_prefix = argv[0] + strlen("-check-prefix=");
  3048. ++argv;
  3049. --argc;
  3050. }
  3051. }
  3052. if (argc == 0) {
  3053. fprintf(stderr, "no compilation database\n");
  3054. return -1;
  3055. }
  3056. if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
  3057. /* displayDiagnostics=*/1))) {
  3058. fprintf(stderr, "Could not create Index\n");
  3059. return 1;
  3060. }
  3061. idxAction = clang_IndexAction_create(Idx);
  3062. {
  3063. const char *database = argv[0];
  3064. CXCompilationDatabase db = 0;
  3065. CXCompileCommands CCmds = 0;
  3066. CXCompileCommand CCmd;
  3067. CXCompilationDatabase_Error ec;
  3068. CXString wd;
  3069. #define MAX_COMPILE_ARGS 512
  3070. CXString cxargs[MAX_COMPILE_ARGS];
  3071. const char *args[MAX_COMPILE_ARGS];
  3072. char *tmp;
  3073. unsigned len;
  3074. char *buildDir;
  3075. int i, a, numCmds, numArgs;
  3076. len = strlen(database);
  3077. tmp = (char *) malloc(len+1);
  3078. memcpy(tmp, database, len+1);
  3079. buildDir = dirname(tmp);
  3080. db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
  3081. if (db) {
  3082. if (ec!=CXCompilationDatabase_NoError) {
  3083. printf("unexpected error %d code while loading compilation database\n", ec);
  3084. errorCode = -1;
  3085. goto cdb_end;
  3086. }
  3087. if (chdir(buildDir) != 0) {
  3088. printf("Could not chdir to %s\n", buildDir);
  3089. errorCode = -1;
  3090. goto cdb_end;
  3091. }
  3092. CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
  3093. if (!CCmds) {
  3094. printf("compilation db is empty\n");
  3095. errorCode = -1;
  3096. goto cdb_end;
  3097. }
  3098. numCmds = clang_CompileCommands_getSize(CCmds);
  3099. if (numCmds==0) {
  3100. fprintf(stderr, "should not get an empty compileCommand set\n");
  3101. errorCode = -1;
  3102. goto cdb_end;
  3103. }
  3104. for (i=0; i<numCmds && errorCode == 0; ++i) {
  3105. CCmd = clang_CompileCommands_getCommand(CCmds, i);
  3106. wd = clang_CompileCommand_getDirectory(CCmd);
  3107. if (chdir(clang_getCString(wd)) != 0) {
  3108. printf("Could not chdir to %s\n", clang_getCString(wd));
  3109. errorCode = -1;
  3110. goto cdb_end;
  3111. }
  3112. clang_disposeString(wd);
  3113. numArgs = clang_CompileCommand_getNumArgs(CCmd);
  3114. if (numArgs > MAX_COMPILE_ARGS){
  3115. fprintf(stderr, "got more compile arguments than maximum\n");
  3116. errorCode = -1;
  3117. goto cdb_end;
  3118. }
  3119. for (a=0; a<numArgs; ++a) {
  3120. cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
  3121. args[a] = clang_getCString(cxargs[a]);
  3122. }
  3123. errorCode = index_compile_args(numArgs, args, idxAction,
  3124. /*importedASTs=*/0, check_prefix);
  3125. for (a=0; a<numArgs; ++a)
  3126. clang_disposeString(cxargs[a]);
  3127. }
  3128. } else {
  3129. printf("database loading failed with error code %d.\n", ec);
  3130. errorCode = -1;
  3131. }
  3132. cdb_end:
  3133. clang_CompileCommands_dispose(CCmds);
  3134. clang_CompilationDatabase_dispose(db);
  3135. free(tmp);
  3136. }
  3137. clang_IndexAction_dispose(idxAction);
  3138. clang_disposeIndex(Idx);
  3139. return errorCode;
  3140. }
  3141. int perform_token_annotation(int argc, const char **argv) {
  3142. const char *input = argv[1];
  3143. char *filename = 0;
  3144. unsigned line, second_line;
  3145. unsigned column, second_column;
  3146. CXIndex CIdx;
  3147. CXTranslationUnit TU = 0;
  3148. int errorCode;
  3149. struct CXUnsavedFile *unsaved_files = 0;
  3150. int num_unsaved_files = 0;
  3151. CXToken *tokens;
  3152. unsigned num_tokens;
  3153. CXSourceRange range;
  3154. CXSourceLocation startLoc, endLoc;
  3155. CXFile file = 0;
  3156. CXCursor *cursors = 0;
  3157. CXSourceRangeList *skipped_ranges = 0;
  3158. enum CXErrorCode Err;
  3159. unsigned i;
  3160. input += strlen("-test-annotate-tokens=");
  3161. if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
  3162. &second_line, &second_column)))
  3163. return errorCode;
  3164. if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
  3165. free(filename);
  3166. return -1;
  3167. }
  3168. CIdx = clang_createIndex(0, 1);
  3169. Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
  3170. argv + num_unsaved_files + 2,
  3171. argc - num_unsaved_files - 3,
  3172. unsaved_files,
  3173. num_unsaved_files,
  3174. getDefaultParsingOptions(), &TU);
  3175. if (Err != CXError_Success) {
  3176. fprintf(stderr, "unable to parse input\n");
  3177. describeLibclangFailure(Err);
  3178. clang_disposeIndex(CIdx);
  3179. free(filename);
  3180. free_remapped_files(unsaved_files, num_unsaved_files);
  3181. return -1;
  3182. }
  3183. errorCode = 0;
  3184. if (checkForErrors(TU) != 0) {
  3185. errorCode = -1;
  3186. goto teardown;
  3187. }
  3188. if (getenv("CINDEXTEST_EDITING")) {
  3189. for (i = 0; i < 5; ++i) {
  3190. Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
  3191. clang_defaultReparseOptions(TU));
  3192. if (Err != CXError_Success) {
  3193. fprintf(stderr, "Unable to reparse translation unit!\n");
  3194. describeLibclangFailure(Err);
  3195. errorCode = -1;
  3196. goto teardown;
  3197. }
  3198. }
  3199. }
  3200. if (checkForErrors(TU) != 0) {
  3201. errorCode = -1;
  3202. goto teardown;
  3203. }
  3204. file = clang_getFile(TU, filename);
  3205. if (!file) {
  3206. fprintf(stderr, "file %s is not in this translation unit\n", filename);
  3207. errorCode = -1;
  3208. goto teardown;
  3209. }
  3210. startLoc = clang_getLocation(TU, file, line, column);
  3211. if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
  3212. fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
  3213. column);
  3214. errorCode = -1;
  3215. goto teardown;
  3216. }
  3217. endLoc = clang_getLocation(TU, file, second_line, second_column);
  3218. if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
  3219. fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
  3220. second_line, second_column);
  3221. errorCode = -1;
  3222. goto teardown;
  3223. }
  3224. range = clang_getRange(startLoc, endLoc);
  3225. clang_tokenize(TU, range, &tokens, &num_tokens);
  3226. if (checkForErrors(TU) != 0) {
  3227. errorCode = -1;
  3228. goto teardown;
  3229. }
  3230. cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
  3231. clang_annotateTokens(TU, tokens, num_tokens, cursors);
  3232. if (checkForErrors(TU) != 0) {
  3233. errorCode = -1;
  3234. goto teardown;
  3235. }
  3236. skipped_ranges = clang_getSkippedRanges(TU, file);
  3237. for (i = 0; i != skipped_ranges->count; ++i) {
  3238. unsigned start_line, start_column, end_line, end_column;
  3239. clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
  3240. 0, &start_line, &start_column, 0);
  3241. clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
  3242. 0, &end_line, &end_column, 0);
  3243. printf("Skipping: ");
  3244. PrintExtent(stdout, start_line, start_column, end_line, end_column);
  3245. printf("\n");
  3246. }
  3247. clang_disposeSourceRangeList(skipped_ranges);
  3248. for (i = 0; i != num_tokens; ++i) {
  3249. const char *kind = "<unknown>";
  3250. CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
  3251. CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
  3252. unsigned start_line, start_column, end_line, end_column;
  3253. switch (clang_getTokenKind(tokens[i])) {
  3254. case CXToken_Punctuation: kind = "Punctuation"; break;
  3255. case CXToken_Keyword: kind = "Keyword"; break;
  3256. case CXToken_Identifier: kind = "Identifier"; break;
  3257. case CXToken_Literal: kind = "Literal"; break;
  3258. case CXToken_Comment: kind = "Comment"; break;
  3259. }
  3260. clang_getSpellingLocation(clang_getRangeStart(extent),
  3261. 0, &start_line, &start_column, 0);
  3262. clang_getSpellingLocation(clang_getRangeEnd(extent),
  3263. 0, &end_line, &end_column, 0);
  3264. printf("%s: \"%s\" ", kind, clang_getCString(spelling));
  3265. clang_disposeString(spelling);
  3266. PrintExtent(stdout, start_line, start_column, end_line, end_column);
  3267. if (!clang_isInvalid(cursors[i].kind)) {
  3268. printf(" ");
  3269. PrintCursor(cursors[i], NULL);
  3270. }
  3271. printf("\n");
  3272. }
  3273. free(cursors);
  3274. clang_disposeTokens(TU, tokens, num_tokens);
  3275. teardown:
  3276. PrintDiagnostics(TU);
  3277. clang_disposeTranslationUnit(TU);
  3278. clang_disposeIndex(CIdx);
  3279. free(filename);
  3280. free_remapped_files(unsaved_files, num_unsaved_files);
  3281. return errorCode;
  3282. }
  3283. static int
  3284. perform_test_compilation_db(const char *database, int argc, const char **argv) {
  3285. CXCompilationDatabase db;
  3286. CXCompileCommands CCmds;
  3287. CXCompileCommand CCmd;
  3288. CXCompilationDatabase_Error ec;
  3289. CXString wd;
  3290. CXString arg;
  3291. int errorCode = 0;
  3292. char *tmp;
  3293. unsigned len;
  3294. char *buildDir;
  3295. int i, j, a, numCmds, numArgs;
  3296. len = strlen(database);
  3297. tmp = (char *) malloc(len+1);
  3298. memcpy(tmp, database, len+1);
  3299. buildDir = dirname(tmp);
  3300. db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
  3301. if (db) {
  3302. if (ec!=CXCompilationDatabase_NoError) {
  3303. printf("unexpected error %d code while loading compilation database\n", ec);
  3304. errorCode = -1;
  3305. goto cdb_end;
  3306. }
  3307. for (i=0; i<argc && errorCode==0; ) {
  3308. if (strcmp(argv[i],"lookup")==0){
  3309. CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
  3310. if (!CCmds) {
  3311. printf("file %s not found in compilation db\n", argv[i+1]);
  3312. errorCode = -1;
  3313. break;
  3314. }
  3315. numCmds = clang_CompileCommands_getSize(CCmds);
  3316. if (numCmds==0) {
  3317. fprintf(stderr, "should not get an empty compileCommand set for file"
  3318. " '%s'\n", argv[i+1]);
  3319. errorCode = -1;
  3320. break;
  3321. }
  3322. for (j=0; j<numCmds; ++j) {
  3323. CCmd = clang_CompileCommands_getCommand(CCmds, j);
  3324. wd = clang_CompileCommand_getDirectory(CCmd);
  3325. printf("workdir:'%s'", clang_getCString(wd));
  3326. clang_disposeString(wd);
  3327. printf(" cmdline:'");
  3328. numArgs = clang_CompileCommand_getNumArgs(CCmd);
  3329. for (a=0; a<numArgs; ++a) {
  3330. if (a) printf(" ");
  3331. arg = clang_CompileCommand_getArg(CCmd, a);
  3332. printf("%s", clang_getCString(arg));
  3333. clang_disposeString(arg);
  3334. }
  3335. printf("'\n");
  3336. }
  3337. clang_CompileCommands_dispose(CCmds);
  3338. i += 2;
  3339. }
  3340. }
  3341. clang_CompilationDatabase_dispose(db);
  3342. } else {
  3343. printf("database loading failed with error code %d.\n", ec);
  3344. errorCode = -1;
  3345. }
  3346. cdb_end:
  3347. free(tmp);
  3348. return errorCode;
  3349. }
  3350. /******************************************************************************/
  3351. /* USR printing. */
  3352. /******************************************************************************/
  3353. static int insufficient_usr(const char *kind, const char *usage) {
  3354. fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
  3355. return 1;
  3356. }
  3357. static unsigned isUSR(const char *s) {
  3358. return s[0] == 'c' && s[1] == ':';
  3359. }
  3360. static int not_usr(const char *s, const char *arg) {
  3361. fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
  3362. return 1;
  3363. }
  3364. static void print_usr(CXString usr) {
  3365. const char *s = clang_getCString(usr);
  3366. printf("%s\n", s);
  3367. clang_disposeString(usr);
  3368. }
  3369. static void display_usrs() {
  3370. fprintf(stderr, "-print-usrs options:\n"
  3371. " ObjCCategory <class name> <category name>\n"
  3372. " ObjCClass <class name>\n"
  3373. " ObjCIvar <ivar name> <class USR>\n"
  3374. " ObjCMethod <selector> [0=class method|1=instance method] "
  3375. "<class USR>\n"
  3376. " ObjCProperty <property name> <class USR>\n"
  3377. " ObjCProtocol <protocol name>\n");
  3378. }
  3379. int print_usrs(const char **I, const char **E) {
  3380. while (I != E) {
  3381. const char *kind = *I;
  3382. unsigned len = strlen(kind);
  3383. switch (len) {
  3384. case 8:
  3385. if (memcmp(kind, "ObjCIvar", 8) == 0) {
  3386. if (I + 2 >= E)
  3387. return insufficient_usr(kind, "<ivar name> <class USR>");
  3388. if (!isUSR(I[2]))
  3389. return not_usr("<class USR>", I[2]);
  3390. else {
  3391. CXString x;
  3392. x.data = (void*) I[2];
  3393. x.private_flags = 0;
  3394. print_usr(clang_constructUSR_ObjCIvar(I[1], x));
  3395. }
  3396. I += 3;
  3397. continue;
  3398. }
  3399. break;
  3400. case 9:
  3401. if (memcmp(kind, "ObjCClass", 9) == 0) {
  3402. if (I + 1 >= E)
  3403. return insufficient_usr(kind, "<class name>");
  3404. print_usr(clang_constructUSR_ObjCClass(I[1]));
  3405. I += 2;
  3406. continue;
  3407. }
  3408. break;
  3409. case 10:
  3410. if (memcmp(kind, "ObjCMethod", 10) == 0) {
  3411. if (I + 3 >= E)
  3412. return insufficient_usr(kind, "<method selector> "
  3413. "[0=class method|1=instance method] <class USR>");
  3414. if (!isUSR(I[3]))
  3415. return not_usr("<class USR>", I[3]);
  3416. else {
  3417. CXString x;
  3418. x.data = (void*) I[3];
  3419. x.private_flags = 0;
  3420. print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
  3421. }
  3422. I += 4;
  3423. continue;
  3424. }
  3425. break;
  3426. case 12:
  3427. if (memcmp(kind, "ObjCCategory", 12) == 0) {
  3428. if (I + 2 >= E)
  3429. return insufficient_usr(kind, "<class name> <category name>");
  3430. print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
  3431. I += 3;
  3432. continue;
  3433. }
  3434. if (memcmp(kind, "ObjCProtocol", 12) == 0) {
  3435. if (I + 1 >= E)
  3436. return insufficient_usr(kind, "<protocol name>");
  3437. print_usr(clang_constructUSR_ObjCProtocol(I[1]));
  3438. I += 2;
  3439. continue;
  3440. }
  3441. if (memcmp(kind, "ObjCProperty", 12) == 0) {
  3442. if (I + 2 >= E)
  3443. return insufficient_usr(kind, "<property name> <class USR>");
  3444. if (!isUSR(I[2]))
  3445. return not_usr("<class USR>", I[2]);
  3446. else {
  3447. CXString x;
  3448. x.data = (void*) I[2];
  3449. x.private_flags = 0;
  3450. print_usr(clang_constructUSR_ObjCProperty(I[1], x));
  3451. }
  3452. I += 3;
  3453. continue;
  3454. }
  3455. break;
  3456. default:
  3457. break;
  3458. }
  3459. break;
  3460. }
  3461. if (I != E) {
  3462. fprintf(stderr, "Invalid USR kind: %s\n", *I);
  3463. display_usrs();
  3464. return 1;
  3465. }
  3466. return 0;
  3467. }
  3468. int print_usrs_file(const char *file_name) {
  3469. char line[2048];
  3470. const char *args[128];
  3471. unsigned numChars = 0;
  3472. FILE *fp = fopen(file_name, "r");
  3473. if (!fp) {
  3474. fprintf(stderr, "error: cannot open '%s'\n", file_name);
  3475. return 1;
  3476. }
  3477. /* This code is not really all that safe, but it works fine for testing. */
  3478. while (!feof(fp)) {
  3479. char c = fgetc(fp);
  3480. if (c == '\n') {
  3481. unsigned i = 0;
  3482. const char *s = 0;
  3483. if (numChars == 0)
  3484. continue;
  3485. line[numChars] = '\0';
  3486. numChars = 0;
  3487. if (line[0] == '/' && line[1] == '/')
  3488. continue;
  3489. s = strtok(line, " ");
  3490. while (s) {
  3491. args[i] = s;
  3492. ++i;
  3493. s = strtok(0, " ");
  3494. }
  3495. if (print_usrs(&args[0], &args[i]))
  3496. return 1;
  3497. }
  3498. else
  3499. line[numChars++] = c;
  3500. }
  3501. fclose(fp);
  3502. return 0;
  3503. }
  3504. /******************************************************************************/
  3505. /* Command line processing. */
  3506. /******************************************************************************/
  3507. int write_pch_file(const char *filename, int argc, const char *argv[]) {
  3508. CXIndex Idx;
  3509. CXTranslationUnit TU;
  3510. struct CXUnsavedFile *unsaved_files = 0;
  3511. int num_unsaved_files = 0;
  3512. enum CXErrorCode Err;
  3513. int result = 0;
  3514. Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
  3515. if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
  3516. clang_disposeIndex(Idx);
  3517. return -1;
  3518. }
  3519. Err = clang_parseTranslationUnit2(
  3520. Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files,
  3521. unsaved_files, num_unsaved_files,
  3522. CXTranslationUnit_Incomplete |
  3523. CXTranslationUnit_DetailedPreprocessingRecord |
  3524. CXTranslationUnit_ForSerialization,
  3525. &TU);
  3526. if (Err != CXError_Success) {
  3527. fprintf(stderr, "Unable to load translation unit!\n");
  3528. describeLibclangFailure(Err);
  3529. free_remapped_files(unsaved_files, num_unsaved_files);
  3530. clang_disposeTranslationUnit(TU);
  3531. clang_disposeIndex(Idx);
  3532. return 1;
  3533. }
  3534. switch (clang_saveTranslationUnit(TU, filename,
  3535. clang_defaultSaveOptions(TU))) {
  3536. case CXSaveError_None:
  3537. break;
  3538. case CXSaveError_TranslationErrors:
  3539. fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
  3540. filename);
  3541. result = 2;
  3542. break;
  3543. case CXSaveError_InvalidTU:
  3544. fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
  3545. filename);
  3546. result = 3;
  3547. break;
  3548. case CXSaveError_Unknown:
  3549. default:
  3550. fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
  3551. result = 1;
  3552. break;
  3553. }
  3554. clang_disposeTranslationUnit(TU);
  3555. free_remapped_files(unsaved_files, num_unsaved_files);
  3556. clang_disposeIndex(Idx);
  3557. return result;
  3558. }
  3559. /******************************************************************************/
  3560. /* Serialized diagnostics. */
  3561. /******************************************************************************/
  3562. static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
  3563. switch (error) {
  3564. case CXLoadDiag_CannotLoad: return "Cannot Load File";
  3565. case CXLoadDiag_None: break;
  3566. case CXLoadDiag_Unknown: return "Unknown";
  3567. case CXLoadDiag_InvalidFile: return "Invalid File";
  3568. }
  3569. return "None";
  3570. }
  3571. static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
  3572. switch (severity) {
  3573. case CXDiagnostic_Note: return "note";
  3574. case CXDiagnostic_Error: return "error";
  3575. case CXDiagnostic_Fatal: return "fatal";
  3576. case CXDiagnostic_Ignored: return "ignored";
  3577. case CXDiagnostic_Warning: return "warning";
  3578. }
  3579. return "unknown";
  3580. }
  3581. static void printIndent(unsigned indent) {
  3582. if (indent == 0)
  3583. return;
  3584. fprintf(stderr, "+");
  3585. --indent;
  3586. while (indent > 0) {
  3587. fprintf(stderr, "-");
  3588. --indent;
  3589. }
  3590. }
  3591. static void printLocation(CXSourceLocation L) {
  3592. CXFile File;
  3593. CXString FileName;
  3594. unsigned line, column, offset;
  3595. clang_getExpansionLocation(L, &File, &line, &column, &offset);
  3596. FileName = clang_getFileName(File);
  3597. fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
  3598. clang_disposeString(FileName);
  3599. }
  3600. static void printRanges(CXDiagnostic D, unsigned indent) {
  3601. unsigned i, n = clang_getDiagnosticNumRanges(D);
  3602. for (i = 0; i < n; ++i) {
  3603. CXSourceLocation Start, End;
  3604. CXSourceRange SR = clang_getDiagnosticRange(D, i);
  3605. Start = clang_getRangeStart(SR);
  3606. End = clang_getRangeEnd(SR);
  3607. printIndent(indent);
  3608. fprintf(stderr, "Range: ");
  3609. printLocation(Start);
  3610. fprintf(stderr, " ");
  3611. printLocation(End);
  3612. fprintf(stderr, "\n");
  3613. }
  3614. }
  3615. static void printFixIts(CXDiagnostic D, unsigned indent) {
  3616. unsigned i, n = clang_getDiagnosticNumFixIts(D);
  3617. fprintf(stderr, "Number FIXITs = %d\n", n);
  3618. for (i = 0 ; i < n; ++i) {
  3619. CXSourceRange ReplacementRange;
  3620. CXString text;
  3621. text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
  3622. printIndent(indent);
  3623. fprintf(stderr, "FIXIT: (");
  3624. printLocation(clang_getRangeStart(ReplacementRange));
  3625. fprintf(stderr, " - ");
  3626. printLocation(clang_getRangeEnd(ReplacementRange));
  3627. fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
  3628. clang_disposeString(text);
  3629. }
  3630. }
  3631. static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
  3632. unsigned i, n;
  3633. if (!Diags)
  3634. return;
  3635. n = clang_getNumDiagnosticsInSet(Diags);
  3636. for (i = 0; i < n; ++i) {
  3637. CXSourceLocation DiagLoc;
  3638. CXDiagnostic D;
  3639. CXFile File;
  3640. CXString FileName, DiagSpelling, DiagOption, DiagCat;
  3641. unsigned line, column, offset;
  3642. const char *DiagOptionStr = 0, *DiagCatStr = 0;
  3643. D = clang_getDiagnosticInSet(Diags, i);
  3644. DiagLoc = clang_getDiagnosticLocation(D);
  3645. clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
  3646. FileName = clang_getFileName(File);
  3647. DiagSpelling = clang_getDiagnosticSpelling(D);
  3648. printIndent(indent);
  3649. fprintf(stderr, "%s:%d:%d: %s: %s",
  3650. clang_getCString(FileName),
  3651. line,
  3652. column,
  3653. getSeverityString(clang_getDiagnosticSeverity(D)),
  3654. clang_getCString(DiagSpelling));
  3655. DiagOption = clang_getDiagnosticOption(D, 0);
  3656. DiagOptionStr = clang_getCString(DiagOption);
  3657. if (DiagOptionStr) {
  3658. fprintf(stderr, " [%s]", DiagOptionStr);
  3659. }
  3660. DiagCat = clang_getDiagnosticCategoryText(D);
  3661. DiagCatStr = clang_getCString(DiagCat);
  3662. if (DiagCatStr) {
  3663. fprintf(stderr, " [%s]", DiagCatStr);
  3664. }
  3665. fprintf(stderr, "\n");
  3666. printRanges(D, indent);
  3667. printFixIts(D, indent);
  3668. /* Print subdiagnostics. */
  3669. printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
  3670. clang_disposeString(FileName);
  3671. clang_disposeString(DiagSpelling);
  3672. clang_disposeString(DiagOption);
  3673. clang_disposeString(DiagCat);
  3674. }
  3675. }
  3676. static int read_diagnostics(const char *filename) {
  3677. enum CXLoadDiag_Error error;
  3678. CXString errorString;
  3679. CXDiagnosticSet Diags = 0;
  3680. Diags = clang_loadDiagnostics(filename, &error, &errorString);
  3681. if (!Diags) {
  3682. fprintf(stderr, "Trouble deserializing file (%s): %s\n",
  3683. getDiagnosticCodeStr(error),
  3684. clang_getCString(errorString));
  3685. clang_disposeString(errorString);
  3686. return 1;
  3687. }
  3688. printDiagnosticSet(Diags, 0);
  3689. fprintf(stderr, "Number of diagnostics: %d\n",
  3690. clang_getNumDiagnosticsInSet(Diags));
  3691. clang_disposeDiagnosticSet(Diags);
  3692. return 0;
  3693. }
  3694. static int perform_print_build_session_timestamp(void) {
  3695. printf("%lld\n", clang_getBuildSessionTimestamp());
  3696. return 0;
  3697. }
  3698. /******************************************************************************/
  3699. /* Command line processing. */
  3700. /******************************************************************************/
  3701. static CXCursorVisitor GetVisitor(const char *s) {
  3702. if (s[0] == '\0')
  3703. return FilteredPrintingVisitor;
  3704. if (strcmp(s, "-usrs") == 0)
  3705. return USRVisitor;
  3706. if (strncmp(s, "-memory-usage", 13) == 0)
  3707. return GetVisitor(s + 13);
  3708. return NULL;
  3709. }
  3710. static void print_usage(void) {
  3711. fprintf(stderr,
  3712. "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
  3713. " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
  3714. " c-index-test -cursor-at=<site> <compiler arguments>\n"
  3715. " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
  3716. " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
  3717. " c-index-test -file-refs-at=<site> <compiler arguments>\n"
  3718. " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
  3719. fprintf(stderr,
  3720. " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
  3721. " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
  3722. " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
  3723. " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
  3724. " c-index-test -test-file-scan <AST file> <source file> "
  3725. "[FileCheck prefix]\n");
  3726. fprintf(stderr,
  3727. " c-index-test -test-load-tu <AST file> <symbol filter> "
  3728. "[FileCheck prefix]\n"
  3729. " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
  3730. "[FileCheck prefix]\n"
  3731. " c-index-test -test-load-source <symbol filter> {<args>}*\n");
  3732. fprintf(stderr,
  3733. " c-index-test -test-load-source-memory-usage "
  3734. "<symbol filter> {<args>}*\n"
  3735. " c-index-test -test-load-source-reparse <trials> <symbol filter> "
  3736. " {<args>}*\n"
  3737. " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
  3738. " c-index-test -test-load-source-usrs-memory-usage "
  3739. "<symbol filter> {<args>}*\n"
  3740. " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
  3741. " c-index-test -test-inclusion-stack-source {<args>}*\n"
  3742. " c-index-test -test-inclusion-stack-tu <AST file>\n");
  3743. fprintf(stderr,
  3744. " c-index-test -test-print-linkage-source {<args>}*\n"
  3745. " c-index-test -test-print-visibility {<args>}*\n"
  3746. " c-index-test -test-print-type {<args>}*\n"
  3747. " c-index-test -test-print-type-size {<args>}*\n"
  3748. " c-index-test -test-print-bitwidth {<args>}*\n"
  3749. " c-index-test -test-print-type-declaration {<args>}*\n"
  3750. " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
  3751. " c-index-test -print-usr-file <file>\n"
  3752. " c-index-test -write-pch <file> <compiler arguments>\n");
  3753. fprintf(stderr,
  3754. " c-index-test -compilation-db [lookup <filename>] database\n");
  3755. fprintf(stderr,
  3756. " c-index-test -print-build-session-timestamp\n");
  3757. fprintf(stderr,
  3758. " c-index-test -read-diagnostics <file>\n\n");
  3759. fprintf(stderr,
  3760. " <symbol filter> values:\n%s",
  3761. " all - load all symbols, including those from PCH\n"
  3762. " local - load all symbols except those in PCH\n"
  3763. " category - only load ObjC categories (non-PCH)\n"
  3764. " interface - only load ObjC interfaces (non-PCH)\n"
  3765. " protocol - only load ObjC protocols (non-PCH)\n"
  3766. " function - only load functions (non-PCH)\n"
  3767. " typedef - only load typdefs (non-PCH)\n"
  3768. " scan-function - scan function bodies (non-PCH)\n\n");
  3769. }
  3770. /***/
  3771. int cindextest_main(int argc, const char **argv) {
  3772. clang_enableStackTraces();
  3773. if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
  3774. return read_diagnostics(argv[2]);
  3775. if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
  3776. return perform_code_completion(argc, argv, 0);
  3777. if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
  3778. return perform_code_completion(argc, argv, 1);
  3779. if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
  3780. return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
  3781. if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
  3782. return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
  3783. inspect_evaluate_cursor);
  3784. if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
  3785. return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
  3786. inspect_macroinfo_cursor);
  3787. if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
  3788. return find_file_refs_at(argc, argv);
  3789. if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
  3790. return find_file_includes_in(argc, argv);
  3791. if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
  3792. return index_file(argc - 2, argv + 2, /*full=*/0);
  3793. if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
  3794. return index_file(argc - 2, argv + 2, /*full=*/1);
  3795. if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
  3796. return index_tu(argc - 2, argv + 2);
  3797. if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
  3798. return index_compile_db(argc - 2, argv + 2);
  3799. else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
  3800. CXCursorVisitor I = GetVisitor(argv[1] + 13);
  3801. if (I)
  3802. return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
  3803. NULL);
  3804. }
  3805. else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
  3806. CXCursorVisitor I = GetVisitor(argv[1] + 25);
  3807. if (I) {
  3808. int trials = atoi(argv[2]);
  3809. return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
  3810. NULL);
  3811. }
  3812. }
  3813. else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
  3814. CXCursorVisitor I = GetVisitor(argv[1] + 17);
  3815. PostVisitTU postVisit = 0;
  3816. if (strstr(argv[1], "-memory-usage"))
  3817. postVisit = PrintMemoryUsage;
  3818. if (I)
  3819. return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
  3820. postVisit);
  3821. }
  3822. else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
  3823. return perform_file_scan(argv[2], argv[3],
  3824. argc >= 5 ? argv[4] : 0);
  3825. else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
  3826. return perform_token_annotation(argc, argv);
  3827. else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
  3828. return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
  3829. PrintInclusionStack);
  3830. else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
  3831. return perform_test_load_tu(argv[2], "all", NULL, NULL,
  3832. PrintInclusionStack);
  3833. else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
  3834. return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
  3835. NULL);
  3836. else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0)
  3837. return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility,
  3838. NULL);
  3839. else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
  3840. return perform_test_load_source(argc - 2, argv + 2, "all",
  3841. PrintType, 0);
  3842. else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
  3843. return perform_test_load_source(argc - 2, argv + 2, "all",
  3844. PrintTypeSize, 0);
  3845. else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
  3846. return perform_test_load_source(argc - 2, argv + 2, "all",
  3847. PrintTypeDeclaration, 0);
  3848. else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
  3849. return perform_test_load_source(argc - 2, argv + 2, "all",
  3850. PrintBitWidth, 0);
  3851. else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
  3852. return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
  3853. else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
  3854. return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
  3855. else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
  3856. if (argc > 2)
  3857. return print_usrs(argv + 2, argv + argc);
  3858. else {
  3859. display_usrs();
  3860. return 1;
  3861. }
  3862. }
  3863. else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
  3864. return print_usrs_file(argv[2]);
  3865. else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
  3866. return write_pch_file(argv[2], argc - 3, argv + 3);
  3867. else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
  3868. return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
  3869. else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
  3870. return perform_print_build_session_timestamp();
  3871. print_usage();
  3872. return 1;
  3873. }
  3874. /***/
  3875. /* We intentionally run in a separate thread to ensure we at least minimal
  3876. * testing of a multithreaded environment (for example, having a reduced stack
  3877. * size). */
  3878. typedef struct thread_info {
  3879. int (*main_func)(int argc, const char **argv);
  3880. int argc;
  3881. const char **argv;
  3882. int result;
  3883. } thread_info;
  3884. void thread_runner(void *client_data_v) {
  3885. thread_info *client_data = client_data_v;
  3886. client_data->result = client_data->main_func(client_data->argc,
  3887. client_data->argv);
  3888. }
  3889. static void flush_atexit(void) {
  3890. /* stdout, and surprisingly even stderr, are not always flushed on process
  3891. * and thread exit, particularly when the system is under heavy load. */
  3892. fflush(stdout);
  3893. fflush(stderr);
  3894. }
  3895. int main(int argc, const char **argv) {
  3896. thread_info client_data;
  3897. atexit(flush_atexit);
  3898. #ifdef CLANG_HAVE_LIBXML
  3899. LIBXML_TEST_VERSION
  3900. #endif
  3901. client_data.main_func = cindextest_main;
  3902. client_data.argc = argc;
  3903. client_data.argv = argv;
  3904. if (argc > 1 && strcmp(argv[1], "core") == 0) {
  3905. client_data.main_func = indextest_core_main;
  3906. --client_data.argc;
  3907. ++client_data.argv;
  3908. }
  3909. if (getenv("CINDEXTEST_NOTHREADS"))
  3910. return client_data.main_func(client_data.argc, client_data.argv);
  3911. clang_executeOnThread(thread_runner, &client_data, 0);
  3912. return client_data.result;
  3913. }