brintos

brintos / llvm-project-archived public Read only

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