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