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