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