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