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