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