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