Clang Project

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