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