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