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