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