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