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