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