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