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