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