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