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