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