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