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