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