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