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