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