c-index-test.c revision e4a990f34904eb572c8d6aa1deef19465214359c
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 if (Cursor.kind == CXCursor_ObjCMessageExpr) { 1959 CXType T = clang_Cursor_getReceiverType(Cursor); 1960 CXString S = clang_getTypeKindSpelling(T.kind); 1961 printf(" Receiver-type=%s", clang_getCString(S)); 1962 clang_disposeString(S); 1963 } 1964 1965 { 1966 CXModule mod = clang_Cursor_getModule(Cursor); 1967 CXString name; 1968 unsigned i, numHeaders; 1969 if (mod) { 1970 name = clang_Module_getFullName(mod); 1971 numHeaders = clang_Module_getNumTopLevelHeaders(mod); 1972 printf(" ModuleName=%s Headers(%d):", 1973 clang_getCString(name), numHeaders); 1974 clang_disposeString(name); 1975 for (i = 0; i < numHeaders; ++i) { 1976 CXFile file = clang_Module_getTopLevelHeader(mod, i); 1977 CXString filename = clang_getFileName(file); 1978 printf("\n%s", clang_getCString(filename)); 1979 clang_disposeString(filename); 1980 } 1981 } 1982 } 1983 1984 if (completionString != NULL) { 1985 printf("\nCompletion string: "); 1986 print_completion_string(completionString, stdout); 1987 } 1988 printf("\n"); 1989 free(Locations[Loc].filename); 1990 } 1991 } 1992 } 1993 1994 PrintDiagnostics(TU); 1995 clang_disposeTranslationUnit(TU); 1996 clang_disposeIndex(CIdx); 1997 free(Locations); 1998 free_remapped_files(unsaved_files, num_unsaved_files); 1999 return 0; 2000} 2001 2002static enum CXVisitorResult findFileRefsVisit(void *context, 2003 CXCursor cursor, CXSourceRange range) { 2004 if (clang_Range_isNull(range)) 2005 return CXVisit_Continue; 2006 2007 PrintCursor(cursor, NULL); 2008 PrintRange(range, ""); 2009 printf("\n"); 2010 return CXVisit_Continue; 2011} 2012 2013static int find_file_refs_at(int argc, const char **argv) { 2014 CXIndex CIdx; 2015 int errorCode; 2016 struct CXUnsavedFile *unsaved_files = 0; 2017 int num_unsaved_files = 0; 2018 CXTranslationUnit TU; 2019 CXCursor Cursor; 2020 CursorSourceLocation *Locations = 0; 2021 unsigned NumLocations = 0, Loc; 2022 unsigned Repeats = 1; 2023 unsigned I; 2024 2025 /* Count the number of locations. */ 2026 while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1]) 2027 ++NumLocations; 2028 2029 /* Parse the locations. */ 2030 assert(NumLocations > 0 && "Unable to count locations?"); 2031 Locations = (CursorSourceLocation *)malloc( 2032 NumLocations * sizeof(CursorSourceLocation)); 2033 for (Loc = 0; Loc < NumLocations; ++Loc) { 2034 const char *input = argv[Loc + 1] + strlen("-file-refs-at="); 2035 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, 2036 &Locations[Loc].line, 2037 &Locations[Loc].column, 0, 0))) 2038 return errorCode; 2039 } 2040 2041 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, 2042 &num_unsaved_files)) 2043 return -1; 2044 2045 if (getenv("CINDEXTEST_EDITING")) 2046 Repeats = 5; 2047 2048 /* Parse the translation unit. When we're testing clang_getCursor() after 2049 reparsing, don't remap unsaved files until the second parse. */ 2050 CIdx = clang_createIndex(1, 1); 2051 TU = clang_parseTranslationUnit(CIdx, argv[argc - 1], 2052 argv + num_unsaved_files + 1 + NumLocations, 2053 argc - num_unsaved_files - 2 - NumLocations, 2054 unsaved_files, 2055 Repeats > 1? 0 : num_unsaved_files, 2056 getDefaultParsingOptions()); 2057 2058 if (!TU) { 2059 fprintf(stderr, "unable to parse input\n"); 2060 return -1; 2061 } 2062 2063 if (checkForErrors(TU) != 0) 2064 return -1; 2065 2066 for (I = 0; I != Repeats; ++I) { 2067 if (Repeats > 1 && 2068 clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, 2069 clang_defaultReparseOptions(TU))) { 2070 clang_disposeTranslationUnit(TU); 2071 return 1; 2072 } 2073 2074 if (checkForErrors(TU) != 0) 2075 return -1; 2076 2077 for (Loc = 0; Loc < NumLocations; ++Loc) { 2078 CXFile file = clang_getFile(TU, Locations[Loc].filename); 2079 if (!file) 2080 continue; 2081 2082 Cursor = clang_getCursor(TU, 2083 clang_getLocation(TU, file, Locations[Loc].line, 2084 Locations[Loc].column)); 2085 2086 if (checkForErrors(TU) != 0) 2087 return -1; 2088 2089 if (I + 1 == Repeats) { 2090 CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit }; 2091 PrintCursor(Cursor, NULL); 2092 printf("\n"); 2093 clang_findReferencesInFile(Cursor, file, visitor); 2094 free(Locations[Loc].filename); 2095 2096 if (checkForErrors(TU) != 0) 2097 return -1; 2098 } 2099 } 2100 } 2101 2102 PrintDiagnostics(TU); 2103 clang_disposeTranslationUnit(TU); 2104 clang_disposeIndex(CIdx); 2105 free(Locations); 2106 free_remapped_files(unsaved_files, num_unsaved_files); 2107 return 0; 2108} 2109 2110#define MAX_IMPORTED_ASTFILES 200 2111 2112typedef struct { 2113 char **filenames; 2114 unsigned num_files; 2115} ImportedASTFilesData; 2116 2117static ImportedASTFilesData *importedASTs_create() { 2118 ImportedASTFilesData *p; 2119 p = malloc(sizeof(ImportedASTFilesData)); 2120 p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *)); 2121 p->num_files = 0; 2122 return p; 2123} 2124 2125static void importedASTs_dispose(ImportedASTFilesData *p) { 2126 unsigned i; 2127 if (!p) 2128 return; 2129 2130 for (i = 0; i < p->num_files; ++i) 2131 free(p->filenames[i]); 2132 free(p->filenames); 2133 free(p); 2134} 2135 2136static void importedASTS_insert(ImportedASTFilesData *p, const char *file) { 2137 unsigned i; 2138 assert(p && file); 2139 for (i = 0; i < p->num_files; ++i) 2140 if (strcmp(file, p->filenames[i]) == 0) 2141 return; 2142 assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES); 2143 p->filenames[p->num_files++] = strdup(file); 2144} 2145 2146typedef struct { 2147 const char *check_prefix; 2148 int first_check_printed; 2149 int fail_for_error; 2150 int abort; 2151 const char *main_filename; 2152 ImportedASTFilesData *importedASTs; 2153} IndexData; 2154 2155static void printCheck(IndexData *data) { 2156 if (data->check_prefix) { 2157 if (data->first_check_printed) { 2158 printf("// %s-NEXT: ", data->check_prefix); 2159 } else { 2160 printf("// %s : ", data->check_prefix); 2161 data->first_check_printed = 1; 2162 } 2163 } 2164} 2165 2166static void printCXIndexFile(CXIdxClientFile file) { 2167 CXString filename = clang_getFileName((CXFile)file); 2168 printf("%s", clang_getCString(filename)); 2169 clang_disposeString(filename); 2170} 2171 2172static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) { 2173 IndexData *index_data; 2174 CXString filename; 2175 const char *cname; 2176 CXIdxClientFile file; 2177 unsigned line, column; 2178 int isMainFile; 2179 2180 index_data = (IndexData *)client_data; 2181 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0); 2182 if (line == 0) { 2183 printf("<invalid>"); 2184 return; 2185 } 2186 if (!file) { 2187 printf("<no idxfile>"); 2188 return; 2189 } 2190 filename = clang_getFileName((CXFile)file); 2191 cname = clang_getCString(filename); 2192 if (strcmp(cname, index_data->main_filename) == 0) 2193 isMainFile = 1; 2194 else 2195 isMainFile = 0; 2196 clang_disposeString(filename); 2197 2198 if (!isMainFile) { 2199 printCXIndexFile(file); 2200 printf(":"); 2201 } 2202 printf("%d:%d", line, column); 2203} 2204 2205static unsigned digitCount(unsigned val) { 2206 unsigned c = 1; 2207 while (1) { 2208 if (val < 10) 2209 return c; 2210 ++c; 2211 val /= 10; 2212 } 2213} 2214 2215static CXIdxClientContainer makeClientContainer(const CXIdxEntityInfo *info, 2216 CXIdxLoc loc) { 2217 const char *name; 2218 char *newStr; 2219 CXIdxClientFile file; 2220 unsigned line, column; 2221 2222 name = info->name; 2223 if (!name) 2224 name = "<anon-tag>"; 2225 2226 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0); 2227 /* FIXME: free these.*/ 2228 newStr = (char *)malloc(strlen(name) + 2229 digitCount(line) + digitCount(column) + 3); 2230 sprintf(newStr, "%s:%d:%d", name, line, column); 2231 return (CXIdxClientContainer)newStr; 2232} 2233 2234static void printCXIndexContainer(const CXIdxContainerInfo *info) { 2235 CXIdxClientContainer container; 2236 container = clang_index_getClientContainer(info); 2237 if (!container) 2238 printf("[<<NULL>>]"); 2239 else 2240 printf("[%s]", (const char *)container); 2241} 2242 2243static const char *getEntityKindString(CXIdxEntityKind kind) { 2244 switch (kind) { 2245 case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>"; 2246 case CXIdxEntity_Typedef: return "typedef"; 2247 case CXIdxEntity_Function: return "function"; 2248 case CXIdxEntity_Variable: return "variable"; 2249 case CXIdxEntity_Field: return "field"; 2250 case CXIdxEntity_EnumConstant: return "enumerator"; 2251 case CXIdxEntity_ObjCClass: return "objc-class"; 2252 case CXIdxEntity_ObjCProtocol: return "objc-protocol"; 2253 case CXIdxEntity_ObjCCategory: return "objc-category"; 2254 case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method"; 2255 case CXIdxEntity_ObjCClassMethod: return "objc-class-method"; 2256 case CXIdxEntity_ObjCProperty: return "objc-property"; 2257 case CXIdxEntity_ObjCIvar: return "objc-ivar"; 2258 case CXIdxEntity_Enum: return "enum"; 2259 case CXIdxEntity_Struct: return "struct"; 2260 case CXIdxEntity_Union: return "union"; 2261 case CXIdxEntity_CXXClass: return "c++-class"; 2262 case CXIdxEntity_CXXNamespace: return "namespace"; 2263 case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias"; 2264 case CXIdxEntity_CXXStaticVariable: return "c++-static-var"; 2265 case CXIdxEntity_CXXStaticMethod: return "c++-static-method"; 2266 case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method"; 2267 case CXIdxEntity_CXXConstructor: return "constructor"; 2268 case CXIdxEntity_CXXDestructor: return "destructor"; 2269 case CXIdxEntity_CXXConversionFunction: return "conversion-func"; 2270 case CXIdxEntity_CXXTypeAlias: return "type-alias"; 2271 case CXIdxEntity_CXXInterface: return "c++-__interface"; 2272 } 2273 assert(0 && "Garbage entity kind"); 2274 return 0; 2275} 2276 2277static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) { 2278 switch (kind) { 2279 case CXIdxEntity_NonTemplate: return ""; 2280 case CXIdxEntity_Template: return "-template"; 2281 case CXIdxEntity_TemplatePartialSpecialization: 2282 return "-template-partial-spec"; 2283 case CXIdxEntity_TemplateSpecialization: return "-template-spec"; 2284 } 2285 assert(0 && "Garbage entity kind"); 2286 return 0; 2287} 2288 2289static const char *getEntityLanguageString(CXIdxEntityLanguage kind) { 2290 switch (kind) { 2291 case CXIdxEntityLang_None: return "<none>"; 2292 case CXIdxEntityLang_C: return "C"; 2293 case CXIdxEntityLang_ObjC: return "ObjC"; 2294 case CXIdxEntityLang_CXX: return "C++"; 2295 } 2296 assert(0 && "Garbage language kind"); 2297 return 0; 2298} 2299 2300static void printEntityInfo(const char *cb, 2301 CXClientData client_data, 2302 const CXIdxEntityInfo *info) { 2303 const char *name; 2304 IndexData *index_data; 2305 unsigned i; 2306 index_data = (IndexData *)client_data; 2307 printCheck(index_data); 2308 2309 if (!info) { 2310 printf("%s: <<NULL>>", cb); 2311 return; 2312 } 2313 2314 name = info->name; 2315 if (!name) 2316 name = "<anon-tag>"; 2317 2318 printf("%s: kind: %s%s", cb, getEntityKindString(info->kind), 2319 getEntityTemplateKindString(info->templateKind)); 2320 printf(" | name: %s", name); 2321 printf(" | USR: %s", info->USR); 2322 printf(" | lang: %s", getEntityLanguageString(info->lang)); 2323 2324 for (i = 0; i != info->numAttributes; ++i) { 2325 const CXIdxAttrInfo *Attr = info->attributes[i]; 2326 printf(" <attribute>: "); 2327 PrintCursor(Attr->cursor, NULL); 2328 } 2329} 2330 2331static void printBaseClassInfo(CXClientData client_data, 2332 const CXIdxBaseClassInfo *info) { 2333 printEntityInfo(" <base>", client_data, info->base); 2334 printf(" | cursor: "); 2335 PrintCursor(info->cursor, NULL); 2336 printf(" | loc: "); 2337 printCXIndexLoc(info->loc, client_data); 2338} 2339 2340static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo, 2341 CXClientData client_data) { 2342 unsigned i; 2343 for (i = 0; i < ProtoInfo->numProtocols; ++i) { 2344 printEntityInfo(" <protocol>", client_data, 2345 ProtoInfo->protocols[i]->protocol); 2346 printf(" | cursor: "); 2347 PrintCursor(ProtoInfo->protocols[i]->cursor, NULL); 2348 printf(" | loc: "); 2349 printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data); 2350 printf("\n"); 2351 } 2352} 2353 2354static void index_diagnostic(CXClientData client_data, 2355 CXDiagnosticSet diagSet, void *reserved) { 2356 CXString str; 2357 const char *cstr; 2358 unsigned numDiags, i; 2359 CXDiagnostic diag; 2360 IndexData *index_data; 2361 index_data = (IndexData *)client_data; 2362 printCheck(index_data); 2363 2364 numDiags = clang_getNumDiagnosticsInSet(diagSet); 2365 for (i = 0; i != numDiags; ++i) { 2366 diag = clang_getDiagnosticInSet(diagSet, i); 2367 str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions()); 2368 cstr = clang_getCString(str); 2369 printf("[diagnostic]: %s\n", cstr); 2370 clang_disposeString(str); 2371 2372 if (getenv("CINDEXTEST_FAILONERROR") && 2373 clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) { 2374 index_data->fail_for_error = 1; 2375 } 2376 } 2377} 2378 2379static CXIdxClientFile index_enteredMainFile(CXClientData client_data, 2380 CXFile file, void *reserved) { 2381 IndexData *index_data; 2382 CXString filename; 2383 2384 index_data = (IndexData *)client_data; 2385 printCheck(index_data); 2386 2387 filename = clang_getFileName(file); 2388 index_data->main_filename = clang_getCString(filename); 2389 clang_disposeString(filename); 2390 2391 printf("[enteredMainFile]: "); 2392 printCXIndexFile((CXIdxClientFile)file); 2393 printf("\n"); 2394 2395 return (CXIdxClientFile)file; 2396} 2397 2398static CXIdxClientFile index_ppIncludedFile(CXClientData client_data, 2399 const CXIdxIncludedFileInfo *info) { 2400 IndexData *index_data; 2401 index_data = (IndexData *)client_data; 2402 printCheck(index_data); 2403 2404 printf("[ppIncludedFile]: "); 2405 printCXIndexFile((CXIdxClientFile)info->file); 2406 printf(" | name: \"%s\"", info->filename); 2407 printf(" | hash loc: "); 2408 printCXIndexLoc(info->hashLoc, client_data); 2409 printf(" | isImport: %d | isAngled: %d | isModule: %d\n", 2410 info->isImport, info->isAngled, info->isModuleImport); 2411 2412 return (CXIdxClientFile)info->file; 2413} 2414 2415static CXIdxClientFile index_importedASTFile(CXClientData client_data, 2416 const CXIdxImportedASTFileInfo *info) { 2417 IndexData *index_data; 2418 index_data = (IndexData *)client_data; 2419 printCheck(index_data); 2420 2421 if (index_data->importedASTs) { 2422 CXString filename = clang_getFileName(info->file); 2423 importedASTS_insert(index_data->importedASTs, clang_getCString(filename)); 2424 clang_disposeString(filename); 2425 } 2426 2427 printf("[importedASTFile]: "); 2428 printCXIndexFile((CXIdxClientFile)info->file); 2429 if (info->module) { 2430 CXString name = clang_Module_getFullName(info->module); 2431 printf(" | loc: "); 2432 printCXIndexLoc(info->loc, client_data); 2433 printf(" | name: \"%s\"", clang_getCString(name)); 2434 printf(" | isImplicit: %d\n", info->isImplicit); 2435 clang_disposeString(name); 2436 } else { 2437 /* PCH file, the rest are not relevant. */ 2438 printf("\n"); 2439 } 2440 2441 return (CXIdxClientFile)info->file; 2442} 2443 2444static CXIdxClientContainer index_startedTranslationUnit(CXClientData client_data, 2445 void *reserved) { 2446 IndexData *index_data; 2447 index_data = (IndexData *)client_data; 2448 printCheck(index_data); 2449 2450 printf("[startedTranslationUnit]\n"); 2451 return (CXIdxClientContainer)"TU"; 2452} 2453 2454static void index_indexDeclaration(CXClientData client_data, 2455 const CXIdxDeclInfo *info) { 2456 IndexData *index_data; 2457 const CXIdxObjCCategoryDeclInfo *CatInfo; 2458 const CXIdxObjCInterfaceDeclInfo *InterInfo; 2459 const CXIdxObjCProtocolRefListInfo *ProtoInfo; 2460 const CXIdxObjCPropertyDeclInfo *PropInfo; 2461 const CXIdxCXXClassDeclInfo *CXXClassInfo; 2462 unsigned i; 2463 index_data = (IndexData *)client_data; 2464 2465 printEntityInfo("[indexDeclaration]", client_data, info->entityInfo); 2466 printf(" | cursor: "); 2467 PrintCursor(info->cursor, NULL); 2468 printf(" | loc: "); 2469 printCXIndexLoc(info->loc, client_data); 2470 printf(" | semantic-container: "); 2471 printCXIndexContainer(info->semanticContainer); 2472 printf(" | lexical-container: "); 2473 printCXIndexContainer(info->lexicalContainer); 2474 printf(" | isRedecl: %d", info->isRedeclaration); 2475 printf(" | isDef: %d", info->isDefinition); 2476 printf(" | isContainer: %d", info->isContainer); 2477 printf(" | isImplicit: %d\n", info->isImplicit); 2478 2479 for (i = 0; i != info->numAttributes; ++i) { 2480 const CXIdxAttrInfo *Attr = info->attributes[i]; 2481 printf(" <attribute>: "); 2482 PrintCursor(Attr->cursor, NULL); 2483 printf("\n"); 2484 } 2485 2486 if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) { 2487 const char *kindName = 0; 2488 CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind; 2489 switch (K) { 2490 case CXIdxObjCContainer_ForwardRef: 2491 kindName = "forward-ref"; break; 2492 case CXIdxObjCContainer_Interface: 2493 kindName = "interface"; break; 2494 case CXIdxObjCContainer_Implementation: 2495 kindName = "implementation"; break; 2496 } 2497 printCheck(index_data); 2498 printf(" <ObjCContainerInfo>: kind: %s\n", kindName); 2499 } 2500 2501 if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) { 2502 printEntityInfo(" <ObjCCategoryInfo>: class", client_data, 2503 CatInfo->objcClass); 2504 printf(" | cursor: "); 2505 PrintCursor(CatInfo->classCursor, NULL); 2506 printf(" | loc: "); 2507 printCXIndexLoc(CatInfo->classLoc, client_data); 2508 printf("\n"); 2509 } 2510 2511 if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) { 2512 if (InterInfo->superInfo) { 2513 printBaseClassInfo(client_data, InterInfo->superInfo); 2514 printf("\n"); 2515 } 2516 } 2517 2518 if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) { 2519 printProtocolList(ProtoInfo, client_data); 2520 } 2521 2522 if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) { 2523 if (PropInfo->getter) { 2524 printEntityInfo(" <getter>", client_data, PropInfo->getter); 2525 printf("\n"); 2526 } 2527 if (PropInfo->setter) { 2528 printEntityInfo(" <setter>", client_data, PropInfo->setter); 2529 printf("\n"); 2530 } 2531 } 2532 2533 if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) { 2534 for (i = 0; i != CXXClassInfo->numBases; ++i) { 2535 printBaseClassInfo(client_data, CXXClassInfo->bases[i]); 2536 printf("\n"); 2537 } 2538 } 2539 2540 if (info->declAsContainer) 2541 clang_index_setClientContainer(info->declAsContainer, 2542 makeClientContainer(info->entityInfo, info->loc)); 2543} 2544 2545static void index_indexEntityReference(CXClientData client_data, 2546 const CXIdxEntityRefInfo *info) { 2547 printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity); 2548 printf(" | cursor: "); 2549 PrintCursor(info->cursor, NULL); 2550 printf(" | loc: "); 2551 printCXIndexLoc(info->loc, client_data); 2552 printEntityInfo(" | <parent>:", client_data, info->parentEntity); 2553 printf(" | container: "); 2554 printCXIndexContainer(info->container); 2555 printf(" | refkind: "); 2556 switch (info->kind) { 2557 case CXIdxEntityRef_Direct: printf("direct"); break; 2558 case CXIdxEntityRef_Implicit: printf("implicit"); break; 2559 } 2560 printf("\n"); 2561} 2562 2563static int index_abortQuery(CXClientData client_data, void *reserved) { 2564 IndexData *index_data; 2565 index_data = (IndexData *)client_data; 2566 return index_data->abort; 2567} 2568 2569static IndexerCallbacks IndexCB = { 2570 index_abortQuery, 2571 index_diagnostic, 2572 index_enteredMainFile, 2573 index_ppIncludedFile, 2574 index_importedASTFile, 2575 index_startedTranslationUnit, 2576 index_indexDeclaration, 2577 index_indexEntityReference 2578}; 2579 2580static unsigned getIndexOptions(void) { 2581 unsigned index_opts; 2582 index_opts = 0; 2583 if (getenv("CINDEXTEST_SUPPRESSREFS")) 2584 index_opts |= CXIndexOpt_SuppressRedundantRefs; 2585 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS")) 2586 index_opts |= CXIndexOpt_IndexFunctionLocalSymbols; 2587 2588 return index_opts; 2589} 2590 2591static int index_file(int argc, const char **argv, int full) { 2592 const char *check_prefix; 2593 CXIndex Idx; 2594 CXIndexAction idxAction; 2595 IndexData index_data; 2596 unsigned index_opts; 2597 int result; 2598 2599 check_prefix = 0; 2600 if (argc > 0) { 2601 if (strstr(argv[0], "-check-prefix=") == argv[0]) { 2602 check_prefix = argv[0] + strlen("-check-prefix="); 2603 ++argv; 2604 --argc; 2605 } 2606 } 2607 2608 if (argc == 0) { 2609 fprintf(stderr, "no compiler arguments\n"); 2610 return -1; 2611 } 2612 2613 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, 2614 /* displayDiagnosics=*/1))) { 2615 fprintf(stderr, "Could not create Index\n"); 2616 return 1; 2617 } 2618 idxAction = 0; 2619 2620 index_data.check_prefix = check_prefix; 2621 index_data.first_check_printed = 0; 2622 index_data.fail_for_error = 0; 2623 index_data.abort = 0; 2624 index_data.main_filename = ""; 2625 index_data.importedASTs = 0; 2626 2627 if (full) 2628 index_data.importedASTs = importedASTs_create(); 2629 2630 index_opts = getIndexOptions(); 2631 idxAction = clang_IndexAction_create(Idx); 2632 result = clang_indexSourceFile(idxAction, &index_data, 2633 &IndexCB,sizeof(IndexCB), index_opts, 2634 0, argv, argc, 0, 0, 0, 2635 getDefaultParsingOptions()); 2636 if (index_data.fail_for_error) 2637 result = -1; 2638 2639 if (full) { 2640 CXTranslationUnit TU; 2641 unsigned i; 2642 2643 for (i = 0; i < index_data.importedASTs->num_files; ++i) { 2644 if (!CreateTranslationUnit(Idx, index_data.importedASTs->filenames[i], 2645 &TU)) { 2646 result = -1; 2647 goto finished; 2648 } 2649 result = clang_indexTranslationUnit(idxAction, &index_data, 2650 &IndexCB,sizeof(IndexCB), 2651 index_opts, TU); 2652 clang_disposeTranslationUnit(TU); 2653 } 2654 } 2655 2656finished: 2657 importedASTs_dispose(index_data.importedASTs); 2658 clang_IndexAction_dispose(idxAction); 2659 clang_disposeIndex(Idx); 2660 return result; 2661} 2662 2663static int index_tu(int argc, const char **argv) { 2664 CXIndex Idx; 2665 CXIndexAction idxAction; 2666 CXTranslationUnit TU; 2667 const char *check_prefix; 2668 IndexData index_data; 2669 unsigned index_opts; 2670 int result; 2671 2672 check_prefix = 0; 2673 if (argc > 0) { 2674 if (strstr(argv[0], "-check-prefix=") == argv[0]) { 2675 check_prefix = argv[0] + strlen("-check-prefix="); 2676 ++argv; 2677 --argc; 2678 } 2679 } 2680 2681 if (argc == 0) { 2682 fprintf(stderr, "no ast file\n"); 2683 return -1; 2684 } 2685 2686 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, 2687 /* displayDiagnosics=*/1))) { 2688 fprintf(stderr, "Could not create Index\n"); 2689 return 1; 2690 } 2691 idxAction = 0; 2692 TU = 0; 2693 result = 1; 2694 2695 if (!CreateTranslationUnit(Idx, argv[0], &TU)) 2696 goto finished; 2697 2698 index_data.check_prefix = check_prefix; 2699 index_data.first_check_printed = 0; 2700 index_data.fail_for_error = 0; 2701 index_data.abort = 0; 2702 index_data.main_filename = ""; 2703 index_data.importedASTs = 0; 2704 2705 index_opts = getIndexOptions(); 2706 idxAction = clang_IndexAction_create(Idx); 2707 result = clang_indexTranslationUnit(idxAction, &index_data, 2708 &IndexCB,sizeof(IndexCB), 2709 index_opts, TU); 2710 if (index_data.fail_for_error) 2711 goto finished; 2712 2713 finished: 2714 clang_IndexAction_dispose(idxAction); 2715 clang_disposeTranslationUnit(TU); 2716 clang_disposeIndex(Idx); 2717 2718 return result; 2719} 2720 2721int perform_token_annotation(int argc, const char **argv) { 2722 const char *input = argv[1]; 2723 char *filename = 0; 2724 unsigned line, second_line; 2725 unsigned column, second_column; 2726 CXIndex CIdx; 2727 CXTranslationUnit TU = 0; 2728 int errorCode; 2729 struct CXUnsavedFile *unsaved_files = 0; 2730 int num_unsaved_files = 0; 2731 CXToken *tokens; 2732 unsigned num_tokens; 2733 CXSourceRange range; 2734 CXSourceLocation startLoc, endLoc; 2735 CXFile file = 0; 2736 CXCursor *cursors = 0; 2737 unsigned i; 2738 2739 input += strlen("-test-annotate-tokens="); 2740 if ((errorCode = parse_file_line_column(input, &filename, &line, &column, 2741 &second_line, &second_column))) 2742 return errorCode; 2743 2744 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) { 2745 free(filename); 2746 return -1; 2747 } 2748 2749 CIdx = clang_createIndex(0, 1); 2750 TU = clang_parseTranslationUnit(CIdx, argv[argc - 1], 2751 argv + num_unsaved_files + 2, 2752 argc - num_unsaved_files - 3, 2753 unsaved_files, 2754 num_unsaved_files, 2755 getDefaultParsingOptions()); 2756 if (!TU) { 2757 fprintf(stderr, "unable to parse input\n"); 2758 clang_disposeIndex(CIdx); 2759 free(filename); 2760 free_remapped_files(unsaved_files, num_unsaved_files); 2761 return -1; 2762 } 2763 errorCode = 0; 2764 2765 if (checkForErrors(TU) != 0) { 2766 errorCode = -1; 2767 goto teardown; 2768 } 2769 2770 if (getenv("CINDEXTEST_EDITING")) { 2771 for (i = 0; i < 5; ++i) { 2772 if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files, 2773 clang_defaultReparseOptions(TU))) { 2774 fprintf(stderr, "Unable to reparse translation unit!\n"); 2775 errorCode = -1; 2776 goto teardown; 2777 } 2778 } 2779 } 2780 2781 if (checkForErrors(TU) != 0) { 2782 errorCode = -1; 2783 goto teardown; 2784 } 2785 2786 file = clang_getFile(TU, filename); 2787 if (!file) { 2788 fprintf(stderr, "file %s is not in this translation unit\n", filename); 2789 errorCode = -1; 2790 goto teardown; 2791 } 2792 2793 startLoc = clang_getLocation(TU, file, line, column); 2794 if (clang_equalLocations(clang_getNullLocation(), startLoc)) { 2795 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, 2796 column); 2797 errorCode = -1; 2798 goto teardown; 2799 } 2800 2801 endLoc = clang_getLocation(TU, file, second_line, second_column); 2802 if (clang_equalLocations(clang_getNullLocation(), endLoc)) { 2803 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, 2804 second_line, second_column); 2805 errorCode = -1; 2806 goto teardown; 2807 } 2808 2809 range = clang_getRange(startLoc, endLoc); 2810 clang_tokenize(TU, range, &tokens, &num_tokens); 2811 2812 if (checkForErrors(TU) != 0) { 2813 errorCode = -1; 2814 goto teardown; 2815 } 2816 2817 cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor)); 2818 clang_annotateTokens(TU, tokens, num_tokens, cursors); 2819 2820 if (checkForErrors(TU) != 0) { 2821 errorCode = -1; 2822 goto teardown; 2823 } 2824 2825 for (i = 0; i != num_tokens; ++i) { 2826 const char *kind = "<unknown>"; 2827 CXString spelling = clang_getTokenSpelling(TU, tokens[i]); 2828 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]); 2829 unsigned start_line, start_column, end_line, end_column; 2830 2831 switch (clang_getTokenKind(tokens[i])) { 2832 case CXToken_Punctuation: kind = "Punctuation"; break; 2833 case CXToken_Keyword: kind = "Keyword"; break; 2834 case CXToken_Identifier: kind = "Identifier"; break; 2835 case CXToken_Literal: kind = "Literal"; break; 2836 case CXToken_Comment: kind = "Comment"; break; 2837 } 2838 clang_getSpellingLocation(clang_getRangeStart(extent), 2839 0, &start_line, &start_column, 0); 2840 clang_getSpellingLocation(clang_getRangeEnd(extent), 2841 0, &end_line, &end_column, 0); 2842 printf("%s: \"%s\" ", kind, clang_getCString(spelling)); 2843 clang_disposeString(spelling); 2844 PrintExtent(stdout, start_line, start_column, end_line, end_column); 2845 if (!clang_isInvalid(cursors[i].kind)) { 2846 printf(" "); 2847 PrintCursor(cursors[i], NULL); 2848 } 2849 printf("\n"); 2850 } 2851 free(cursors); 2852 clang_disposeTokens(TU, tokens, num_tokens); 2853 2854 teardown: 2855 PrintDiagnostics(TU); 2856 clang_disposeTranslationUnit(TU); 2857 clang_disposeIndex(CIdx); 2858 free(filename); 2859 free_remapped_files(unsaved_files, num_unsaved_files); 2860 return errorCode; 2861} 2862 2863static int 2864perform_test_compilation_db(const char *database, int argc, const char **argv) { 2865 CXCompilationDatabase db; 2866 CXCompileCommands CCmds; 2867 CXCompileCommand CCmd; 2868 CXCompilationDatabase_Error ec; 2869 CXString wd; 2870 CXString arg; 2871 int errorCode = 0; 2872 char *tmp; 2873 unsigned len; 2874 char *buildDir; 2875 int i, j, a, numCmds, numArgs; 2876 2877 len = strlen(database); 2878 tmp = (char *) malloc(len+1); 2879 memcpy(tmp, database, len+1); 2880 buildDir = dirname(tmp); 2881 2882 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec); 2883 2884 if (db) { 2885 2886 if (ec!=CXCompilationDatabase_NoError) { 2887 printf("unexpected error %d code while loading compilation database\n", ec); 2888 errorCode = -1; 2889 goto cdb_end; 2890 } 2891 2892 for (i=0; i<argc && errorCode==0; ) { 2893 if (strcmp(argv[i],"lookup")==0){ 2894 CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]); 2895 2896 if (!CCmds) { 2897 printf("file %s not found in compilation db\n", argv[i+1]); 2898 errorCode = -1; 2899 break; 2900 } 2901 2902 numCmds = clang_CompileCommands_getSize(CCmds); 2903 2904 if (numCmds==0) { 2905 fprintf(stderr, "should not get an empty compileCommand set for file" 2906 " '%s'\n", argv[i+1]); 2907 errorCode = -1; 2908 break; 2909 } 2910 2911 for (j=0; j<numCmds; ++j) { 2912 CCmd = clang_CompileCommands_getCommand(CCmds, j); 2913 2914 wd = clang_CompileCommand_getDirectory(CCmd); 2915 printf("workdir:'%s'", clang_getCString(wd)); 2916 clang_disposeString(wd); 2917 2918 printf(" cmdline:'"); 2919 numArgs = clang_CompileCommand_getNumArgs(CCmd); 2920 for (a=0; a<numArgs; ++a) { 2921 if (a) printf(" "); 2922 arg = clang_CompileCommand_getArg(CCmd, a); 2923 printf("%s", clang_getCString(arg)); 2924 clang_disposeString(arg); 2925 } 2926 printf("'\n"); 2927 } 2928 2929 clang_CompileCommands_dispose(CCmds); 2930 2931 i += 2; 2932 } 2933 } 2934 clang_CompilationDatabase_dispose(db); 2935 } else { 2936 printf("database loading failed with error code %d.\n", ec); 2937 errorCode = -1; 2938 } 2939 2940cdb_end: 2941 free(tmp); 2942 2943 return errorCode; 2944} 2945 2946/******************************************************************************/ 2947/* USR printing. */ 2948/******************************************************************************/ 2949 2950static int insufficient_usr(const char *kind, const char *usage) { 2951 fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage); 2952 return 1; 2953} 2954 2955static unsigned isUSR(const char *s) { 2956 return s[0] == 'c' && s[1] == ':'; 2957} 2958 2959static int not_usr(const char *s, const char *arg) { 2960 fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg); 2961 return 1; 2962} 2963 2964static void print_usr(CXString usr) { 2965 const char *s = clang_getCString(usr); 2966 printf("%s\n", s); 2967 clang_disposeString(usr); 2968} 2969 2970static void display_usrs() { 2971 fprintf(stderr, "-print-usrs options:\n" 2972 " ObjCCategory <class name> <category name>\n" 2973 " ObjCClass <class name>\n" 2974 " ObjCIvar <ivar name> <class USR>\n" 2975 " ObjCMethod <selector> [0=class method|1=instance method] " 2976 "<class USR>\n" 2977 " ObjCProperty <property name> <class USR>\n" 2978 " ObjCProtocol <protocol name>\n"); 2979} 2980 2981int print_usrs(const char **I, const char **E) { 2982 while (I != E) { 2983 const char *kind = *I; 2984 unsigned len = strlen(kind); 2985 switch (len) { 2986 case 8: 2987 if (memcmp(kind, "ObjCIvar", 8) == 0) { 2988 if (I + 2 >= E) 2989 return insufficient_usr(kind, "<ivar name> <class USR>"); 2990 if (!isUSR(I[2])) 2991 return not_usr("<class USR>", I[2]); 2992 else { 2993 CXString x; 2994 x.data = (void*) I[2]; 2995 x.private_flags = 0; 2996 print_usr(clang_constructUSR_ObjCIvar(I[1], x)); 2997 } 2998 2999 I += 3; 3000 continue; 3001 } 3002 break; 3003 case 9: 3004 if (memcmp(kind, "ObjCClass", 9) == 0) { 3005 if (I + 1 >= E) 3006 return insufficient_usr(kind, "<class name>"); 3007 print_usr(clang_constructUSR_ObjCClass(I[1])); 3008 I += 2; 3009 continue; 3010 } 3011 break; 3012 case 10: 3013 if (memcmp(kind, "ObjCMethod", 10) == 0) { 3014 if (I + 3 >= E) 3015 return insufficient_usr(kind, "<method selector> " 3016 "[0=class method|1=instance method] <class USR>"); 3017 if (!isUSR(I[3])) 3018 return not_usr("<class USR>", I[3]); 3019 else { 3020 CXString x; 3021 x.data = (void*) I[3]; 3022 x.private_flags = 0; 3023 print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x)); 3024 } 3025 I += 4; 3026 continue; 3027 } 3028 break; 3029 case 12: 3030 if (memcmp(kind, "ObjCCategory", 12) == 0) { 3031 if (I + 2 >= E) 3032 return insufficient_usr(kind, "<class name> <category name>"); 3033 print_usr(clang_constructUSR_ObjCCategory(I[1], I[2])); 3034 I += 3; 3035 continue; 3036 } 3037 if (memcmp(kind, "ObjCProtocol", 12) == 0) { 3038 if (I + 1 >= E) 3039 return insufficient_usr(kind, "<protocol name>"); 3040 print_usr(clang_constructUSR_ObjCProtocol(I[1])); 3041 I += 2; 3042 continue; 3043 } 3044 if (memcmp(kind, "ObjCProperty", 12) == 0) { 3045 if (I + 2 >= E) 3046 return insufficient_usr(kind, "<property name> <class USR>"); 3047 if (!isUSR(I[2])) 3048 return not_usr("<class USR>", I[2]); 3049 else { 3050 CXString x; 3051 x.data = (void*) I[2]; 3052 x.private_flags = 0; 3053 print_usr(clang_constructUSR_ObjCProperty(I[1], x)); 3054 } 3055 I += 3; 3056 continue; 3057 } 3058 break; 3059 default: 3060 break; 3061 } 3062 break; 3063 } 3064 3065 if (I != E) { 3066 fprintf(stderr, "Invalid USR kind: %s\n", *I); 3067 display_usrs(); 3068 return 1; 3069 } 3070 return 0; 3071} 3072 3073int print_usrs_file(const char *file_name) { 3074 char line[2048]; 3075 const char *args[128]; 3076 unsigned numChars = 0; 3077 3078 FILE *fp = fopen(file_name, "r"); 3079 if (!fp) { 3080 fprintf(stderr, "error: cannot open '%s'\n", file_name); 3081 return 1; 3082 } 3083 3084 /* This code is not really all that safe, but it works fine for testing. */ 3085 while (!feof(fp)) { 3086 char c = fgetc(fp); 3087 if (c == '\n') { 3088 unsigned i = 0; 3089 const char *s = 0; 3090 3091 if (numChars == 0) 3092 continue; 3093 3094 line[numChars] = '\0'; 3095 numChars = 0; 3096 3097 if (line[0] == '/' && line[1] == '/') 3098 continue; 3099 3100 s = strtok(line, " "); 3101 while (s) { 3102 args[i] = s; 3103 ++i; 3104 s = strtok(0, " "); 3105 } 3106 if (print_usrs(&args[0], &args[i])) 3107 return 1; 3108 } 3109 else 3110 line[numChars++] = c; 3111 } 3112 3113 fclose(fp); 3114 return 0; 3115} 3116 3117/******************************************************************************/ 3118/* Command line processing. */ 3119/******************************************************************************/ 3120int write_pch_file(const char *filename, int argc, const char *argv[]) { 3121 CXIndex Idx; 3122 CXTranslationUnit TU; 3123 struct CXUnsavedFile *unsaved_files = 0; 3124 int num_unsaved_files = 0; 3125 int result = 0; 3126 3127 Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1); 3128 3129 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { 3130 clang_disposeIndex(Idx); 3131 return -1; 3132 } 3133 3134 TU = clang_parseTranslationUnit(Idx, 0, 3135 argv + num_unsaved_files, 3136 argc - num_unsaved_files, 3137 unsaved_files, 3138 num_unsaved_files, 3139 CXTranslationUnit_Incomplete | 3140 CXTranslationUnit_ForSerialization); 3141 if (!TU) { 3142 fprintf(stderr, "Unable to load translation unit!\n"); 3143 free_remapped_files(unsaved_files, num_unsaved_files); 3144 clang_disposeIndex(Idx); 3145 return 1; 3146 } 3147 3148 switch (clang_saveTranslationUnit(TU, filename, 3149 clang_defaultSaveOptions(TU))) { 3150 case CXSaveError_None: 3151 break; 3152 3153 case CXSaveError_TranslationErrors: 3154 fprintf(stderr, "Unable to write PCH file %s: translation errors\n", 3155 filename); 3156 result = 2; 3157 break; 3158 3159 case CXSaveError_InvalidTU: 3160 fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n", 3161 filename); 3162 result = 3; 3163 break; 3164 3165 case CXSaveError_Unknown: 3166 default: 3167 fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename); 3168 result = 1; 3169 break; 3170 } 3171 3172 clang_disposeTranslationUnit(TU); 3173 free_remapped_files(unsaved_files, num_unsaved_files); 3174 clang_disposeIndex(Idx); 3175 return result; 3176} 3177 3178/******************************************************************************/ 3179/* Serialized diagnostics. */ 3180/******************************************************************************/ 3181 3182static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) { 3183 switch (error) { 3184 case CXLoadDiag_CannotLoad: return "Cannot Load File"; 3185 case CXLoadDiag_None: break; 3186 case CXLoadDiag_Unknown: return "Unknown"; 3187 case CXLoadDiag_InvalidFile: return "Invalid File"; 3188 } 3189 return "None"; 3190} 3191 3192static const char *getSeverityString(enum CXDiagnosticSeverity severity) { 3193 switch (severity) { 3194 case CXDiagnostic_Note: return "note"; 3195 case CXDiagnostic_Error: return "error"; 3196 case CXDiagnostic_Fatal: return "fatal"; 3197 case CXDiagnostic_Ignored: return "ignored"; 3198 case CXDiagnostic_Warning: return "warning"; 3199 } 3200 return "unknown"; 3201} 3202 3203static void printIndent(unsigned indent) { 3204 if (indent == 0) 3205 return; 3206 fprintf(stderr, "+"); 3207 --indent; 3208 while (indent > 0) { 3209 fprintf(stderr, "-"); 3210 --indent; 3211 } 3212} 3213 3214static void printLocation(CXSourceLocation L) { 3215 CXFile File; 3216 CXString FileName; 3217 unsigned line, column, offset; 3218 3219 clang_getExpansionLocation(L, &File, &line, &column, &offset); 3220 FileName = clang_getFileName(File); 3221 3222 fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column); 3223 clang_disposeString(FileName); 3224} 3225 3226static void printRanges(CXDiagnostic D, unsigned indent) { 3227 unsigned i, n = clang_getDiagnosticNumRanges(D); 3228 3229 for (i = 0; i < n; ++i) { 3230 CXSourceLocation Start, End; 3231 CXSourceRange SR = clang_getDiagnosticRange(D, i); 3232 Start = clang_getRangeStart(SR); 3233 End = clang_getRangeEnd(SR); 3234 3235 printIndent(indent); 3236 fprintf(stderr, "Range: "); 3237 printLocation(Start); 3238 fprintf(stderr, " "); 3239 printLocation(End); 3240 fprintf(stderr, "\n"); 3241 } 3242} 3243 3244static void printFixIts(CXDiagnostic D, unsigned indent) { 3245 unsigned i, n = clang_getDiagnosticNumFixIts(D); 3246 fprintf(stderr, "Number FIXITs = %d\n", n); 3247 for (i = 0 ; i < n; ++i) { 3248 CXSourceRange ReplacementRange; 3249 CXString text; 3250 text = clang_getDiagnosticFixIt(D, i, &ReplacementRange); 3251 3252 printIndent(indent); 3253 fprintf(stderr, "FIXIT: ("); 3254 printLocation(clang_getRangeStart(ReplacementRange)); 3255 fprintf(stderr, " - "); 3256 printLocation(clang_getRangeEnd(ReplacementRange)); 3257 fprintf(stderr, "): \"%s\"\n", clang_getCString(text)); 3258 clang_disposeString(text); 3259 } 3260} 3261 3262static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) { 3263 unsigned i, n; 3264 3265 if (!Diags) 3266 return; 3267 3268 n = clang_getNumDiagnosticsInSet(Diags); 3269 for (i = 0; i < n; ++i) { 3270 CXSourceLocation DiagLoc; 3271 CXDiagnostic D; 3272 CXFile File; 3273 CXString FileName, DiagSpelling, DiagOption, DiagCat; 3274 unsigned line, column, offset; 3275 const char *DiagOptionStr = 0, *DiagCatStr = 0; 3276 3277 D = clang_getDiagnosticInSet(Diags, i); 3278 DiagLoc = clang_getDiagnosticLocation(D); 3279 clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset); 3280 FileName = clang_getFileName(File); 3281 DiagSpelling = clang_getDiagnosticSpelling(D); 3282 3283 printIndent(indent); 3284 3285 fprintf(stderr, "%s:%d:%d: %s: %s", 3286 clang_getCString(FileName), 3287 line, 3288 column, 3289 getSeverityString(clang_getDiagnosticSeverity(D)), 3290 clang_getCString(DiagSpelling)); 3291 3292 DiagOption = clang_getDiagnosticOption(D, 0); 3293 DiagOptionStr = clang_getCString(DiagOption); 3294 if (DiagOptionStr) { 3295 fprintf(stderr, " [%s]", DiagOptionStr); 3296 } 3297 3298 DiagCat = clang_getDiagnosticCategoryText(D); 3299 DiagCatStr = clang_getCString(DiagCat); 3300 if (DiagCatStr) { 3301 fprintf(stderr, " [%s]", DiagCatStr); 3302 } 3303 3304 fprintf(stderr, "\n"); 3305 3306 printRanges(D, indent); 3307 printFixIts(D, indent); 3308 3309 /* Print subdiagnostics. */ 3310 printDiagnosticSet(clang_getChildDiagnostics(D), indent+2); 3311 3312 clang_disposeString(FileName); 3313 clang_disposeString(DiagSpelling); 3314 clang_disposeString(DiagOption); 3315 } 3316} 3317 3318static int read_diagnostics(const char *filename) { 3319 enum CXLoadDiag_Error error; 3320 CXString errorString; 3321 CXDiagnosticSet Diags = 0; 3322 3323 Diags = clang_loadDiagnostics(filename, &error, &errorString); 3324 if (!Diags) { 3325 fprintf(stderr, "Trouble deserializing file (%s): %s\n", 3326 getDiagnosticCodeStr(error), 3327 clang_getCString(errorString)); 3328 clang_disposeString(errorString); 3329 return 1; 3330 } 3331 3332 printDiagnosticSet(Diags, 0); 3333 fprintf(stderr, "Number of diagnostics: %d\n", 3334 clang_getNumDiagnosticsInSet(Diags)); 3335 clang_disposeDiagnosticSet(Diags); 3336 return 0; 3337} 3338 3339/******************************************************************************/ 3340/* Command line processing. */ 3341/******************************************************************************/ 3342 3343static CXCursorVisitor GetVisitor(const char *s) { 3344 if (s[0] == '\0') 3345 return FilteredPrintingVisitor; 3346 if (strcmp(s, "-usrs") == 0) 3347 return USRVisitor; 3348 if (strncmp(s, "-memory-usage", 13) == 0) 3349 return GetVisitor(s + 13); 3350 return NULL; 3351} 3352 3353static void print_usage(void) { 3354 fprintf(stderr, 3355 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" 3356 " c-index-test -code-completion-timing=<site> <compiler arguments>\n" 3357 " c-index-test -cursor-at=<site> <compiler arguments>\n" 3358 " c-index-test -file-refs-at=<site> <compiler arguments>\n"); 3359 fprintf(stderr, 3360 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n" 3361 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n" 3362 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n" 3363 " c-index-test -test-file-scan <AST file> <source file> " 3364 "[FileCheck prefix]\n"); 3365 fprintf(stderr, 3366 " c-index-test -test-load-tu <AST file> <symbol filter> " 3367 "[FileCheck prefix]\n" 3368 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> " 3369 "[FileCheck prefix]\n" 3370 " c-index-test -test-load-source <symbol filter> {<args>}*\n"); 3371 fprintf(stderr, 3372 " c-index-test -test-load-source-memory-usage " 3373 "<symbol filter> {<args>}*\n" 3374 " c-index-test -test-load-source-reparse <trials> <symbol filter> " 3375 " {<args>}*\n" 3376 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n" 3377 " c-index-test -test-load-source-usrs-memory-usage " 3378 "<symbol filter> {<args>}*\n" 3379 " c-index-test -test-annotate-tokens=<range> {<args>}*\n" 3380 " c-index-test -test-inclusion-stack-source {<args>}*\n" 3381 " c-index-test -test-inclusion-stack-tu <AST file>\n"); 3382 fprintf(stderr, 3383 " c-index-test -test-print-linkage-source {<args>}*\n" 3384 " c-index-test -test-print-typekind {<args>}*\n" 3385 " c-index-test -print-usr [<CursorKind> {<args>}]*\n" 3386 " c-index-test -print-usr-file <file>\n" 3387 " c-index-test -write-pch <file> <compiler arguments>\n"); 3388 fprintf(stderr, 3389 " c-index-test -compilation-db [lookup <filename>] database\n"); 3390 fprintf(stderr, 3391 " c-index-test -read-diagnostics <file>\n\n"); 3392 fprintf(stderr, 3393 " <symbol filter> values:\n%s", 3394 " all - load all symbols, including those from PCH\n" 3395 " local - load all symbols except those in PCH\n" 3396 " category - only load ObjC categories (non-PCH)\n" 3397 " interface - only load ObjC interfaces (non-PCH)\n" 3398 " protocol - only load ObjC protocols (non-PCH)\n" 3399 " function - only load functions (non-PCH)\n" 3400 " typedef - only load typdefs (non-PCH)\n" 3401 " scan-function - scan function bodies (non-PCH)\n\n"); 3402} 3403 3404/***/ 3405 3406int cindextest_main(int argc, const char **argv) { 3407 clang_enableStackTraces(); 3408 if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0) 3409 return read_diagnostics(argv[2]); 3410 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) 3411 return perform_code_completion(argc, argv, 0); 3412 if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1]) 3413 return perform_code_completion(argc, argv, 1); 3414 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1]) 3415 return inspect_cursor_at(argc, argv); 3416 if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1]) 3417 return find_file_refs_at(argc, argv); 3418 if (argc > 2 && strcmp(argv[1], "-index-file") == 0) 3419 return index_file(argc - 2, argv + 2, /*full=*/0); 3420 if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0) 3421 return index_file(argc - 2, argv + 2, /*full=*/1); 3422 if (argc > 2 && strcmp(argv[1], "-index-tu") == 0) 3423 return index_tu(argc - 2, argv + 2); 3424 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) { 3425 CXCursorVisitor I = GetVisitor(argv[1] + 13); 3426 if (I) 3427 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I, 3428 NULL); 3429 } 3430 else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){ 3431 CXCursorVisitor I = GetVisitor(argv[1] + 25); 3432 if (I) { 3433 int trials = atoi(argv[2]); 3434 return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I, 3435 NULL); 3436 } 3437 } 3438 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { 3439 CXCursorVisitor I = GetVisitor(argv[1] + 17); 3440 3441 PostVisitTU postVisit = 0; 3442 if (strstr(argv[1], "-memory-usage")) 3443 postVisit = PrintMemoryUsage; 3444 3445 if (I) 3446 return perform_test_load_source(argc - 3, argv + 3, argv[2], I, 3447 postVisit); 3448 } 3449 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) 3450 return perform_file_scan(argv[2], argv[3], 3451 argc >= 5 ? argv[4] : 0); 3452 else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1]) 3453 return perform_token_annotation(argc, argv); 3454 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0) 3455 return perform_test_load_source(argc - 2, argv + 2, "all", NULL, 3456 PrintInclusionStack); 3457 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0) 3458 return perform_test_load_tu(argv[2], "all", NULL, NULL, 3459 PrintInclusionStack); 3460 else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) 3461 return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, 3462 NULL); 3463 else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0) 3464 return perform_test_load_source(argc - 2, argv + 2, "all", 3465 PrintTypeKind, 0); 3466 else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { 3467 if (argc > 2) 3468 return print_usrs(argv + 2, argv + argc); 3469 else { 3470 display_usrs(); 3471 return 1; 3472 } 3473 } 3474 else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0) 3475 return print_usrs_file(argv[2]); 3476 else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0) 3477 return write_pch_file(argv[2], argc - 3, argv + 3); 3478 else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0) 3479 return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2); 3480 3481 print_usage(); 3482 return 1; 3483} 3484 3485/***/ 3486 3487/* We intentionally run in a separate thread to ensure we at least minimal 3488 * testing of a multithreaded environment (for example, having a reduced stack 3489 * size). */ 3490 3491typedef struct thread_info { 3492 int argc; 3493 const char **argv; 3494 int result; 3495} thread_info; 3496void thread_runner(void *client_data_v) { 3497 thread_info *client_data = client_data_v; 3498 client_data->result = cindextest_main(client_data->argc, client_data->argv); 3499#ifdef __CYGWIN__ 3500 fflush(stdout); /* stdout is not flushed on Cygwin. */ 3501#endif 3502} 3503 3504int main(int argc, const char **argv) { 3505 thread_info client_data; 3506 3507#ifdef CLANG_HAVE_LIBXML 3508 LIBXML_TEST_VERSION 3509#endif 3510 3511 if (getenv("CINDEXTEST_NOTHREADS")) 3512 return cindextest_main(argc, argv); 3513 3514 client_data.argc = argc; 3515 client_data.argv = argv; 3516 clang_executeOnThread(thread_runner, &client_data, 0); 3517 return client_data.result; 3518} 3519