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