3 #include "clang/Config/config.h"
4 #include "clang-c/Index.h"
5 #include "clang-c/CXCompilationDatabase.h"
6 #include "clang-c/BuildSystem.h"
7 #include "clang-c/Documentation.h"
14 #ifdef CLANG_HAVE_LIBXML
15 #include <libxml/parser.h>
16 #include <libxml/relaxng.h>
17 #include <libxml/xmlerror.h>
26 extern int indextest_core_main(int argc, const char **argv);
28 /******************************************************************************/
29 /* Utility functions. */
30 /******************************************************************************/
33 char *basename(const char* path)
35 char* base1 = (char*)strrchr(path, '/');
36 char* base2 = (char*)strrchr(path, '\\');
38 return((base1 > base2) ? base1 + 1 : base2 + 1);
46 char *dirname(char* path)
48 char* base1 = (char*)strrchr(path, '/');
49 char* base2 = (char*)strrchr(path, '\\');
63 extern char *basename(const char *);
64 extern char *dirname(char *);
67 /** \brief Return the default parsing options. */
68 static unsigned getDefaultParsingOptions() {
69 unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
71 if (getenv("CINDEXTEST_EDITING"))
72 options |= clang_defaultEditingTranslationUnitOptions();
73 if (getenv("CINDEXTEST_COMPLETION_CACHING"))
74 options |= CXTranslationUnit_CacheCompletionResults;
75 if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
76 options &= ~CXTranslationUnit_CacheCompletionResults;
77 if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
78 options |= CXTranslationUnit_SkipFunctionBodies;
79 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
80 options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
81 if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
82 options |= CXTranslationUnit_CreatePreambleOnFirstParse;
83 if (getenv("CINDEXTEST_KEEP_GOING"))
84 options |= CXTranslationUnit_KeepGoing;
89 /** \brief Returns 0 in case of success, non-zero in case of a failure. */
90 static int checkForErrors(CXTranslationUnit TU);
92 static void describeLibclangFailure(enum CXErrorCode Err) {
95 fprintf(stderr, "Success\n");
99 fprintf(stderr, "Failure (no details available)\n");
102 case CXError_Crashed:
103 fprintf(stderr, "Failure: libclang crashed\n");
106 case CXError_InvalidArguments:
107 fprintf(stderr, "Failure: invalid arguments passed to a libclang routine\n");
110 case CXError_ASTReadError:
111 fprintf(stderr, "Failure: AST deserialization error occurred\n");
116 static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
117 unsigned end_line, unsigned end_column) {
118 fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
119 end_line, end_column);
122 static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
123 CXTranslationUnit *TU) {
124 enum CXErrorCode Err = clang_createTranslationUnit2(Idx, file, TU);
125 if (Err != CXError_Success) {
126 fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
127 describeLibclangFailure(Err);
134 void free_remapped_files(struct CXUnsavedFile *unsaved_files,
135 int num_unsaved_files) {
137 for (i = 0; i != num_unsaved_files; ++i) {
138 free((char *)unsaved_files[i].Filename);
139 free((char *)unsaved_files[i].Contents);
144 static int parse_remapped_files_with_opt(const char *opt_name,
145 int argc, const char **argv,
147 struct CXUnsavedFile **unsaved_files,
148 int *num_unsaved_files) {
151 int prefix_len = strlen(opt_name);
154 *num_unsaved_files = 0;
156 /* Count the number of remapped files. */
157 for (arg = start_arg; arg < argc; ++arg) {
158 if (strncmp(argv[arg], opt_name, prefix_len))
161 assert(*num_unsaved_files < (int)(sizeof(arg_indices)/sizeof(int)));
162 arg_indices[*num_unsaved_files] = arg;
163 ++*num_unsaved_files;
166 if (*num_unsaved_files == 0)
170 = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
172 for (i = 0; i != *num_unsaved_files; ++i) {
173 struct CXUnsavedFile *unsaved = *unsaved_files + i;
174 const char *arg_string = argv[arg_indices[i]] + prefix_len;
179 const char *sep = strchr(arg_string, ',');
182 "error: %sfrom:to argument is missing comma\n", opt_name);
183 free_remapped_files(*unsaved_files, i);
185 *num_unsaved_files = 0;
189 /* Open the file that we're remapping to. */
190 to_file = fopen(sep + 1, "rb");
192 fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
194 free_remapped_files(*unsaved_files, i);
196 *num_unsaved_files = 0;
200 /* Determine the length of the file we're remapping to. */
201 fseek(to_file, 0, SEEK_END);
202 unsaved->Length = ftell(to_file);
203 fseek(to_file, 0, SEEK_SET);
205 /* Read the contents of the file we're remapping to. */
206 contents = (char *)malloc(unsaved->Length + 1);
207 if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
208 fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
209 (feof(to_file) ? "EOF" : "error"), sep + 1);
211 free_remapped_files(*unsaved_files, i);
214 *num_unsaved_files = 0;
217 contents[unsaved->Length] = 0;
218 unsaved->Contents = contents;
220 /* Close the file. */
223 /* Copy the file name that we're remapping from. */
224 filename_len = sep - arg_string;
225 filename = (char *)malloc(filename_len + 1);
226 memcpy(filename, arg_string, filename_len);
227 filename[filename_len] = 0;
228 unsaved->Filename = filename;
234 static int parse_remapped_files(int argc, const char **argv, int start_arg,
235 struct CXUnsavedFile **unsaved_files,
236 int *num_unsaved_files) {
237 return parse_remapped_files_with_opt("-remap-file=", argc, argv, start_arg,
238 unsaved_files, num_unsaved_files);
241 static int parse_remapped_files_with_try(int try_idx,
242 int argc, const char **argv,
244 struct CXUnsavedFile **unsaved_files,
245 int *num_unsaved_files) {
246 struct CXUnsavedFile *unsaved_files_no_try_idx;
247 int num_unsaved_files_no_try_idx;
248 struct CXUnsavedFile *unsaved_files_try_idx;
249 int num_unsaved_files_try_idx;
253 ret = parse_remapped_files(argc, argv, start_arg,
254 &unsaved_files_no_try_idx, &num_unsaved_files_no_try_idx);
258 sprintf(opt_name, "-remap-file-%d=", try_idx);
259 ret = parse_remapped_files_with_opt(opt_name, argc, argv, start_arg,
260 &unsaved_files_try_idx, &num_unsaved_files_try_idx);
264 if (num_unsaved_files_no_try_idx == 0) {
265 *unsaved_files = unsaved_files_try_idx;
266 *num_unsaved_files = num_unsaved_files_try_idx;
269 if (num_unsaved_files_try_idx == 0) {
270 *unsaved_files = unsaved_files_no_try_idx;
271 *num_unsaved_files = num_unsaved_files_no_try_idx;
275 *num_unsaved_files = num_unsaved_files_no_try_idx + num_unsaved_files_try_idx;
277 = (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
278 sizeof(struct CXUnsavedFile) *
280 memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
281 unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
282 num_unsaved_files_try_idx);
283 free(unsaved_files_try_idx);
287 static const char *parse_comments_schema(int argc, const char **argv) {
288 const char *CommentsSchemaArg = "-comments-xml-schema=";
289 const char *CommentSchemaFile = NULL;
292 return CommentSchemaFile;
294 if (!strncmp(argv[0], CommentsSchemaArg, strlen(CommentsSchemaArg)))
295 CommentSchemaFile = argv[0] + strlen(CommentsSchemaArg);
297 return CommentSchemaFile;
300 /******************************************************************************/
301 /* Pretty-printing. */
302 /******************************************************************************/
304 static const char *FileCheckPrefix = "CHECK";
306 static void PrintCString(const char *CStr) {
307 if (CStr != NULL && CStr[0] != '\0') {
308 for ( ; *CStr; ++CStr) {
309 const char C = *CStr;
311 case '\n': printf("\\n"); break;
312 case '\r': printf("\\r"); break;
313 case '\t': printf("\\t"); break;
314 case '\v': printf("\\v"); break;
315 case '\f': printf("\\f"); break;
316 default: putchar(C); break;
322 static void PrintCStringWithPrefix(const char *Prefix, const char *CStr) {
323 printf(" %s=[", Prefix);
328 static void PrintCXStringAndDispose(CXString Str) {
329 PrintCString(clang_getCString(Str));
330 clang_disposeString(Str);
333 static void PrintCXStringWithPrefix(const char *Prefix, CXString Str) {
334 PrintCStringWithPrefix(Prefix, clang_getCString(Str));
337 static void PrintCXStringWithPrefixAndDispose(const char *Prefix,
339 PrintCStringWithPrefix(Prefix, clang_getCString(Str));
340 clang_disposeString(Str);
343 static void PrintRange(CXSourceRange R, const char *str) {
344 CXFile begin_file, end_file;
345 unsigned begin_line, begin_column, end_line, end_column;
347 clang_getSpellingLocation(clang_getRangeStart(R),
348 &begin_file, &begin_line, &begin_column, 0);
349 clang_getSpellingLocation(clang_getRangeEnd(R),
350 &end_file, &end_line, &end_column, 0);
351 if (!begin_file || !end_file)
356 PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
359 int want_display_name = 0;
361 static void printVersion(const char *Prefix, CXVersion Version) {
362 if (Version.Major < 0)
364 printf("%s%d", Prefix, Version.Major);
366 if (Version.Minor < 0)
368 printf(".%d", Version.Minor);
370 if (Version.Subminor < 0)
372 printf(".%d", Version.Subminor);
375 struct CommentASTDumpingContext {
379 static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
383 enum CXCommentKind Kind = clang_Comment_getKind(Comment);
386 for (i = 0, e = Ctx->IndentLevel; i != e; ++i)
392 printf("CXComment_Null");
395 printf("CXComment_Text");
396 PrintCXStringWithPrefixAndDispose("Text",
397 clang_TextComment_getText(Comment));
398 if (clang_Comment_isWhitespace(Comment))
399 printf(" IsWhitespace");
400 if (clang_InlineContentComment_hasTrailingNewline(Comment))
401 printf(" HasTrailingNewline");
403 case CXComment_InlineCommand:
404 printf("CXComment_InlineCommand");
405 PrintCXStringWithPrefixAndDispose(
407 clang_InlineCommandComment_getCommandName(Comment));
408 switch (clang_InlineCommandComment_getRenderKind(Comment)) {
409 case CXCommentInlineCommandRenderKind_Normal:
410 printf(" RenderNormal");
412 case CXCommentInlineCommandRenderKind_Bold:
413 printf(" RenderBold");
415 case CXCommentInlineCommandRenderKind_Monospaced:
416 printf(" RenderMonospaced");
418 case CXCommentInlineCommandRenderKind_Emphasized:
419 printf(" RenderEmphasized");
422 for (i = 0, e = clang_InlineCommandComment_getNumArgs(Comment);
424 printf(" Arg[%u]=", i);
425 PrintCXStringAndDispose(
426 clang_InlineCommandComment_getArgText(Comment, i));
428 if (clang_InlineContentComment_hasTrailingNewline(Comment))
429 printf(" HasTrailingNewline");
431 case CXComment_HTMLStartTag: {
433 printf("CXComment_HTMLStartTag");
434 PrintCXStringWithPrefixAndDispose(
436 clang_HTMLTagComment_getTagName(Comment));
437 NumAttrs = clang_HTMLStartTag_getNumAttrs(Comment);
440 for (i = 0; i != NumAttrs; ++i) {
442 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment, i));
444 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment, i));
447 if (clang_HTMLStartTagComment_isSelfClosing(Comment))
448 printf(" SelfClosing");
449 if (clang_InlineContentComment_hasTrailingNewline(Comment))
450 printf(" HasTrailingNewline");
453 case CXComment_HTMLEndTag:
454 printf("CXComment_HTMLEndTag");
455 PrintCXStringWithPrefixAndDispose(
457 clang_HTMLTagComment_getTagName(Comment));
458 if (clang_InlineContentComment_hasTrailingNewline(Comment))
459 printf(" HasTrailingNewline");
461 case CXComment_Paragraph:
462 printf("CXComment_Paragraph");
463 if (clang_Comment_isWhitespace(Comment))
464 printf(" IsWhitespace");
466 case CXComment_BlockCommand:
467 printf("CXComment_BlockCommand");
468 PrintCXStringWithPrefixAndDispose(
470 clang_BlockCommandComment_getCommandName(Comment));
471 for (i = 0, e = clang_BlockCommandComment_getNumArgs(Comment);
473 printf(" Arg[%u]=", i);
474 PrintCXStringAndDispose(
475 clang_BlockCommandComment_getArgText(Comment, i));
478 case CXComment_ParamCommand:
479 printf("CXComment_ParamCommand");
480 switch (clang_ParamCommandComment_getDirection(Comment)) {
481 case CXCommentParamPassDirection_In:
484 case CXCommentParamPassDirection_Out:
487 case CXCommentParamPassDirection_InOut:
491 if (clang_ParamCommandComment_isDirectionExplicit(Comment))
492 printf(" explicitly");
494 printf(" implicitly");
495 PrintCXStringWithPrefixAndDispose(
497 clang_ParamCommandComment_getParamName(Comment));
498 if (clang_ParamCommandComment_isParamIndexValid(Comment))
499 printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment));
501 printf(" ParamIndex=Invalid");
503 case CXComment_TParamCommand:
504 printf("CXComment_TParamCommand");
505 PrintCXStringWithPrefixAndDispose(
507 clang_TParamCommandComment_getParamName(Comment));
508 if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
509 printf(" ParamPosition={");
510 for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
512 printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
518 printf(" ParamPosition=Invalid");
520 case CXComment_VerbatimBlockCommand:
521 printf("CXComment_VerbatimBlockCommand");
522 PrintCXStringWithPrefixAndDispose(
524 clang_BlockCommandComment_getCommandName(Comment));
526 case CXComment_VerbatimBlockLine:
527 printf("CXComment_VerbatimBlockLine");
528 PrintCXStringWithPrefixAndDispose(
530 clang_VerbatimBlockLineComment_getText(Comment));
532 case CXComment_VerbatimLine:
533 printf("CXComment_VerbatimLine");
534 PrintCXStringWithPrefixAndDispose(
536 clang_VerbatimLineComment_getText(Comment));
538 case CXComment_FullComment:
539 printf("CXComment_FullComment");
542 if (Kind != CXComment_Null) {
543 const unsigned NumChildren = clang_Comment_getNumChildren(Comment);
545 for (i = 0; i != NumChildren; ++i) {
546 printf("\n// %s: ", FileCheckPrefix);
547 DumpCXCommentInternal(Ctx, clang_Comment_getChild(Comment, i));
554 static void DumpCXComment(CXComment Comment) {
555 struct CommentASTDumpingContext Ctx;
557 printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix, FileCheckPrefix);
558 DumpCXCommentInternal(&Ctx, Comment);
562 static void ValidateCommentXML(const char *Str, const char *CommentSchemaFile) {
563 #ifdef CLANG_HAVE_LIBXML
564 xmlRelaxNGParserCtxtPtr RNGParser;
565 xmlRelaxNGPtr Schema;
567 xmlRelaxNGValidCtxtPtr ValidationCtxt;
570 if (!CommentSchemaFile)
573 RNGParser = xmlRelaxNGNewParserCtxt(CommentSchemaFile);
575 printf(" libXMLError");
578 Schema = xmlRelaxNGParse(RNGParser);
580 Doc = xmlParseDoc((const xmlChar *) Str);
583 xmlErrorPtr Error = xmlGetLastError();
584 printf(" CommentXMLInvalid [not well-formed XML: %s]", Error->message);
588 ValidationCtxt = xmlRelaxNGNewValidCtxt(Schema);
589 status = xmlRelaxNGValidateDoc(ValidationCtxt, Doc);
591 printf(" CommentXMLValid");
592 else if (status > 0) {
593 xmlErrorPtr Error = xmlGetLastError();
594 printf(" CommentXMLInvalid [not vaild XML: %s]", Error->message);
596 printf(" libXMLError");
598 xmlRelaxNGFreeValidCtxt(ValidationCtxt);
600 xmlRelaxNGFree(Schema);
601 xmlRelaxNGFreeParserCtxt(RNGParser);
605 static void PrintCursorComments(CXCursor Cursor,
606 const char *CommentSchemaFile) {
609 const char *RawCommentCString;
610 CXString BriefComment;
611 const char *BriefCommentCString;
613 RawComment = clang_Cursor_getRawCommentText(Cursor);
614 RawCommentCString = clang_getCString(RawComment);
615 if (RawCommentCString != NULL && RawCommentCString[0] != '\0') {
616 PrintCStringWithPrefix("RawComment", RawCommentCString);
617 PrintRange(clang_Cursor_getCommentRange(Cursor), "RawCommentRange");
619 BriefComment = clang_Cursor_getBriefCommentText(Cursor);
620 BriefCommentCString = clang_getCString(BriefComment);
621 if (BriefCommentCString != NULL && BriefCommentCString[0] != '\0')
622 PrintCStringWithPrefix("BriefComment", BriefCommentCString);
623 clang_disposeString(BriefComment);
625 clang_disposeString(RawComment);
629 CXComment Comment = clang_Cursor_getParsedComment(Cursor);
630 if (clang_Comment_getKind(Comment) != CXComment_Null) {
631 PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
632 clang_FullComment_getAsHTML(Comment));
635 XML = clang_FullComment_getAsXML(Comment);
636 PrintCXStringWithPrefix("FullCommentAsXML", XML);
637 ValidateCommentXML(clang_getCString(XML), CommentSchemaFile);
638 clang_disposeString(XML);
641 DumpCXComment(Comment);
651 static int lineCol_cmp(const void *p1, const void *p2) {
652 const LineCol *lhs = p1;
653 const LineCol *rhs = p2;
654 if (lhs->line != rhs->line)
655 return (int)lhs->line - (int)rhs->line;
656 return (int)lhs->col - (int)rhs->col;
659 static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
660 CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
661 if (clang_isInvalid(Cursor.kind)) {
662 CXString ks = clang_getCursorKindSpelling(Cursor.kind);
663 printf("Invalid Cursor => %s", clang_getCString(ks));
664 clang_disposeString(ks);
669 unsigned line, column;
670 CXCursor SpecializationOf;
671 CXCursor *overridden;
672 unsigned num_overridden;
673 unsigned RefNameRangeNr;
674 CXSourceRange CursorExtent;
675 CXSourceRange RefNameRange;
676 int AlwaysUnavailable;
677 int AlwaysDeprecated;
678 CXString UnavailableMessage;
679 CXString DeprecatedMessage;
680 CXPlatformAvailability PlatformAvailability[2];
681 int NumPlatformAvailability;
684 ks = clang_getCursorKindSpelling(Cursor.kind);
685 string = want_display_name? clang_getCursorDisplayName(Cursor)
686 : clang_getCursorSpelling(Cursor);
687 printf("%s=%s", clang_getCString(ks),
688 clang_getCString(string));
689 clang_disposeString(ks);
690 clang_disposeString(string);
692 Referenced = clang_getCursorReferenced(Cursor);
693 if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
694 if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) {
695 unsigned I, N = clang_getNumOverloadedDecls(Referenced);
697 for (I = 0; I != N; ++I) {
698 CXCursor Ovl = clang_getOverloadedDecl(Referenced, I);
699 CXSourceLocation Loc;
703 Loc = clang_getCursorLocation(Ovl);
704 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
705 printf("%d:%d", line, column);
709 CXSourceLocation Loc = clang_getCursorLocation(Referenced);
710 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
711 printf(":%d:%d", line, column);
714 if (clang_getCursorKind(Referenced) == CXCursor_TypedefDecl) {
715 CXType T = clang_getCursorType(Referenced);
716 if (clang_Type_isTransparentTagTypedef(T)) {
717 CXType Underlying = clang_getTypedefDeclUnderlyingType(Referenced);
718 CXString S = clang_getTypeSpelling(Underlying);
719 printf(" (Transparent: %s)", clang_getCString(S));
720 clang_disposeString(S);
725 if (clang_isCursorDefinition(Cursor))
726 printf(" (Definition)");
728 switch (clang_getCursorAvailability(Cursor)) {
729 case CXAvailability_Available:
732 case CXAvailability_Deprecated:
733 printf(" (deprecated)");
736 case CXAvailability_NotAvailable:
737 printf(" (unavailable)");
740 case CXAvailability_NotAccessible:
741 printf(" (inaccessible)");
745 NumPlatformAvailability
746 = clang_getCursorPlatformAvailability(Cursor,
751 PlatformAvailability, 2);
752 if (AlwaysUnavailable) {
753 printf(" (always unavailable: \"%s\")",
754 clang_getCString(UnavailableMessage));
755 } else if (AlwaysDeprecated) {
756 printf(" (always deprecated: \"%s\")",
757 clang_getCString(DeprecatedMessage));
759 for (I = 0; I != NumPlatformAvailability; ++I) {
763 printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
764 if (PlatformAvailability[I].Unavailable)
765 printf(", unavailable");
767 printVersion(", introduced=", PlatformAvailability[I].Introduced);
768 printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
769 printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
771 if (clang_getCString(PlatformAvailability[I].Message)[0])
772 printf(", message=\"%s\"",
773 clang_getCString(PlatformAvailability[I].Message));
777 for (I = 0; I != NumPlatformAvailability; ++I) {
780 clang_disposeCXPlatformAvailability(PlatformAvailability + I);
783 clang_disposeString(DeprecatedMessage);
784 clang_disposeString(UnavailableMessage);
786 if (clang_CXXConstructor_isDefaultConstructor(Cursor))
787 printf(" (default constructor)");
789 if (clang_CXXConstructor_isMoveConstructor(Cursor))
790 printf(" (move constructor)");
791 if (clang_CXXConstructor_isCopyConstructor(Cursor))
792 printf(" (copy constructor)");
793 if (clang_CXXConstructor_isConvertingConstructor(Cursor))
794 printf(" (converting constructor)");
795 if (clang_CXXField_isMutable(Cursor))
796 printf(" (mutable)");
797 if (clang_CXXMethod_isDefaulted(Cursor))
798 printf(" (defaulted)");
799 if (clang_CXXMethod_isStatic(Cursor))
801 if (clang_CXXMethod_isVirtual(Cursor))
802 printf(" (virtual)");
803 if (clang_CXXMethod_isConst(Cursor))
805 if (clang_CXXMethod_isPureVirtual(Cursor))
807 if (clang_Cursor_isVariadic(Cursor))
808 printf(" (variadic)");
809 if (clang_Cursor_isObjCOptional(Cursor))
810 printf(" (@optional)");
812 if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
814 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
815 CXString S = clang_getTypeKindSpelling(T.kind);
816 printf(" [IBOutletCollection=%s]", clang_getCString(S));
817 clang_disposeString(S);
820 if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
821 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
822 unsigned isVirtual = clang_isVirtualBase(Cursor);
823 const char *accessStr = 0;
826 case CX_CXXInvalidAccessSpecifier:
827 accessStr = "invalid"; break;
829 accessStr = "public"; break;
830 case CX_CXXProtected:
831 accessStr = "protected"; break;
833 accessStr = "private"; break;
836 printf(" [access=%s isVirtual=%s]", accessStr,
837 isVirtual ? "true" : "false");
840 SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
841 if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
842 CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
843 CXString Name = clang_getCursorSpelling(SpecializationOf);
844 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
845 printf(" [Specialization of %s:%d:%d]",
846 clang_getCString(Name), line, column);
847 clang_disposeString(Name);
849 if (Cursor.kind == CXCursor_FunctionDecl) {
850 /* Collect the template parameter kinds from the base template. */
851 int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
853 if (NumTemplateArgs < 0) {
854 printf(" [no template arg info]");
856 for (I = 0; I < NumTemplateArgs; I++) {
857 enum CXTemplateArgumentKind TAK =
858 clang_Cursor_getTemplateArgumentKind(Cursor, I);
860 case CXTemplateArgumentKind_Type:
862 CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
863 CXString S = clang_getTypeSpelling(T);
864 printf(" [Template arg %d: kind: %d, type: %s]",
865 I, TAK, clang_getCString(S));
866 clang_disposeString(S);
869 case CXTemplateArgumentKind_Integral:
870 printf(" [Template arg %d: kind: %d, intval: %lld]",
871 I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
874 printf(" [Template arg %d: kind: %d]\n", I, TAK);
880 clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
881 if (num_overridden) {
883 LineCol lineCols[50];
884 assert(num_overridden <= 50);
885 printf(" [Overrides ");
886 for (I = 0; I != num_overridden; ++I) {
887 CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
888 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
889 lineCols[I].line = line;
890 lineCols[I].col = column;
892 /* Make the order of the override list deterministic. */
893 qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
894 for (I = 0; I != num_overridden; ++I) {
897 printf("@%d:%d", lineCols[I].line, lineCols[I].col);
900 clang_disposeOverriddenCursors(overridden);
903 if (Cursor.kind == CXCursor_InclusionDirective) {
904 CXFile File = clang_getIncludedFile(Cursor);
905 CXString Included = clang_getFileName(File);
906 printf(" (%s)", clang_getCString(Included));
907 clang_disposeString(Included);
909 if (clang_isFileMultipleIncludeGuarded(TU, File))
910 printf(" [multi-include guarded]");
913 CursorExtent = clang_getCursorExtent(Cursor);
914 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
915 CXNameRange_WantQualifier
916 | CXNameRange_WantSinglePiece
917 | CXNameRange_WantTemplateArgs,
919 if (!clang_equalRanges(CursorExtent, RefNameRange))
920 PrintRange(RefNameRange, "SingleRefName");
922 for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
923 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
924 CXNameRange_WantQualifier
925 | CXNameRange_WantTemplateArgs,
927 if (clang_equalRanges(clang_getNullRange(), RefNameRange))
929 if (!clang_equalRanges(CursorExtent, RefNameRange))
930 PrintRange(RefNameRange, "RefName");
933 PrintCursorComments(Cursor, CommentSchemaFile);
936 unsigned PropAttrs = clang_Cursor_getObjCPropertyAttributes(Cursor, 0);
937 if (PropAttrs != CXObjCPropertyAttr_noattr) {
939 #define PRINT_PROP_ATTR(A) \
940 if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
941 PRINT_PROP_ATTR(readonly);
942 PRINT_PROP_ATTR(getter);
943 PRINT_PROP_ATTR(assign);
944 PRINT_PROP_ATTR(readwrite);
945 PRINT_PROP_ATTR(retain);
946 PRINT_PROP_ATTR(copy);
947 PRINT_PROP_ATTR(nonatomic);
948 PRINT_PROP_ATTR(setter);
949 PRINT_PROP_ATTR(atomic);
950 PRINT_PROP_ATTR(weak);
951 PRINT_PROP_ATTR(strong);
952 PRINT_PROP_ATTR(unsafe_unretained);
953 PRINT_PROP_ATTR(class);
959 unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
960 if (QT != CXObjCDeclQualifier_None) {
962 #define PRINT_OBJC_QUAL(A) \
963 if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
965 PRINT_OBJC_QUAL(Inout);
966 PRINT_OBJC_QUAL(Out);
967 PRINT_OBJC_QUAL(Bycopy);
968 PRINT_OBJC_QUAL(Byref);
969 PRINT_OBJC_QUAL(Oneway);
976 static const char* GetCursorSource(CXCursor Cursor) {
977 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
980 clang_getExpansionLocation(Loc, &file, 0, 0, 0);
981 source = clang_getFileName(file);
982 if (!clang_getCString(source)) {
983 clang_disposeString(source);
984 return "<invalid loc>";
987 const char *b = basename(clang_getCString(source));
988 clang_disposeString(source);
993 /******************************************************************************/
995 /******************************************************************************/
997 typedef void (*PostVisitTU)(CXTranslationUnit);
999 void PrintDiagnostic(CXDiagnostic Diagnostic) {
1003 unsigned display_opts = CXDiagnostic_DisplaySourceLocation
1004 | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
1005 | CXDiagnostic_DisplayOption;
1006 unsigned i, num_fixits;
1008 if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
1011 Msg = clang_formatDiagnostic(Diagnostic, display_opts);
1012 fprintf(stderr, "%s\n", clang_getCString(Msg));
1013 clang_disposeString(Msg);
1015 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
1020 num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
1021 fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
1022 for (i = 0; i != num_fixits; ++i) {
1023 CXSourceRange range;
1024 CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
1025 CXSourceLocation start = clang_getRangeStart(range);
1026 CXSourceLocation end = clang_getRangeEnd(range);
1027 unsigned start_line, start_column, end_line, end_column;
1028 CXFile start_file, end_file;
1029 clang_getSpellingLocation(start, &start_file, &start_line,
1031 clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
1032 if (clang_equalLocations(start, end)) {
1034 if (start_file == file)
1035 fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
1036 clang_getCString(insertion_text), start_line, start_column);
1037 } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
1039 if (start_file == file && end_file == file) {
1040 fprintf(out, "FIX-IT: Remove ");
1041 PrintExtent(out, start_line, start_column, end_line, end_column);
1046 if (start_file == end_file) {
1047 fprintf(out, "FIX-IT: Replace ");
1048 PrintExtent(out, start_line, start_column, end_line, end_column);
1049 fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
1052 clang_disposeString(insertion_text);
1056 void PrintDiagnosticSet(CXDiagnosticSet Set) {
1057 int i = 0, n = clang_getNumDiagnosticsInSet(Set);
1058 for ( ; i != n ; ++i) {
1059 CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
1060 CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
1061 PrintDiagnostic(Diag);
1063 PrintDiagnosticSet(ChildDiags);
1067 void PrintDiagnostics(CXTranslationUnit TU) {
1068 CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
1069 PrintDiagnosticSet(TUSet);
1070 clang_disposeDiagnosticSet(TUSet);
1073 void PrintMemoryUsage(CXTranslationUnit TU) {
1074 unsigned long total = 0;
1076 CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
1077 fprintf(stderr, "Memory usage:\n");
1078 for (i = 0 ; i != usage.numEntries; ++i) {
1079 const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
1080 unsigned long amount = usage.entries[i].amount;
1082 fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
1083 ((double) amount)/(1024*1024));
1085 fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
1086 ((double) total)/(1024*1024));
1087 clang_disposeCXTUResourceUsage(usage);
1090 /******************************************************************************/
1091 /* Logic for testing traversal. */
1092 /******************************************************************************/
1094 static void PrintCursorExtent(CXCursor C) {
1095 CXSourceRange extent = clang_getCursorExtent(C);
1096 PrintRange(extent, "Extent");
1099 /* Data used by the visitors. */
1101 CXTranslationUnit TU;
1102 enum CXCursorKind *Filter;
1103 const char *CommentSchemaFile;
1107 enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
1109 CXClientData ClientData) {
1110 VisitorData *Data = (VisitorData *)ClientData;
1111 if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
1112 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
1113 unsigned line, column;
1114 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
1115 printf("// %s: %s:%d:%d: ", FileCheckPrefix,
1116 GetCursorSource(Cursor), line, column);
1117 PrintCursor(Cursor, Data->CommentSchemaFile);
1118 PrintCursorExtent(Cursor);
1119 if (clang_isDeclaration(Cursor.kind)) {
1120 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
1121 const char *accessStr = 0;
1124 case CX_CXXInvalidAccessSpecifier: break;
1126 accessStr = "public"; break;
1127 case CX_CXXProtected:
1128 accessStr = "protected"; break;
1130 accessStr = "private"; break;
1134 printf(" [access=%s]", accessStr);
1137 return CXChildVisit_Recurse;
1140 return CXChildVisit_Continue;
1143 static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
1145 CXClientData ClientData) {
1146 const char *startBuf, *endBuf;
1147 unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
1149 VisitorData *Data = (VisitorData *)ClientData;
1151 if (Cursor.kind != CXCursor_FunctionDecl ||
1152 !clang_isCursorDefinition(Cursor))
1153 return CXChildVisit_Continue;
1155 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
1156 &startLine, &startColumn,
1157 &endLine, &endColumn);
1158 /* Probe the entire body, looking for both decls and refs. */
1159 curLine = startLine;
1160 curColumn = startColumn;
1162 while (startBuf < endBuf) {
1163 CXSourceLocation Loc;
1167 if (*startBuf == '\n') {
1171 } else if (*startBuf != '\t')
1174 Loc = clang_getCursorLocation(Cursor);
1175 clang_getSpellingLocation(Loc, &file, 0, 0, 0);
1177 source = clang_getFileName(file);
1178 if (clang_getCString(source)) {
1179 CXSourceLocation RefLoc
1180 = clang_getLocation(Data->TU, file, curLine, curColumn);
1181 Ref = clang_getCursor(Data->TU, RefLoc);
1182 if (Ref.kind == CXCursor_NoDeclFound) {
1183 /* Nothing found here; that's fine. */
1184 } else if (Ref.kind != CXCursor_FunctionDecl) {
1185 printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
1186 curLine, curColumn);
1187 PrintCursor(Ref, Data->CommentSchemaFile);
1191 clang_disposeString(source);
1195 return CXChildVisit_Continue;
1198 /******************************************************************************/
1200 /******************************************************************************/
1202 enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
1203 CXClientData ClientData) {
1204 VisitorData *Data = (VisitorData *)ClientData;
1205 if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
1206 CXString USR = clang_getCursorUSR(C);
1207 const char *cstr = clang_getCString(USR);
1208 if (!cstr || cstr[0] == '\0') {
1209 clang_disposeString(USR);
1210 return CXChildVisit_Recurse;
1212 printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
1214 PrintCursorExtent(C);
1216 clang_disposeString(USR);
1218 return CXChildVisit_Recurse;
1221 return CXChildVisit_Continue;
1224 /******************************************************************************/
1225 /* Inclusion stack testing. */
1226 /******************************************************************************/
1228 void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
1229 unsigned includeStackLen, CXClientData data) {
1234 fname = clang_getFileName(includedFile);
1235 printf("file: %s\nincluded by:\n", clang_getCString(fname));
1236 clang_disposeString(fname);
1238 for (i = 0; i < includeStackLen; ++i) {
1239 CXFile includingFile;
1240 unsigned line, column;
1241 clang_getSpellingLocation(includeStack[i], &includingFile, &line,
1243 fname = clang_getFileName(includingFile);
1244 printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
1245 clang_disposeString(fname);
1250 void PrintInclusionStack(CXTranslationUnit TU) {
1251 clang_getInclusions(TU, InclusionVisitor, NULL);
1254 /******************************************************************************/
1255 /* Linkage testing. */
1256 /******************************************************************************/
1258 static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
1260 const char *linkage = 0;
1262 if (clang_isInvalid(clang_getCursorKind(cursor)))
1263 return CXChildVisit_Recurse;
1265 switch (clang_getCursorLinkage(cursor)) {
1266 case CXLinkage_Invalid: break;
1267 case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
1268 case CXLinkage_Internal: linkage = "Internal"; break;
1269 case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
1270 case CXLinkage_External: linkage = "External"; break;
1274 PrintCursor(cursor, NULL);
1275 printf("linkage=%s\n", linkage);
1278 return CXChildVisit_Recurse;
1281 /******************************************************************************/
1282 /* Visibility testing. */
1283 /******************************************************************************/
1285 static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p,
1287 const char *visibility = 0;
1289 if (clang_isInvalid(clang_getCursorKind(cursor)))
1290 return CXChildVisit_Recurse;
1292 switch (clang_getCursorVisibility(cursor)) {
1293 case CXVisibility_Invalid: break;
1294 case CXVisibility_Hidden: visibility = "Hidden"; break;
1295 case CXVisibility_Protected: visibility = "Protected"; break;
1296 case CXVisibility_Default: visibility = "Default"; break;
1300 PrintCursor(cursor, NULL);
1301 printf("visibility=%s\n", visibility);
1304 return CXChildVisit_Recurse;
1307 /******************************************************************************/
1308 /* Typekind testing. */
1309 /******************************************************************************/
1311 static void PrintTypeAndTypeKind(CXType T, const char *Format) {
1312 CXString TypeSpelling, TypeKindSpelling;
1314 TypeSpelling = clang_getTypeSpelling(T);
1315 TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
1317 clang_getCString(TypeSpelling),
1318 clang_getCString(TypeKindSpelling));
1319 clang_disposeString(TypeSpelling);
1320 clang_disposeString(TypeKindSpelling);
1323 static enum CXVisitorResult FieldVisitor(CXCursor C,
1324 CXClientData client_data) {
1325 (*(int *) client_data)+=1;
1326 return CXVisit_Continue;
1329 static void PrintTypeTemplateArgs(CXType T, const char *Format) {
1330 int NumTArgs = clang_Type_getNumTemplateArguments(T);
1331 if (NumTArgs != -1 && NumTArgs != 0) {
1334 printf(Format, NumTArgs);
1335 for (i = 0; i < NumTArgs; ++i) {
1336 TArg = clang_Type_getTemplateArgumentAsType(T, i);
1337 if (TArg.kind != CXType_Invalid) {
1338 PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
1341 /* Ensure that the returned type is invalid when indexing off-by-one. */
1342 TArg = clang_Type_getTemplateArgumentAsType(T, i);
1343 assert(TArg.kind == CXType_Invalid);
1348 static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
1350 if (!clang_isInvalid(clang_getCursorKind(cursor))) {
1351 CXType T = clang_getCursorType(cursor);
1352 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
1353 PrintCursor(cursor, NULL);
1354 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
1355 if (clang_isConstQualifiedType(T))
1357 if (clang_isVolatileQualifiedType(T))
1358 printf(" volatile");
1359 if (clang_isRestrictQualifiedType(T))
1360 printf(" restrict");
1361 if (RQ == CXRefQualifier_LValue)
1362 printf(" lvalue-ref-qualifier");
1363 if (RQ == CXRefQualifier_RValue)
1364 printf(" rvalue-ref-qualifier");
1365 /* Print the template argument types if they exist. */
1366 PrintTypeTemplateArgs(T, " [templateargs/%d=");
1367 /* Print the canonical type if it is different. */
1369 CXType CT = clang_getCanonicalType(T);
1370 if (!clang_equalTypes(T, CT)) {
1371 PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
1372 PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d=");
1375 /* Print the return type if it exists. */
1377 CXType RT = clang_getCursorResultType(cursor);
1378 if (RT.kind != CXType_Invalid) {
1379 PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
1382 /* Print the argument types if they exist. */
1384 int NumArgs = clang_Cursor_getNumArguments(cursor);
1385 if (NumArgs != -1 && NumArgs != 0) {
1388 for (i = 0; i < NumArgs; ++i) {
1389 CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
1390 if (T.kind != CXType_Invalid) {
1391 PrintTypeAndTypeKind(T, " [%s] [%s]");
1397 /* Print if this is a non-POD type. */
1398 printf(" [isPOD=%d]", clang_isPODType(T));
1399 /* Print the pointee type. */
1401 CXType PT = clang_getPointeeType(T);
1402 if (PT.kind != CXType_Invalid) {
1403 PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
1406 /* Print the number of fields if they exist. */
1409 if (clang_Type_visitFields(T, FieldVisitor, &numFields)){
1410 if (numFields != 0) {
1411 printf(" [nbFields=%d]", numFields);
1413 /* Print if it is an anonymous record. */
1415 unsigned isAnon = clang_Cursor_isAnonymous(cursor);
1417 printf(" [isAnon=%d]", isAnon);
1425 return CXChildVisit_Recurse;
1428 static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
1431 enum CXCursorKind K = clang_getCursorKind(cursor);
1432 if (clang_isInvalid(K))
1433 return CXChildVisit_Recurse;
1434 T = clang_getCursorType(cursor);
1435 PrintCursor(cursor, NULL);
1436 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
1437 /* Print the type sizeof if applicable. */
1439 long long Size = clang_Type_getSizeOf(T);
1440 if (Size >= 0 || Size < -1 ) {
1441 printf(" [sizeof=%lld]", Size);
1444 /* Print the type alignof if applicable. */
1446 long long Align = clang_Type_getAlignOf(T);
1447 if (Align >= 0 || Align < -1) {
1448 printf(" [alignof=%lld]", Align);
1451 /* Print the record field offset if applicable. */
1453 CXString FieldSpelling = clang_getCursorSpelling(cursor);
1454 const char *FieldName = clang_getCString(FieldSpelling);
1455 /* recurse to get the first parent record that is not anonymous. */
1456 unsigned RecordIsAnonymous = 0;
1457 if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
1459 CXCursor Parent = p;
1462 Parent = clang_getCursorSemanticParent(Record);
1463 RecordIsAnonymous = clang_Cursor_isAnonymous(Record);
1464 /* Recurse as long as the parent is a CXType_Record and the Record
1466 } while ( clang_getCursorType(Parent).kind == CXType_Record &&
1467 RecordIsAnonymous > 0);
1469 long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record),
1471 long long Offset2 = clang_Cursor_getOffsetOfField(cursor);
1472 if (Offset == Offset2){
1473 printf(" [offsetof=%lld]", Offset);
1475 /* Offsets will be different in anonymous records. */
1476 printf(" [offsetof=%lld/%lld]", Offset, Offset2);
1480 clang_disposeString(FieldSpelling);
1482 /* Print if its a bitfield */
1484 int IsBitfield = clang_Cursor_isBitField(cursor);
1486 printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
1489 return CXChildVisit_Recurse;
1492 /******************************************************************************/
1493 /* Mangling testing. */
1494 /******************************************************************************/
1496 static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p,
1498 CXString MangledName;
1499 if (clang_isUnexposed(clang_getCursorKind(cursor)))
1500 return CXChildVisit_Recurse;
1501 PrintCursor(cursor, NULL);
1502 MangledName = clang_Cursor_getMangling(cursor);
1503 printf(" [mangled=%s]\n", clang_getCString(MangledName));
1504 clang_disposeString(MangledName);
1505 return CXChildVisit_Continue;
1508 static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
1511 CXStringSet *Manglings = NULL;
1512 if (clang_isUnexposed(clang_getCursorKind(cursor)))
1513 return CXChildVisit_Recurse;
1514 if (!clang_isDeclaration(clang_getCursorKind(cursor)))
1515 return CXChildVisit_Recurse;
1516 if (clang_getCursorKind(cursor) == CXCursor_ParmDecl)
1517 return CXChildVisit_Continue;
1518 PrintCursor(cursor, NULL);
1519 Manglings = clang_Cursor_getCXXManglings(cursor);
1520 for (I = 0, E = Manglings->Count; I < E; ++I)
1521 printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
1522 clang_disposeStringSet(Manglings);
1524 return CXChildVisit_Recurse;
1527 /******************************************************************************/
1528 /* Bitwidth testing. */
1529 /******************************************************************************/
1531 static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
1534 if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
1535 return CXChildVisit_Recurse;
1537 Bitwidth = clang_getFieldDeclBitWidth(cursor);
1538 if (Bitwidth >= 0) {
1539 PrintCursor(cursor, NULL);
1540 printf(" bitwidth=%d\n", Bitwidth);
1543 return CXChildVisit_Recurse;
1546 /******************************************************************************/
1547 /* Type declaration testing */
1548 /******************************************************************************/
1550 static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
1552 CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
1554 if (clang_isDeclaration(typeDeclaration.kind)) {
1555 PrintCursor(cursor, NULL);
1556 PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
1559 return CXChildVisit_Recurse;
1562 /******************************************************************************/
1563 /* Loading ASTs/source. */
1564 /******************************************************************************/
1566 static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
1567 const char *filter, const char *prefix,
1568 CXCursorVisitor Visitor,
1570 const char *CommentSchemaFile) {
1573 FileCheckPrefix = prefix;
1576 enum CXCursorKind K = CXCursor_NotImplemented;
1577 enum CXCursorKind *ck = &K;
1580 /* Perform some simple filtering. */
1581 if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
1582 else if (!strcmp(filter, "all-display") ||
1583 !strcmp(filter, "local-display")) {
1585 want_display_name = 1;
1587 else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
1588 else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
1589 else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
1590 else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
1591 else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
1592 else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
1593 else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
1595 fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
1601 Data.CommentSchemaFile = CommentSchemaFile;
1602 clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
1608 PrintDiagnostics(TU);
1609 if (checkForErrors(TU) != 0) {
1610 clang_disposeTranslationUnit(TU);
1614 clang_disposeTranslationUnit(TU);
1618 int perform_test_load_tu(const char *file, const char *filter,
1619 const char *prefix, CXCursorVisitor Visitor,
1622 CXTranslationUnit TU;
1624 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1625 !strcmp(filter, "local") ? 1 : 0,
1626 /* displayDiagnostics=*/1);
1628 if (!CreateTranslationUnit(Idx, file, &TU)) {
1629 clang_disposeIndex(Idx);
1633 result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
1634 clang_disposeIndex(Idx);
1638 int perform_test_load_source(int argc, const char **argv,
1639 const char *filter, CXCursorVisitor Visitor,
1642 CXTranslationUnit TU;
1643 const char *CommentSchemaFile;
1644 struct CXUnsavedFile *unsaved_files = 0;
1645 int num_unsaved_files = 0;
1646 enum CXErrorCode Err;
1648 unsigned Repeats = 0;
1651 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1652 (!strcmp(filter, "local") ||
1653 !strcmp(filter, "local-display"))? 1 : 0,
1654 /* displayDiagnostics=*/1);
1656 if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
1661 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1662 clang_disposeIndex(Idx);
1666 if (getenv("CINDEXTEST_EDITING"))
1669 Err = clang_parseTranslationUnit2(Idx, 0,
1670 argv + num_unsaved_files,
1671 argc - num_unsaved_files,
1672 unsaved_files, num_unsaved_files,
1673 getDefaultParsingOptions(), &TU);
1674 if (Err != CXError_Success) {
1675 fprintf(stderr, "Unable to load translation unit!\n");
1676 describeLibclangFailure(Err);
1677 free_remapped_files(unsaved_files, num_unsaved_files);
1678 clang_disposeIndex(Idx);
1682 for (I = 0; I != Repeats; ++I) {
1683 if (checkForErrors(TU) != 0)
1687 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
1688 clang_defaultReparseOptions(TU));
1689 if (Err != CXError_Success) {
1690 describeLibclangFailure(Err);
1691 free_remapped_files(unsaved_files, num_unsaved_files);
1692 clang_disposeIndex(Idx);
1698 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
1700 free_remapped_files(unsaved_files, num_unsaved_files);
1701 clang_disposeIndex(Idx);
1705 int perform_test_reparse_source(int argc, const char **argv, int trials,
1706 const char *filter, CXCursorVisitor Visitor,
1709 CXTranslationUnit TU;
1710 struct CXUnsavedFile *unsaved_files = 0;
1711 int num_unsaved_files = 0;
1712 int compiler_arg_idx = 0;
1713 enum CXErrorCode Err;
1716 int remap_after_trial = 0;
1719 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1720 !strcmp(filter, "local") ? 1 : 0,
1721 /* displayDiagnostics=*/1);
1723 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1724 clang_disposeIndex(Idx);
1728 for (i = 0; i < argc; ++i) {
1729 if (strcmp(argv[i], "--") == 0)
1733 compiler_arg_idx = i+1;
1734 if (num_unsaved_files > compiler_arg_idx)
1735 compiler_arg_idx = num_unsaved_files;
1737 /* Load the initial translation unit -- we do this without honoring remapped
1738 * files, so that we have a way to test results after changing the source. */
1739 Err = clang_parseTranslationUnit2(Idx, 0,
1740 argv + compiler_arg_idx,
1741 argc - compiler_arg_idx,
1742 0, 0, getDefaultParsingOptions(), &TU);
1743 if (Err != CXError_Success) {
1744 fprintf(stderr, "Unable to load translation unit!\n");
1745 describeLibclangFailure(Err);
1746 free_remapped_files(unsaved_files, num_unsaved_files);
1747 clang_disposeIndex(Idx);
1751 if (checkForErrors(TU) != 0)
1754 if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
1756 strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
1759 for (trial = 0; trial < trials; ++trial) {
1760 free_remapped_files(unsaved_files, num_unsaved_files);
1761 if (parse_remapped_files_with_try(trial, argc, argv, 0,
1762 &unsaved_files, &num_unsaved_files)) {
1763 clang_disposeTranslationUnit(TU);
1764 clang_disposeIndex(Idx);
1768 Err = clang_reparseTranslationUnit(
1770 trial >= remap_after_trial ? num_unsaved_files : 0,
1771 trial >= remap_after_trial ? unsaved_files : 0,
1772 clang_defaultReparseOptions(TU));
1773 if (Err != CXError_Success) {
1774 fprintf(stderr, "Unable to reparse translation unit!\n");
1775 describeLibclangFailure(Err);
1776 clang_disposeTranslationUnit(TU);
1777 free_remapped_files(unsaved_files, num_unsaved_files);
1778 clang_disposeIndex(Idx);
1782 if (checkForErrors(TU) != 0)
1786 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
1788 free_remapped_files(unsaved_files, num_unsaved_files);
1789 clang_disposeIndex(Idx);
1793 /******************************************************************************/
1794 /* Logic for testing clang_getCursor(). */
1795 /******************************************************************************/
1797 static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
1798 unsigned start_line, unsigned start_col,
1799 unsigned end_line, unsigned end_col,
1800 const char *prefix) {
1801 printf("// %s: ", FileCheckPrefix);
1803 printf("-%s", prefix);
1804 PrintExtent(stdout, start_line, start_col, end_line, end_col);
1806 PrintCursor(cursor, NULL);
1810 static int perform_file_scan(const char *ast_file, const char *source_file,
1811 const char *prefix) {
1813 CXTranslationUnit TU;
1815 CXCursor prevCursor = clang_getNullCursor();
1817 unsigned line = 1, col = 1;
1818 unsigned start_line = 1, start_col = 1;
1820 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
1821 /* displayDiagnostics=*/1))) {
1822 fprintf(stderr, "Could not create Index\n");
1826 if (!CreateTranslationUnit(Idx, ast_file, &TU))
1829 if ((fp = fopen(source_file, "r")) == NULL) {
1830 fprintf(stderr, "Could not open '%s'\n", source_file);
1831 clang_disposeTranslationUnit(TU);
1835 file = clang_getFile(TU, source_file);
1846 /* Check the cursor at this position, and dump the previous one if we have
1847 * found something new.
1849 cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
1850 if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
1851 prevCursor.kind != CXCursor_InvalidFile) {
1852 print_cursor_file_scan(TU, prevCursor, start_line, start_col,
1860 prevCursor = cursor;
1864 clang_disposeTranslationUnit(TU);
1865 clang_disposeIndex(Idx);
1869 /******************************************************************************/
1870 /* Logic for testing clang code completion. */
1871 /******************************************************************************/
1873 /* Parse file:line:column from the input string. Returns 0 on success, non-zero
1874 on failure. If successful, the pointer *filename will contain newly-allocated
1875 memory (that will be owned by the caller) to store the file name. */
1876 int parse_file_line_column(const char *input, char **filename, unsigned *line,
1877 unsigned *column, unsigned *second_line,
1878 unsigned *second_column) {
1879 /* Find the second colon. */
1880 const char *last_colon = strrchr(input, ':');
1881 unsigned values[4], i;
1882 unsigned num_values = (second_line && second_column)? 4 : 2;
1885 if (!last_colon || last_colon == input) {
1886 if (num_values == 4)
1887 fprintf(stderr, "could not parse filename:line:column:line:column in "
1890 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
1894 for (i = 0; i != num_values; ++i) {
1895 const char *prev_colon;
1897 /* Parse the next line or column. */
1898 values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
1899 if (*endptr != 0 && *endptr != ':') {
1900 fprintf(stderr, "could not parse %s in '%s'\n",
1901 (i % 2 ? "column" : "line"), input);
1905 if (i + 1 == num_values)
1908 /* Find the previous colon. */
1909 prev_colon = last_colon - 1;
1910 while (prev_colon != input && *prev_colon != ':')
1912 if (prev_colon == input) {
1913 fprintf(stderr, "could not parse %s in '%s'\n",
1914 (i % 2 == 0? "column" : "line"), input);
1918 last_colon = prev_colon;
1922 *column = values[1];
1924 if (second_line && second_column) {
1925 *second_line = values[2];
1926 *second_column = values[3];
1929 /* Copy the file name. */
1930 *filename = (char*)malloc(last_colon - input + 1);
1931 memcpy(*filename, input, last_colon - input);
1932 (*filename)[last_colon - input] = 0;
1937 clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
1939 case CXCompletionChunk_Optional: return "Optional";
1940 case CXCompletionChunk_TypedText: return "TypedText";
1941 case CXCompletionChunk_Text: return "Text";
1942 case CXCompletionChunk_Placeholder: return "Placeholder";
1943 case CXCompletionChunk_Informative: return "Informative";
1944 case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
1945 case CXCompletionChunk_LeftParen: return "LeftParen";
1946 case CXCompletionChunk_RightParen: return "RightParen";
1947 case CXCompletionChunk_LeftBracket: return "LeftBracket";
1948 case CXCompletionChunk_RightBracket: return "RightBracket";
1949 case CXCompletionChunk_LeftBrace: return "LeftBrace";
1950 case CXCompletionChunk_RightBrace: return "RightBrace";
1951 case CXCompletionChunk_LeftAngle: return "LeftAngle";
1952 case CXCompletionChunk_RightAngle: return "RightAngle";
1953 case CXCompletionChunk_Comma: return "Comma";
1954 case CXCompletionChunk_ResultType: return "ResultType";
1955 case CXCompletionChunk_Colon: return "Colon";
1956 case CXCompletionChunk_SemiColon: return "SemiColon";
1957 case CXCompletionChunk_Equal: return "Equal";
1958 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
1959 case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
1965 static int checkForErrors(CXTranslationUnit TU) {
1970 if (!getenv("CINDEXTEST_FAILONERROR"))
1973 Num = clang_getNumDiagnostics(TU);
1974 for (i = 0; i != Num; ++i) {
1975 Diag = clang_getDiagnostic(TU, i);
1976 if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
1977 DiagStr = clang_formatDiagnostic(Diag,
1978 clang_defaultDiagnosticDisplayOptions());
1979 fprintf(stderr, "%s\n", clang_getCString(DiagStr));
1980 clang_disposeString(DiagStr);
1981 clang_disposeDiagnostic(Diag);
1984 clang_disposeDiagnostic(Diag);
1990 static void print_completion_string(CXCompletionString completion_string,
1994 N = clang_getNumCompletionChunks(completion_string);
1995 for (I = 0; I != N; ++I) {
1998 enum CXCompletionChunkKind Kind
1999 = clang_getCompletionChunkKind(completion_string, I);
2001 if (Kind == CXCompletionChunk_Optional) {
2002 fprintf(file, "{Optional ");
2003 print_completion_string(
2004 clang_getCompletionChunkCompletionString(completion_string, I),
2010 if (Kind == CXCompletionChunk_VerticalSpace) {
2011 fprintf(file, "{VerticalSpace }");
2015 text = clang_getCompletionChunkText(completion_string, I);
2016 cstr = clang_getCString(text);
2017 fprintf(file, "{%s %s}",
2018 clang_getCompletionChunkKindSpelling(Kind),
2020 clang_disposeString(text);
2025 static void print_completion_result(CXCompletionResult *completion_result,
2027 CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
2028 unsigned annotationCount;
2029 enum CXCursorKind ParentKind;
2030 CXString ParentName;
2031 CXString BriefComment;
2032 CXString Annotation;
2033 const char *BriefCommentCString;
2035 fprintf(file, "%s:", clang_getCString(ks));
2036 clang_disposeString(ks);
2038 print_completion_string(completion_result->CompletionString, file);
2039 fprintf(file, " (%u)",
2040 clang_getCompletionPriority(completion_result->CompletionString));
2041 switch (clang_getCompletionAvailability(completion_result->CompletionString)){
2042 case CXAvailability_Available:
2045 case CXAvailability_Deprecated:
2046 fprintf(file, " (deprecated)");
2049 case CXAvailability_NotAvailable:
2050 fprintf(file, " (unavailable)");
2053 case CXAvailability_NotAccessible:
2054 fprintf(file, " (inaccessible)");
2058 annotationCount = clang_getCompletionNumAnnotations(
2059 completion_result->CompletionString);
2060 if (annotationCount) {
2062 fprintf(file, " (");
2063 for (i = 0; i < annotationCount; ++i) {
2065 fprintf(file, ", ");
2067 clang_getCompletionAnnotation(completion_result->CompletionString, i);
2068 fprintf(file, "\"%s\"", clang_getCString(Annotation));
2069 clang_disposeString(Annotation);
2074 if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
2075 ParentName = clang_getCompletionParent(completion_result->CompletionString,
2077 if (ParentKind != CXCursor_NotImplemented) {
2078 CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
2079 fprintf(file, " (parent: %s '%s')",
2080 clang_getCString(KindSpelling),
2081 clang_getCString(ParentName));
2082 clang_disposeString(KindSpelling);
2084 clang_disposeString(ParentName);
2087 BriefComment = clang_getCompletionBriefComment(
2088 completion_result->CompletionString);
2089 BriefCommentCString = clang_getCString(BriefComment);
2090 if (BriefCommentCString && *BriefCommentCString != '\0') {
2091 fprintf(file, "(brief comment: %s)", BriefCommentCString);
2093 clang_disposeString(BriefComment);
2095 fprintf(file, "\n");
2098 void print_completion_contexts(unsigned long long contexts, FILE *file) {
2099 fprintf(file, "Completion contexts:\n");
2100 if (contexts == CXCompletionContext_Unknown) {
2101 fprintf(file, "Unknown\n");
2103 if (contexts & CXCompletionContext_AnyType) {
2104 fprintf(file, "Any type\n");
2106 if (contexts & CXCompletionContext_AnyValue) {
2107 fprintf(file, "Any value\n");
2109 if (contexts & CXCompletionContext_ObjCObjectValue) {
2110 fprintf(file, "Objective-C object value\n");
2112 if (contexts & CXCompletionContext_ObjCSelectorValue) {
2113 fprintf(file, "Objective-C selector value\n");
2115 if (contexts & CXCompletionContext_CXXClassTypeValue) {
2116 fprintf(file, "C++ class type value\n");
2118 if (contexts & CXCompletionContext_DotMemberAccess) {
2119 fprintf(file, "Dot member access\n");
2121 if (contexts & CXCompletionContext_ArrowMemberAccess) {
2122 fprintf(file, "Arrow member access\n");
2124 if (contexts & CXCompletionContext_ObjCPropertyAccess) {
2125 fprintf(file, "Objective-C property access\n");
2127 if (contexts & CXCompletionContext_EnumTag) {
2128 fprintf(file, "Enum tag\n");
2130 if (contexts & CXCompletionContext_UnionTag) {
2131 fprintf(file, "Union tag\n");
2133 if (contexts & CXCompletionContext_StructTag) {
2134 fprintf(file, "Struct tag\n");
2136 if (contexts & CXCompletionContext_ClassTag) {
2137 fprintf(file, "Class name\n");
2139 if (contexts & CXCompletionContext_Namespace) {
2140 fprintf(file, "Namespace or namespace alias\n");
2142 if (contexts & CXCompletionContext_NestedNameSpecifier) {
2143 fprintf(file, "Nested name specifier\n");
2145 if (contexts & CXCompletionContext_ObjCInterface) {
2146 fprintf(file, "Objective-C interface\n");
2148 if (contexts & CXCompletionContext_ObjCProtocol) {
2149 fprintf(file, "Objective-C protocol\n");
2151 if (contexts & CXCompletionContext_ObjCCategory) {
2152 fprintf(file, "Objective-C category\n");
2154 if (contexts & CXCompletionContext_ObjCInstanceMessage) {
2155 fprintf(file, "Objective-C instance method\n");
2157 if (contexts & CXCompletionContext_ObjCClassMessage) {
2158 fprintf(file, "Objective-C class method\n");
2160 if (contexts & CXCompletionContext_ObjCSelectorName) {
2161 fprintf(file, "Objective-C selector name\n");
2163 if (contexts & CXCompletionContext_MacroName) {
2164 fprintf(file, "Macro name\n");
2166 if (contexts & CXCompletionContext_NaturalLanguage) {
2167 fprintf(file, "Natural language\n");
2171 int perform_code_completion(int argc, const char **argv, int timing_only) {
2172 const char *input = argv[1];
2178 struct CXUnsavedFile *unsaved_files = 0;
2179 int num_unsaved_files = 0;
2180 CXCodeCompleteResults *results = 0;
2181 enum CXErrorCode Err;
2182 CXTranslationUnit TU;
2183 unsigned I, Repeats = 1;
2184 unsigned completionOptions = clang_defaultCodeCompleteOptions();
2186 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
2187 completionOptions |= CXCodeComplete_IncludeCodePatterns;
2188 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
2189 completionOptions |= CXCodeComplete_IncludeBriefComments;
2192 input += strlen("-code-completion-timing=");
2194 input += strlen("-code-completion-at=");
2196 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
2200 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
2203 CIdx = clang_createIndex(0, 0);
2205 if (getenv("CINDEXTEST_EDITING"))
2208 Err = clang_parseTranslationUnit2(CIdx, 0,
2209 argv + num_unsaved_files + 2,
2210 argc - num_unsaved_files - 2,
2211 0, 0, getDefaultParsingOptions(), &TU);
2212 if (Err != CXError_Success) {
2213 fprintf(stderr, "Unable to load translation unit!\n");
2214 describeLibclangFailure(Err);
2218 Err = clang_reparseTranslationUnit(TU, 0, 0,
2219 clang_defaultReparseOptions(TU));
2221 if (Err != CXError_Success) {
2222 fprintf(stderr, "Unable to reparse translation unit!\n");
2223 describeLibclangFailure(Err);
2224 clang_disposeTranslationUnit(TU);
2228 for (I = 0; I != Repeats; ++I) {
2229 results = clang_codeCompleteAt(TU, filename, line, column,
2230 unsaved_files, num_unsaved_files,
2233 fprintf(stderr, "Unable to perform code completion!\n");
2237 clang_disposeCodeCompleteResults(results);
2241 unsigned i, n = results->NumResults, containerIsIncomplete = 0;
2242 unsigned long long contexts;
2243 enum CXCursorKind containerKind;
2244 CXString objCSelector;
2245 const char *selectorString;
2247 /* Sort the code-completion results based on the typed text. */
2248 clang_sortCodeCompletionResults(results->Results, results->NumResults);
2250 for (i = 0; i != n; ++i)
2251 print_completion_result(results->Results + i, stdout);
2253 n = clang_codeCompleteGetNumDiagnostics(results);
2254 for (i = 0; i != n; ++i) {
2255 CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
2256 PrintDiagnostic(diag);
2257 clang_disposeDiagnostic(diag);
2260 contexts = clang_codeCompleteGetContexts(results);
2261 print_completion_contexts(contexts, stdout);
2263 containerKind = clang_codeCompleteGetContainerKind(results,
2264 &containerIsIncomplete);
2266 if (containerKind != CXCursor_InvalidCode) {
2267 /* We have found a container */
2268 CXString containerUSR, containerKindSpelling;
2269 containerKindSpelling = clang_getCursorKindSpelling(containerKind);
2270 printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
2271 clang_disposeString(containerKindSpelling);
2273 if (containerIsIncomplete) {
2274 printf("Container is incomplete\n");
2277 printf("Container is complete\n");
2280 containerUSR = clang_codeCompleteGetContainerUSR(results);
2281 printf("Container USR: %s\n", clang_getCString(containerUSR));
2282 clang_disposeString(containerUSR);
2285 objCSelector = clang_codeCompleteGetObjCSelector(results);
2286 selectorString = clang_getCString(objCSelector);
2287 if (selectorString && strlen(selectorString) > 0) {
2288 printf("Objective-C selector: %s\n", selectorString);
2290 clang_disposeString(objCSelector);
2292 clang_disposeCodeCompleteResults(results);
2294 clang_disposeTranslationUnit(TU);
2295 clang_disposeIndex(CIdx);
2298 free_remapped_files(unsaved_files, num_unsaved_files);
2307 } CursorSourceLocation;
2309 typedef void (*cursor_handler_t)(CXCursor cursor);
2311 static int inspect_cursor_at(int argc, const char **argv,
2312 const char *locations_flag,
2313 cursor_handler_t handler) {
2316 struct CXUnsavedFile *unsaved_files = 0;
2317 int num_unsaved_files = 0;
2318 enum CXErrorCode Err;
2319 CXTranslationUnit TU;
2321 CursorSourceLocation *Locations = 0;
2322 unsigned NumLocations = 0, Loc;
2323 unsigned Repeats = 1;
2326 /* Count the number of locations. */
2327 while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
2330 /* Parse the locations. */
2331 assert(NumLocations > 0 && "Unable to count locations?");
2332 Locations = (CursorSourceLocation *)malloc(
2333 NumLocations * sizeof(CursorSourceLocation));
2334 for (Loc = 0; Loc < NumLocations; ++Loc) {
2335 const char *input = argv[Loc + 1] + strlen(locations_flag);
2336 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2337 &Locations[Loc].line,
2338 &Locations[Loc].column, 0, 0)))
2342 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
2343 &num_unsaved_files))
2346 if (getenv("CINDEXTEST_EDITING"))
2349 /* Parse the translation unit. When we're testing clang_getCursor() after
2350 reparsing, don't remap unsaved files until the second parse. */
2351 CIdx = clang_createIndex(1, 1);
2352 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2353 argv + num_unsaved_files + 1 + NumLocations,
2354 argc - num_unsaved_files - 2 - NumLocations,
2356 Repeats > 1? 0 : num_unsaved_files,
2357 getDefaultParsingOptions(), &TU);
2358 if (Err != CXError_Success) {
2359 fprintf(stderr, "unable to parse input\n");
2360 describeLibclangFailure(Err);
2364 if (checkForErrors(TU) != 0)
2367 for (I = 0; I != Repeats; ++I) {
2369 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2370 clang_defaultReparseOptions(TU));
2371 if (Err != CXError_Success) {
2372 describeLibclangFailure(Err);
2373 clang_disposeTranslationUnit(TU);
2378 if (checkForErrors(TU) != 0)
2381 for (Loc = 0; Loc < NumLocations; ++Loc) {
2382 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2386 Cursor = clang_getCursor(TU,
2387 clang_getLocation(TU, file, Locations[Loc].line,
2388 Locations[Loc].column));
2390 if (checkForErrors(TU) != 0)
2393 if (I + 1 == Repeats) {
2395 free(Locations[Loc].filename);
2400 PrintDiagnostics(TU);
2401 clang_disposeTranslationUnit(TU);
2402 clang_disposeIndex(CIdx);
2404 free_remapped_files(unsaved_files, num_unsaved_files);
2408 static void inspect_print_cursor(CXCursor Cursor) {
2409 CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
2410 CXCompletionString completionString = clang_getCursorCompletionString(
2412 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2415 unsigned line, column;
2416 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2417 printf("%d:%d ", line, column);
2418 PrintCursor(Cursor, NULL);
2419 PrintCursorExtent(Cursor);
2420 Spelling = clang_getCursorSpelling(Cursor);
2421 cspell = clang_getCString(Spelling);
2422 if (cspell && strlen(cspell) != 0) {
2423 unsigned pieceIndex;
2424 printf(" Spelling=%s (", cspell);
2425 for (pieceIndex = 0; ; ++pieceIndex) {
2426 CXSourceRange range =
2427 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2428 if (clang_Range_isNull(range))
2430 PrintRange(range, 0);
2434 clang_disposeString(Spelling);
2435 if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
2436 printf(" Selector index=%d",
2437 clang_Cursor_getObjCSelectorIndex(Cursor));
2438 if (clang_Cursor_isDynamicCall(Cursor))
2439 printf(" Dynamic-call");
2440 if (Cursor.kind == CXCursor_ObjCMessageExpr) {
2441 CXType T = clang_Cursor_getReceiverType(Cursor);
2442 CXString S = clang_getTypeKindSpelling(T.kind);
2443 printf(" Receiver-type=%s", clang_getCString(S));
2444 clang_disposeString(S);
2448 CXModule mod = clang_Cursor_getModule(Cursor);
2450 CXString name, astFilename;
2451 unsigned i, numHeaders;
2453 astFile = clang_Module_getASTFile(mod);
2454 astFilename = clang_getFileName(astFile);
2455 name = clang_Module_getFullName(mod);
2456 numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
2457 printf(" ModuleName=%s (%s) system=%d Headers(%d):",
2458 clang_getCString(name), clang_getCString(astFilename),
2459 clang_Module_isSystem(mod), numHeaders);
2460 clang_disposeString(name);
2461 clang_disposeString(astFilename);
2462 for (i = 0; i < numHeaders; ++i) {
2463 CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
2464 CXString filename = clang_getFileName(file);
2465 printf("\n%s", clang_getCString(filename));
2466 clang_disposeString(filename);
2471 if (completionString != NULL) {
2472 printf("\nCompletion string: ");
2473 print_completion_string(completionString, stdout);
2478 static void display_evaluate_results(CXEvalResult result) {
2479 switch (clang_EvalResult_getKind(result)) {
2482 printf("Kind: Int, ");
2483 if (clang_EvalResult_isUnsignedInt(result)) {
2484 unsigned long long val = clang_EvalResult_getAsUnsigned(result);
2485 printf("unsigned, Value: %llu", val);
2487 long long val = clang_EvalResult_getAsLongLong(result);
2488 printf("Value: %lld", val);
2494 double val = clang_EvalResult_getAsDouble(result);
2495 printf("Kind: Float , Value: %f", val);
2498 case CXEval_ObjCStrLiteral:
2500 const char* str = clang_EvalResult_getAsStr(result);
2501 printf("Kind: ObjCString , Value: %s", str);
2504 case CXEval_StrLiteral:
2506 const char* str = clang_EvalResult_getAsStr(result);
2507 printf("Kind: CString , Value: %s", str);
2512 const char* str = clang_EvalResult_getAsStr(result);
2513 printf("Kind: CFString , Value: %s", str);
2517 printf("Unexposed");
2522 static void inspect_evaluate_cursor(CXCursor Cursor) {
2523 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2526 unsigned line, column;
2529 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2530 printf("%d:%d ", line, column);
2531 PrintCursor(Cursor, NULL);
2532 PrintCursorExtent(Cursor);
2533 Spelling = clang_getCursorSpelling(Cursor);
2534 cspell = clang_getCString(Spelling);
2535 if (cspell && strlen(cspell) != 0) {
2536 unsigned pieceIndex;
2537 printf(" Spelling=%s (", cspell);
2538 for (pieceIndex = 0; ; ++pieceIndex) {
2539 CXSourceRange range =
2540 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2541 if (clang_Range_isNull(range))
2543 PrintRange(range, 0);
2547 clang_disposeString(Spelling);
2549 ER = clang_Cursor_Evaluate(Cursor);
2551 printf("Not Evaluatable");
2553 display_evaluate_results(ER);
2554 clang_EvalResult_dispose(ER);
2559 static void inspect_macroinfo_cursor(CXCursor Cursor) {
2560 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2563 unsigned line, column;
2564 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2565 printf("%d:%d ", line, column);
2566 PrintCursor(Cursor, NULL);
2567 PrintCursorExtent(Cursor);
2568 Spelling = clang_getCursorSpelling(Cursor);
2569 cspell = clang_getCString(Spelling);
2570 if (cspell && strlen(cspell) != 0) {
2571 unsigned pieceIndex;
2572 printf(" Spelling=%s (", cspell);
2573 for (pieceIndex = 0; ; ++pieceIndex) {
2574 CXSourceRange range =
2575 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2576 if (clang_Range_isNull(range))
2578 PrintRange(range, 0);
2582 clang_disposeString(Spelling);
2584 if (clang_Cursor_isMacroBuiltin(Cursor)) {
2585 printf("[builtin macro]");
2586 } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
2587 printf("[function macro]");
2592 static enum CXVisitorResult findFileRefsVisit(void *context,
2593 CXCursor cursor, CXSourceRange range) {
2594 if (clang_Range_isNull(range))
2595 return CXVisit_Continue;
2597 PrintCursor(cursor, NULL);
2598 PrintRange(range, "");
2600 return CXVisit_Continue;
2603 static int find_file_refs_at(int argc, const char **argv) {
2606 struct CXUnsavedFile *unsaved_files = 0;
2607 int num_unsaved_files = 0;
2608 enum CXErrorCode Err;
2609 CXTranslationUnit TU;
2611 CursorSourceLocation *Locations = 0;
2612 unsigned NumLocations = 0, Loc;
2613 unsigned Repeats = 1;
2616 /* Count the number of locations. */
2617 while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
2620 /* Parse the locations. */
2621 assert(NumLocations > 0 && "Unable to count locations?");
2622 Locations = (CursorSourceLocation *)malloc(
2623 NumLocations * sizeof(CursorSourceLocation));
2624 for (Loc = 0; Loc < NumLocations; ++Loc) {
2625 const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
2626 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2627 &Locations[Loc].line,
2628 &Locations[Loc].column, 0, 0)))
2632 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
2633 &num_unsaved_files))
2636 if (getenv("CINDEXTEST_EDITING"))
2639 /* Parse the translation unit. When we're testing clang_getCursor() after
2640 reparsing, don't remap unsaved files until the second parse. */
2641 CIdx = clang_createIndex(1, 1);
2642 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2643 argv + num_unsaved_files + 1 + NumLocations,
2644 argc - num_unsaved_files - 2 - NumLocations,
2646 Repeats > 1? 0 : num_unsaved_files,
2647 getDefaultParsingOptions(), &TU);
2648 if (Err != CXError_Success) {
2649 fprintf(stderr, "unable to parse input\n");
2650 describeLibclangFailure(Err);
2651 clang_disposeTranslationUnit(TU);
2655 if (checkForErrors(TU) != 0)
2658 for (I = 0; I != Repeats; ++I) {
2660 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2661 clang_defaultReparseOptions(TU));
2662 if (Err != CXError_Success) {
2663 describeLibclangFailure(Err);
2664 clang_disposeTranslationUnit(TU);
2669 if (checkForErrors(TU) != 0)
2672 for (Loc = 0; Loc < NumLocations; ++Loc) {
2673 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2677 Cursor = clang_getCursor(TU,
2678 clang_getLocation(TU, file, Locations[Loc].line,
2679 Locations[Loc].column));
2681 if (checkForErrors(TU) != 0)
2684 if (I + 1 == Repeats) {
2685 CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
2686 PrintCursor(Cursor, NULL);
2688 clang_findReferencesInFile(Cursor, file, visitor);
2689 free(Locations[Loc].filename);
2691 if (checkForErrors(TU) != 0)
2697 PrintDiagnostics(TU);
2698 clang_disposeTranslationUnit(TU);
2699 clang_disposeIndex(CIdx);
2701 free_remapped_files(unsaved_files, num_unsaved_files);
2705 static enum CXVisitorResult findFileIncludesVisit(void *context,
2706 CXCursor cursor, CXSourceRange range) {
2707 PrintCursor(cursor, NULL);
2708 PrintRange(range, "");
2710 return CXVisit_Continue;
2713 static int find_file_includes_in(int argc, const char **argv) {
2715 struct CXUnsavedFile *unsaved_files = 0;
2716 int num_unsaved_files = 0;
2717 enum CXErrorCode Err;
2718 CXTranslationUnit TU;
2719 const char **Filenames = 0;
2720 unsigned NumFilenames = 0;
2721 unsigned Repeats = 1;
2724 /* Count the number of locations. */
2725 while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
2728 /* Parse the locations. */
2729 assert(NumFilenames > 0 && "Unable to count filenames?");
2730 Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
2731 for (I = 0; I < NumFilenames; ++I) {
2732 const char *input = argv[I + 1] + strlen("-file-includes-in=");
2733 /* Copy the file name. */
2734 Filenames[I] = input;
2737 if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
2738 &num_unsaved_files))
2741 if (getenv("CINDEXTEST_EDITING"))
2744 /* Parse the translation unit. When we're testing clang_getCursor() after
2745 reparsing, don't remap unsaved files until the second parse. */
2746 CIdx = clang_createIndex(1, 1);
2747 Err = clang_parseTranslationUnit2(
2748 CIdx, argv[argc - 1],
2749 argv + num_unsaved_files + 1 + NumFilenames,
2750 argc - num_unsaved_files - 2 - NumFilenames,
2752 Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU);
2754 if (Err != CXError_Success) {
2755 fprintf(stderr, "unable to parse input\n");
2756 describeLibclangFailure(Err);
2757 clang_disposeTranslationUnit(TU);
2761 if (checkForErrors(TU) != 0)
2764 for (I = 0; I != Repeats; ++I) {
2766 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2767 clang_defaultReparseOptions(TU));
2768 if (Err != CXError_Success) {
2769 describeLibclangFailure(Err);
2770 clang_disposeTranslationUnit(TU);
2775 if (checkForErrors(TU) != 0)
2778 for (FI = 0; FI < NumFilenames; ++FI) {
2779 CXFile file = clang_getFile(TU, Filenames[FI]);
2783 if (checkForErrors(TU) != 0)
2786 if (I + 1 == Repeats) {
2787 CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
2788 clang_findIncludesInFile(TU, file, visitor);
2790 if (checkForErrors(TU) != 0)
2796 PrintDiagnostics(TU);
2797 clang_disposeTranslationUnit(TU);
2798 clang_disposeIndex(CIdx);
2799 free((void *)Filenames);
2800 free_remapped_files(unsaved_files, num_unsaved_files);
2804 #define MAX_IMPORTED_ASTFILES 200
2809 } ImportedASTFilesData;
2811 static ImportedASTFilesData *importedASTs_create() {
2812 ImportedASTFilesData *p;
2813 p = malloc(sizeof(ImportedASTFilesData));
2814 p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
2819 static void importedASTs_dispose(ImportedASTFilesData *p) {
2824 for (i = 0; i < p->num_files; ++i)
2825 free(p->filenames[i]);
2830 static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
2833 for (i = 0; i < p->num_files; ++i)
2834 if (strcmp(file, p->filenames[i]) == 0)
2836 assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
2837 p->filenames[p->num_files++] = strdup(file);
2840 typedef struct IndexDataStringList_ {
2841 struct IndexDataStringList_ *next;
2842 char data[1]; /* Dynamically sized. */
2843 } IndexDataStringList;
2846 const char *check_prefix;
2847 int first_check_printed;
2850 const char *main_filename;
2851 ImportedASTFilesData *importedASTs;
2852 IndexDataStringList *strings;
2853 CXTranslationUnit TU;
2856 static void free_client_data(IndexData *index_data) {
2857 IndexDataStringList *node = index_data->strings;
2859 IndexDataStringList *next = node->next;
2863 index_data->strings = NULL;
2866 static void printCheck(IndexData *data) {
2867 if (data->check_prefix) {
2868 if (data->first_check_printed) {
2869 printf("// %s-NEXT: ", data->check_prefix);
2871 printf("// %s : ", data->check_prefix);
2872 data->first_check_printed = 1;
2877 static void printCXIndexFile(CXIdxClientFile file) {
2878 CXString filename = clang_getFileName((CXFile)file);
2879 printf("%s", clang_getCString(filename));
2880 clang_disposeString(filename);
2883 static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
2884 IndexData *index_data;
2887 CXIdxClientFile file;
2888 unsigned line, column;
2891 index_data = (IndexData *)client_data;
2892 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
2894 printf("<invalid>");
2898 printf("<no idxfile>");
2901 filename = clang_getFileName((CXFile)file);
2902 cname = clang_getCString(filename);
2903 if (strcmp(cname, index_data->main_filename) == 0)
2907 clang_disposeString(filename);
2910 printCXIndexFile(file);
2913 printf("%d:%d", line, column);
2916 static unsigned digitCount(unsigned val) {
2926 static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
2927 const CXIdxEntityInfo *info,
2929 IndexData *index_data;
2930 IndexDataStringList *node;
2933 CXIdxClientFile file;
2934 unsigned line, column;
2938 name = "<anon-tag>";
2940 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
2943 (IndexDataStringList *)malloc(sizeof(IndexDataStringList) + strlen(name) +
2944 digitCount(line) + digitCount(column) + 2);
2945 newStr = node->data;
2946 sprintf(newStr, "%s:%d:%d", name, line, column);
2948 /* Remember string so it can be freed later. */
2949 index_data = (IndexData *)client_data;
2950 node->next = index_data->strings;
2951 index_data->strings = node;
2953 return (CXIdxClientContainer)newStr;
2956 static void printCXIndexContainer(const CXIdxContainerInfo *info) {
2957 CXIdxClientContainer container;
2958 container = clang_index_getClientContainer(info);
2960 printf("[<<NULL>>]");
2962 printf("[%s]", (const char *)container);
2965 static const char *getEntityKindString(CXIdxEntityKind kind) {
2967 case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
2968 case CXIdxEntity_Typedef: return "typedef";
2969 case CXIdxEntity_Function: return "function";
2970 case CXIdxEntity_Variable: return "variable";
2971 case CXIdxEntity_Field: return "field";
2972 case CXIdxEntity_EnumConstant: return "enumerator";
2973 case CXIdxEntity_ObjCClass: return "objc-class";
2974 case CXIdxEntity_ObjCProtocol: return "objc-protocol";
2975 case CXIdxEntity_ObjCCategory: return "objc-category";
2976 case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
2977 case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
2978 case CXIdxEntity_ObjCProperty: return "objc-property";
2979 case CXIdxEntity_ObjCIvar: return "objc-ivar";
2980 case CXIdxEntity_Enum: return "enum";
2981 case CXIdxEntity_Struct: return "struct";
2982 case CXIdxEntity_Union: return "union";
2983 case CXIdxEntity_CXXClass: return "c++-class";
2984 case CXIdxEntity_CXXNamespace: return "namespace";
2985 case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
2986 case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
2987 case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
2988 case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
2989 case CXIdxEntity_CXXConstructor: return "constructor";
2990 case CXIdxEntity_CXXDestructor: return "destructor";
2991 case CXIdxEntity_CXXConversionFunction: return "conversion-func";
2992 case CXIdxEntity_CXXTypeAlias: return "type-alias";
2993 case CXIdxEntity_CXXInterface: return "c++-__interface";
2995 assert(0 && "Garbage entity kind");
2999 static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
3001 case CXIdxEntity_NonTemplate: return "";
3002 case CXIdxEntity_Template: return "-template";
3003 case CXIdxEntity_TemplatePartialSpecialization:
3004 return "-template-partial-spec";
3005 case CXIdxEntity_TemplateSpecialization: return "-template-spec";
3007 assert(0 && "Garbage entity kind");
3011 static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
3013 case CXIdxEntityLang_None: return "<none>";
3014 case CXIdxEntityLang_C: return "C";
3015 case CXIdxEntityLang_ObjC: return "ObjC";
3016 case CXIdxEntityLang_CXX: return "C++";
3018 assert(0 && "Garbage language kind");
3022 static void printEntityInfo(const char *cb,
3023 CXClientData client_data,
3024 const CXIdxEntityInfo *info) {
3026 IndexData *index_data;
3028 index_data = (IndexData *)client_data;
3029 printCheck(index_data);
3032 printf("%s: <<NULL>>", cb);
3038 name = "<anon-tag>";
3040 printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
3041 getEntityTemplateKindString(info->templateKind));
3042 printf(" | name: %s", name);
3043 printf(" | USR: %s", info->USR);
3044 printf(" | lang: %s", getEntityLanguageString(info->lang));
3046 for (i = 0; i != info->numAttributes; ++i) {
3047 const CXIdxAttrInfo *Attr = info->attributes[i];
3048 printf(" <attribute>: ");
3049 PrintCursor(Attr->cursor, NULL);
3053 static void printBaseClassInfo(CXClientData client_data,
3054 const CXIdxBaseClassInfo *info) {
3055 printEntityInfo(" <base>", client_data, info->base);
3056 printf(" | cursor: ");
3057 PrintCursor(info->cursor, NULL);
3059 printCXIndexLoc(info->loc, client_data);
3062 static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
3063 CXClientData client_data) {
3065 for (i = 0; i < ProtoInfo->numProtocols; ++i) {
3066 printEntityInfo(" <protocol>", client_data,
3067 ProtoInfo->protocols[i]->protocol);
3068 printf(" | cursor: ");
3069 PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
3071 printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
3076 static void index_diagnostic(CXClientData client_data,
3077 CXDiagnosticSet diagSet, void *reserved) {
3080 unsigned numDiags, i;
3082 IndexData *index_data;
3083 index_data = (IndexData *)client_data;
3084 printCheck(index_data);
3086 numDiags = clang_getNumDiagnosticsInSet(diagSet);
3087 for (i = 0; i != numDiags; ++i) {
3088 diag = clang_getDiagnosticInSet(diagSet, i);
3089 str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
3090 cstr = clang_getCString(str);
3091 printf("[diagnostic]: %s\n", cstr);
3092 clang_disposeString(str);
3094 if (getenv("CINDEXTEST_FAILONERROR") &&
3095 clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
3096 index_data->fail_for_error = 1;
3101 static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
3102 CXFile file, void *reserved) {
3103 IndexData *index_data;
3106 index_data = (IndexData *)client_data;
3107 printCheck(index_data);
3109 filename = clang_getFileName(file);
3110 index_data->main_filename = clang_getCString(filename);
3111 clang_disposeString(filename);
3113 printf("[enteredMainFile]: ");
3114 printCXIndexFile((CXIdxClientFile)file);
3117 return (CXIdxClientFile)file;
3120 static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
3121 const CXIdxIncludedFileInfo *info) {
3122 IndexData *index_data;
3124 index_data = (IndexData *)client_data;
3125 printCheck(index_data);
3127 printf("[ppIncludedFile]: ");
3128 printCXIndexFile((CXIdxClientFile)info->file);
3129 printf(" | name: \"%s\"", info->filename);
3130 printf(" | hash loc: ");
3131 printCXIndexLoc(info->hashLoc, client_data);
3132 printf(" | isImport: %d | isAngled: %d | isModule: %d",
3133 info->isImport, info->isAngled, info->isModuleImport);
3135 Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
3137 CXString str = clang_Module_getFullName(Mod);
3138 const char *cstr = clang_getCString(str);
3139 printf(" | module: %s", cstr);
3140 clang_disposeString(str);
3145 return (CXIdxClientFile)info->file;
3148 static CXIdxClientFile index_importedASTFile(CXClientData client_data,
3149 const CXIdxImportedASTFileInfo *info) {
3150 IndexData *index_data;
3151 index_data = (IndexData *)client_data;
3152 printCheck(index_data);
3154 if (index_data->importedASTs) {
3155 CXString filename = clang_getFileName(info->file);
3156 importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
3157 clang_disposeString(filename);
3160 printf("[importedASTFile]: ");
3161 printCXIndexFile((CXIdxClientFile)info->file);
3163 CXString name = clang_Module_getFullName(info->module);
3165 printCXIndexLoc(info->loc, client_data);
3166 printf(" | name: \"%s\"", clang_getCString(name));
3167 printf(" | isImplicit: %d\n", info->isImplicit);
3168 clang_disposeString(name);
3170 /* PCH file, the rest are not relevant. */
3174 return (CXIdxClientFile)info->file;
3177 static CXIdxClientContainer
3178 index_startedTranslationUnit(CXClientData client_data, void *reserved) {
3179 IndexData *index_data;
3180 index_data = (IndexData *)client_data;
3181 printCheck(index_data);
3183 printf("[startedTranslationUnit]\n");
3184 return (CXIdxClientContainer)"TU";
3187 static void index_indexDeclaration(CXClientData client_data,
3188 const CXIdxDeclInfo *info) {
3189 IndexData *index_data;
3190 const CXIdxObjCCategoryDeclInfo *CatInfo;
3191 const CXIdxObjCInterfaceDeclInfo *InterInfo;
3192 const CXIdxObjCProtocolRefListInfo *ProtoInfo;
3193 const CXIdxObjCPropertyDeclInfo *PropInfo;
3194 const CXIdxCXXClassDeclInfo *CXXClassInfo;
3196 index_data = (IndexData *)client_data;
3198 printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
3199 printf(" | cursor: ");
3200 PrintCursor(info->cursor, NULL);
3202 printCXIndexLoc(info->loc, client_data);
3203 printf(" | semantic-container: ");
3204 printCXIndexContainer(info->semanticContainer);
3205 printf(" | lexical-container: ");
3206 printCXIndexContainer(info->lexicalContainer);
3207 printf(" | isRedecl: %d", info->isRedeclaration);
3208 printf(" | isDef: %d", info->isDefinition);
3209 if (info->flags & CXIdxDeclFlag_Skipped) {
3210 assert(!info->isContainer);
3211 printf(" | isContainer: skipped");
3213 printf(" | isContainer: %d", info->isContainer);
3215 printf(" | isImplicit: %d\n", info->isImplicit);
3217 for (i = 0; i != info->numAttributes; ++i) {
3218 const CXIdxAttrInfo *Attr = info->attributes[i];
3219 printf(" <attribute>: ");
3220 PrintCursor(Attr->cursor, NULL);
3224 if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
3225 const char *kindName = 0;
3226 CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
3228 case CXIdxObjCContainer_ForwardRef:
3229 kindName = "forward-ref"; break;
3230 case CXIdxObjCContainer_Interface:
3231 kindName = "interface"; break;
3232 case CXIdxObjCContainer_Implementation:
3233 kindName = "implementation"; break;
3235 printCheck(index_data);
3236 printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
3239 if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
3240 printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
3241 CatInfo->objcClass);
3242 printf(" | cursor: ");
3243 PrintCursor(CatInfo->classCursor, NULL);
3245 printCXIndexLoc(CatInfo->classLoc, client_data);
3249 if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
3250 if (InterInfo->superInfo) {
3251 printBaseClassInfo(client_data, InterInfo->superInfo);
3256 if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
3257 printProtocolList(ProtoInfo, client_data);
3260 if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
3261 if (PropInfo->getter) {
3262 printEntityInfo(" <getter>", client_data, PropInfo->getter);
3265 if (PropInfo->setter) {
3266 printEntityInfo(" <setter>", client_data, PropInfo->setter);
3271 if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
3272 for (i = 0; i != CXXClassInfo->numBases; ++i) {
3273 printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
3278 if (info->declAsContainer)
3279 clang_index_setClientContainer(
3280 info->declAsContainer,
3281 makeClientContainer(client_data, info->entityInfo, info->loc));
3284 static void index_indexEntityReference(CXClientData client_data,
3285 const CXIdxEntityRefInfo *info) {
3286 printEntityInfo("[indexEntityReference]", client_data,
3287 info->referencedEntity);
3288 printf(" | cursor: ");
3289 PrintCursor(info->cursor, NULL);
3291 printCXIndexLoc(info->loc, client_data);
3292 printEntityInfo(" | <parent>:", client_data, info->parentEntity);
3293 printf(" | container: ");
3294 printCXIndexContainer(info->container);
3295 printf(" | refkind: ");
3296 switch (info->kind) {
3297 case CXIdxEntityRef_Direct: printf("direct"); break;
3298 case CXIdxEntityRef_Implicit: printf("implicit"); break;
3303 static int index_abortQuery(CXClientData client_data, void *reserved) {
3304 IndexData *index_data;
3305 index_data = (IndexData *)client_data;
3306 return index_data->abort;
3309 static IndexerCallbacks IndexCB = {
3312 index_enteredMainFile,
3313 index_ppIncludedFile,
3314 index_importedASTFile,
3315 index_startedTranslationUnit,
3316 index_indexDeclaration,
3317 index_indexEntityReference
3320 static unsigned getIndexOptions(void) {
3321 unsigned index_opts;
3323 if (getenv("CINDEXTEST_SUPPRESSREFS"))
3324 index_opts |= CXIndexOpt_SuppressRedundantRefs;
3325 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
3326 index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
3327 if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
3328 index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
3333 static int index_compile_args(int num_args, const char **args,
3334 CXIndexAction idxAction,
3335 ImportedASTFilesData *importedASTs,
3336 const char *check_prefix) {
3337 IndexData index_data;
3338 unsigned index_opts;
3341 if (num_args == 0) {
3342 fprintf(stderr, "no compiler arguments\n");
3346 index_data.check_prefix = check_prefix;
3347 index_data.first_check_printed = 0;
3348 index_data.fail_for_error = 0;
3349 index_data.abort = 0;
3350 index_data.main_filename = "";
3351 index_data.importedASTs = importedASTs;
3352 index_data.strings = NULL;
3353 index_data.TU = NULL;
3355 index_opts = getIndexOptions();
3356 result = clang_indexSourceFile(idxAction, &index_data,
3357 &IndexCB,sizeof(IndexCB), index_opts,
3358 0, args, num_args, 0, 0, 0,
3359 getDefaultParsingOptions());
3360 if (result != CXError_Success)
3361 describeLibclangFailure(result);
3363 if (index_data.fail_for_error)
3366 free_client_data(&index_data);
3370 static int index_ast_file(const char *ast_file,
3372 CXIndexAction idxAction,
3373 ImportedASTFilesData *importedASTs,
3374 const char *check_prefix) {
3375 CXTranslationUnit TU;
3376 IndexData index_data;
3377 unsigned index_opts;
3380 if (!CreateTranslationUnit(Idx, ast_file, &TU))
3383 index_data.check_prefix = check_prefix;
3384 index_data.first_check_printed = 0;
3385 index_data.fail_for_error = 0;
3386 index_data.abort = 0;
3387 index_data.main_filename = "";
3388 index_data.importedASTs = importedASTs;
3389 index_data.strings = NULL;
3392 index_opts = getIndexOptions();
3393 result = clang_indexTranslationUnit(idxAction, &index_data,
3394 &IndexCB,sizeof(IndexCB),
3396 if (index_data.fail_for_error)
3399 clang_disposeTranslationUnit(TU);
3400 free_client_data(&index_data);
3404 static int index_file(int argc, const char **argv, int full) {
3405 const char *check_prefix;
3407 CXIndexAction idxAction;
3408 ImportedASTFilesData *importedASTs;
3413 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3414 check_prefix = argv[0] + strlen("-check-prefix=");
3420 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3421 /* displayDiagnostics=*/1))) {
3422 fprintf(stderr, "Could not create Index\n");
3425 idxAction = clang_IndexAction_create(Idx);
3428 importedASTs = importedASTs_create();
3430 result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
3436 for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
3437 result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
3438 importedASTs, check_prefix);
3443 importedASTs_dispose(importedASTs);
3444 clang_IndexAction_dispose(idxAction);
3445 clang_disposeIndex(Idx);
3449 static int index_tu(int argc, const char **argv) {
3450 const char *check_prefix;
3452 CXIndexAction idxAction;
3457 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3458 check_prefix = argv[0] + strlen("-check-prefix=");
3464 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3465 /* displayDiagnostics=*/1))) {
3466 fprintf(stderr, "Could not create Index\n");
3469 idxAction = clang_IndexAction_create(Idx);
3471 result = index_ast_file(argv[0], Idx, idxAction,
3472 /*importedASTs=*/0, check_prefix);
3474 clang_IndexAction_dispose(idxAction);
3475 clang_disposeIndex(Idx);
3479 static int index_compile_db(int argc, const char **argv) {
3480 const char *check_prefix;
3482 CXIndexAction idxAction;
3487 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3488 check_prefix = argv[0] + strlen("-check-prefix=");
3495 fprintf(stderr, "no compilation database\n");
3499 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3500 /* displayDiagnostics=*/1))) {
3501 fprintf(stderr, "Could not create Index\n");
3504 idxAction = clang_IndexAction_create(Idx);
3507 const char *database = argv[0];
3508 CXCompilationDatabase db = 0;
3509 CXCompileCommands CCmds = 0;
3510 CXCompileCommand CCmd;
3511 CXCompilationDatabase_Error ec;
3513 #define MAX_COMPILE_ARGS 512
3514 CXString cxargs[MAX_COMPILE_ARGS];
3515 const char *args[MAX_COMPILE_ARGS];
3519 int i, a, numCmds, numArgs;
3521 len = strlen(database);
3522 tmp = (char *) malloc(len+1);
3523 memcpy(tmp, database, len+1);
3524 buildDir = dirname(tmp);
3526 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
3530 if (ec!=CXCompilationDatabase_NoError) {
3531 printf("unexpected error %d code while loading compilation database\n", ec);
3536 if (chdir(buildDir) != 0) {
3537 printf("Could not chdir to %s\n", buildDir);
3542 CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
3544 printf("compilation db is empty\n");
3549 numCmds = clang_CompileCommands_getSize(CCmds);
3552 fprintf(stderr, "should not get an empty compileCommand set\n");
3557 for (i=0; i<numCmds && errorCode == 0; ++i) {
3558 CCmd = clang_CompileCommands_getCommand(CCmds, i);
3560 wd = clang_CompileCommand_getDirectory(CCmd);
3561 if (chdir(clang_getCString(wd)) != 0) {
3562 printf("Could not chdir to %s\n", clang_getCString(wd));
3566 clang_disposeString(wd);
3568 numArgs = clang_CompileCommand_getNumArgs(CCmd);
3569 if (numArgs > MAX_COMPILE_ARGS){
3570 fprintf(stderr, "got more compile arguments than maximum\n");
3574 for (a=0; a<numArgs; ++a) {
3575 cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
3576 args[a] = clang_getCString(cxargs[a]);
3579 errorCode = index_compile_args(numArgs, args, idxAction,
3580 /*importedASTs=*/0, check_prefix);
3582 for (a=0; a<numArgs; ++a)
3583 clang_disposeString(cxargs[a]);
3586 printf("database loading failed with error code %d.\n", ec);
3591 clang_CompileCommands_dispose(CCmds);
3592 clang_CompilationDatabase_dispose(db);
3597 clang_IndexAction_dispose(idxAction);
3598 clang_disposeIndex(Idx);
3602 int perform_token_annotation(int argc, const char **argv) {
3603 const char *input = argv[1];
3605 unsigned line, second_line;
3606 unsigned column, second_column;
3608 CXTranslationUnit TU = 0;
3610 struct CXUnsavedFile *unsaved_files = 0;
3611 int num_unsaved_files = 0;
3613 unsigned num_tokens;
3614 CXSourceRange range;
3615 CXSourceLocation startLoc, endLoc;
3617 CXCursor *cursors = 0;
3618 CXSourceRangeList *skipped_ranges = 0;
3619 enum CXErrorCode Err;
3622 input += strlen("-test-annotate-tokens=");
3623 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
3624 &second_line, &second_column)))
3627 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
3632 CIdx = clang_createIndex(0, 1);
3633 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
3634 argv + num_unsaved_files + 2,
3635 argc - num_unsaved_files - 3,
3638 getDefaultParsingOptions(), &TU);
3639 if (Err != CXError_Success) {
3640 fprintf(stderr, "unable to parse input\n");
3641 describeLibclangFailure(Err);
3642 clang_disposeIndex(CIdx);
3644 free_remapped_files(unsaved_files, num_unsaved_files);
3649 if (checkForErrors(TU) != 0) {
3654 if (getenv("CINDEXTEST_EDITING")) {
3655 for (i = 0; i < 5; ++i) {
3656 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
3657 clang_defaultReparseOptions(TU));
3658 if (Err != CXError_Success) {
3659 fprintf(stderr, "Unable to reparse translation unit!\n");
3660 describeLibclangFailure(Err);
3667 if (checkForErrors(TU) != 0) {
3672 file = clang_getFile(TU, filename);
3674 fprintf(stderr, "file %s is not in this translation unit\n", filename);
3679 startLoc = clang_getLocation(TU, file, line, column);
3680 if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
3681 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
3687 endLoc = clang_getLocation(TU, file, second_line, second_column);
3688 if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
3689 fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
3690 second_line, second_column);
3695 range = clang_getRange(startLoc, endLoc);
3696 clang_tokenize(TU, range, &tokens, &num_tokens);
3698 if (checkForErrors(TU) != 0) {
3703 cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
3704 clang_annotateTokens(TU, tokens, num_tokens, cursors);
3706 if (checkForErrors(TU) != 0) {
3711 skipped_ranges = clang_getSkippedRanges(TU, file);
3712 for (i = 0; i != skipped_ranges->count; ++i) {
3713 unsigned start_line, start_column, end_line, end_column;
3714 clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
3715 0, &start_line, &start_column, 0);
3716 clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
3717 0, &end_line, &end_column, 0);
3718 printf("Skipping: ");
3719 PrintExtent(stdout, start_line, start_column, end_line, end_column);
3722 clang_disposeSourceRangeList(skipped_ranges);
3724 for (i = 0; i != num_tokens; ++i) {
3725 const char *kind = "<unknown>";
3726 CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
3727 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
3728 unsigned start_line, start_column, end_line, end_column;
3730 switch (clang_getTokenKind(tokens[i])) {
3731 case CXToken_Punctuation: kind = "Punctuation"; break;
3732 case CXToken_Keyword: kind = "Keyword"; break;
3733 case CXToken_Identifier: kind = "Identifier"; break;
3734 case CXToken_Literal: kind = "Literal"; break;
3735 case CXToken_Comment: kind = "Comment"; break;
3737 clang_getSpellingLocation(clang_getRangeStart(extent),
3738 0, &start_line, &start_column, 0);
3739 clang_getSpellingLocation(clang_getRangeEnd(extent),
3740 0, &end_line, &end_column, 0);
3741 printf("%s: \"%s\" ", kind, clang_getCString(spelling));
3742 clang_disposeString(spelling);
3743 PrintExtent(stdout, start_line, start_column, end_line, end_column);
3744 if (!clang_isInvalid(cursors[i].kind)) {
3746 PrintCursor(cursors[i], NULL);
3751 clang_disposeTokens(TU, tokens, num_tokens);
3754 PrintDiagnostics(TU);
3755 clang_disposeTranslationUnit(TU);
3756 clang_disposeIndex(CIdx);
3758 free_remapped_files(unsaved_files, num_unsaved_files);
3763 perform_test_compilation_db(const char *database, int argc, const char **argv) {
3764 CXCompilationDatabase db;
3765 CXCompileCommands CCmds;
3766 CXCompileCommand CCmd;
3767 CXCompilationDatabase_Error ec;
3774 int i, j, a, numCmds, numArgs;
3776 len = strlen(database);
3777 tmp = (char *) malloc(len+1);
3778 memcpy(tmp, database, len+1);
3779 buildDir = dirname(tmp);
3781 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
3785 if (ec!=CXCompilationDatabase_NoError) {
3786 printf("unexpected error %d code while loading compilation database\n", ec);
3791 for (i=0; i<argc && errorCode==0; ) {
3792 if (strcmp(argv[i],"lookup")==0){
3793 CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
3796 printf("file %s not found in compilation db\n", argv[i+1]);
3801 numCmds = clang_CompileCommands_getSize(CCmds);
3804 fprintf(stderr, "should not get an empty compileCommand set for file"
3805 " '%s'\n", argv[i+1]);
3810 for (j=0; j<numCmds; ++j) {
3811 CCmd = clang_CompileCommands_getCommand(CCmds, j);
3813 wd = clang_CompileCommand_getDirectory(CCmd);
3814 printf("workdir:'%s'", clang_getCString(wd));
3815 clang_disposeString(wd);
3817 printf(" cmdline:'");
3818 numArgs = clang_CompileCommand_getNumArgs(CCmd);
3819 for (a=0; a<numArgs; ++a) {
3821 arg = clang_CompileCommand_getArg(CCmd, a);
3822 printf("%s", clang_getCString(arg));
3823 clang_disposeString(arg);
3828 clang_CompileCommands_dispose(CCmds);
3833 clang_CompilationDatabase_dispose(db);
3835 printf("database loading failed with error code %d.\n", ec);
3845 /******************************************************************************/
3847 /******************************************************************************/
3849 static int insufficient_usr(const char *kind, const char *usage) {
3850 fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
3854 static unsigned isUSR(const char *s) {
3855 return s[0] == 'c' && s[1] == ':';
3858 static int not_usr(const char *s, const char *arg) {
3859 fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
3863 static void print_usr(CXString usr) {
3864 const char *s = clang_getCString(usr);
3866 clang_disposeString(usr);
3869 static void display_usrs() {
3870 fprintf(stderr, "-print-usrs options:\n"
3871 " ObjCCategory <class name> <category name>\n"
3872 " ObjCClass <class name>\n"
3873 " ObjCIvar <ivar name> <class USR>\n"
3874 " ObjCMethod <selector> [0=class method|1=instance method] "
3876 " ObjCProperty <property name> <class USR>\n"
3877 " ObjCProtocol <protocol name>\n");
3880 int print_usrs(const char **I, const char **E) {
3882 const char *kind = *I;
3883 unsigned len = strlen(kind);
3886 if (memcmp(kind, "ObjCIvar", 8) == 0) {
3888 return insufficient_usr(kind, "<ivar name> <class USR>");
3890 return not_usr("<class USR>", I[2]);
3893 x.data = (void*) I[2];
3894 x.private_flags = 0;
3895 print_usr(clang_constructUSR_ObjCIvar(I[1], x));
3903 if (memcmp(kind, "ObjCClass", 9) == 0) {
3905 return insufficient_usr(kind, "<class name>");
3906 print_usr(clang_constructUSR_ObjCClass(I[1]));
3912 if (memcmp(kind, "ObjCMethod", 10) == 0) {
3914 return insufficient_usr(kind, "<method selector> "
3915 "[0=class method|1=instance method] <class USR>");
3917 return not_usr("<class USR>", I[3]);
3920 x.data = (void*) I[3];
3921 x.private_flags = 0;
3922 print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
3929 if (memcmp(kind, "ObjCCategory", 12) == 0) {
3931 return insufficient_usr(kind, "<class name> <category name>");
3932 print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
3936 if (memcmp(kind, "ObjCProtocol", 12) == 0) {
3938 return insufficient_usr(kind, "<protocol name>");
3939 print_usr(clang_constructUSR_ObjCProtocol(I[1]));
3943 if (memcmp(kind, "ObjCProperty", 12) == 0) {
3945 return insufficient_usr(kind, "<property name> <class USR>");
3947 return not_usr("<class USR>", I[2]);
3950 x.data = (void*) I[2];
3951 x.private_flags = 0;
3952 print_usr(clang_constructUSR_ObjCProperty(I[1], x));
3965 fprintf(stderr, "Invalid USR kind: %s\n", *I);
3972 int print_usrs_file(const char *file_name) {
3974 const char *args[128];
3975 unsigned numChars = 0;
3977 FILE *fp = fopen(file_name, "r");
3979 fprintf(stderr, "error: cannot open '%s'\n", file_name);
3983 /* This code is not really all that safe, but it works fine for testing. */
3993 line[numChars] = '\0';
3996 if (line[0] == '/' && line[1] == '/')
3999 s = strtok(line, " ");
4005 if (print_usrs(&args[0], &args[i]))
4009 line[numChars++] = c;
4016 /******************************************************************************/
4017 /* Command line processing. */
4018 /******************************************************************************/
4019 int write_pch_file(const char *filename, int argc, const char *argv[]) {
4021 CXTranslationUnit TU;
4022 struct CXUnsavedFile *unsaved_files = 0;
4023 int num_unsaved_files = 0;
4024 enum CXErrorCode Err;
4027 Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
4029 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
4030 clang_disposeIndex(Idx);
4034 Err = clang_parseTranslationUnit2(
4035 Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files,
4036 unsaved_files, num_unsaved_files,
4037 CXTranslationUnit_Incomplete |
4038 CXTranslationUnit_DetailedPreprocessingRecord |
4039 CXTranslationUnit_ForSerialization,
4041 if (Err != CXError_Success) {
4042 fprintf(stderr, "Unable to load translation unit!\n");
4043 describeLibclangFailure(Err);
4044 free_remapped_files(unsaved_files, num_unsaved_files);
4045 clang_disposeTranslationUnit(TU);
4046 clang_disposeIndex(Idx);
4050 switch (clang_saveTranslationUnit(TU, filename,
4051 clang_defaultSaveOptions(TU))) {
4052 case CXSaveError_None:
4055 case CXSaveError_TranslationErrors:
4056 fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
4061 case CXSaveError_InvalidTU:
4062 fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
4067 case CXSaveError_Unknown:
4069 fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
4074 clang_disposeTranslationUnit(TU);
4075 free_remapped_files(unsaved_files, num_unsaved_files);
4076 clang_disposeIndex(Idx);
4080 /******************************************************************************/
4081 /* Serialized diagnostics. */
4082 /******************************************************************************/
4084 static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
4086 case CXLoadDiag_CannotLoad: return "Cannot Load File";
4087 case CXLoadDiag_None: break;
4088 case CXLoadDiag_Unknown: return "Unknown";
4089 case CXLoadDiag_InvalidFile: return "Invalid File";
4094 static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
4096 case CXDiagnostic_Note: return "note";
4097 case CXDiagnostic_Error: return "error";
4098 case CXDiagnostic_Fatal: return "fatal";
4099 case CXDiagnostic_Ignored: return "ignored";
4100 case CXDiagnostic_Warning: return "warning";
4105 static void printIndent(unsigned indent) {
4108 fprintf(stderr, "+");
4110 while (indent > 0) {
4111 fprintf(stderr, "-");
4116 static void printLocation(CXSourceLocation L) {
4119 unsigned line, column, offset;
4121 clang_getExpansionLocation(L, &File, &line, &column, &offset);
4122 FileName = clang_getFileName(File);
4124 fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
4125 clang_disposeString(FileName);
4128 static void printRanges(CXDiagnostic D, unsigned indent) {
4129 unsigned i, n = clang_getDiagnosticNumRanges(D);
4131 for (i = 0; i < n; ++i) {
4132 CXSourceLocation Start, End;
4133 CXSourceRange SR = clang_getDiagnosticRange(D, i);
4134 Start = clang_getRangeStart(SR);
4135 End = clang_getRangeEnd(SR);
4137 printIndent(indent);
4138 fprintf(stderr, "Range: ");
4139 printLocation(Start);
4140 fprintf(stderr, " ");
4142 fprintf(stderr, "\n");
4146 static void printFixIts(CXDiagnostic D, unsigned indent) {
4147 unsigned i, n = clang_getDiagnosticNumFixIts(D);
4148 fprintf(stderr, "Number FIXITs = %d\n", n);
4149 for (i = 0 ; i < n; ++i) {
4150 CXSourceRange ReplacementRange;
4152 text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
4154 printIndent(indent);
4155 fprintf(stderr, "FIXIT: (");
4156 printLocation(clang_getRangeStart(ReplacementRange));
4157 fprintf(stderr, " - ");
4158 printLocation(clang_getRangeEnd(ReplacementRange));
4159 fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
4160 clang_disposeString(text);
4164 static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
4170 n = clang_getNumDiagnosticsInSet(Diags);
4171 for (i = 0; i < n; ++i) {
4172 CXSourceLocation DiagLoc;
4175 CXString FileName, DiagSpelling, DiagOption, DiagCat;
4176 unsigned line, column, offset;
4177 const char *DiagOptionStr = 0, *DiagCatStr = 0;
4179 D = clang_getDiagnosticInSet(Diags, i);
4180 DiagLoc = clang_getDiagnosticLocation(D);
4181 clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
4182 FileName = clang_getFileName(File);
4183 DiagSpelling = clang_getDiagnosticSpelling(D);
4185 printIndent(indent);
4187 fprintf(stderr, "%s:%d:%d: %s: %s",
4188 clang_getCString(FileName),
4191 getSeverityString(clang_getDiagnosticSeverity(D)),
4192 clang_getCString(DiagSpelling));
4194 DiagOption = clang_getDiagnosticOption(D, 0);
4195 DiagOptionStr = clang_getCString(DiagOption);
4196 if (DiagOptionStr) {
4197 fprintf(stderr, " [%s]", DiagOptionStr);
4200 DiagCat = clang_getDiagnosticCategoryText(D);
4201 DiagCatStr = clang_getCString(DiagCat);
4203 fprintf(stderr, " [%s]", DiagCatStr);
4206 fprintf(stderr, "\n");
4208 printRanges(D, indent);
4209 printFixIts(D, indent);
4211 /* Print subdiagnostics. */
4212 printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
4214 clang_disposeString(FileName);
4215 clang_disposeString(DiagSpelling);
4216 clang_disposeString(DiagOption);
4217 clang_disposeString(DiagCat);
4221 static int read_diagnostics(const char *filename) {
4222 enum CXLoadDiag_Error error;
4223 CXString errorString;
4224 CXDiagnosticSet Diags = 0;
4226 Diags = clang_loadDiagnostics(filename, &error, &errorString);
4228 fprintf(stderr, "Trouble deserializing file (%s): %s\n",
4229 getDiagnosticCodeStr(error),
4230 clang_getCString(errorString));
4231 clang_disposeString(errorString);
4235 printDiagnosticSet(Diags, 0);
4236 fprintf(stderr, "Number of diagnostics: %d\n",
4237 clang_getNumDiagnosticsInSet(Diags));
4238 clang_disposeDiagnosticSet(Diags);
4242 static int perform_print_build_session_timestamp(void) {
4243 printf("%lld\n", clang_getBuildSessionTimestamp());
4247 /******************************************************************************/
4248 /* Command line processing. */
4249 /******************************************************************************/
4251 static CXCursorVisitor GetVisitor(const char *s) {
4253 return FilteredPrintingVisitor;
4254 if (strcmp(s, "-usrs") == 0)
4256 if (strncmp(s, "-memory-usage", 13) == 0)
4257 return GetVisitor(s + 13);
4261 static void print_usage(void) {
4263 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
4264 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
4265 " c-index-test -cursor-at=<site> <compiler arguments>\n"
4266 " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
4267 " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
4268 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
4269 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
4271 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4272 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4273 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
4274 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
4275 " c-index-test -test-file-scan <AST file> <source file> "
4276 "[FileCheck prefix]\n");
4278 " c-index-test -test-load-tu <AST file> <symbol filter> "
4279 "[FileCheck prefix]\n"
4280 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
4281 "[FileCheck prefix]\n"
4282 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
4284 " c-index-test -test-load-source-memory-usage "
4285 "<symbol filter> {<args>}*\n"
4286 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
4288 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
4289 " c-index-test -test-load-source-usrs-memory-usage "
4290 "<symbol filter> {<args>}*\n"
4291 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
4292 " c-index-test -test-inclusion-stack-source {<args>}*\n"
4293 " c-index-test -test-inclusion-stack-tu <AST file>\n");
4295 " c-index-test -test-print-linkage-source {<args>}*\n"
4296 " c-index-test -test-print-visibility {<args>}*\n"
4297 " c-index-test -test-print-type {<args>}*\n"
4298 " c-index-test -test-print-type-size {<args>}*\n"
4299 " c-index-test -test-print-bitwidth {<args>}*\n"
4300 " c-index-test -test-print-type-declaration {<args>}*\n"
4301 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
4302 " c-index-test -print-usr-file <file>\n"
4303 " c-index-test -write-pch <file> <compiler arguments>\n");
4305 " c-index-test -compilation-db [lookup <filename>] database\n");
4307 " c-index-test -print-build-session-timestamp\n");
4309 " c-index-test -read-diagnostics <file>\n\n");
4311 " <symbol filter> values:\n%s",
4312 " all - load all symbols, including those from PCH\n"
4313 " local - load all symbols except those in PCH\n"
4314 " category - only load ObjC categories (non-PCH)\n"
4315 " interface - only load ObjC interfaces (non-PCH)\n"
4316 " protocol - only load ObjC protocols (non-PCH)\n"
4317 " function - only load functions (non-PCH)\n"
4318 " typedef - only load typdefs (non-PCH)\n"
4319 " scan-function - scan function bodies (non-PCH)\n\n");
4324 int cindextest_main(int argc, const char **argv) {
4325 clang_enableStackTraces();
4326 if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
4327 return read_diagnostics(argv[2]);
4328 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
4329 return perform_code_completion(argc, argv, 0);
4330 if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
4331 return perform_code_completion(argc, argv, 1);
4332 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
4333 return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
4334 if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
4335 return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
4336 inspect_evaluate_cursor);
4337 if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
4338 return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
4339 inspect_macroinfo_cursor);
4340 if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
4341 return find_file_refs_at(argc, argv);
4342 if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
4343 return find_file_includes_in(argc, argv);
4344 if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
4345 return index_file(argc - 2, argv + 2, /*full=*/0);
4346 if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
4347 return index_file(argc - 2, argv + 2, /*full=*/1);
4348 if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
4349 return index_tu(argc - 2, argv + 2);
4350 if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
4351 return index_compile_db(argc - 2, argv + 2);
4352 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
4353 CXCursorVisitor I = GetVisitor(argv[1] + 13);
4355 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
4358 else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
4359 CXCursorVisitor I = GetVisitor(argv[1] + 25);
4361 int trials = atoi(argv[2]);
4362 return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
4366 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
4367 CXCursorVisitor I = GetVisitor(argv[1] + 17);
4369 PostVisitTU postVisit = 0;
4370 if (strstr(argv[1], "-memory-usage"))
4371 postVisit = PrintMemoryUsage;
4374 return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
4377 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
4378 return perform_file_scan(argv[2], argv[3],
4379 argc >= 5 ? argv[4] : 0);
4380 else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
4381 return perform_token_annotation(argc, argv);
4382 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
4383 return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
4384 PrintInclusionStack);
4385 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
4386 return perform_test_load_tu(argv[2], "all", NULL, NULL,
4387 PrintInclusionStack);
4388 else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
4389 return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
4391 else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0)
4392 return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility,
4394 else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
4395 return perform_test_load_source(argc - 2, argv + 2, "all",
4397 else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
4398 return perform_test_load_source(argc - 2, argv + 2, "all",
4400 else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
4401 return perform_test_load_source(argc - 2, argv + 2, "all",
4402 PrintTypeDeclaration, 0);
4403 else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
4404 return perform_test_load_source(argc - 2, argv + 2, "all",
4406 else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
4407 return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
4408 else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
4409 return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
4410 else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
4412 return print_usrs(argv + 2, argv + argc);
4418 else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
4419 return print_usrs_file(argv[2]);
4420 else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
4421 return write_pch_file(argv[2], argc - 3, argv + 3);
4422 else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
4423 return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
4424 else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
4425 return perform_print_build_session_timestamp();
4433 /* We intentionally run in a separate thread to ensure we at least minimal
4434 * testing of a multithreaded environment (for example, having a reduced stack
4437 typedef struct thread_info {
4438 int (*main_func)(int argc, const char **argv);
4443 void thread_runner(void *client_data_v) {
4444 thread_info *client_data = client_data_v;
4445 client_data->result = client_data->main_func(client_data->argc,
4449 static void flush_atexit(void) {
4450 /* stdout, and surprisingly even stderr, are not always flushed on process
4451 * and thread exit, particularly when the system is under heavy load. */
4456 int main(int argc, const char **argv) {
4457 thread_info client_data;
4459 atexit(flush_atexit);
4461 #ifdef CLANG_HAVE_LIBXML
4465 if (argc > 1 && strcmp(argv[1], "core") == 0)
4466 return indextest_core_main(argc, argv);
4468 client_data.main_func = cindextest_main;
4469 client_data.argc = argc;
4470 client_data.argv = argv;
4472 if (getenv("CINDEXTEST_NOTHREADS"))
4473 return client_data.main_func(client_data.argc, client_data.argv);
4475 clang_executeOnThread(thread_runner, &client_data, 0);
4476 return client_data.result;