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