3 #include "clang-c/Index.h"
10 /******************************************************************************/
11 /* Utility functions. */
12 /******************************************************************************/
15 char *basename(const char* path
)
17 char* base1
= (char*)strrchr(path
, '/');
18 char* base2
= (char*)strrchr(path
, '\\');
20 return((base1
> base2
) ? base1
+ 1 : base2
+ 1);
29 extern char *basename(const char *);
32 /** \brief Return the default parsing options. */
33 static unsigned getDefaultParsingOptions() {
34 unsigned options
= CXTranslationUnit_DetailedPreprocessingRecord
;
36 if (getenv("CINDEXTEST_EDITING"))
37 options
|= clang_defaultEditingTranslationUnitOptions();
38 if (getenv("CINDEXTEST_COMPLETION_CACHING"))
39 options
|= CXTranslationUnit_CacheCompletionResults
;
44 static void PrintExtent(FILE *out
, unsigned begin_line
, unsigned begin_column
,
45 unsigned end_line
, unsigned end_column
) {
46 fprintf(out
, "[%d:%d - %d:%d]", begin_line
, begin_column
,
47 end_line
, end_column
);
50 static unsigned CreateTranslationUnit(CXIndex Idx
, const char *file
,
51 CXTranslationUnit
*TU
) {
53 *TU
= clang_createTranslationUnit(Idx
, file
);
55 fprintf(stderr
, "Unable to load translation unit from '%s'!\n", file
);
61 void free_remapped_files(struct CXUnsavedFile
*unsaved_files
,
62 int num_unsaved_files
) {
64 for (i
= 0; i
!= num_unsaved_files
; ++i
) {
65 free((char *)unsaved_files
[i
].Filename
);
66 free((char *)unsaved_files
[i
].Contents
);
71 int parse_remapped_files(int argc
, const char **argv
, int start_arg
,
72 struct CXUnsavedFile
**unsaved_files
,
73 int *num_unsaved_files
) {
76 int prefix_len
= strlen("-remap-file=");
78 *num_unsaved_files
= 0;
80 /* Count the number of remapped files. */
81 for (arg
= start_arg
; arg
< argc
; ++arg
) {
82 if (strncmp(argv
[arg
], "-remap-file=", prefix_len
))
88 if (*num_unsaved_files
== 0)
92 = (struct CXUnsavedFile
*)malloc(sizeof(struct CXUnsavedFile
) *
94 for (arg
= start_arg
, i
= 0; i
!= *num_unsaved_files
; ++i
, ++arg
) {
95 struct CXUnsavedFile
*unsaved
= *unsaved_files
+ i
;
96 const char *arg_string
= argv
[arg
] + prefix_len
;
101 const char *semi
= strchr(arg_string
, ';');
104 "error: -remap-file=from;to argument is missing semicolon\n");
105 free_remapped_files(*unsaved_files
, i
);
107 *num_unsaved_files
= 0;
111 /* Open the file that we're remapping to. */
112 to_file
= fopen(semi
+ 1, "rb");
114 fprintf(stderr
, "error: cannot open file %s that we are remapping to\n",
116 free_remapped_files(*unsaved_files
, i
);
118 *num_unsaved_files
= 0;
122 /* Determine the length of the file we're remapping to. */
123 fseek(to_file
, 0, SEEK_END
);
124 unsaved
->Length
= ftell(to_file
);
125 fseek(to_file
, 0, SEEK_SET
);
127 /* Read the contents of the file we're remapping to. */
128 contents
= (char *)malloc(unsaved
->Length
+ 1);
129 if (fread(contents
, 1, unsaved
->Length
, to_file
) != unsaved
->Length
) {
130 fprintf(stderr
, "error: unexpected %s reading 'to' file %s\n",
131 (feof(to_file
) ? "EOF" : "error"), semi
+ 1);
133 free_remapped_files(*unsaved_files
, i
);
135 *num_unsaved_files
= 0;
138 contents
[unsaved
->Length
] = 0;
139 unsaved
->Contents
= contents
;
141 /* Close the file. */
144 /* Copy the file name that we're remapping from. */
145 filename_len
= semi
- arg_string
;
146 filename
= (char *)malloc(filename_len
+ 1);
147 memcpy(filename
, arg_string
, filename_len
);
148 filename
[filename_len
] = 0;
149 unsaved
->Filename
= filename
;
155 /******************************************************************************/
156 /* Pretty-printing. */
157 /******************************************************************************/
159 int want_display_name
= 0;
161 static void PrintCursor(CXCursor Cursor
) {
162 if (clang_isInvalid(Cursor
.kind
)) {
163 CXString ks
= clang_getCursorKindSpelling(Cursor
.kind
);
164 printf("Invalid Cursor => %s", clang_getCString(ks
));
165 clang_disposeString(ks
);
170 unsigned line
, column
;
171 CXCursor SpecializationOf
;
172 CXCursor
*overridden
;
173 unsigned num_overridden
;
175 ks
= clang_getCursorKindSpelling(Cursor
.kind
);
176 string
= want_display_name
? clang_getCursorDisplayName(Cursor
)
177 : clang_getCursorSpelling(Cursor
);
178 printf("%s=%s", clang_getCString(ks
),
179 clang_getCString(string
));
180 clang_disposeString(ks
);
181 clang_disposeString(string
);
183 Referenced
= clang_getCursorReferenced(Cursor
);
184 if (!clang_equalCursors(Referenced
, clang_getNullCursor())) {
185 if (clang_getCursorKind(Referenced
) == CXCursor_OverloadedDeclRef
) {
186 unsigned I
, N
= clang_getNumOverloadedDecls(Referenced
);
188 for (I
= 0; I
!= N
; ++I
) {
189 CXCursor Ovl
= clang_getOverloadedDecl(Referenced
, I
);
190 CXSourceLocation Loc
;
194 Loc
= clang_getCursorLocation(Ovl
);
195 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
196 printf("%d:%d", line
, column
);
200 CXSourceLocation Loc
= clang_getCursorLocation(Referenced
);
201 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
202 printf(":%d:%d", line
, column
);
206 if (clang_isCursorDefinition(Cursor
))
207 printf(" (Definition)");
209 switch (clang_getCursorAvailability(Cursor
)) {
210 case CXAvailability_Available
:
213 case CXAvailability_Deprecated
:
214 printf(" (deprecated)");
217 case CXAvailability_NotAvailable
:
218 printf(" (unavailable)");
222 if (Cursor
.kind
== CXCursor_IBOutletCollectionAttr
) {
224 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor
));
225 CXString S
= clang_getTypeKindSpelling(T
.kind
);
226 printf(" [IBOutletCollection=%s]", clang_getCString(S
));
227 clang_disposeString(S
);
230 if (Cursor
.kind
== CXCursor_CXXBaseSpecifier
) {
231 enum CX_CXXAccessSpecifier access
= clang_getCXXAccessSpecifier(Cursor
);
232 unsigned isVirtual
= clang_isVirtualBase(Cursor
);
233 const char *accessStr
= 0;
236 case CX_CXXInvalidAccessSpecifier
:
237 accessStr
= "invalid"; break;
239 accessStr
= "public"; break;
240 case CX_CXXProtected
:
241 accessStr
= "protected"; break;
243 accessStr
= "private"; break;
246 printf(" [access=%s isVirtual=%s]", accessStr
,
247 isVirtual
? "true" : "false");
250 SpecializationOf
= clang_getSpecializedCursorTemplate(Cursor
);
251 if (!clang_equalCursors(SpecializationOf
, clang_getNullCursor())) {
252 CXSourceLocation Loc
= clang_getCursorLocation(SpecializationOf
);
253 CXString Name
= clang_getCursorSpelling(SpecializationOf
);
254 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
255 printf(" [Specialization of %s:%d:%d]",
256 clang_getCString(Name
), line
, column
);
257 clang_disposeString(Name
);
260 clang_getOverriddenCursors(Cursor
, &overridden
, &num_overridden
);
261 if (num_overridden
) {
263 printf(" [Overrides ");
264 for (I
= 0; I
!= num_overridden
; ++I
) {
265 CXSourceLocation Loc
= clang_getCursorLocation(overridden
[I
]);
266 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
269 printf("@%d:%d", line
, column
);
272 clang_disposeOverriddenCursors(overridden
);
275 if (Cursor
.kind
== CXCursor_InclusionDirective
) {
276 CXFile File
= clang_getIncludedFile(Cursor
);
277 CXString Included
= clang_getFileName(File
);
278 printf(" (%s)", clang_getCString(Included
));
279 clang_disposeString(Included
);
284 static const char* GetCursorSource(CXCursor Cursor
) {
285 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
288 clang_getSpellingLocation(Loc
, &file
, 0, 0, 0);
289 source
= clang_getFileName(file
);
290 if (!clang_getCString(source
)) {
291 clang_disposeString(source
);
292 return "<invalid loc>";
295 const char *b
= basename(clang_getCString(source
));
296 clang_disposeString(source
);
301 /******************************************************************************/
303 /******************************************************************************/
305 typedef void (*PostVisitTU
)(CXTranslationUnit
);
307 void PrintDiagnostic(CXDiagnostic Diagnostic
) {
311 unsigned display_opts
= CXDiagnostic_DisplaySourceLocation
312 | CXDiagnostic_DisplayColumn
| CXDiagnostic_DisplaySourceRanges
313 | CXDiagnostic_DisplayOption
;
314 unsigned i
, num_fixits
;
316 if (clang_getDiagnosticSeverity(Diagnostic
) == CXDiagnostic_Ignored
)
319 Msg
= clang_formatDiagnostic(Diagnostic
, display_opts
);
320 fprintf(stderr
, "%s\n", clang_getCString(Msg
));
321 clang_disposeString(Msg
);
323 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic
),
328 num_fixits
= clang_getDiagnosticNumFixIts(Diagnostic
);
329 for (i
= 0; i
!= num_fixits
; ++i
) {
331 CXString insertion_text
= clang_getDiagnosticFixIt(Diagnostic
, i
, &range
);
332 CXSourceLocation start
= clang_getRangeStart(range
);
333 CXSourceLocation end
= clang_getRangeEnd(range
);
334 unsigned start_line
, start_column
, end_line
, end_column
;
335 CXFile start_file
, end_file
;
336 clang_getSpellingLocation(start
, &start_file
, &start_line
,
338 clang_getSpellingLocation(end
, &end_file
, &end_line
, &end_column
, 0);
339 if (clang_equalLocations(start
, end
)) {
341 if (start_file
== file
)
342 fprintf(out
, "FIX-IT: Insert \"%s\" at %d:%d\n",
343 clang_getCString(insertion_text
), start_line
, start_column
);
344 } else if (strcmp(clang_getCString(insertion_text
), "") == 0) {
346 if (start_file
== file
&& end_file
== file
) {
347 fprintf(out
, "FIX-IT: Remove ");
348 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
353 if (start_file
== end_file
) {
354 fprintf(out
, "FIX-IT: Replace ");
355 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
356 fprintf(out
, " with \"%s\"\n", clang_getCString(insertion_text
));
360 clang_disposeString(insertion_text
);
364 void PrintDiagnostics(CXTranslationUnit TU
) {
365 int i
, n
= clang_getNumDiagnostics(TU
);
366 for (i
= 0; i
!= n
; ++i
) {
367 CXDiagnostic Diag
= clang_getDiagnostic(TU
, i
);
368 PrintDiagnostic(Diag
);
369 clang_disposeDiagnostic(Diag
);
373 /******************************************************************************/
374 /* Logic for testing traversal. */
375 /******************************************************************************/
377 static const char *FileCheckPrefix
= "CHECK";
379 static void PrintCursorExtent(CXCursor C
) {
380 CXSourceRange extent
= clang_getCursorExtent(C
);
381 CXFile begin_file
, end_file
;
382 unsigned begin_line
, begin_column
, end_line
, end_column
;
384 clang_getSpellingLocation(clang_getRangeStart(extent
),
385 &begin_file
, &begin_line
, &begin_column
, 0);
386 clang_getSpellingLocation(clang_getRangeEnd(extent
),
387 &end_file
, &end_line
, &end_column
, 0);
388 if (!begin_file
|| !end_file
)
392 PrintExtent(stdout
, begin_line
, begin_column
, end_line
, end_column
);
395 /* Data used by all of the visitors. */
397 CXTranslationUnit TU
;
398 enum CXCursorKind
*Filter
;
402 enum CXChildVisitResult
FilteredPrintingVisitor(CXCursor Cursor
,
404 CXClientData ClientData
) {
405 VisitorData
*Data
= (VisitorData
*)ClientData
;
406 if (!Data
->Filter
|| (Cursor
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
407 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
408 unsigned line
, column
;
409 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
410 printf("// %s: %s:%d:%d: ", FileCheckPrefix
,
411 GetCursorSource(Cursor
), line
, column
);
413 PrintCursorExtent(Cursor
);
415 return CXChildVisit_Recurse
;
418 return CXChildVisit_Continue
;
421 static enum CXChildVisitResult
FunctionScanVisitor(CXCursor Cursor
,
423 CXClientData ClientData
) {
424 const char *startBuf
, *endBuf
;
425 unsigned startLine
, startColumn
, endLine
, endColumn
, curLine
, curColumn
;
427 VisitorData
*Data
= (VisitorData
*)ClientData
;
429 if (Cursor
.kind
!= CXCursor_FunctionDecl
||
430 !clang_isCursorDefinition(Cursor
))
431 return CXChildVisit_Continue
;
433 clang_getDefinitionSpellingAndExtent(Cursor
, &startBuf
, &endBuf
,
434 &startLine
, &startColumn
,
435 &endLine
, &endColumn
);
436 /* Probe the entire body, looking for both decls and refs. */
438 curColumn
= startColumn
;
440 while (startBuf
< endBuf
) {
441 CXSourceLocation Loc
;
445 if (*startBuf
== '\n') {
449 } else if (*startBuf
!= '\t')
452 Loc
= clang_getCursorLocation(Cursor
);
453 clang_getSpellingLocation(Loc
, &file
, 0, 0, 0);
455 source
= clang_getFileName(file
);
456 if (clang_getCString(source
)) {
457 CXSourceLocation RefLoc
458 = clang_getLocation(Data
->TU
, file
, curLine
, curColumn
);
459 Ref
= clang_getCursor(Data
->TU
, RefLoc
);
460 if (Ref
.kind
== CXCursor_NoDeclFound
) {
461 /* Nothing found here; that's fine. */
462 } else if (Ref
.kind
!= CXCursor_FunctionDecl
) {
463 printf("// %s: %s:%d:%d: ", FileCheckPrefix
, GetCursorSource(Ref
),
469 clang_disposeString(source
);
473 return CXChildVisit_Continue
;
476 /******************************************************************************/
478 /******************************************************************************/
480 enum CXChildVisitResult
USRVisitor(CXCursor C
, CXCursor parent
,
481 CXClientData ClientData
) {
482 VisitorData
*Data
= (VisitorData
*)ClientData
;
483 if (!Data
->Filter
|| (C
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
484 CXString USR
= clang_getCursorUSR(C
);
485 const char *cstr
= clang_getCString(USR
);
486 if (!cstr
|| cstr
[0] == '\0') {
487 clang_disposeString(USR
);
488 return CXChildVisit_Recurse
;
490 printf("// %s: %s %s", FileCheckPrefix
, GetCursorSource(C
), cstr
);
492 PrintCursorExtent(C
);
494 clang_disposeString(USR
);
496 return CXChildVisit_Recurse
;
499 return CXChildVisit_Continue
;
502 /******************************************************************************/
503 /* Inclusion stack testing. */
504 /******************************************************************************/
506 void InclusionVisitor(CXFile includedFile
, CXSourceLocation
*includeStack
,
507 unsigned includeStackLen
, CXClientData data
) {
512 fname
= clang_getFileName(includedFile
);
513 printf("file: %s\nincluded by:\n", clang_getCString(fname
));
514 clang_disposeString(fname
);
516 for (i
= 0; i
< includeStackLen
; ++i
) {
517 CXFile includingFile
;
518 unsigned line
, column
;
519 clang_getSpellingLocation(includeStack
[i
], &includingFile
, &line
,
521 fname
= clang_getFileName(includingFile
);
522 printf(" %s:%d:%d\n", clang_getCString(fname
), line
, column
);
523 clang_disposeString(fname
);
528 void PrintInclusionStack(CXTranslationUnit TU
) {
529 clang_getInclusions(TU
, InclusionVisitor
, NULL
);
532 /******************************************************************************/
533 /* Linkage testing. */
534 /******************************************************************************/
536 static enum CXChildVisitResult
PrintLinkage(CXCursor cursor
, CXCursor p
,
538 const char *linkage
= 0;
540 if (clang_isInvalid(clang_getCursorKind(cursor
)))
541 return CXChildVisit_Recurse
;
543 switch (clang_getCursorLinkage(cursor
)) {
544 case CXLinkage_Invalid
: break;
545 case CXLinkage_NoLinkage
: linkage
= "NoLinkage"; break;
546 case CXLinkage_Internal
: linkage
= "Internal"; break;
547 case CXLinkage_UniqueExternal
: linkage
= "UniqueExternal"; break;
548 case CXLinkage_External
: linkage
= "External"; break;
553 printf("linkage=%s\n", linkage
);
556 return CXChildVisit_Recurse
;
559 /******************************************************************************/
560 /* Typekind testing. */
561 /******************************************************************************/
563 static enum CXChildVisitResult
PrintTypeKind(CXCursor cursor
, CXCursor p
,
566 if (!clang_isInvalid(clang_getCursorKind(cursor
))) {
567 CXType T
= clang_getCursorType(cursor
);
568 CXString S
= clang_getTypeKindSpelling(T
.kind
);
570 printf(" typekind=%s", clang_getCString(S
));
571 if (clang_isConstQualifiedType(T
))
573 if (clang_isVolatileQualifiedType(T
))
575 if (clang_isRestrictQualifiedType(T
))
577 clang_disposeString(S
);
578 /* Print the canonical type if it is different. */
580 CXType CT
= clang_getCanonicalType(T
);
581 if (!clang_equalTypes(T
, CT
)) {
582 CXString CS
= clang_getTypeKindSpelling(CT
.kind
);
583 printf(" [canonical=%s]", clang_getCString(CS
));
584 clang_disposeString(CS
);
587 /* Print the return type if it exists. */
589 CXType RT
= clang_getCursorResultType(cursor
);
590 if (RT
.kind
!= CXType_Invalid
) {
591 CXString RS
= clang_getTypeKindSpelling(RT
.kind
);
592 printf(" [result=%s]", clang_getCString(RS
));
593 clang_disposeString(RS
);
596 /* Print if this is a non-POD type. */
597 printf(" [isPOD=%d]", clang_isPODType(T
));
601 return CXChildVisit_Recurse
;
605 /******************************************************************************/
606 /* Loading ASTs/source. */
607 /******************************************************************************/
609 static int perform_test_load(CXIndex Idx
, CXTranslationUnit TU
,
610 const char *filter
, const char *prefix
,
611 CXCursorVisitor Visitor
,
615 FileCheckPrefix
= prefix
;
618 enum CXCursorKind K
= CXCursor_NotImplemented
;
619 enum CXCursorKind
*ck
= &K
;
622 /* Perform some simple filtering. */
623 if (!strcmp(filter
, "all") || !strcmp(filter
, "local")) ck
= NULL
;
624 else if (!strcmp(filter
, "all-display") ||
625 !strcmp(filter
, "local-display")) {
627 want_display_name
= 1;
629 else if (!strcmp(filter
, "none")) K
= (enum CXCursorKind
) ~0;
630 else if (!strcmp(filter
, "category")) K
= CXCursor_ObjCCategoryDecl
;
631 else if (!strcmp(filter
, "interface")) K
= CXCursor_ObjCInterfaceDecl
;
632 else if (!strcmp(filter
, "protocol")) K
= CXCursor_ObjCProtocolDecl
;
633 else if (!strcmp(filter
, "function")) K
= CXCursor_FunctionDecl
;
634 else if (!strcmp(filter
, "typedef")) K
= CXCursor_TypedefDecl
;
635 else if (!strcmp(filter
, "scan-function")) Visitor
= FunctionScanVisitor
;
637 fprintf(stderr
, "Unknown filter for -test-load-tu: %s\n", filter
);
643 clang_visitChildren(clang_getTranslationUnitCursor(TU
), Visitor
, &Data
);
649 PrintDiagnostics(TU
);
650 clang_disposeTranslationUnit(TU
);
654 int perform_test_load_tu(const char *file
, const char *filter
,
655 const char *prefix
, CXCursorVisitor Visitor
,
658 CXTranslationUnit TU
;
660 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
661 !strcmp(filter
, "local") ? 1 : 0,
662 /* displayDiagnosics=*/1);
664 if (!CreateTranslationUnit(Idx
, file
, &TU
)) {
665 clang_disposeIndex(Idx
);
669 result
= perform_test_load(Idx
, TU
, filter
, prefix
, Visitor
, PV
);
670 clang_disposeIndex(Idx
);
674 int perform_test_load_source(int argc
, const char **argv
,
675 const char *filter
, CXCursorVisitor Visitor
,
678 CXTranslationUnit TU
;
679 struct CXUnsavedFile
*unsaved_files
= 0;
680 int num_unsaved_files
= 0;
683 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
684 (!strcmp(filter
, "local") ||
685 !strcmp(filter
, "local-display"))? 1 : 0,
686 /* displayDiagnosics=*/0);
688 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
689 clang_disposeIndex(Idx
);
693 TU
= clang_createTranslationUnitFromSourceFile(Idx
, 0,
694 argc
- num_unsaved_files
,
695 argv
+ num_unsaved_files
,
699 fprintf(stderr
, "Unable to load translation unit!\n");
700 free_remapped_files(unsaved_files
, num_unsaved_files
);
701 clang_disposeIndex(Idx
);
705 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
);
706 free_remapped_files(unsaved_files
, num_unsaved_files
);
707 clang_disposeIndex(Idx
);
711 int perform_test_reparse_source(int argc
, const char **argv
, int trials
,
712 const char *filter
, CXCursorVisitor Visitor
,
715 CXTranslationUnit TU
;
716 struct CXUnsavedFile
*unsaved_files
= 0;
717 int num_unsaved_files
= 0;
721 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
722 !strcmp(filter
, "local") ? 1 : 0,
723 /* displayDiagnosics=*/0);
725 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
726 clang_disposeIndex(Idx
);
730 /* Load the initial translation unit -- we do this without honoring remapped
731 * files, so that we have a way to test results after changing the source. */
732 TU
= clang_parseTranslationUnit(Idx
, 0,
733 argv
+ num_unsaved_files
,
734 argc
- num_unsaved_files
,
735 0, 0, getDefaultParsingOptions());
737 fprintf(stderr
, "Unable to load translation unit!\n");
738 free_remapped_files(unsaved_files
, num_unsaved_files
);
739 clang_disposeIndex(Idx
);
743 for (trial
= 0; trial
< trials
; ++trial
) {
744 if (clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
745 clang_defaultReparseOptions(TU
))) {
746 fprintf(stderr
, "Unable to reparse translation unit!\n");
747 clang_disposeTranslationUnit(TU
);
748 free_remapped_files(unsaved_files
, num_unsaved_files
);
749 clang_disposeIndex(Idx
);
754 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
);
755 free_remapped_files(unsaved_files
, num_unsaved_files
);
756 clang_disposeIndex(Idx
);
760 /******************************************************************************/
761 /* Logic for testing clang_getCursor(). */
762 /******************************************************************************/
764 static void print_cursor_file_scan(CXCursor cursor
,
765 unsigned start_line
, unsigned start_col
,
766 unsigned end_line
, unsigned end_col
,
767 const char *prefix
) {
768 printf("// %s: ", FileCheckPrefix
);
770 printf("-%s", prefix
);
771 PrintExtent(stdout
, start_line
, start_col
, end_line
, end_col
);
777 static int perform_file_scan(const char *ast_file
, const char *source_file
,
778 const char *prefix
) {
780 CXTranslationUnit TU
;
782 CXCursor prevCursor
= clang_getNullCursor();
784 unsigned line
= 1, col
= 1;
785 unsigned start_line
= 1, start_col
= 1;
787 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
788 /* displayDiagnosics=*/1))) {
789 fprintf(stderr
, "Could not create Index\n");
793 if (!CreateTranslationUnit(Idx
, ast_file
, &TU
))
796 if ((fp
= fopen(source_file
, "r")) == NULL
) {
797 fprintf(stderr
, "Could not open '%s'\n", source_file
);
801 file
= clang_getFile(TU
, source_file
);
812 /* Check the cursor at this position, and dump the previous one if we have
813 * found something new.
815 cursor
= clang_getCursor(TU
, clang_getLocation(TU
, file
, line
, col
));
816 if ((c
== EOF
|| !clang_equalCursors(cursor
, prevCursor
)) &&
817 prevCursor
.kind
!= CXCursor_InvalidFile
) {
818 print_cursor_file_scan(prevCursor
, start_line
, start_col
,
830 clang_disposeTranslationUnit(TU
);
831 clang_disposeIndex(Idx
);
835 /******************************************************************************/
836 /* Logic for testing clang code completion. */
837 /******************************************************************************/
839 /* Parse file:line:column from the input string. Returns 0 on success, non-zero
840 on failure. If successful, the pointer *filename will contain newly-allocated
841 memory (that will be owned by the caller) to store the file name. */
842 int parse_file_line_column(const char *input
, char **filename
, unsigned *line
,
843 unsigned *column
, unsigned *second_line
,
844 unsigned *second_column
) {
845 /* Find the second colon. */
846 const char *last_colon
= strrchr(input
, ':');
847 unsigned values
[4], i
;
848 unsigned num_values
= (second_line
&& second_column
)? 4 : 2;
851 if (!last_colon
|| last_colon
== input
) {
853 fprintf(stderr
, "could not parse filename:line:column:line:column in "
856 fprintf(stderr
, "could not parse filename:line:column in '%s'\n", input
);
860 for (i
= 0; i
!= num_values
; ++i
) {
861 const char *prev_colon
;
863 /* Parse the next line or column. */
864 values
[num_values
- i
- 1] = strtol(last_colon
+ 1, &endptr
, 10);
865 if (*endptr
!= 0 && *endptr
!= ':') {
866 fprintf(stderr
, "could not parse %s in '%s'\n",
867 (i
% 2 ? "column" : "line"), input
);
871 if (i
+ 1 == num_values
)
874 /* Find the previous colon. */
875 prev_colon
= last_colon
- 1;
876 while (prev_colon
!= input
&& *prev_colon
!= ':')
878 if (prev_colon
== input
) {
879 fprintf(stderr
, "could not parse %s in '%s'\n",
880 (i
% 2 == 0? "column" : "line"), input
);
884 last_colon
= prev_colon
;
890 if (second_line
&& second_column
) {
891 *second_line
= values
[2];
892 *second_column
= values
[3];
895 /* Copy the file name. */
896 *filename
= (char*)malloc(last_colon
- input
+ 1);
897 memcpy(*filename
, input
, last_colon
- input
);
898 (*filename
)[last_colon
- input
] = 0;
903 clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind
) {
905 case CXCompletionChunk_Optional
: return "Optional";
906 case CXCompletionChunk_TypedText
: return "TypedText";
907 case CXCompletionChunk_Text
: return "Text";
908 case CXCompletionChunk_Placeholder
: return "Placeholder";
909 case CXCompletionChunk_Informative
: return "Informative";
910 case CXCompletionChunk_CurrentParameter
: return "CurrentParameter";
911 case CXCompletionChunk_LeftParen
: return "LeftParen";
912 case CXCompletionChunk_RightParen
: return "RightParen";
913 case CXCompletionChunk_LeftBracket
: return "LeftBracket";
914 case CXCompletionChunk_RightBracket
: return "RightBracket";
915 case CXCompletionChunk_LeftBrace
: return "LeftBrace";
916 case CXCompletionChunk_RightBrace
: return "RightBrace";
917 case CXCompletionChunk_LeftAngle
: return "LeftAngle";
918 case CXCompletionChunk_RightAngle
: return "RightAngle";
919 case CXCompletionChunk_Comma
: return "Comma";
920 case CXCompletionChunk_ResultType
: return "ResultType";
921 case CXCompletionChunk_Colon
: return "Colon";
922 case CXCompletionChunk_SemiColon
: return "SemiColon";
923 case CXCompletionChunk_Equal
: return "Equal";
924 case CXCompletionChunk_HorizontalSpace
: return "HorizontalSpace";
925 case CXCompletionChunk_VerticalSpace
: return "VerticalSpace";
931 void print_completion_string(CXCompletionString completion_string
, FILE *file
) {
934 N
= clang_getNumCompletionChunks(completion_string
);
935 for (I
= 0; I
!= N
; ++I
) {
938 enum CXCompletionChunkKind Kind
939 = clang_getCompletionChunkKind(completion_string
, I
);
941 if (Kind
== CXCompletionChunk_Optional
) {
942 fprintf(file
, "{Optional ");
943 print_completion_string(
944 clang_getCompletionChunkCompletionString(completion_string
, I
),
950 if (Kind
== CXCompletionChunk_VerticalSpace
) {
951 fprintf(file
, "{VerticalSpace }");
955 text
= clang_getCompletionChunkText(completion_string
, I
);
956 cstr
= clang_getCString(text
);
957 fprintf(file
, "{%s %s}",
958 clang_getCompletionChunkKindSpelling(Kind
),
960 clang_disposeString(text
);
965 void print_completion_result(CXCompletionResult
*completion_result
,
966 CXClientData client_data
) {
967 FILE *file
= (FILE *)client_data
;
968 CXString ks
= clang_getCursorKindSpelling(completion_result
->CursorKind
);
970 fprintf(file
, "%s:", clang_getCString(ks
));
971 clang_disposeString(ks
);
973 print_completion_string(completion_result
->CompletionString
, file
);
974 fprintf(file
, " (%u)",
975 clang_getCompletionPriority(completion_result
->CompletionString
));
976 switch (clang_getCompletionAvailability(completion_result
->CompletionString
)){
977 case CXAvailability_Available
:
980 case CXAvailability_Deprecated
:
981 fprintf(file
, " (deprecated)");
984 case CXAvailability_NotAvailable
:
985 fprintf(file
, " (unavailable)");
991 int my_stricmp(const char *s1
, const char *s2
) {
993 int c1
= tolower(*s1
), c2
= tolower(*s2
);
1010 int perform_code_completion(int argc
, const char **argv
, int timing_only
) {
1011 const char *input
= argv
[1];
1017 struct CXUnsavedFile
*unsaved_files
= 0;
1018 int num_unsaved_files
= 0;
1019 CXCodeCompleteResults
*results
= 0;
1020 CXTranslationUnit TU
= 0;
1021 unsigned I
, Repeats
= 1;
1022 unsigned completionOptions
= clang_defaultCodeCompleteOptions();
1024 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
1025 completionOptions
|= CXCodeComplete_IncludeCodePatterns
;
1028 input
+= strlen("-code-completion-timing=");
1030 input
+= strlen("-code-completion-at=");
1032 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
1036 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
))
1039 CIdx
= clang_createIndex(0, 0);
1041 if (getenv("CINDEXTEST_EDITING"))
1044 TU
= clang_parseTranslationUnit(CIdx
, 0,
1045 argv
+ num_unsaved_files
+ 2,
1046 argc
- num_unsaved_files
- 2,
1047 0, 0, getDefaultParsingOptions());
1049 fprintf(stderr
, "Unable to load translation unit!\n");
1053 if (clang_reparseTranslationUnit(TU
, 0, 0, clang_defaultReparseOptions(TU
))) {
1054 fprintf(stderr
, "Unable to reparse translation init!\n");
1058 for (I
= 0; I
!= Repeats
; ++I
) {
1059 results
= clang_codeCompleteAt(TU
, filename
, line
, column
,
1060 unsaved_files
, num_unsaved_files
,
1063 fprintf(stderr
, "Unable to perform code completion!\n");
1067 clang_disposeCodeCompleteResults(results
);
1071 unsigned i
, n
= results
->NumResults
;
1073 /* Sort the code-completion results based on the typed text. */
1074 clang_sortCodeCompletionResults(results
->Results
, results
->NumResults
);
1076 for (i
= 0; i
!= n
; ++i
)
1077 print_completion_result(results
->Results
+ i
, stdout
);
1079 n
= clang_codeCompleteGetNumDiagnostics(results
);
1080 for (i
= 0; i
!= n
; ++i
) {
1081 CXDiagnostic diag
= clang_codeCompleteGetDiagnostic(results
, i
);
1082 PrintDiagnostic(diag
);
1083 clang_disposeDiagnostic(diag
);
1085 clang_disposeCodeCompleteResults(results
);
1087 clang_disposeTranslationUnit(TU
);
1088 clang_disposeIndex(CIdx
);
1091 free_remapped_files(unsaved_files
, num_unsaved_files
);
1100 } CursorSourceLocation
;
1102 int inspect_cursor_at(int argc
, const char **argv
) {
1105 struct CXUnsavedFile
*unsaved_files
= 0;
1106 int num_unsaved_files
= 0;
1107 CXTranslationUnit TU
;
1109 CursorSourceLocation
*Locations
= 0;
1110 unsigned NumLocations
= 0, Loc
;
1111 unsigned Repeats
= 1;
1114 /* Count the number of locations. */
1115 while (strstr(argv
[NumLocations
+1], "-cursor-at=") == argv
[NumLocations
+1])
1118 /* Parse the locations. */
1119 assert(NumLocations
> 0 && "Unable to count locations?");
1120 Locations
= (CursorSourceLocation
*)malloc(
1121 NumLocations
* sizeof(CursorSourceLocation
));
1122 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
1123 const char *input
= argv
[Loc
+ 1] + strlen("-cursor-at=");
1124 if ((errorCode
= parse_file_line_column(input
, &Locations
[Loc
].filename
,
1125 &Locations
[Loc
].line
,
1126 &Locations
[Loc
].column
, 0, 0)))
1130 if (parse_remapped_files(argc
, argv
, NumLocations
+ 1, &unsaved_files
,
1131 &num_unsaved_files
))
1134 if (getenv("CINDEXTEST_EDITING"))
1137 /* Parse the translation unit. When we're testing clang_getCursor() after
1138 reparsing, don't remap unsaved files until the second parse. */
1139 CIdx
= clang_createIndex(1, 1);
1140 TU
= clang_parseTranslationUnit(CIdx
, argv
[argc
- 1],
1141 argv
+ num_unsaved_files
+ 1 + NumLocations
,
1142 argc
- num_unsaved_files
- 2 - NumLocations
,
1144 Repeats
> 1? 0 : num_unsaved_files
,
1145 getDefaultParsingOptions());
1148 fprintf(stderr
, "unable to parse input\n");
1152 for (I
= 0; I
!= Repeats
; ++I
) {
1154 clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
1155 clang_defaultReparseOptions(TU
))) {
1156 clang_disposeTranslationUnit(TU
);
1160 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
1161 CXFile file
= clang_getFile(TU
, Locations
[Loc
].filename
);
1165 Cursor
= clang_getCursor(TU
,
1166 clang_getLocation(TU
, file
, Locations
[Loc
].line
,
1167 Locations
[Loc
].column
));
1168 if (I
+ 1 == Repeats
) {
1169 PrintCursor(Cursor
);
1171 free(Locations
[Loc
].filename
);
1176 PrintDiagnostics(TU
);
1177 clang_disposeTranslationUnit(TU
);
1178 clang_disposeIndex(CIdx
);
1180 free_remapped_files(unsaved_files
, num_unsaved_files
);
1184 int perform_token_annotation(int argc
, const char **argv
) {
1185 const char *input
= argv
[1];
1187 unsigned line
, second_line
;
1188 unsigned column
, second_column
;
1190 CXTranslationUnit TU
= 0;
1192 struct CXUnsavedFile
*unsaved_files
= 0;
1193 int num_unsaved_files
= 0;
1195 unsigned num_tokens
;
1196 CXSourceRange range
;
1197 CXSourceLocation startLoc
, endLoc
;
1199 CXCursor
*cursors
= 0;
1202 input
+= strlen("-test-annotate-tokens=");
1203 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
1204 &second_line
, &second_column
)))
1207 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
))
1210 CIdx
= clang_createIndex(0, 1);
1211 TU
= clang_createTranslationUnitFromSourceFile(CIdx
, argv
[argc
- 1],
1212 argc
- num_unsaved_files
- 3,
1213 argv
+ num_unsaved_files
+ 2,
1217 fprintf(stderr
, "unable to parse input\n");
1218 clang_disposeIndex(CIdx
);
1220 free_remapped_files(unsaved_files
, num_unsaved_files
);
1225 file
= clang_getFile(TU
, filename
);
1227 fprintf(stderr
, "file %s is not in this translation unit\n", filename
);
1232 startLoc
= clang_getLocation(TU
, file
, line
, column
);
1233 if (clang_equalLocations(clang_getNullLocation(), startLoc
)) {
1234 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
, line
,
1240 endLoc
= clang_getLocation(TU
, file
, second_line
, second_column
);
1241 if (clang_equalLocations(clang_getNullLocation(), endLoc
)) {
1242 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
,
1243 second_line
, second_column
);
1248 range
= clang_getRange(startLoc
, endLoc
);
1249 clang_tokenize(TU
, range
, &tokens
, &num_tokens
);
1250 cursors
= (CXCursor
*)malloc(num_tokens
* sizeof(CXCursor
));
1251 clang_annotateTokens(TU
, tokens
, num_tokens
, cursors
);
1252 for (i
= 0; i
!= num_tokens
; ++i
) {
1253 const char *kind
= "<unknown>";
1254 CXString spelling
= clang_getTokenSpelling(TU
, tokens
[i
]);
1255 CXSourceRange extent
= clang_getTokenExtent(TU
, tokens
[i
]);
1256 unsigned start_line
, start_column
, end_line
, end_column
;
1258 switch (clang_getTokenKind(tokens
[i
])) {
1259 case CXToken_Punctuation
: kind
= "Punctuation"; break;
1260 case CXToken_Keyword
: kind
= "Keyword"; break;
1261 case CXToken_Identifier
: kind
= "Identifier"; break;
1262 case CXToken_Literal
: kind
= "Literal"; break;
1263 case CXToken_Comment
: kind
= "Comment"; break;
1265 clang_getSpellingLocation(clang_getRangeStart(extent
),
1266 0, &start_line
, &start_column
, 0);
1267 clang_getSpellingLocation(clang_getRangeEnd(extent
),
1268 0, &end_line
, &end_column
, 0);
1269 printf("%s: \"%s\" ", kind
, clang_getCString(spelling
));
1270 PrintExtent(stdout
, start_line
, start_column
, end_line
, end_column
);
1271 if (!clang_isInvalid(cursors
[i
].kind
)) {
1273 PrintCursor(cursors
[i
]);
1278 clang_disposeTokens(TU
, tokens
, num_tokens
);
1281 PrintDiagnostics(TU
);
1282 clang_disposeTranslationUnit(TU
);
1283 clang_disposeIndex(CIdx
);
1285 free_remapped_files(unsaved_files
, num_unsaved_files
);
1289 /******************************************************************************/
1291 /******************************************************************************/
1293 static int insufficient_usr(const char *kind
, const char *usage
) {
1294 fprintf(stderr
, "USR for '%s' requires: %s\n", kind
, usage
);
1298 static unsigned isUSR(const char *s
) {
1299 return s
[0] == 'c' && s
[1] == ':';
1302 static int not_usr(const char *s
, const char *arg
) {
1303 fprintf(stderr
, "'%s' argument ('%s') is not a USR\n", s
, arg
);
1307 static void print_usr(CXString usr
) {
1308 const char *s
= clang_getCString(usr
);
1310 clang_disposeString(usr
);
1313 static void display_usrs() {
1314 fprintf(stderr
, "-print-usrs options:\n"
1315 " ObjCCategory <class name> <category name>\n"
1316 " ObjCClass <class name>\n"
1317 " ObjCIvar <ivar name> <class USR>\n"
1318 " ObjCMethod <selector> [0=class method|1=instance method] "
1320 " ObjCProperty <property name> <class USR>\n"
1321 " ObjCProtocol <protocol name>\n");
1324 int print_usrs(const char **I
, const char **E
) {
1326 const char *kind
= *I
;
1327 unsigned len
= strlen(kind
);
1330 if (memcmp(kind
, "ObjCIvar", 8) == 0) {
1332 return insufficient_usr(kind
, "<ivar name> <class USR>");
1334 return not_usr("<class USR>", I
[2]);
1337 x
.data
= (void*) I
[2];
1338 x
.private_flags
= 0;
1339 print_usr(clang_constructUSR_ObjCIvar(I
[1], x
));
1347 if (memcmp(kind
, "ObjCClass", 9) == 0) {
1349 return insufficient_usr(kind
, "<class name>");
1350 print_usr(clang_constructUSR_ObjCClass(I
[1]));
1356 if (memcmp(kind
, "ObjCMethod", 10) == 0) {
1358 return insufficient_usr(kind
, "<method selector> "
1359 "[0=class method|1=instance method] <class USR>");
1361 return not_usr("<class USR>", I
[3]);
1364 x
.data
= (void*) I
[3];
1365 x
.private_flags
= 0;
1366 print_usr(clang_constructUSR_ObjCMethod(I
[1], atoi(I
[2]), x
));
1373 if (memcmp(kind
, "ObjCCategory", 12) == 0) {
1375 return insufficient_usr(kind
, "<class name> <category name>");
1376 print_usr(clang_constructUSR_ObjCCategory(I
[1], I
[2]));
1380 if (memcmp(kind
, "ObjCProtocol", 12) == 0) {
1382 return insufficient_usr(kind
, "<protocol name>");
1383 print_usr(clang_constructUSR_ObjCProtocol(I
[1]));
1387 if (memcmp(kind
, "ObjCProperty", 12) == 0) {
1389 return insufficient_usr(kind
, "<property name> <class USR>");
1391 return not_usr("<class USR>", I
[2]);
1394 x
.data
= (void*) I
[2];
1395 x
.private_flags
= 0;
1396 print_usr(clang_constructUSR_ObjCProperty(I
[1], x
));
1409 fprintf(stderr
, "Invalid USR kind: %s\n", *I
);
1416 int print_usrs_file(const char *file_name
) {
1418 const char *args
[128];
1419 unsigned numChars
= 0;
1421 FILE *fp
= fopen(file_name
, "r");
1423 fprintf(stderr
, "error: cannot open '%s'\n", file_name
);
1427 /* This code is not really all that safe, but it works fine for testing. */
1437 line
[numChars
] = '\0';
1440 if (line
[0] == '/' && line
[1] == '/')
1443 s
= strtok(line
, " ");
1449 if (print_usrs(&args
[0], &args
[i
]))
1453 line
[numChars
++] = c
;
1460 /******************************************************************************/
1461 /* Command line processing. */
1462 /******************************************************************************/
1463 int write_pch_file(const char *filename
, int argc
, const char *argv
[]) {
1465 CXTranslationUnit TU
;
1466 struct CXUnsavedFile
*unsaved_files
= 0;
1467 int num_unsaved_files
= 0;
1469 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnosics=*/1);
1471 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
1472 clang_disposeIndex(Idx
);
1476 TU
= clang_parseTranslationUnit(Idx
, 0,
1477 argv
+ num_unsaved_files
,
1478 argc
- num_unsaved_files
,
1481 CXTranslationUnit_Incomplete
);
1483 fprintf(stderr
, "Unable to load translation unit!\n");
1484 free_remapped_files(unsaved_files
, num_unsaved_files
);
1485 clang_disposeIndex(Idx
);
1489 if (clang_saveTranslationUnit(TU
, filename
, clang_defaultSaveOptions(TU
)))
1490 fprintf(stderr
, "Unable to write PCH file %s\n", filename
);
1491 clang_disposeTranslationUnit(TU
);
1492 free_remapped_files(unsaved_files
, num_unsaved_files
);
1493 clang_disposeIndex(Idx
);
1497 /******************************************************************************/
1498 /* Command line processing. */
1499 /******************************************************************************/
1501 static CXCursorVisitor
GetVisitor(const char *s
) {
1503 return FilteredPrintingVisitor
;
1504 if (strcmp(s
, "-usrs") == 0)
1509 static void print_usage(void) {
1511 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
1512 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
1513 " c-index-test -cursor-at=<site> <compiler arguments>\n"
1514 " c-index-test -test-file-scan <AST file> <source file> "
1515 "[FileCheck prefix]\n"
1516 " c-index-test -test-load-tu <AST file> <symbol filter> "
1517 "[FileCheck prefix]\n"
1518 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
1519 "[FileCheck prefix]\n"
1520 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
1522 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
1524 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
1525 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
1526 " c-index-test -test-inclusion-stack-source {<args>}*\n"
1527 " c-index-test -test-inclusion-stack-tu <AST file>\n"
1528 " c-index-test -test-print-linkage-source {<args>}*\n"
1529 " c-index-test -test-print-typekind {<args>}*\n"
1530 " c-index-test -print-usr [<CursorKind> {<args>}]*\n");
1532 " c-index-test -print-usr-file <file>\n"
1533 " c-index-test -write-pch <file> <compiler arguments>\n\n");
1535 " <symbol filter> values:\n%s",
1536 " all - load all symbols, including those from PCH\n"
1537 " local - load all symbols except those in PCH\n"
1538 " category - only load ObjC categories (non-PCH)\n"
1539 " interface - only load ObjC interfaces (non-PCH)\n"
1540 " protocol - only load ObjC protocols (non-PCH)\n"
1541 " function - only load functions (non-PCH)\n"
1542 " typedef - only load typdefs (non-PCH)\n"
1543 " scan-function - scan function bodies (non-PCH)\n\n");
1548 int cindextest_main(int argc
, const char **argv
) {
1549 clang_enableStackTraces();
1550 if (argc
> 2 && strstr(argv
[1], "-code-completion-at=") == argv
[1])
1551 return perform_code_completion(argc
, argv
, 0);
1552 if (argc
> 2 && strstr(argv
[1], "-code-completion-timing=") == argv
[1])
1553 return perform_code_completion(argc
, argv
, 1);
1554 if (argc
> 2 && strstr(argv
[1], "-cursor-at=") == argv
[1])
1555 return inspect_cursor_at(argc
, argv
);
1556 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-tu", 13) == 0) {
1557 CXCursorVisitor I
= GetVisitor(argv
[1] + 13);
1559 return perform_test_load_tu(argv
[2], argv
[3], argc
>= 5 ? argv
[4] : 0, I
,
1562 else if (argc
>= 5 && strncmp(argv
[1], "-test-load-source-reparse", 25) == 0){
1563 CXCursorVisitor I
= GetVisitor(argv
[1] + 25);
1565 int trials
= atoi(argv
[2]);
1566 return perform_test_reparse_source(argc
- 4, argv
+ 4, trials
, argv
[3], I
,
1570 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-source", 17) == 0) {
1571 CXCursorVisitor I
= GetVisitor(argv
[1] + 17);
1573 return perform_test_load_source(argc
- 3, argv
+ 3, argv
[2], I
, NULL
);
1575 else if (argc
>= 4 && strcmp(argv
[1], "-test-file-scan") == 0)
1576 return perform_file_scan(argv
[2], argv
[3],
1577 argc
>= 5 ? argv
[4] : 0);
1578 else if (argc
> 2 && strstr(argv
[1], "-test-annotate-tokens=") == argv
[1])
1579 return perform_token_annotation(argc
, argv
);
1580 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-source") == 0)
1581 return perform_test_load_source(argc
- 2, argv
+ 2, "all", NULL
,
1582 PrintInclusionStack
);
1583 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-tu") == 0)
1584 return perform_test_load_tu(argv
[2], "all", NULL
, NULL
,
1585 PrintInclusionStack
);
1586 else if (argc
> 2 && strcmp(argv
[1], "-test-print-linkage-source") == 0)
1587 return perform_test_load_source(argc
- 2, argv
+ 2, "all", PrintLinkage
,
1589 else if (argc
> 2 && strcmp(argv
[1], "-test-print-typekind") == 0)
1590 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
1592 else if (argc
> 1 && strcmp(argv
[1], "-print-usr") == 0) {
1594 return print_usrs(argv
+ 2, argv
+ argc
);
1600 else if (argc
> 2 && strcmp(argv
[1], "-print-usr-file") == 0)
1601 return print_usrs_file(argv
[2]);
1602 else if (argc
> 2 && strcmp(argv
[1], "-write-pch") == 0)
1603 return write_pch_file(argv
[2], argc
- 3, argv
+ 3);
1611 /* We intentionally run in a separate thread to ensure we at least minimal
1612 * testing of a multithreaded environment (for example, having a reduced stack
1615 typedef struct thread_info
{
1620 void thread_runner(void *client_data_v
) {
1621 thread_info
*client_data
= client_data_v
;
1622 client_data
->result
= cindextest_main(client_data
->argc
, client_data
->argv
);
1625 int main(int argc
, const char **argv
) {
1626 thread_info client_data
;
1628 if (getenv("CINDEXTEST_NOTHREADS"))
1629 return cindextest_main(argc
, argv
);
1631 client_data
.argc
= argc
;
1632 client_data
.argv
= argv
;
1633 clang_executeOnThread(thread_runner
, &client_data
, 0);
1634 return client_data
.result
;