c-index-test.c revision b699866820102a69d83d6ac6941985c5ef4e8c40
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 31static unsigned CreateTranslationUnit(CXIndex Idx, const char *file, 32 CXTranslationUnit *TU) { 33 34 *TU = clang_createTranslationUnit(Idx, file); 35 if (!TU) { 36 fprintf(stderr, "Unable to load translation unit from '%s'!\n", file); 37 return 0; 38 } 39 return 1; 40} 41 42/******************************************************************************/ 43/* Pretty-printing. */ 44/******************************************************************************/ 45 46static void PrintCursor(CXCursor Cursor) { 47 if (clang_isInvalid(Cursor.kind)) 48 printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind)); 49 else { 50 CXString string; 51 CXCursor Referenced; 52 string = clang_getCursorSpelling(Cursor); 53 printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind), 54 clang_getCString(string)); 55 clang_disposeString(string); 56 57 Referenced = clang_getCursorReferenced(Cursor); 58 if (!clang_equalCursors(Referenced, clang_getNullCursor())) { 59 CXSourceLocation Loc = clang_getCursorLocation(Referenced); 60 printf(":%d:%d", Loc.line, Loc.column); 61 } 62 63 if (clang_isCursorDefinition(Cursor)) 64 printf(" (Definition)"); 65 } 66} 67 68static const char* GetCursorSource(CXCursor Cursor) { 69 const char *source = clang_getFileName(clang_getCursorLocation(Cursor).file); 70 if (!source) 71 return "<invalid loc>"; 72 return basename(source); 73} 74 75/******************************************************************************/ 76/* Logic for testing clang_loadTranslationUnit(). */ 77/******************************************************************************/ 78 79static const char *FileCheckPrefix = "CHECK"; 80 81static void PrintCursorExtent(CXCursor C) { 82 CXSourceRange extent = clang_getCursorExtent(C); 83 /* FIXME: Better way to check for empty extents? */ 84 if (!extent.begin.file) 85 return; 86 printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column, 87 extent.end.line, extent.end.column); 88} 89 90static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) { 91 if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { 92 CXSourceLocation Loc = clang_getCursorLocation(Cursor); 93 const char *source = clang_getFileName(Loc.file); 94 if (!source) 95 source = "<invalid loc>"; 96 printf("// %s: %s:%d:%d: ", FileCheckPrefix, source, Loc.line, Loc.column); 97 PrintCursor(Cursor); 98 PrintCursorExtent(Cursor); 99 100 printf("\n"); 101 } 102} 103 104static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, 105 CXClientData Filter) { 106 if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { 107 CXDecl D; 108 CXSourceLocation Loc = clang_getCursorLocation(Cursor); 109 printf("// %s: %s:%d:%d: ", FileCheckPrefix, 110 GetCursorSource(Cursor), Loc.line, Loc.column); 111 PrintCursor(Cursor); 112 113 D = clang_getCursorDecl(Cursor); 114 if (!D) { 115 printf("\n"); 116 return; 117 } 118 119 PrintCursorExtent(Cursor); 120 printf("\n"); 121 clang_loadDeclaration(D, DeclVisitor, 0); 122 } 123} 124 125static void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor, 126 CXClientData Filter) { 127 const char *startBuf, *endBuf; 128 unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn; 129 CXCursor Ref; 130 131 if (Cursor.kind != CXCursor_FunctionDecl || 132 !clang_isCursorDefinition(Cursor)) 133 return; 134 135 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf, 136 &startLine, &startColumn, 137 &endLine, &endColumn); 138 /* Probe the entire body, looking for both decls and refs. */ 139 curLine = startLine; 140 curColumn = startColumn; 141 142 while (startBuf < endBuf) { 143 CXSourceLocation Loc; 144 const char *source = 0; 145 146 if (*startBuf == '\n') { 147 startBuf++; 148 curLine++; 149 curColumn = 1; 150 } else if (*startBuf != '\t') 151 curColumn++; 152 153 Loc = clang_getCursorLocation(Cursor); 154 source = clang_getFileName(Loc.file); 155 if (source) { 156 Ref = clang_getCursor(Unit, source, curLine, curColumn); 157 if (Ref.kind == CXCursor_NoDeclFound) { 158 /* Nothing found here; that's fine. */ 159 } else if (Ref.kind != CXCursor_FunctionDecl) { 160 printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref), 161 curLine, curColumn); 162 PrintCursor(Ref); 163 printf("\n"); 164 } 165 } 166 startBuf++; 167 } 168} 169 170/******************************************************************************/ 171/* USR testing. */ 172/******************************************************************************/ 173 174static void USRDeclVisitor(CXDecl D, CXCursor C, CXClientData Filter) { 175 if (!Filter || (C.kind == *(enum CXCursorKind *)Filter)) { 176 CXString USR = clang_getCursorUSR(C); 177 if (!USR.Spelling) { 178 clang_disposeString(USR); 179 return; 180 } 181 printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling); 182 PrintCursorExtent(C); 183 printf("\n"); 184 clang_disposeString(USR); 185 } 186} 187 188static void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor, 189 CXClientData Filter) { 190 CXDecl D = clang_getCursorDecl(Cursor); 191 if (D) { 192 /* USRDeclVisitor(Unit, Cursor.decl, Cursor, Filter);*/ 193 clang_loadDeclaration(D, USRDeclVisitor, 0); 194 } 195} 196 197/******************************************************************************/ 198/* Loading ASTs/source. */ 199/******************************************************************************/ 200 201static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, 202 const char *filter, const char *prefix, 203 CXTranslationUnitIterator Visitor) { 204 enum CXCursorKind K = CXCursor_NotImplemented; 205 enum CXCursorKind *ck = &K; 206 207 if (prefix) 208 FileCheckPrefix = prefix; 209 210 /* Perform some simple filtering. */ 211 if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL; 212 else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; 213 else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl; 214 else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl; 215 else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl; 216 else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl; 217 else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor; 218 else { 219 fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter); 220 return 1; 221 } 222 223 clang_loadTranslationUnit(TU, Visitor, ck); 224 clang_disposeTranslationUnit(TU); 225 return 0; 226} 227 228int perform_test_load_tu(const char *file, const char *filter, 229 const char *prefix, 230 CXTranslationUnitIterator Visitor) { 231 CXIndex Idx; 232 CXTranslationUnit TU; 233 Idx = clang_createIndex(/* excludeDeclsFromPCH */ 234 !strcmp(filter, "local") ? 1 : 0, 235 /* displayDiagnostics */ 1); 236 237 if (!CreateTranslationUnit(Idx, file, &TU)) 238 return 1; 239 240 return perform_test_load(Idx, TU, filter, prefix, Visitor); 241} 242 243int perform_test_load_source(int argc, const char **argv, const char *filter, 244 CXTranslationUnitIterator Visitor) { 245 const char *UseExternalASTs = 246 getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION"); 247 CXIndex Idx; 248 CXTranslationUnit TU; 249 Idx = clang_createIndex(/* excludeDeclsFromPCH */ 250 !strcmp(filter, "local") ? 1 : 0, 251 /* displayDiagnostics */ 1); 252 253 if (UseExternalASTs && strlen(UseExternalASTs)) 254 clang_setUseExternalASTGeneration(Idx, 1); 255 256 TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv); 257 if (!TU) { 258 fprintf(stderr, "Unable to load translation unit!\n"); 259 return 1; 260 } 261 262 return perform_test_load(Idx, TU, filter, NULL, Visitor); 263} 264 265/******************************************************************************/ 266/* Logic for testing clang_getCursor(). */ 267/******************************************************************************/ 268 269static void print_cursor_file_scan(CXCursor cursor, 270 unsigned start_line, unsigned start_col, 271 unsigned end_line, unsigned end_col, 272 const char *prefix) { 273 printf("// %s: ", FileCheckPrefix); 274 if (prefix) 275 printf("-%s", prefix); 276 printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ", 277 start_line, start_col, end_line, end_col); 278 PrintCursor(cursor); 279 printf("\n"); 280} 281 282static int perform_file_scan(const char *ast_file, const char *source_file, 283 const char *prefix) { 284 CXIndex Idx; 285 CXTranslationUnit TU; 286 FILE *fp; 287 unsigned line; 288 CXCursor prevCursor; 289 unsigned printed; 290 unsigned start_line, start_col, last_line, last_col; 291 size_t i; 292 293 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, 294 /* displayDiagnostics */ 1))) { 295 fprintf(stderr, "Could not create Index\n"); 296 return 1; 297 } 298 299 if (!CreateTranslationUnit(Idx, ast_file, &TU)) 300 return 1; 301 302 if ((fp = fopen(source_file, "r")) == NULL) { 303 fprintf(stderr, "Could not open '%s'\n", source_file); 304 return 1; 305 } 306 307 line = 0; 308 prevCursor = clang_getNullCursor(); 309 printed = 0; 310 start_line = last_line = 1; 311 start_col = last_col = 1; 312 313 while (!feof(fp)) { 314 size_t len = 0; 315 int c; 316 317 while ((c = fgetc(fp)) != EOF) { 318 len++; 319 if (c == '\n') 320 break; 321 } 322 323 ++line; 324 325 for (i = 0; i < len ; ++i) { 326 CXCursor cursor; 327 cursor = clang_getCursor(TU, source_file, line, i+1); 328 329 if (!clang_equalCursors(cursor, prevCursor) && 330 prevCursor.kind != CXCursor_InvalidFile) { 331 print_cursor_file_scan(prevCursor, start_line, start_col, 332 last_line, last_col, prefix); 333 printed = 1; 334 start_line = line; 335 start_col = (unsigned) i+1; 336 } 337 else { 338 printed = 0; 339 } 340 341 prevCursor = cursor; 342 last_line = line; 343 last_col = (unsigned) i+1; 344 } 345 } 346 347 if (!printed && prevCursor.kind != CXCursor_InvalidFile) { 348 print_cursor_file_scan(prevCursor, start_line, start_col, 349 last_line, last_col, prefix); 350 } 351 352 fclose(fp); 353 return 0; 354} 355 356/******************************************************************************/ 357/* Logic for testing clang_codeComplete(). */ 358/******************************************************************************/ 359 360/* Parse file:line:column from the input string. Returns 0 on success, non-zero 361 on failure. If successful, the pointer *filename will contain newly-allocated 362 memory (that will be owned by the caller) to store the file name. */ 363int parse_file_line_column(const char *input, char **filename, unsigned *line, 364 unsigned *column) { 365 /* Find the second colon. */ 366 const char *second_colon = strrchr(input, ':'), *first_colon; 367 char *endptr = 0; 368 if (!second_colon || second_colon == input) { 369 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input); 370 return 1; 371 } 372 373 /* Parse the column number. */ 374 *column = strtol(second_colon + 1, &endptr, 10); 375 if (*endptr != 0) { 376 fprintf(stderr, "could not parse column in '%s'\n", input); 377 return 1; 378 } 379 380 /* Find the first colon. */ 381 first_colon = second_colon - 1; 382 while (first_colon != input && *first_colon != ':') 383 --first_colon; 384 if (first_colon == input) { 385 fprintf(stderr, "could not parse line in '%s'\n", input); 386 return 1; 387 } 388 389 /* Parse the line number. */ 390 *line = strtol(first_colon + 1, &endptr, 10); 391 if (*endptr != ':') { 392 fprintf(stderr, "could not parse line in '%s'\n", input); 393 return 1; 394 } 395 396 /* Copy the file name. */ 397 *filename = (char*)malloc(first_colon - input + 1); 398 memcpy(*filename, input, first_colon - input); 399 (*filename)[first_colon - input] = 0; 400 return 0; 401} 402 403const char * 404clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { 405 switch (Kind) { 406 case CXCompletionChunk_Optional: return "Optional"; 407 case CXCompletionChunk_TypedText: return "TypedText"; 408 case CXCompletionChunk_Text: return "Text"; 409 case CXCompletionChunk_Placeholder: return "Placeholder"; 410 case CXCompletionChunk_Informative: return "Informative"; 411 case CXCompletionChunk_CurrentParameter: return "CurrentParameter"; 412 case CXCompletionChunk_LeftParen: return "LeftParen"; 413 case CXCompletionChunk_RightParen: return "RightParen"; 414 case CXCompletionChunk_LeftBracket: return "LeftBracket"; 415 case CXCompletionChunk_RightBracket: return "RightBracket"; 416 case CXCompletionChunk_LeftBrace: return "LeftBrace"; 417 case CXCompletionChunk_RightBrace: return "RightBrace"; 418 case CXCompletionChunk_LeftAngle: return "LeftAngle"; 419 case CXCompletionChunk_RightAngle: return "RightAngle"; 420 case CXCompletionChunk_Comma: return "Comma"; 421 case CXCompletionChunk_ResultType: return "ResultType"; 422 case CXCompletionChunk_Colon: return "Colon"; 423 case CXCompletionChunk_SemiColon: return "SemiColon"; 424 case CXCompletionChunk_Equal: return "Equal"; 425 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace"; 426 case CXCompletionChunk_VerticalSpace: return "VerticalSpace"; 427 } 428 429 return "Unknown"; 430} 431 432void print_completion_string(CXCompletionString completion_string, FILE *file) { 433 int I, N; 434 435 N = clang_getNumCompletionChunks(completion_string); 436 for (I = 0; I != N; ++I) { 437 const char *text = 0; 438 enum CXCompletionChunkKind Kind 439 = clang_getCompletionChunkKind(completion_string, I); 440 441 if (Kind == CXCompletionChunk_Optional) { 442 fprintf(file, "{Optional "); 443 print_completion_string( 444 clang_getCompletionChunkCompletionString(completion_string, I), 445 file); 446 fprintf(file, "}"); 447 continue; 448 } 449 450 text = clang_getCompletionChunkText(completion_string, I); 451 fprintf(file, "{%s %s}", 452 clang_getCompletionChunkKindSpelling(Kind), 453 text? text : ""); 454 } 455} 456 457void print_completion_result(CXCompletionResult *completion_result, 458 CXClientData client_data) { 459 FILE *file = (FILE *)client_data; 460 fprintf(file, "%s:", 461 clang_getCursorKindSpelling(completion_result->CursorKind)); 462 print_completion_string(completion_result->CompletionString, file); 463 fprintf(file, "\n"); 464} 465 466void free_remapped_files(struct CXUnsavedFile *unsaved_files, 467 int num_unsaved_files) { 468 int i; 469 for (i = 0; i != num_unsaved_files; ++i) { 470 free((char *)unsaved_files[i].Filename); 471 free((char *)unsaved_files[i].Contents); 472 } 473} 474 475int parse_remapped_files(int argc, const char **argv, int start_arg, 476 struct CXUnsavedFile **unsaved_files, 477 int *num_unsaved_files) { 478 int i; 479 int arg; 480 int prefix_len = strlen("-remap-file="); 481 *unsaved_files = 0; 482 *num_unsaved_files = 0; 483 484 /* Count the number of remapped files. */ 485 for (arg = start_arg; arg < argc; ++arg) { 486 if (strncmp(argv[arg], "-remap-file=", prefix_len)) 487 break; 488 489 ++*num_unsaved_files; 490 } 491 492 if (*num_unsaved_files == 0) 493 return 0; 494 495 *unsaved_files 496 = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) * 497 *num_unsaved_files); 498 for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) { 499 struct CXUnsavedFile *unsaved = *unsaved_files + i; 500 const char *arg_string = argv[arg] + prefix_len; 501 int filename_len; 502 char *filename; 503 char *contents; 504 FILE *to_file; 505 const char *semi = strchr(arg_string, ';'); 506 if (!semi) { 507 fprintf(stderr, 508 "error: -remap-file=from;to argument is missing semicolon\n"); 509 free_remapped_files(*unsaved_files, i); 510 *unsaved_files = 0; 511 *num_unsaved_files = 0; 512 return -1; 513 } 514 515 /* Open the file that we're remapping to. */ 516 to_file = fopen(semi + 1, "r"); 517 if (!to_file) { 518 fprintf(stderr, "error: cannot open file %s that we are remapping to\n", 519 semi + 1); 520 free_remapped_files(*unsaved_files, i); 521 *unsaved_files = 0; 522 *num_unsaved_files = 0; 523 return -1; 524 } 525 526 /* Determine the length of the file we're remapping to. */ 527 fseek(to_file, 0, SEEK_END); 528 unsaved->Length = ftell(to_file); 529 fseek(to_file, 0, SEEK_SET); 530 531 /* Read the contents of the file we're remapping to. */ 532 contents = (char *)malloc(unsaved->Length + 1); 533 if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) { 534 fprintf(stderr, "error: unexpected %s reading 'to' file %s\n", 535 (feof(to_file) ? "EOF" : "error"), semi + 1); 536 fclose(to_file); 537 free_remapped_files(*unsaved_files, i); 538 *unsaved_files = 0; 539 *num_unsaved_files = 0; 540 return -1; 541 } 542 contents[unsaved->Length] = 0; 543 unsaved->Contents = contents; 544 545 /* Close the file. */ 546 fclose(to_file); 547 548 /* Copy the file name that we're remapping from. */ 549 filename_len = semi - arg_string; 550 filename = (char *)malloc(filename_len + 1); 551 memcpy(filename, arg_string, filename_len); 552 filename[filename_len] = 0; 553 unsaved->Filename = filename; 554 } 555 556 return 0; 557} 558 559int perform_code_completion(int argc, const char **argv) { 560 const char *input = argv[1]; 561 char *filename = 0; 562 unsigned line; 563 unsigned column; 564 CXIndex CIdx; 565 int errorCode; 566 struct CXUnsavedFile *unsaved_files = 0; 567 int num_unsaved_files = 0; 568 CXCodeCompleteResults *results = 0; 569 570 input += strlen("-code-completion-at="); 571 if ((errorCode = parse_file_line_column(input, &filename, &line, &column))) 572 return errorCode; 573 574 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) 575 return -1; 576 577 CIdx = clang_createIndex(0, 0); 578 results = clang_codeComplete(CIdx, 579 argv[argc - 1], argc - num_unsaved_files - 3, 580 argv + num_unsaved_files + 2, 581 num_unsaved_files, unsaved_files, 582 filename, line, column); 583 if (results) { 584 unsigned i, n = results->NumResults; 585 for (i = 0; i != n; ++i) 586 print_completion_result(results->Results + i, stdout); 587 clang_disposeCodeCompleteResults(results); 588 } 589 590 clang_disposeIndex(CIdx); 591 free(filename); 592 593 free_remapped_files(unsaved_files, num_unsaved_files); 594 595 return 0; 596} 597 598typedef struct { 599 char *filename; 600 unsigned line; 601 unsigned column; 602} CursorSourceLocation; 603 604int inspect_cursor_at(int argc, const char **argv) { 605 CXIndex CIdx; 606 int errorCode; 607 struct CXUnsavedFile *unsaved_files = 0; 608 int num_unsaved_files = 0; 609 CXTranslationUnit TU; 610 CXCursor Cursor; 611 CursorSourceLocation *Locations = 0; 612 unsigned NumLocations = 0, Loc; 613 614 /* Count the number of locations. */ 615 while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1]) 616 ++NumLocations; 617 618 /* Parse the locations. */ 619 assert(NumLocations > 0 && "Unable to count locations?"); 620 Locations = (CursorSourceLocation *)malloc( 621 NumLocations * sizeof(CursorSourceLocation)); 622 for (Loc = 0; Loc < NumLocations; ++Loc) { 623 const char *input = argv[Loc + 1] + strlen("-cursor-at="); 624 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename, 625 &Locations[Loc].line, 626 &Locations[Loc].column))) 627 return errorCode; 628 } 629 630 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files, 631 &num_unsaved_files)) 632 return -1; 633 634 if (num_unsaved_files > 0) { 635 fprintf(stderr, "cannot remap files when looking for a cursor\n"); 636 return -1; 637 } 638 639 CIdx = clang_createIndex(0, 1); 640 TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1], 641 argc - num_unsaved_files - 2 - NumLocations, 642 argv + num_unsaved_files + 1 + NumLocations); 643 if (!TU) { 644 fprintf(stderr, "unable to parse input\n"); 645 return -1; 646 } 647 648 for (Loc = 0; Loc < NumLocations; ++Loc) { 649 Cursor = clang_getCursor(TU, Locations[Loc].filename, 650 Locations[Loc].line, Locations[Loc].column); 651 PrintCursor(Cursor); 652 printf("\n"); 653 free(Locations[Loc].filename); 654 } 655 656 clang_disposeTranslationUnit(TU); 657 clang_disposeIndex(CIdx); 658 free(Locations); 659 free_remapped_files(unsaved_files, num_unsaved_files); 660 return 0; 661} 662 663/******************************************************************************/ 664/* Command line processing. */ 665/******************************************************************************/ 666 667static CXTranslationUnitIterator GetVisitor(const char *s) { 668 if (s[0] == '\0') 669 return TranslationUnitVisitor; 670 if (strcmp(s, "-usrs") == 0) 671 return USRVisitor; 672 return NULL; 673} 674 675static void print_usage(void) { 676 fprintf(stderr, 677 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n" 678 " c-index-test -cursor-at=<site> <compiler arguments>\n" 679 " c-index-test -test-file-scan <AST file> <source file> " 680 "[FileCheck prefix]\n" 681 " c-index-test -test-load-tu <AST file> <symbol filter> " 682 "[FileCheck prefix]\n" 683 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> " 684 "[FileCheck prefix]\n" 685 " c-index-test -test-load-source <symbol filter> {<args>}*\n" 686 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n"); 687 fprintf(stderr, 688 " <symbol filter> values:\n%s", 689 " all - load all symbols, including those from PCH\n" 690 " local - load all symbols except those in PCH\n" 691 " category - only load ObjC categories (non-PCH)\n" 692 " interface - only load ObjC interfaces (non-PCH)\n" 693 " protocol - only load ObjC protocols (non-PCH)\n" 694 " function - only load functions (non-PCH)\n" 695 " typedef - only load typdefs (non-PCH)\n" 696 " scan-function - scan function bodies (non-PCH)\n\n"); 697} 698 699int main(int argc, const char **argv) { 700 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) 701 return perform_code_completion(argc, argv); 702 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1]) 703 return inspect_cursor_at(argc, argv); 704 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) { 705 CXTranslationUnitIterator I = GetVisitor(argv[1] + 13); 706 if (I) 707 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I); 708 } 709 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) { 710 CXTranslationUnitIterator I = GetVisitor(argv[1] + 17); 711 if (I) 712 return perform_test_load_source(argc - 3, argv + 3, argv[2], I); 713 } 714 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0) 715 return perform_file_scan(argv[2], argv[3], 716 argc >= 5 ? argv[4] : 0); 717 718 print_usage(); 719 return 1; 720} 721