c-index-test.c revision df95a13ec73d2cdaea79555cb412d767f4963120
1/* c-index-test.c */ 2 3#include "clang-c/Index.h" 4#include <stdlib.h> 5#include <stdio.h> 6#include <string.h> 7#include <assert.h> 8 9/******************************************************************************/ 10/* Utility functions. */ 11/******************************************************************************/ 12 13#ifdef _MSC_VER 14char *basename(const char* path) 15{ 16 char* base1 = (char*)strrchr(path, '/'); 17 char* base2 = (char*)strrchr(path, '\\'); 18 if (base1 && base2) 19 return((base1 > base2) ? base1 + 1 : base2 + 1); 20 else if (base1) 21 return(base1 + 1); 22 else if (base2) 23 return(base2 + 1); 24 25 return((char*)path); 26} 27#else 28extern char *basename(const char *); 29#endif 30 31/** \brief Return the default parsing options. */ 32static unsigned getDefaultParsingOptions() { 33 unsigned options = CXTranslationUnit_DetailedPreprocessingRecord; 34 35 if (getenv("CINDEXTEST_EDITING")) 36 options |= CXTranslationUnit_Editing; 37 38 return options; 39} 40 41static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column, 42 unsigned end_line, unsigned end_column) { 43 fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column, 44 end_line, end_column); 45} 46 47static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, 48 CXTranslationUnit *TU) { 49 50 *TU = clang_createTranslationUnit(Idx, file); 51 if (!*TU) { 52 fprintf(stderr, "Unable to load translation unit from '%s'!\n", file); 53 return 0; 54 } 55 return 1; 56} 57 58void free_remapped_files(struct CXUnsavedFile *unsaved_files, 59 int num_unsaved_files) { 60 int i; 61 for (i = 0; i != num_unsaved_files; ++i) { 62 free((char *)unsaved_files[i].Filename); 63 free((char *)unsaved_files[i].Contents); 64 } 65} 66 67int parse_remapped_files(int argc, const char **argv, int start_arg, 68 struct CXUnsavedFile **unsaved_files, 69 int *num_unsaved_files) { 70 int i; 71 int arg; 72 int prefix_len = strlen("-remap-file="); 73 *unsaved_files = 0; 74 *num_unsaved_files = 0; 75 76 /* Count the number of remapped files. */ 77 for (arg = start_arg; arg < argc; ++arg) { 78 if (strncmp(argv[arg], "-remap-file=", prefix_len)) 79 break; 80 81 ++*num_unsaved_files; 82 } 83 84 if (*num_unsaved_files == 0) 85 return 0; 86 87 *unsaved_files 88 = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * 89 *num_unsaved_files); 90 for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { 91 struct CXUnsavedFile *unsaved = *unsaved_files + i; 92 const char *arg_string = argv[arg] + prefix_len; 93 int filename_len; 94 char *filename; 95 char *contents; 96 FILE *to_file; 97 const char *semi = strchr(arg_string, ';'); 98 if (!semi) { 99 fprintf(stderr, 100 "error: -remap-file=from;to argument is missing semicolon\n"); 101 free_remapped_files(*unsaved_files, i); 102 *unsaved_files = 0; 103 *num_unsaved_files = 0; 104 return -1; 105 } 106 107 /* Open the file that we're remapping to. */ 108 to_file = fopen(semi + 1, "r"); 109 if (!to_file) { 110 fprintf(stderr, "error: cannot open file %s that we are remapping to\n", 111 semi + 1); 112 free_remapped_files(*unsaved_files, i); 113 *unsaved_files = 0; 114 *num_unsaved_files = 0; 115 return -1; 116 } 117 118 /* Determine the length of the file we're remapping to. */ 119 fseek(to_file, 0, SEEK_END); 120 unsaved->Length = ftell(to_file); 121 fseek(to_file, 0, SEEK_SET); 122 123 /* Read the contents of the file we're remapping to. */ 124 contents = (char *)malloc(unsaved->Length + 1); 125 if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { 126 fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", 127 (feof(to_file) ? "EOF" : "error"), semi + 1); 128 fclose(to_file); 129 free_remapped_files(*unsaved_files, i); 130 *unsaved_files = 0; 131 *num_unsaved_files = 0; 132 return -1; 133 } 134 contents[unsaved->Length] = 0; 135 unsaved->Contents = contents; 136 137 /* Close the file. */ 138 fclose(to_file); 139 140 /* Copy the file name that we're remapping from. */ 141 filename_len = semi - arg_string; 142 filename = (char *)malloc(filename_len + 1); 143 memcpy(filename, arg_string, filename_len); 144 filename[filename_len] = 0; 145 unsaved->Filename = filename; 146 } 147 148 return 0; 149} 150 151/******************************************************************************/ 152/* Pretty-printing. */ 153/******************************************************************************/ 154 155static void PrintCursor(CXCursor Cursor) { 156 if (clang_isInvalid(Cursor.kind)) { 157 CXString ks = clang_getCursorKindSpelling(Cursor.kind); 158 printf("Invalid Cursor => %s", clang_getCString(ks)); 159 clang_disposeString(ks); 160 } 161 else { 162 CXString string, ks; 163 CXCursor Referenced; 164 unsigned line, column; 165 166 ks = clang_getCursorKindSpelling(Cursor.kind); 167 string = clang_getCursorSpelling(Cursor); 168 printf("%s=%s", clang_getCString(ks), 169 clang_getCString(string)); 170 clang_disposeString(ks); 171 clang_disposeString(string); 172 173 Referenced = clang_getCursorReferenced(Cursor); 174 if (!clang_equalCursors(Referenced, clang_getNullCursor())) { 175 CXSourceLocation Loc = clang_getCursorLocation(Referenced); 176 clang_getInstantiationLocation(Loc, 0, &line, &column, 0); 177 printf(":%d:%d", line, column); 178 } 179 180 if (clang_isCursorDefinition(Cursor)) 181 printf(" (Definition)"); 182 } 183} 184 185static const char* GetCursorSource(CXCursor Cursor) { 186 CXSourceLocation Loc = clang_getCursorLocation(Cursor); 187 CXString source; 188 CXFile file; 189 clang_getInstantiationLocation(Loc, &file, 0, 0, 0); 190 source = clang_getFileName(file); 191 if (!clang_getCString(source)) { 192 clang_disposeString(source); 193 return "<invalid loc>"; 194 } 195 else { 196 const char *b = basename(clang_getCString(source)); 197 clang_disposeString(source); 198 return b; 199 } 200} 201 202/******************************************************************************/ 203/* Callbacks. */ 204/******************************************************************************/ 205 206typedef void (*PostVisitTU)(CXTranslationUnit); 207 208void PrintDiagnostic(CXDiagnostic Diagnostic) { 209 FILE *out = stderr; 210 CXFile file; 211 CXString Msg; 212 unsigned display_opts = CXDiagnostic_DisplaySourceLocation 213 | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges; 214 unsigned i, num_fixits; 215 216 if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored) 217 return; 218 219 Msg = clang_formatDiagnostic(Diagnostic, display_opts); 220 fprintf(stderr, "%s\n", clang_getCString(Msg)); 221 clang_disposeString(Msg); 222 223 clang_getInstantiationLocation(clang_getDiagnosticLocation(Diagnostic), 224 &file, 0, 0, 0); 225 if (!file) 226 return; 227 228 num_fixits = clang_getDiagnosticNumFixIts(Diagnostic); 229 for (i = 0; i != num_fixits; ++i) { 230 CXSourceRange range; 231 CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range); 232 CXSourceLocation start = clang_getRangeStart(range); 233 CXSourceLocation end = clang_getRangeEnd(range); 234 unsigned start_line, start_column, end_line, end_column; 235 CXFile start_file, end_file; 236 clang_getInstantiationLocation(start, &start_file, &start_line, 237 &start_column, 0); 238 clang_getInstantiationLocation(end, &end_file, &end_line, &end_column, 0); 239 if (clang_equalLocations(start, end)) { 240 /* Insertion. */ 241 if (start_file == file) 242 fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n", 243 clang_getCString(insertion_text), start_line, start_column); 244 } else if (strcmp(clang_getCString(insertion_text), "") == 0) { 245 /* Removal. */ 246 if (start_file == file && end_file == file) { 247 fprintf(out, "FIX-IT: Remove "); 248 PrintExtent(out, start_line, start_column, end_line, end_column); 249 fprintf(out, "\n"); 250 } 251 } else { 252 /* Replacement. */ 253 if (start_file == end_file) { 254 fprintf(out, "FIX-IT: Replace "); 255 PrintExtent(out, start_line, start_column, end_line, end_column); 256 fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text)); 257 } 258 break; 259 } 260 clang_disposeString(insertion_text); 261 } 262} 263 264void PrintDiagnostics(CXTranslationUnit TU) { 265 int i, n = clang_getNumDiagnostics(TU); 266 for (i = 0; i != n; ++i) { 267 CXDiagnostic Diag = clang_getDiagnostic(TU, i); 268 PrintDiagnostic(Diag); 269 clang_disposeDiagnostic(Diag); 270 } 271} 272 273/******************************************************************************/ 274/* Logic for testing traversal. */ 275/******************************************************************************/ 276 277static const char *FileCheckPrefix = "CHECK"; 278 279static void PrintCursorExtent(CXCursor C) { 280 CXSourceRange extent = clang_getCursorExtent(C); 281 CXFile begin_file, end_file; 282 unsigned begin_line, begin_column, end_line, end_column; 283 284 clang_getInstantiationLocation(clang_getRangeStart(extent), 285 &begin_file, &begin_line, &begin_column, 0); 286 clang_getInstantiationLocation(clang_getRangeEnd(extent), 287 &end_file, &end_line, &end_column, 0); 288 if (!begin_file || !end_file) 289 return; 290 291 printf(" Extent="); 292 PrintExtent(stdout, begin_line, begin_column, end_line, end_column); 293} 294 295/* Data used by all of the visitors. */ 296typedef struct { 297 CXTranslationUnit TU; 298 enum CXCursorKind *Filter; 299} VisitorData; 300 301 302enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor, 303 CXCursor Parent, 304 CXClientData ClientData) { 305 VisitorData *Data = (VisitorData *)ClientData; 306 if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) { 307 CXSourceLocation Loc = clang_getCursorLocation(Cursor); 308 unsigned line, column; 309 clang_getInstantiationLocation(Loc, 0, &line, &column, 0); 310 printf("// %s: %s:%d:%d: ", FileCheckPrefix, 311 GetCursorSource(Cursor), line, column); 312 PrintCursor(Cursor); 313 PrintCursorExtent(Cursor); 314 printf("\n"); 315 return CXChildVisit_Recurse; 316 } 317 318 return CXChildVisit_Continue; 319} 320 321static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor, 322 CXCursor Parent, 323 CXClientData ClientData) { 324 const char *startBuf, *endBuf; 325 unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn; 326 CXCursor Ref; 327 VisitorData *Data = (VisitorData *)ClientData; 328 329 if (Cursor.kind != CXCursor_FunctionDecl || 330 !clang_isCursorDefinition(Cursor)) 331 return CXChildVisit_Continue; 332 333 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf, 334 &startLine, &startColumn, 335 &endLine, &endColumn); 336 /* Probe the entire body, looking for both decls and refs. */ 337 curLine = startLine; 338 curColumn = startColumn; 339 340 while (startBuf < endBuf) { 341 CXSourceLocation Loc; 342 CXFile file; 343 CXString source; 344 345 if (*startBuf == '\n') { 346 startBuf++; 347 curLine++; 348 curColumn = 1; 349 } else if (*startBuf != '\t') 350 curColumn++; 351 352 Loc = clang_getCursorLocation(Cursor); 353 clang_getInstantiationLocation(Loc, &file, 0, 0, 0); 354 355 source = clang_getFileName(file); 356 if (clang_getCString(source)) { 357 CXSourceLocation RefLoc 358 = clang_getLocation(Data->TU, file, curLine, curColumn); 359 Ref = clang_getCursor(Data->TU, RefLoc); 360 if (Ref.kind == CXCursor_NoDeclFound) { 361 /* Nothing found here; that's fine. */ 362 } else if (Ref.kind != CXCursor_FunctionDecl) { 363 printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), 364 curLine, curColumn); 365 PrintCursor(Ref); 366 printf("\n"); 367 } 368 } 369 clang_disposeString(source); 370 startBuf++; 371 } 372 373 return CXChildVisit_Continue; 374} 375 376/******************************************************************************/ 377/* USR testing. */ 378/******************************************************************************/ 379 380enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent, 381 CXClientData ClientData) { 382 VisitorData *Data = (VisitorData *)ClientData; 383 if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) { 384 CXString USR = clang_getCursorUSR(C); 385 const char *cstr = clang_getCString(USR); 386 if (!cstr || cstr[0] == '\0') { 387 clang_disposeString(USR); 388 return CXChildVisit_Recurse; 389 } 390 printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr); 391 392 PrintCursorExtent(C); 393 printf("\n"); 394 clang_disposeString(USR); 395 396 return CXChildVisit_Recurse; 397 } 398 399 return CXChildVisit_Continue; 400} 401 402/******************************************************************************/ 403/* Inclusion stack testing. */ 404/******************************************************************************/ 405 406void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack, 407 unsigned includeStackLen, CXClientData data) { 408 409 unsigned i; 410 CXString fname; 411 412 fname = clang_getFileName(includedFile); 413 printf("file: %s\nincluded by:\n", clang_getCString(fname)); 414 clang_disposeString(fname); 415 416 for (i = 0; i < includeStackLen; ++i) { 417 CXFile includingFile; 418 unsigned line, column; 419 clang_getInstantiationLocation(includeStack[i], &includingFile, &line, 420 &column, 0); 421 fname = clang_getFileName(includingFile); 422 printf(" %s:%d:%d\n", clang_getCString(fname), line, column); 423 clang_disposeString(fname); 424 } 425 printf("\n"); 426} 427 428void PrintInclusionStack(CXTranslationUnit TU) { 429 clang_getInclusions(TU, InclusionVisitor, NULL); 430} 431 432/******************************************************************************/ 433/* Linkage testing. */ 434/******************************************************************************/ 435 436static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, 437 CXClientData d) { 438 const char *linkage = 0; 439 440 if (clang_isInvalid(clang_getCursorKind(cursor))) 441 return CXChildVisit_Recurse; 442 443 switch (clang_getCursorLinkage(cursor)) { 444 case CXLinkage_Invalid: break; 445 case CXLinkage_NoLinkage: linkage = "NoLinkage"; break; 446 case CXLinkage_Internal: linkage = "Internal"; break; 447 case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break; 448 case CXLinkage_External: linkage = "External"; break; 449 } 450 451 if (linkage) { 452 PrintCursor(cursor); 453 printf("linkage=%s\n", linkage); 454 } 455 456 return CXChildVisit_Recurse; 457} 458 459/******************************************************************************/ 460/* Typekind testing. */ 461/******************************************************************************/ 462 463static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, 464 CXClientData d) { 465 466 if (!clang_isInvalid(clang_getCursorKind(cursor))) { 467 CXType T = clang_getCursorType(cursor); 468 CXString S = clang_getTypeKindSpelling(T.kind); 469 PrintCursor(cursor); 470 printf(" typekind=%s", clang_getCString(S)); 471 clang_disposeString(S); 472 /* Print the canonical type if it is different. */ 473 { 474 CXType CT = clang_getCanonicalType(T); 475 if (!clang_equalTypes(T, CT)) { 476 CXString CS = clang_getTypeKindSpelling(CT.kind); 477 printf(" [canonical=%s]", clang_getCString(CS)); 478 clang_disposeString(CS); 479 } 480 } 481 /* Print the return type if it exists. */ 482 { 483 CXType RT = clang_getCursorResultType(cursor); 484 if (RT.kind != CXType_Invalid) { 485 CXString RS = clang_getTypeKindSpelling(RT.kind); 486 printf(" [result=%s]", clang_getCString(RS)); 487 clang_disposeString(RS); 488 } 489 } 490 /* Print if this is a non-POD type. */ 491 printf(" [isPOD=%d]", clang_isPODType(T)); 492 493 printf("\n"); 494 } 495 return CXChildVisit_Recurse; 496} 497 498 499/******************************************************************************/ 500/* Loading ASTs/source. */ 501/******************************************************************************/ 502 503static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, 504 const char *filter, const char *prefix, 505 CXCursorVisitor Visitor, 506 PostVisitTU PV) { 507 508 if (prefix) 509 FileCheckPrefix = prefix; 510 511 if (Visitor) { 512 enum CXCursorKind K = CXCursor_NotImplemented; 513 enum CXCursorKind *ck = &K; 514 VisitorData Data; 515 516 /* Perform some simple filtering. */ 517 if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL; 518 else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0; 519 else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; 520 else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl; 521 else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl; 522 else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl; 523 else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl; 524 else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor; 525 else { 526 fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter); 527 return 1; 528 } 529 530 Data.TU = TU; 531 Data.Filter = ck; 532 clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data); 533 } 534 535 if (PV) 536 PV(TU); 537 538 PrintDiagnostics(TU); 539 clang_disposeTranslationUnit(TU); 540 return 0; 541} 542 543int perform_test_load_tu(const char *file, const char *filter, 544 const char *prefix, CXCursorVisitor Visitor, 545 PostVisitTU PV) { 546 CXIndex Idx; 547 CXTranslationUnit TU; 548 int result; 549 Idx = clang_createIndex(/* excludeDeclsFromPCH */ 550 !strcmp(filter, "local") ? 1 : 0, 551 /* displayDiagnosics=*/1); 552 553 if (!CreateTranslationUnit(Idx, file, &TU)) { 554 clang_disposeIndex(Idx); 555 return 1; 556 } 557 558 result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV); 559 clang_disposeIndex(Idx); 560 return result; 561} 562 563int perform_test_load_source(int argc, const char **argv, 564 const char *filter, CXCursorVisitor Visitor, 565 PostVisitTU PV) { 566 const char *UseExternalASTs = 567 getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); 568 CXIndex Idx; 569 CXTranslationUnit TU; 570 struct CXUnsavedFile *unsaved_files = 0; 571 int num_unsaved_files = 0; 572 int result; 573 574 Idx = clang_createIndex(/* excludeDeclsFromPCH */ 575 !strcmp(filter, "local") ? 1 : 0, 576 /* displayDiagnosics=*/1); 577 578 if (UseExternalASTs && strlen(UseExternalASTs)) 579 clang_setUseExternalASTGeneration(Idx, 1); 580 581 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { 582 clang_disposeIndex(Idx); 583 return -1; 584 } 585 586 TU = clang_createTranslationUnitFromSourceFile(Idx, 0, 587 argc - num_unsaved_files, 588 argv + num_unsaved_files, 589 num_unsaved_files, 590 unsaved_files); 591 if (!TU) { 592 fprintf(stderr, "Unable to load translation unit!\n"); 593 free_remapped_files(unsaved_files, num_unsaved_files); 594 clang_disposeIndex(Idx); 595 return 1; 596 } 597 598 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV); 599 free_remapped_files(unsaved_files, num_unsaved_files); 600 clang_disposeIndex(Idx); 601 return result; 602} 603 604int perform_test_reparse_source(int argc, const char **argv, int trials, 605 const char *filter, CXCursorVisitor Visitor, 606 PostVisitTU PV) { 607 const char *UseExternalASTs = 608 getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); 609 CXIndex Idx; 610 CXTranslationUnit TU; 611 struct CXUnsavedFile *unsaved_files = 0; 612 int num_unsaved_files = 0; 613 int result; 614 int trial; 615 616 Idx = clang_createIndex(/* excludeDeclsFromPCH */ 617 !strcmp(filter, "local") ? 1 : 0, 618 /* displayDiagnosics=*/1); 619 620 if (UseExternalASTs && strlen(UseExternalASTs)) 621 clang_setUseExternalASTGeneration(Idx, 1); 622 623 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { 624 clang_disposeIndex(Idx); 625 return -1; 626 } 627 628 TU = clang_parseTranslationUnit(Idx, 0, 629 argv + num_unsaved_files, 630 argc - num_unsaved_files, 631 unsaved_files, 632 num_unsaved_files, 633 getDefaultParsingOptions()); 634 if (!TU) { 635 fprintf(stderr, "Unable to load translation unit!\n"); 636 free_remapped_files(unsaved_files, num_unsaved_files); 637 clang_disposeIndex(Idx); 638 return 1; 639 } 640 641 for (trial = 0; trial < trials; ++trial) { 642 if (clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files)) { 643 clang_disposeTranslationUnit(TU); 644 free_remapped_files(unsaved_files, num_unsaved_files); 645 clang_disposeIndex(Idx); 646 return -1; 647 } 648 } 649 650 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV); 651 free_remapped_files(unsaved_files, num_unsaved_files); 652 clang_disposeIndex(Idx); 653 return result; 654} 655 656/******************************************************************************/ 657/* Logic for testing clang_getCursor(). */ 658/******************************************************************************/ 659 660static void print_cursor_file_scan(CXCursor cursor, 661 unsigned start_line, unsigned start_col, 662 unsigned end_line, unsigned end_col, 663 const char *prefix) { 664 printf("// %s: ", FileCheckPrefix); 665 if (prefix) 666 printf("-%s", prefix); 667 PrintExtent(stdout, start_line, start_col, end_line, end_col); 668 printf(" "); 669 PrintCursor(cursor); 670 printf("\n"); 671} 672 673static int perform_file_scan(const char *ast_file, const char *source_file, 674 const char *prefix) { 675 CXIndex Idx; 676 CXTranslationUnit TU; 677 FILE *fp; 678 CXCursor prevCursor = clang_getNullCursor(); 679 CXFile file; 680 unsigned line = 1, col = 1; 681 unsigned start_line = 1, start_col = 1; 682 683 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, 684 /* displayDiagnosics=*/1))) { 685 fprintf(stderr, "Could not create Index\n"); 686 return 1; 687 } 688 689 if (!CreateTranslationUnit(Idx, ast_file, &TU)) 690 return 1; 691 692 if ((fp = fopen(source_file, "r")) == NULL) { 693 fprintf(stderr, "Could not open '%s'\n", source_file); 694 return 1; 695 } 696 697 file = clang_getFile(TU, source_file); 698 for (;;) { 699 CXCursor cursor; 700 int c = fgetc(fp); 701 702 if (c == '\n') { 703 ++line; 704 col = 1; 705 } else 706 ++col; 707 708 /* Check the cursor at this position, and dump the previous one if we have 709 * found something new. 710 */ 711 cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col)); 712 if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) && 713 prevCursor.kind != CXCursor_InvalidFile) { 714 print_cursor_file_scan(prevCursor, start_line, start_col, 715 line, col, prefix); 716 start_line = line; 717 start_col = col; 718 } 719 if (c == EOF) 720 break; 721 722 prevCursor = cursor; 723 } 724 725 fclose(fp); 726 return 0; 727} 728 729/******************************************************************************/ 730/* Logic for testing clang_codeComplete(). */ 731/******************************************************************************/ 732 733/* Parse file:line:column from the input string. Returns 0 on success, non-zero 734 on failure. If successful, the pointer *filename will contain newly-allocated 735 memory (that will be owned by the caller) to store the file name. */ 736int parse_file_line_column(const char *input, char **filename, unsigned *line, 737 unsigned *column, unsigned *second_line, 738 unsigned *second_column) { 739 /* Find the second colon. */ 740 const char *last_colon = strrchr(input, ':'); 741 unsigned values[4], i; 742 unsigned num_values = (second_line && second_column)? 4 : 2; 743 744 char *endptr = 0; 745 if (!last_colon || last_colon == input) { 746 if (num_values == 4) 747 fprintf(stderr, "could not parse filename:line:column:line:column in " 748 "'%s'\n", input); 749 else 750 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input); 751 return 1; 752 } 753 754 for (i = 0; i != num_values; ++i) { 755 const char *prev_colon; 756 757 /* Parse the next line or column. */ 758 values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10); 759 if (*endptr != 0 && *endptr != ':') { 760 fprintf(stderr, "could not parse %s in '%s'\n", 761 (i % 2 ? "column" : "line"), input); 762 return 1; 763 } 764 765 if (i + 1 == num_values) 766 break; 767 768 /* Find the previous colon. */ 769 prev_colon = last_colon - 1; 770 while (prev_colon != input && *prev_colon != ':') 771 --prev_colon; 772 if (prev_colon == input) { 773 fprintf(stderr, "could not parse %s in '%s'\n", 774 (i % 2 == 0? "column" : "line"), input); 775 return 1; 776 } 777 778 last_colon = prev_colon; 779 } 780 781 *line = values[0]; 782 *column = values[1]; 783 784 if (second_line && second_column) { 785 *second_line = values[2]; 786 *second_column = values[3]; 787 } 788 789 /* Copy the file name. */ 790 *filename = (char*)malloc(last_colon - input + 1); 791 memcpy(*filename, input, last_colon - input); 792 (*filename)[last_colon - input] = 0; 793 return 0; 794} 795 796const char * 797clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { 798 switch (Kind) { 799 case CXCompletionChunk_Optional: return "Optional"; 800 case CXCompletionChunk_TypedText: return "TypedText"; 801 case CXCompletionChunk_Text: return "Text"; 802 case CXCompletionChunk_Placeholder: return "Placeholder"; 803 case CXCompletionChunk_Informative: return "Informative"; 804 case CXCompletionChunk_CurrentParameter: return "CurrentParameter"; 805 case CXCompletionChunk_LeftParen: return "LeftParen"; 806 case CXCompletionChunk_RightParen: return "RightParen"; 807 case CXCompletionChunk_LeftBracket: return "LeftBracket"; 808 case CXCompletionChunk_RightBracket: return "RightBracket"; 809 case CXCompletionChunk_LeftBrace: return "LeftBrace"; 810 case CXCompletionChunk_RightBrace: return "RightBrace"; 811 case CXCompletionChunk_LeftAngle: return "LeftAngle"; 812 case CXCompletionChunk_RightAngle: return "RightAngle"; 813 case CXCompletionChunk_Comma: return "Comma"; 814 case CXCompletionChunk_ResultType: return "ResultType"; 815 case CXCompletionChunk_Colon: return "Colon"; 816 case CXCompletionChunk_SemiColon: return "SemiColon"; 817 case CXCompletionChunk_Equal: return "Equal"; 818 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; 819 case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; 820 } 821 822 return "Unknown"; 823} 824 825void print_completion_string(CXCompletionString completion_string, FILE *file) { 826 int I, N; 827 828 N = clang_getNumCompletionChunks(completion_string); 829 for (I = 0; I != N; ++I) { 830 CXString text; 831 const char *cstr; 832 enum CXCompletionChunkKind Kind 833 = clang_getCompletionChunkKind(completion_string, I); 834 835 if (Kind == CXCompletionChunk_Optional) { 836 fprintf(file, "{Optional "); 837 print_completion_string( 838 clang_getCompletionChunkCompletionString(completion_string, I), 839 file); 840 fprintf(file, "}"); 841 continue; 842 } 843 844 text = clang_getCompletionChunkText(completion_string, I); 845 cstr = clang_getCString(text); 846 fprintf(file, "{%s %s}", 847 clang_getCompletionChunkKindSpelling(Kind), 848 cstr ? cstr : ""); 849 clang_disposeString(text); 850 } 851 852} 853 854void print_completion_result(CXCompletionResult *completion_result, 855 CXClientData client_data) { 856 FILE *file = (FILE *)client_data; 857 CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind); 858 859 fprintf(file, "%s:", clang_getCString(ks)); 860 clang_disposeString(ks); 861 862 print_completion_string(completion_result->CompletionString, file); 863 fprintf(file, " (%u)\n", 864 clang_getCompletionPriority(completion_result->CompletionString)); 865} 866 867int perform_code_completion(int argc, const char **argv, int timing_only) { 868 const char *input = argv[1]; 869 char *filename = 0; 870 unsigned line; 871 unsigned column; 872 CXIndex CIdx; 873 int errorCode; 874 struct CXUnsavedFile *unsaved_files = 0; 875 int num_unsaved_files = 0; 876 CXCodeCompleteResults *results = 0; 877 CXTranslationUnit *TU = 0; 878 879 if (timing_only) 880 input += strlen("-code-completion-timing="); 881 else 882 input += strlen("-code-completion-at="); 883 884 if ((errorCode = parse_file_line_column(input, &filename, &line, &column, 885 0, 0))) 886 return errorCode; 887 888 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) 889 return -1; 890 891 CIdx = clang_createIndex(0, 1); 892 if (getenv("CINDEXTEST_EDITING")) { 893 TU = clang_parseTranslationUnit(CIdx, 0, 894 argv + num_unsaved_files + 2, 895 argc - num_unsaved_files - 2, 896 unsaved_files, 897 num_unsaved_files, 898 getDefaultParsingOptions()); 899 unsigned I, Repeats = 5; 900 for (I = 0; I != Repeats; ++I) { 901 results = clang_codeCompleteAt(TU, filename, line, column, 902 unsaved_files, num_unsaved_files, 903 clang_defaultCodeCompleteOptions()); 904 if (I != Repeats-1) 905 clang_disposeCodeCompleteResults(results); 906 } 907 } else 908 results = clang_codeComplete(CIdx, 909 argv[argc - 1], argc - num_unsaved_files - 3, 910 argv + num_unsaved_files + 2, 911 num_unsaved_files, unsaved_files, 912 filename, line, column); 913 914 if (results) { 915 unsigned i, n = results->NumResults; 916 if (!timing_only) 917 for (i = 0; i != n; ++i) 918 print_completion_result(results->Results + i, stdout); 919 n = clang_codeCompleteGetNumDiagnostics(results); 920 for (i = 0; i != n; ++i) { 921 CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i); 922 PrintDiagnostic(diag); 923 clang_disposeDiagnostic(diag); 924 } 925 clang_disposeCodeCompleteResults(results); 926 } 927 clang_disposeTranslationUnit(TU); 928 clang_disposeIndex(CIdx); 929 free(filename); 930 931 free_remapped_files(unsaved_files, num_unsaved_files); 932 933 return 0; 934} 935 936typedef struct { 937 char *filename; 938 unsigned line; 939 unsigned column; 940} CursorSourceLocation; 941 942int inspect_cursor_at(int argc, const char **argv) { 943 CXIndex CIdx; 944 int errorCode; 945 struct CXUnsavedFile *unsaved_files = 0; 946 int num_unsaved_files = 0; 947 CXTranslationUnit TU; 948 CXCursor Cursor; 949 CursorSourceLocation *Locations = 0; 950 unsigned NumLocations = 0, Loc; 951 952 /* Count the number of locations. */ 953 while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1]) 954 ++NumLocations; 955 956 /* Parse the locations. */ 957 assert(NumLocations > 0 && "Unable to count locations?"); 958 Locations = (CursorSourceLocation *)malloc( 959 NumLocations * sizeof(CursorSourceLocation)); 960 for (Loc = 0; Loc < NumLocations; ++Loc) { 961 const char *input = argv[Loc + 1] + strlen("-cursor-at="); 962 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, 963 &Locations[Loc].line, 964 &Locations[Loc].column, 0, 0))) 965 return errorCode; 966 } 967 968 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, 969 &num_unsaved_files)) 970 return -1; 971 972 CIdx = clang_createIndex(0, 1); 973 TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], 974 argc - num_unsaved_files - 2 - NumLocations, 975 argv + num_unsaved_files + 1 + NumLocations, 976 num_unsaved_files, 977 unsaved_files); 978 if (!TU) { 979 fprintf(stderr, "unable to parse input\n"); 980 return -1; 981 } 982 983 for (Loc = 0; Loc < NumLocations; ++Loc) { 984 CXFile file = clang_getFile(TU, Locations[Loc].filename); 985 if (!file) 986 continue; 987 988 Cursor = clang_getCursor(TU, 989 clang_getLocation(TU, file, Locations[Loc].line, 990 Locations[Loc].column)); 991 PrintCursor(Cursor); 992 printf("\n"); 993 free(Locations[Loc].filename); 994 } 995 996 PrintDiagnostics(TU); 997 clang_disposeTranslationUnit(TU); 998 clang_disposeIndex(CIdx); 999 free(Locations); 1000 free_remapped_files(unsaved_files, num_unsaved_files); 1001 return 0; 1002} 1003 1004int perform_token_annotation(int argc, const char **argv) { 1005 const char *input = argv[1]; 1006 char *filename = 0; 1007 unsigned line, second_line; 1008 unsigned column, second_column; 1009 CXIndex CIdx; 1010 CXTranslationUnit TU = 0; 1011 int errorCode; 1012 struct CXUnsavedFile *unsaved_files = 0; 1013 int num_unsaved_files = 0; 1014 CXToken *tokens; 1015 unsigned num_tokens; 1016 CXSourceRange range; 1017 CXSourceLocation startLoc, endLoc; 1018 CXFile file = 0; 1019 CXCursor *cursors = 0; 1020 unsigned i; 1021 1022 input += strlen("-test-annotate-tokens="); 1023 if ((errorCode = parse_file_line_column(input, &filename, &line, &column, 1024 &second_line, &second_column))) 1025 return errorCode; 1026 1027 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) 1028 return -1; 1029 1030 CIdx = clang_createIndex(0, 1); 1031 TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], 1032 argc - num_unsaved_files - 3, 1033 argv + num_unsaved_files + 2, 1034 num_unsaved_files, 1035 unsaved_files); 1036 if (!TU) { 1037 fprintf(stderr, "unable to parse input\n"); 1038 clang_disposeIndex(CIdx); 1039 free(filename); 1040 free_remapped_files(unsaved_files, num_unsaved_files); 1041 return -1; 1042 } 1043 errorCode = 0; 1044 1045 file = clang_getFile(TU, filename); 1046 if (!file) { 1047 fprintf(stderr, "file %s is not in this translation unit\n", filename); 1048 errorCode = -1; 1049 goto teardown; 1050 } 1051 1052 startLoc = clang_getLocation(TU, file, line, column); 1053 if (clang_equalLocations(clang_getNullLocation(), startLoc)) { 1054 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line, 1055 column); 1056 errorCode = -1; 1057 goto teardown; 1058 } 1059 1060 endLoc = clang_getLocation(TU, file, second_line, second_column); 1061 if (clang_equalLocations(clang_getNullLocation(), endLoc)) { 1062 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, 1063 second_line, second_column); 1064 errorCode = -1; 1065 goto teardown; 1066 } 1067 1068 range = clang_getRange(startLoc, endLoc); 1069 clang_tokenize(TU, range, &tokens, &num_tokens); 1070 cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor)); 1071 clang_annotateTokens(TU, tokens, num_tokens, cursors); 1072 for (i = 0; i != num_tokens; ++i) { 1073 const char *kind = "<unknown>"; 1074 CXString spelling = clang_getTokenSpelling(TU, tokens[i]); 1075 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]); 1076 unsigned start_line, start_column, end_line, end_column; 1077 1078 switch (clang_getTokenKind(tokens[i])) { 1079 case CXToken_Punctuation: kind = "Punctuation"; break; 1080 case CXToken_Keyword: kind = "Keyword"; break; 1081 case CXToken_Identifier: kind = "Identifier"; break; 1082 case CXToken_Literal: kind = "Literal"; break; 1083 case CXToken_Comment: kind = "Comment"; break; 1084 } 1085 clang_getInstantiationLocation(clang_getRangeStart(extent), 1086 0, &start_line, &start_column, 0); 1087 clang_getInstantiationLocation(clang_getRangeEnd(extent), 1088 0, &end_line, &end_column, 0); 1089 printf("%s: \"%s\" ", kind, clang_getCString(spelling)); 1090 PrintExtent(stdout, start_line, start_column, end_line, end_column); 1091 if (!clang_isInvalid(cursors[i].kind)) { 1092 printf(" "); 1093 PrintCursor(cursors[i]); 1094 } 1095 printf("\n"); 1096 } 1097 free(cursors); 1098 1099 teardown: 1100 PrintDiagnostics(TU); 1101 clang_disposeTranslationUnit(TU); 1102 clang_disposeIndex(CIdx); 1103 free(filename); 1104 free_remapped_files(unsaved_files, num_unsaved_files); 1105 return errorCode; 1106} 1107 1108/******************************************************************************/ 1109/* USR printing. */ 1110/******************************************************************************/ 1111 1112static int insufficient_usr(const char *kind, const char *usage) { 1113 fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage); 1114 return 1; 1115} 1116 1117static unsigned isUSR(const char *s) { 1118 return s[0] == 'c' && s[1] == ':'; 1119} 1120 1121static int not_usr(const char *s, const char *arg) { 1122 fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg); 1123 return 1; 1124} 1125 1126static void print_usr(CXString usr) { 1127 const char *s = clang_getCString(usr); 1128 printf("%s\n", s); 1129 clang_disposeString(usr); 1130} 1131 1132static void display_usrs() { 1133 fprintf(stderr, "-print-usrs options:\n" 1134 " ObjCCategory <class name> <category name>\n" 1135 " ObjCClass <class name>\n" 1136 " ObjCIvar <ivar name> <class USR>\n" 1137 " ObjCMethod <selector> [0=class method|1=instance method] " 1138 "<class USR>\n" 1139 " ObjCProperty <property name> <class USR>\n" 1140 " ObjCProtocol <protocol name>\n"); 1141} 1142 1143int print_usrs(const char **I, const char **E) { 1144 while (I != E) { 1145 const char *kind = *I; 1146 unsigned len = strlen(kind); 1147 switch (len) { 1148 case 8: 1149 if (memcmp(kind, "ObjCIvar", 8) == 0) { 1150 if (I + 2 >= E) 1151 return insufficient_usr(kind, "<ivar name> <class USR>"); 1152 if (!isUSR(I[2])) 1153 return not_usr("<class USR>", I[2]); 1154 else { 1155 CXString x; 1156 x.Spelling = I[2]; 1157 x.MustFreeString = 0; 1158 print_usr(clang_constructUSR_ObjCIvar(I[1], x)); 1159 } 1160 1161 I += 3; 1162 continue; 1163 } 1164 break; 1165 case 9: 1166 if (memcmp(kind, "ObjCClass", 9) == 0) { 1167 if (I + 1 >= E) 1168 return insufficient_usr(kind, "<class name>"); 1169 print_usr(clang_constructUSR_ObjCClass(I[1])); 1170 I += 2; 1171 continue; 1172 } 1173 break; 1174 case 10: 1175 if (memcmp(kind, "ObjCMethod", 10) == 0) { 1176 if (I + 3 >= E) 1177 return insufficient_usr(kind, "<method selector> " 1178 "[0=class method|1=instance method] <class USR>"); 1179 if (!isUSR(I[3])) 1180 return not_usr("<class USR>", I[3]); 1181 else { 1182 CXString x; 1183 x.Spelling = I[3]; 1184 x.MustFreeString = 0; 1185 print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x)); 1186 } 1187 I += 4; 1188 continue; 1189 } 1190 break; 1191 case 12: 1192 if (memcmp(kind, "ObjCCategory", 12) == 0) { 1193 if (I + 2 >= E) 1194 return insufficient_usr(kind, "<class name> <category name>"); 1195 print_usr(clang_constructUSR_ObjCCategory(I[1], I[2])); 1196 I += 3; 1197 continue; 1198 } 1199 if (memcmp(kind, "ObjCProtocol", 12) == 0) { 1200 if (I + 1 >= E) 1201 return insufficient_usr(kind, "<protocol name>"); 1202 print_usr(clang_constructUSR_ObjCProtocol(I[1])); 1203 I += 2; 1204 continue; 1205 } 1206 if (memcmp(kind, "ObjCProperty", 12) == 0) { 1207 if (I + 2 >= E) 1208 return insufficient_usr(kind, "<property name> <class USR>"); 1209 if (!isUSR(I[2])) 1210 return not_usr("<class USR>", I[2]); 1211 else { 1212 CXString x; 1213 x.Spelling = I[2]; 1214 x.MustFreeString = 0; 1215 print_usr(clang_constructUSR_ObjCProperty(I[1], x)); 1216 } 1217 I += 3; 1218 continue; 1219 } 1220 break; 1221 default: 1222 break; 1223 } 1224 break; 1225 } 1226 1227 if (I != E) { 1228 fprintf(stderr, "Invalid USR kind: %s\n", *I); 1229 display_usrs(); 1230 return 1; 1231 } 1232 return 0; 1233} 1234 1235int print_usrs_file(const char *file_name) { 1236 char line[2048]; 1237 const char *args[128]; 1238 unsigned numChars = 0; 1239 1240 FILE *fp = fopen(file_name, "r"); 1241 if (!fp) { 1242 fprintf(stderr, "error: cannot open '%s'\n", file_name); 1243 return 1; 1244 } 1245 1246 /* This code is not really all that safe, but it works fine for testing. */ 1247 while (!feof(fp)) { 1248 char c = fgetc(fp); 1249 if (c == '\n') { 1250 unsigned i = 0; 1251 const char *s = 0; 1252 1253 if (numChars == 0) 1254 continue; 1255 1256 line[numChars] = '\0'; 1257 numChars = 0; 1258 1259 if (line[0] == '/' && line[1] == '/') 1260 continue; 1261 1262 s = strtok(line, " "); 1263 while (s) { 1264 args[i] = s; 1265 ++i; 1266 s = strtok(0, " "); 1267 } 1268 if (print_usrs(&args[0], &args[i])) 1269 return 1; 1270 } 1271 else 1272 line[numChars++] = c; 1273 } 1274 1275 fclose(fp); 1276 return 0; 1277} 1278 1279/******************************************************************************/ 1280/* Command line processing. */ 1281/******************************************************************************/ 1282 1283static CXCursorVisitor GetVisitor(const char *s) { 1284 if (s[0] == '\0') 1285 return FilteredPrintingVisitor; 1286 if (strcmp(s, "-usrs") == 0) 1287 return USRVisitor; 1288 return NULL; 1289} 1290 1291static void print_usage(void) { 1292 fprintf(stderr, 1293 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" 1294 " c-index-test -code-completion-timing=<site> <compiler arguments>\n" 1295 " c-index-test -cursor-at=<site> <compiler arguments>\n" 1296 " c-index-test -test-file-scan <AST file> <source file> " 1297 "[FileCheck prefix]\n" 1298 " c-index-test -test-load-tu <AST file> <symbol filter> " 1299 "[FileCheck prefix]\n" 1300 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> " 1301 "[FileCheck prefix]\n" 1302 " c-index-test -test-load-source <symbol filter> {<args>}*\n"); 1303 fprintf(stderr, 1304 " c-index-test -test-load-source-reparse <trials> <symbol filter> " 1305 " {<args>}*\n" 1306 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n" 1307 " c-index-test -test-annotate-tokens=<range> {<args>}*\n" 1308 " c-index-test -test-inclusion-stack-source {<args>}*\n" 1309 " c-index-test -test-inclusion-stack-tu <AST file>\n" 1310 " c-index-test -test-print-linkage-source {<args>}*\n" 1311 " c-index-test -test-print-typekind {<args>}*\n" 1312 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"); 1313 fprintf(stderr, 1314 " c-index-test -print-usr-file <file>\n\n"); 1315 fprintf(stderr, 1316 " <symbol filter> values:\n%s", 1317 " all - load all symbols, including those from PCH\n" 1318 " local - load all symbols except those in PCH\n" 1319 " category - only load ObjC categories (non-PCH)\n" 1320 " interface - only load ObjC interfaces (non-PCH)\n" 1321 " protocol - only load ObjC protocols (non-PCH)\n" 1322 " function - only load functions (non-PCH)\n" 1323 " typedef - only load typdefs (non-PCH)\n" 1324 " scan-function - scan function bodies (non-PCH)\n\n"); 1325} 1326 1327int main(int argc, const char **argv) { 1328 clang_enableStackTraces(); 1329 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) 1330 return perform_code_completion(argc, argv, 0); 1331 if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1]) 1332 return perform_code_completion(argc, argv, 1); 1333 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1]) 1334 return inspect_cursor_at(argc, argv); 1335 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) { 1336 CXCursorVisitor I = GetVisitor(argv[1] + 13); 1337 if (I) 1338 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I, 1339 NULL); 1340 } 1341 else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){ 1342 CXCursorVisitor I = GetVisitor(argv[1] + 25); 1343 if (I) { 1344 int trials = atoi(argv[2]); 1345 return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I, 1346 NULL); 1347 } 1348 } 1349 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { 1350 CXCursorVisitor I = GetVisitor(argv[1] + 17); 1351 if (I) 1352 return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL); 1353 } 1354 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) 1355 return perform_file_scan(argv[2], argv[3], 1356 argc >= 5 ? argv[4] : 0); 1357 else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1]) 1358 return perform_token_annotation(argc, argv); 1359 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0) 1360 return perform_test_load_source(argc - 2, argv + 2, "all", NULL, 1361 PrintInclusionStack); 1362 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0) 1363 return perform_test_load_tu(argv[2], "all", NULL, NULL, 1364 PrintInclusionStack); 1365 else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) 1366 return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, 1367 NULL); 1368 else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0) 1369 return perform_test_load_source(argc - 2, argv + 2, "all", 1370 PrintTypeKind, 0); 1371 else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { 1372 if (argc > 2) 1373 return print_usrs(argv + 2, argv + argc); 1374 else { 1375 display_usrs(); 1376 return 1; 1377 } 1378 } 1379 else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0) 1380 return print_usrs_file(argv[2]); 1381 1382 print_usage(); 1383 return 1; 1384} 1385