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