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