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