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