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