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