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