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);
715 if (clang_isCursorDefinition(Cursor))
716 printf(" (Definition)");
718 switch (clang_getCursorAvailability(Cursor)) {
719 case CXAvailability_Available:
722 case CXAvailability_Deprecated:
723 printf(" (deprecated)");
726 case CXAvailability_NotAvailable:
727 printf(" (unavailable)");
730 case CXAvailability_NotAccessible:
731 printf(" (inaccessible)");
735 NumPlatformAvailability
736 = clang_getCursorPlatformAvailability(Cursor,
741 PlatformAvailability, 2);
742 if (AlwaysUnavailable) {
743 printf(" (always unavailable: \"%s\")",
744 clang_getCString(UnavailableMessage));
745 } else if (AlwaysDeprecated) {
746 printf(" (always deprecated: \"%s\")",
747 clang_getCString(DeprecatedMessage));
749 for (I = 0; I != NumPlatformAvailability; ++I) {
753 printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
754 if (PlatformAvailability[I].Unavailable)
755 printf(", unavailable");
757 printVersion(", introduced=", PlatformAvailability[I].Introduced);
758 printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
759 printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
761 if (clang_getCString(PlatformAvailability[I].Message)[0])
762 printf(", message=\"%s\"",
763 clang_getCString(PlatformAvailability[I].Message));
767 for (I = 0; I != NumPlatformAvailability; ++I) {
770 clang_disposeCXPlatformAvailability(PlatformAvailability + I);
773 clang_disposeString(DeprecatedMessage);
774 clang_disposeString(UnavailableMessage);
776 if (clang_CXXConstructor_isDefaultConstructor(Cursor))
777 printf(" (default constructor)");
779 if (clang_CXXConstructor_isMoveConstructor(Cursor))
780 printf(" (move constructor)");
781 if (clang_CXXConstructor_isCopyConstructor(Cursor))
782 printf(" (copy constructor)");
783 if (clang_CXXConstructor_isConvertingConstructor(Cursor))
784 printf(" (converting constructor)");
785 if (clang_CXXField_isMutable(Cursor))
786 printf(" (mutable)");
787 if (clang_CXXMethod_isDefaulted(Cursor))
788 printf(" (defaulted)");
789 if (clang_CXXMethod_isStatic(Cursor))
791 if (clang_CXXMethod_isVirtual(Cursor))
792 printf(" (virtual)");
793 if (clang_CXXMethod_isConst(Cursor))
795 if (clang_CXXMethod_isPureVirtual(Cursor))
797 if (clang_Cursor_isVariadic(Cursor))
798 printf(" (variadic)");
799 if (clang_Cursor_isObjCOptional(Cursor))
800 printf(" (@optional)");
802 if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
804 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
805 CXString S = clang_getTypeKindSpelling(T.kind);
806 printf(" [IBOutletCollection=%s]", clang_getCString(S));
807 clang_disposeString(S);
810 if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
811 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
812 unsigned isVirtual = clang_isVirtualBase(Cursor);
813 const char *accessStr = 0;
816 case CX_CXXInvalidAccessSpecifier:
817 accessStr = "invalid"; break;
819 accessStr = "public"; break;
820 case CX_CXXProtected:
821 accessStr = "protected"; break;
823 accessStr = "private"; break;
826 printf(" [access=%s isVirtual=%s]", accessStr,
827 isVirtual ? "true" : "false");
830 SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
831 if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
832 CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
833 CXString Name = clang_getCursorSpelling(SpecializationOf);
834 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
835 printf(" [Specialization of %s:%d:%d]",
836 clang_getCString(Name), line, column);
837 clang_disposeString(Name);
839 if (Cursor.kind == CXCursor_FunctionDecl) {
840 /* Collect the template parameter kinds from the base template. */
841 int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
843 if (NumTemplateArgs < 0) {
844 printf(" [no template arg info]");
846 for (I = 0; I < NumTemplateArgs; I++) {
847 enum CXTemplateArgumentKind TAK =
848 clang_Cursor_getTemplateArgumentKind(Cursor, I);
850 case CXTemplateArgumentKind_Type:
852 CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
853 CXString S = clang_getTypeSpelling(T);
854 printf(" [Template arg %d: kind: %d, type: %s]",
855 I, TAK, clang_getCString(S));
856 clang_disposeString(S);
859 case CXTemplateArgumentKind_Integral:
860 printf(" [Template arg %d: kind: %d, intval: %lld]",
861 I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
864 printf(" [Template arg %d: kind: %d]\n", I, TAK);
870 clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
871 if (num_overridden) {
873 LineCol lineCols[50];
874 assert(num_overridden <= 50);
875 printf(" [Overrides ");
876 for (I = 0; I != num_overridden; ++I) {
877 CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
878 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
879 lineCols[I].line = line;
880 lineCols[I].col = column;
882 /* Make the order of the override list deterministic. */
883 qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
884 for (I = 0; I != num_overridden; ++I) {
887 printf("@%d:%d", lineCols[I].line, lineCols[I].col);
890 clang_disposeOverriddenCursors(overridden);
893 if (Cursor.kind == CXCursor_InclusionDirective) {
894 CXFile File = clang_getIncludedFile(Cursor);
895 CXString Included = clang_getFileName(File);
896 printf(" (%s)", clang_getCString(Included));
897 clang_disposeString(Included);
899 if (clang_isFileMultipleIncludeGuarded(TU, File))
900 printf(" [multi-include guarded]");
903 CursorExtent = clang_getCursorExtent(Cursor);
904 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
905 CXNameRange_WantQualifier
906 | CXNameRange_WantSinglePiece
907 | CXNameRange_WantTemplateArgs,
909 if (!clang_equalRanges(CursorExtent, RefNameRange))
910 PrintRange(RefNameRange, "SingleRefName");
912 for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
913 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
914 CXNameRange_WantQualifier
915 | CXNameRange_WantTemplateArgs,
917 if (clang_equalRanges(clang_getNullRange(), RefNameRange))
919 if (!clang_equalRanges(CursorExtent, RefNameRange))
920 PrintRange(RefNameRange, "RefName");
923 PrintCursorComments(Cursor, CommentSchemaFile);
926 unsigned PropAttrs = clang_Cursor_getObjCPropertyAttributes(Cursor, 0);
927 if (PropAttrs != CXObjCPropertyAttr_noattr) {
929 #define PRINT_PROP_ATTR(A) \
930 if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
931 PRINT_PROP_ATTR(readonly);
932 PRINT_PROP_ATTR(getter);
933 PRINT_PROP_ATTR(assign);
934 PRINT_PROP_ATTR(readwrite);
935 PRINT_PROP_ATTR(retain);
936 PRINT_PROP_ATTR(copy);
937 PRINT_PROP_ATTR(nonatomic);
938 PRINT_PROP_ATTR(setter);
939 PRINT_PROP_ATTR(atomic);
940 PRINT_PROP_ATTR(weak);
941 PRINT_PROP_ATTR(strong);
942 PRINT_PROP_ATTR(unsafe_unretained);
943 PRINT_PROP_ATTR(class);
949 unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
950 if (QT != CXObjCDeclQualifier_None) {
952 #define PRINT_OBJC_QUAL(A) \
953 if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
955 PRINT_OBJC_QUAL(Inout);
956 PRINT_OBJC_QUAL(Out);
957 PRINT_OBJC_QUAL(Bycopy);
958 PRINT_OBJC_QUAL(Byref);
959 PRINT_OBJC_QUAL(Oneway);
966 static const char* GetCursorSource(CXCursor Cursor) {
967 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
970 clang_getExpansionLocation(Loc, &file, 0, 0, 0);
971 source = clang_getFileName(file);
972 if (!clang_getCString(source)) {
973 clang_disposeString(source);
974 return "<invalid loc>";
977 const char *b = basename(clang_getCString(source));
978 clang_disposeString(source);
983 /******************************************************************************/
985 /******************************************************************************/
987 typedef void (*PostVisitTU)(CXTranslationUnit);
989 void PrintDiagnostic(CXDiagnostic Diagnostic) {
993 unsigned display_opts = CXDiagnostic_DisplaySourceLocation
994 | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
995 | CXDiagnostic_DisplayOption;
996 unsigned i, num_fixits;
998 if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
1001 Msg = clang_formatDiagnostic(Diagnostic, display_opts);
1002 fprintf(stderr, "%s\n", clang_getCString(Msg));
1003 clang_disposeString(Msg);
1005 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
1010 num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
1011 fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
1012 for (i = 0; i != num_fixits; ++i) {
1013 CXSourceRange range;
1014 CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
1015 CXSourceLocation start = clang_getRangeStart(range);
1016 CXSourceLocation end = clang_getRangeEnd(range);
1017 unsigned start_line, start_column, end_line, end_column;
1018 CXFile start_file, end_file;
1019 clang_getSpellingLocation(start, &start_file, &start_line,
1021 clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
1022 if (clang_equalLocations(start, end)) {
1024 if (start_file == file)
1025 fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
1026 clang_getCString(insertion_text), start_line, start_column);
1027 } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
1029 if (start_file == file && end_file == file) {
1030 fprintf(out, "FIX-IT: Remove ");
1031 PrintExtent(out, start_line, start_column, end_line, end_column);
1036 if (start_file == end_file) {
1037 fprintf(out, "FIX-IT: Replace ");
1038 PrintExtent(out, start_line, start_column, end_line, end_column);
1039 fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
1042 clang_disposeString(insertion_text);
1046 void PrintDiagnosticSet(CXDiagnosticSet Set) {
1047 int i = 0, n = clang_getNumDiagnosticsInSet(Set);
1048 for ( ; i != n ; ++i) {
1049 CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
1050 CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
1051 PrintDiagnostic(Diag);
1053 PrintDiagnosticSet(ChildDiags);
1057 void PrintDiagnostics(CXTranslationUnit TU) {
1058 CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
1059 PrintDiagnosticSet(TUSet);
1060 clang_disposeDiagnosticSet(TUSet);
1063 void PrintMemoryUsage(CXTranslationUnit TU) {
1064 unsigned long total = 0;
1066 CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
1067 fprintf(stderr, "Memory usage:\n");
1068 for (i = 0 ; i != usage.numEntries; ++i) {
1069 const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
1070 unsigned long amount = usage.entries[i].amount;
1072 fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
1073 ((double) amount)/(1024*1024));
1075 fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
1076 ((double) total)/(1024*1024));
1077 clang_disposeCXTUResourceUsage(usage);
1080 /******************************************************************************/
1081 /* Logic for testing traversal. */
1082 /******************************************************************************/
1084 static void PrintCursorExtent(CXCursor C) {
1085 CXSourceRange extent = clang_getCursorExtent(C);
1086 PrintRange(extent, "Extent");
1089 /* Data used by the visitors. */
1091 CXTranslationUnit TU;
1092 enum CXCursorKind *Filter;
1093 const char *CommentSchemaFile;
1097 enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
1099 CXClientData ClientData) {
1100 VisitorData *Data = (VisitorData *)ClientData;
1101 if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
1102 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
1103 unsigned line, column;
1104 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
1105 printf("// %s: %s:%d:%d: ", FileCheckPrefix,
1106 GetCursorSource(Cursor), line, column);
1107 PrintCursor(Cursor, Data->CommentSchemaFile);
1108 PrintCursorExtent(Cursor);
1109 if (clang_isDeclaration(Cursor.kind)) {
1110 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
1111 const char *accessStr = 0;
1114 case CX_CXXInvalidAccessSpecifier: break;
1116 accessStr = "public"; break;
1117 case CX_CXXProtected:
1118 accessStr = "protected"; break;
1120 accessStr = "private"; break;
1124 printf(" [access=%s]", accessStr);
1127 return CXChildVisit_Recurse;
1130 return CXChildVisit_Continue;
1133 static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
1135 CXClientData ClientData) {
1136 const char *startBuf, *endBuf;
1137 unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
1139 VisitorData *Data = (VisitorData *)ClientData;
1141 if (Cursor.kind != CXCursor_FunctionDecl ||
1142 !clang_isCursorDefinition(Cursor))
1143 return CXChildVisit_Continue;
1145 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
1146 &startLine, &startColumn,
1147 &endLine, &endColumn);
1148 /* Probe the entire body, looking for both decls and refs. */
1149 curLine = startLine;
1150 curColumn = startColumn;
1152 while (startBuf < endBuf) {
1153 CXSourceLocation Loc;
1157 if (*startBuf == '\n') {
1161 } else if (*startBuf != '\t')
1164 Loc = clang_getCursorLocation(Cursor);
1165 clang_getSpellingLocation(Loc, &file, 0, 0, 0);
1167 source = clang_getFileName(file);
1168 if (clang_getCString(source)) {
1169 CXSourceLocation RefLoc
1170 = clang_getLocation(Data->TU, file, curLine, curColumn);
1171 Ref = clang_getCursor(Data->TU, RefLoc);
1172 if (Ref.kind == CXCursor_NoDeclFound) {
1173 /* Nothing found here; that's fine. */
1174 } else if (Ref.kind != CXCursor_FunctionDecl) {
1175 printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
1176 curLine, curColumn);
1177 PrintCursor(Ref, Data->CommentSchemaFile);
1181 clang_disposeString(source);
1185 return CXChildVisit_Continue;
1188 /******************************************************************************/
1190 /******************************************************************************/
1192 enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
1193 CXClientData ClientData) {
1194 VisitorData *Data = (VisitorData *)ClientData;
1195 if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
1196 CXString USR = clang_getCursorUSR(C);
1197 const char *cstr = clang_getCString(USR);
1198 if (!cstr || cstr[0] == '\0') {
1199 clang_disposeString(USR);
1200 return CXChildVisit_Recurse;
1202 printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
1204 PrintCursorExtent(C);
1206 clang_disposeString(USR);
1208 return CXChildVisit_Recurse;
1211 return CXChildVisit_Continue;
1214 /******************************************************************************/
1215 /* Inclusion stack testing. */
1216 /******************************************************************************/
1218 void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
1219 unsigned includeStackLen, CXClientData data) {
1224 fname = clang_getFileName(includedFile);
1225 printf("file: %s\nincluded by:\n", clang_getCString(fname));
1226 clang_disposeString(fname);
1228 for (i = 0; i < includeStackLen; ++i) {
1229 CXFile includingFile;
1230 unsigned line, column;
1231 clang_getSpellingLocation(includeStack[i], &includingFile, &line,
1233 fname = clang_getFileName(includingFile);
1234 printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
1235 clang_disposeString(fname);
1240 void PrintInclusionStack(CXTranslationUnit TU) {
1241 clang_getInclusions(TU, InclusionVisitor, NULL);
1244 /******************************************************************************/
1245 /* Linkage testing. */
1246 /******************************************************************************/
1248 static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
1250 const char *linkage = 0;
1252 if (clang_isInvalid(clang_getCursorKind(cursor)))
1253 return CXChildVisit_Recurse;
1255 switch (clang_getCursorLinkage(cursor)) {
1256 case CXLinkage_Invalid: break;
1257 case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
1258 case CXLinkage_Internal: linkage = "Internal"; break;
1259 case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
1260 case CXLinkage_External: linkage = "External"; break;
1264 PrintCursor(cursor, NULL);
1265 printf("linkage=%s\n", linkage);
1268 return CXChildVisit_Recurse;
1271 /******************************************************************************/
1272 /* Visibility testing. */
1273 /******************************************************************************/
1275 static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p,
1277 const char *visibility = 0;
1279 if (clang_isInvalid(clang_getCursorKind(cursor)))
1280 return CXChildVisit_Recurse;
1282 switch (clang_getCursorVisibility(cursor)) {
1283 case CXVisibility_Invalid: break;
1284 case CXVisibility_Hidden: visibility = "Hidden"; break;
1285 case CXVisibility_Protected: visibility = "Protected"; break;
1286 case CXVisibility_Default: visibility = "Default"; break;
1290 PrintCursor(cursor, NULL);
1291 printf("visibility=%s\n", visibility);
1294 return CXChildVisit_Recurse;
1297 /******************************************************************************/
1298 /* Typekind testing. */
1299 /******************************************************************************/
1301 static void PrintTypeAndTypeKind(CXType T, const char *Format) {
1302 CXString TypeSpelling, TypeKindSpelling;
1304 TypeSpelling = clang_getTypeSpelling(T);
1305 TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
1307 clang_getCString(TypeSpelling),
1308 clang_getCString(TypeKindSpelling));
1309 clang_disposeString(TypeSpelling);
1310 clang_disposeString(TypeKindSpelling);
1313 static enum CXVisitorResult FieldVisitor(CXCursor C,
1314 CXClientData client_data) {
1315 (*(int *) client_data)+=1;
1316 return CXVisit_Continue;
1319 static void PrintTypeTemplateArgs(CXType T, const char *Format) {
1320 int NumTArgs = clang_Type_getNumTemplateArguments(T);
1321 if (NumTArgs != -1 && NumTArgs != 0) {
1324 printf(Format, NumTArgs);
1325 for (i = 0; i < NumTArgs; ++i) {
1326 TArg = clang_Type_getTemplateArgumentAsType(T, i);
1327 if (TArg.kind != CXType_Invalid) {
1328 PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
1331 /* Ensure that the returned type is invalid when indexing off-by-one. */
1332 TArg = clang_Type_getTemplateArgumentAsType(T, i);
1333 assert(TArg.kind == CXType_Invalid);
1338 static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
1340 if (!clang_isInvalid(clang_getCursorKind(cursor))) {
1341 CXType T = clang_getCursorType(cursor);
1342 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
1343 PrintCursor(cursor, NULL);
1344 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
1345 if (clang_isConstQualifiedType(T))
1347 if (clang_isVolatileQualifiedType(T))
1348 printf(" volatile");
1349 if (clang_isRestrictQualifiedType(T))
1350 printf(" restrict");
1351 if (RQ == CXRefQualifier_LValue)
1352 printf(" lvalue-ref-qualifier");
1353 if (RQ == CXRefQualifier_RValue)
1354 printf(" rvalue-ref-qualifier");
1355 /* Print the template argument types if they exist. */
1356 PrintTypeTemplateArgs(T, " [templateargs/%d=");
1357 /* Print the canonical type if it is different. */
1359 CXType CT = clang_getCanonicalType(T);
1360 if (!clang_equalTypes(T, CT)) {
1361 PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
1362 PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d=");
1365 /* Print the return type if it exists. */
1367 CXType RT = clang_getCursorResultType(cursor);
1368 if (RT.kind != CXType_Invalid) {
1369 PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
1372 /* Print the argument types if they exist. */
1374 int NumArgs = clang_Cursor_getNumArguments(cursor);
1375 if (NumArgs != -1 && NumArgs != 0) {
1378 for (i = 0; i < NumArgs; ++i) {
1379 CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
1380 if (T.kind != CXType_Invalid) {
1381 PrintTypeAndTypeKind(T, " [%s] [%s]");
1387 /* Print if this is a non-POD type. */
1388 printf(" [isPOD=%d]", clang_isPODType(T));
1389 /* Print the pointee type. */
1391 CXType PT = clang_getPointeeType(T);
1392 if (PT.kind != CXType_Invalid) {
1393 PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
1396 /* Print the number of fields if they exist. */
1399 if (clang_Type_visitFields(T, FieldVisitor, &numFields)){
1400 if (numFields != 0) {
1401 printf(" [nbFields=%d]", numFields);
1403 /* Print if it is an anonymous record. */
1405 unsigned isAnon = clang_Cursor_isAnonymous(cursor);
1407 printf(" [isAnon=%d]", isAnon);
1415 return CXChildVisit_Recurse;
1418 static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
1421 enum CXCursorKind K = clang_getCursorKind(cursor);
1422 if (clang_isInvalid(K))
1423 return CXChildVisit_Recurse;
1424 T = clang_getCursorType(cursor);
1425 PrintCursor(cursor, NULL);
1426 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
1427 /* Print the type sizeof if applicable. */
1429 long long Size = clang_Type_getSizeOf(T);
1430 if (Size >= 0 || Size < -1 ) {
1431 printf(" [sizeof=%lld]", Size);
1434 /* Print the type alignof if applicable. */
1436 long long Align = clang_Type_getAlignOf(T);
1437 if (Align >= 0 || Align < -1) {
1438 printf(" [alignof=%lld]", Align);
1441 /* Print the record field offset if applicable. */
1443 CXString FieldSpelling = clang_getCursorSpelling(cursor);
1444 const char *FieldName = clang_getCString(FieldSpelling);
1445 /* recurse to get the first parent record that is not anonymous. */
1446 unsigned RecordIsAnonymous = 0;
1447 if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
1449 CXCursor Parent = p;
1452 Parent = clang_getCursorSemanticParent(Record);
1453 RecordIsAnonymous = clang_Cursor_isAnonymous(Record);
1454 /* Recurse as long as the parent is a CXType_Record and the Record
1456 } while ( clang_getCursorType(Parent).kind == CXType_Record &&
1457 RecordIsAnonymous > 0);
1459 long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record),
1461 long long Offset2 = clang_Cursor_getOffsetOfField(cursor);
1462 if (Offset == Offset2){
1463 printf(" [offsetof=%lld]", Offset);
1465 /* Offsets will be different in anonymous records. */
1466 printf(" [offsetof=%lld/%lld]", Offset, Offset2);
1470 clang_disposeString(FieldSpelling);
1472 /* Print if its a bitfield */
1474 int IsBitfield = clang_Cursor_isBitField(cursor);
1476 printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
1479 return CXChildVisit_Recurse;
1482 /******************************************************************************/
1483 /* Mangling testing. */
1484 /******************************************************************************/
1486 static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p,
1488 CXString MangledName;
1489 if (clang_isUnexposed(clang_getCursorKind(cursor)))
1490 return CXChildVisit_Recurse;
1491 PrintCursor(cursor, NULL);
1492 MangledName = clang_Cursor_getMangling(cursor);
1493 printf(" [mangled=%s]\n", clang_getCString(MangledName));
1494 clang_disposeString(MangledName);
1495 return CXChildVisit_Continue;
1498 static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
1501 CXStringSet *Manglings = NULL;
1502 if (clang_isUnexposed(clang_getCursorKind(cursor)))
1503 return CXChildVisit_Recurse;
1504 if (!clang_isDeclaration(clang_getCursorKind(cursor)))
1505 return CXChildVisit_Recurse;
1506 if (clang_getCursorKind(cursor) == CXCursor_ParmDecl)
1507 return CXChildVisit_Continue;
1508 PrintCursor(cursor, NULL);
1509 Manglings = clang_Cursor_getCXXManglings(cursor);
1510 for (I = 0, E = Manglings->Count; I < E; ++I)
1511 printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
1512 clang_disposeStringSet(Manglings);
1514 return CXChildVisit_Recurse;
1517 /******************************************************************************/
1518 /* Bitwidth testing. */
1519 /******************************************************************************/
1521 static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
1524 if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
1525 return CXChildVisit_Recurse;
1527 Bitwidth = clang_getFieldDeclBitWidth(cursor);
1528 if (Bitwidth >= 0) {
1529 PrintCursor(cursor, NULL);
1530 printf(" bitwidth=%d\n", Bitwidth);
1533 return CXChildVisit_Recurse;
1536 /******************************************************************************/
1537 /* Type declaration testing */
1538 /******************************************************************************/
1540 static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
1542 CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
1544 if (clang_isDeclaration(typeDeclaration.kind)) {
1545 PrintCursor(cursor, NULL);
1546 PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
1549 return CXChildVisit_Recurse;
1552 /******************************************************************************/
1553 /* Loading ASTs/source. */
1554 /******************************************************************************/
1556 static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
1557 const char *filter, const char *prefix,
1558 CXCursorVisitor Visitor,
1560 const char *CommentSchemaFile) {
1563 FileCheckPrefix = prefix;
1566 enum CXCursorKind K = CXCursor_NotImplemented;
1567 enum CXCursorKind *ck = &K;
1570 /* Perform some simple filtering. */
1571 if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
1572 else if (!strcmp(filter, "all-display") ||
1573 !strcmp(filter, "local-display")) {
1575 want_display_name = 1;
1577 else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
1578 else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
1579 else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
1580 else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
1581 else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
1582 else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
1583 else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
1585 fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
1591 Data.CommentSchemaFile = CommentSchemaFile;
1592 clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
1598 PrintDiagnostics(TU);
1599 if (checkForErrors(TU) != 0) {
1600 clang_disposeTranslationUnit(TU);
1604 clang_disposeTranslationUnit(TU);
1608 int perform_test_load_tu(const char *file, const char *filter,
1609 const char *prefix, CXCursorVisitor Visitor,
1612 CXTranslationUnit TU;
1614 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1615 !strcmp(filter, "local") ? 1 : 0,
1616 /* displayDiagnostics=*/1);
1618 if (!CreateTranslationUnit(Idx, file, &TU)) {
1619 clang_disposeIndex(Idx);
1623 result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
1624 clang_disposeIndex(Idx);
1628 int perform_test_load_source(int argc, const char **argv,
1629 const char *filter, CXCursorVisitor Visitor,
1632 CXTranslationUnit TU;
1633 const char *CommentSchemaFile;
1634 struct CXUnsavedFile *unsaved_files = 0;
1635 int num_unsaved_files = 0;
1636 enum CXErrorCode Err;
1638 unsigned Repeats = 0;
1641 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1642 (!strcmp(filter, "local") ||
1643 !strcmp(filter, "local-display"))? 1 : 0,
1644 /* displayDiagnostics=*/1);
1646 if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
1651 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1652 clang_disposeIndex(Idx);
1656 if (getenv("CINDEXTEST_EDITING"))
1659 Err = clang_parseTranslationUnit2(Idx, 0,
1660 argv + num_unsaved_files,
1661 argc - num_unsaved_files,
1662 unsaved_files, num_unsaved_files,
1663 getDefaultParsingOptions(), &TU);
1664 if (Err != CXError_Success) {
1665 fprintf(stderr, "Unable to load translation unit!\n");
1666 describeLibclangFailure(Err);
1667 free_remapped_files(unsaved_files, num_unsaved_files);
1668 clang_disposeIndex(Idx);
1672 for (I = 0; I != Repeats; ++I) {
1673 if (checkForErrors(TU) != 0)
1677 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
1678 clang_defaultReparseOptions(TU));
1679 if (Err != CXError_Success) {
1680 describeLibclangFailure(Err);
1681 free_remapped_files(unsaved_files, num_unsaved_files);
1682 clang_disposeIndex(Idx);
1688 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
1690 free_remapped_files(unsaved_files, num_unsaved_files);
1691 clang_disposeIndex(Idx);
1695 int perform_test_reparse_source(int argc, const char **argv, int trials,
1696 const char *filter, CXCursorVisitor Visitor,
1699 CXTranslationUnit TU;
1700 struct CXUnsavedFile *unsaved_files = 0;
1701 int num_unsaved_files = 0;
1702 int compiler_arg_idx = 0;
1703 enum CXErrorCode Err;
1706 int remap_after_trial = 0;
1709 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1710 !strcmp(filter, "local") ? 1 : 0,
1711 /* displayDiagnostics=*/1);
1713 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1714 clang_disposeIndex(Idx);
1718 for (i = 0; i < argc; ++i) {
1719 if (strcmp(argv[i], "--") == 0)
1723 compiler_arg_idx = i+1;
1724 if (num_unsaved_files > compiler_arg_idx)
1725 compiler_arg_idx = num_unsaved_files;
1727 /* Load the initial translation unit -- we do this without honoring remapped
1728 * files, so that we have a way to test results after changing the source. */
1729 Err = clang_parseTranslationUnit2(Idx, 0,
1730 argv + compiler_arg_idx,
1731 argc - compiler_arg_idx,
1732 0, 0, getDefaultParsingOptions(), &TU);
1733 if (Err != CXError_Success) {
1734 fprintf(stderr, "Unable to load translation unit!\n");
1735 describeLibclangFailure(Err);
1736 free_remapped_files(unsaved_files, num_unsaved_files);
1737 clang_disposeIndex(Idx);
1741 if (checkForErrors(TU) != 0)
1744 if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
1746 strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
1749 for (trial = 0; trial < trials; ++trial) {
1750 free_remapped_files(unsaved_files, num_unsaved_files);
1751 if (parse_remapped_files_with_try(trial, argc, argv, 0,
1752 &unsaved_files, &num_unsaved_files)) {
1753 clang_disposeTranslationUnit(TU);
1754 clang_disposeIndex(Idx);
1758 Err = clang_reparseTranslationUnit(
1760 trial >= remap_after_trial ? num_unsaved_files : 0,
1761 trial >= remap_after_trial ? unsaved_files : 0,
1762 clang_defaultReparseOptions(TU));
1763 if (Err != CXError_Success) {
1764 fprintf(stderr, "Unable to reparse translation unit!\n");
1765 describeLibclangFailure(Err);
1766 clang_disposeTranslationUnit(TU);
1767 free_remapped_files(unsaved_files, num_unsaved_files);
1768 clang_disposeIndex(Idx);
1772 if (checkForErrors(TU) != 0)
1776 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
1778 free_remapped_files(unsaved_files, num_unsaved_files);
1779 clang_disposeIndex(Idx);
1783 /******************************************************************************/
1784 /* Logic for testing clang_getCursor(). */
1785 /******************************************************************************/
1787 static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
1788 unsigned start_line, unsigned start_col,
1789 unsigned end_line, unsigned end_col,
1790 const char *prefix) {
1791 printf("// %s: ", FileCheckPrefix);
1793 printf("-%s", prefix);
1794 PrintExtent(stdout, start_line, start_col, end_line, end_col);
1796 PrintCursor(cursor, NULL);
1800 static int perform_file_scan(const char *ast_file, const char *source_file,
1801 const char *prefix) {
1803 CXTranslationUnit TU;
1805 CXCursor prevCursor = clang_getNullCursor();
1807 unsigned line = 1, col = 1;
1808 unsigned start_line = 1, start_col = 1;
1810 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
1811 /* displayDiagnostics=*/1))) {
1812 fprintf(stderr, "Could not create Index\n");
1816 if (!CreateTranslationUnit(Idx, ast_file, &TU))
1819 if ((fp = fopen(source_file, "r")) == NULL) {
1820 fprintf(stderr, "Could not open '%s'\n", source_file);
1821 clang_disposeTranslationUnit(TU);
1825 file = clang_getFile(TU, source_file);
1836 /* Check the cursor at this position, and dump the previous one if we have
1837 * found something new.
1839 cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
1840 if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
1841 prevCursor.kind != CXCursor_InvalidFile) {
1842 print_cursor_file_scan(TU, prevCursor, start_line, start_col,
1850 prevCursor = cursor;
1854 clang_disposeTranslationUnit(TU);
1855 clang_disposeIndex(Idx);
1859 /******************************************************************************/
1860 /* Logic for testing clang code completion. */
1861 /******************************************************************************/
1863 /* Parse file:line:column from the input string. Returns 0 on success, non-zero
1864 on failure. If successful, the pointer *filename will contain newly-allocated
1865 memory (that will be owned by the caller) to store the file name. */
1866 int parse_file_line_column(const char *input, char **filename, unsigned *line,
1867 unsigned *column, unsigned *second_line,
1868 unsigned *second_column) {
1869 /* Find the second colon. */
1870 const char *last_colon = strrchr(input, ':');
1871 unsigned values[4], i;
1872 unsigned num_values = (second_line && second_column)? 4 : 2;
1875 if (!last_colon || last_colon == input) {
1876 if (num_values == 4)
1877 fprintf(stderr, "could not parse filename:line:column:line:column in "
1880 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
1884 for (i = 0; i != num_values; ++i) {
1885 const char *prev_colon;
1887 /* Parse the next line or column. */
1888 values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
1889 if (*endptr != 0 && *endptr != ':') {
1890 fprintf(stderr, "could not parse %s in '%s'\n",
1891 (i % 2 ? "column" : "line"), input);
1895 if (i + 1 == num_values)
1898 /* Find the previous colon. */
1899 prev_colon = last_colon - 1;
1900 while (prev_colon != input && *prev_colon != ':')
1902 if (prev_colon == input) {
1903 fprintf(stderr, "could not parse %s in '%s'\n",
1904 (i % 2 == 0? "column" : "line"), input);
1908 last_colon = prev_colon;
1912 *column = values[1];
1914 if (second_line && second_column) {
1915 *second_line = values[2];
1916 *second_column = values[3];
1919 /* Copy the file name. */
1920 *filename = (char*)malloc(last_colon - input + 1);
1921 memcpy(*filename, input, last_colon - input);
1922 (*filename)[last_colon - input] = 0;
1927 clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
1929 case CXCompletionChunk_Optional: return "Optional";
1930 case CXCompletionChunk_TypedText: return "TypedText";
1931 case CXCompletionChunk_Text: return "Text";
1932 case CXCompletionChunk_Placeholder: return "Placeholder";
1933 case CXCompletionChunk_Informative: return "Informative";
1934 case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
1935 case CXCompletionChunk_LeftParen: return "LeftParen";
1936 case CXCompletionChunk_RightParen: return "RightParen";
1937 case CXCompletionChunk_LeftBracket: return "LeftBracket";
1938 case CXCompletionChunk_RightBracket: return "RightBracket";
1939 case CXCompletionChunk_LeftBrace: return "LeftBrace";
1940 case CXCompletionChunk_RightBrace: return "RightBrace";
1941 case CXCompletionChunk_LeftAngle: return "LeftAngle";
1942 case CXCompletionChunk_RightAngle: return "RightAngle";
1943 case CXCompletionChunk_Comma: return "Comma";
1944 case CXCompletionChunk_ResultType: return "ResultType";
1945 case CXCompletionChunk_Colon: return "Colon";
1946 case CXCompletionChunk_SemiColon: return "SemiColon";
1947 case CXCompletionChunk_Equal: return "Equal";
1948 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
1949 case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
1955 static int checkForErrors(CXTranslationUnit TU) {
1960 if (!getenv("CINDEXTEST_FAILONERROR"))
1963 Num = clang_getNumDiagnostics(TU);
1964 for (i = 0; i != Num; ++i) {
1965 Diag = clang_getDiagnostic(TU, i);
1966 if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
1967 DiagStr = clang_formatDiagnostic(Diag,
1968 clang_defaultDiagnosticDisplayOptions());
1969 fprintf(stderr, "%s\n", clang_getCString(DiagStr));
1970 clang_disposeString(DiagStr);
1971 clang_disposeDiagnostic(Diag);
1974 clang_disposeDiagnostic(Diag);
1980 static void print_completion_string(CXCompletionString completion_string,
1984 N = clang_getNumCompletionChunks(completion_string);
1985 for (I = 0; I != N; ++I) {
1988 enum CXCompletionChunkKind Kind
1989 = clang_getCompletionChunkKind(completion_string, I);
1991 if (Kind == CXCompletionChunk_Optional) {
1992 fprintf(file, "{Optional ");
1993 print_completion_string(
1994 clang_getCompletionChunkCompletionString(completion_string, I),
2000 if (Kind == CXCompletionChunk_VerticalSpace) {
2001 fprintf(file, "{VerticalSpace }");
2005 text = clang_getCompletionChunkText(completion_string, I);
2006 cstr = clang_getCString(text);
2007 fprintf(file, "{%s %s}",
2008 clang_getCompletionChunkKindSpelling(Kind),
2010 clang_disposeString(text);
2015 static void print_completion_result(CXCompletionResult *completion_result,
2017 CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
2018 unsigned annotationCount;
2019 enum CXCursorKind ParentKind;
2020 CXString ParentName;
2021 CXString BriefComment;
2022 CXString Annotation;
2023 const char *BriefCommentCString;
2025 fprintf(file, "%s:", clang_getCString(ks));
2026 clang_disposeString(ks);
2028 print_completion_string(completion_result->CompletionString, file);
2029 fprintf(file, " (%u)",
2030 clang_getCompletionPriority(completion_result->CompletionString));
2031 switch (clang_getCompletionAvailability(completion_result->CompletionString)){
2032 case CXAvailability_Available:
2035 case CXAvailability_Deprecated:
2036 fprintf(file, " (deprecated)");
2039 case CXAvailability_NotAvailable:
2040 fprintf(file, " (unavailable)");
2043 case CXAvailability_NotAccessible:
2044 fprintf(file, " (inaccessible)");
2048 annotationCount = clang_getCompletionNumAnnotations(
2049 completion_result->CompletionString);
2050 if (annotationCount) {
2052 fprintf(file, " (");
2053 for (i = 0; i < annotationCount; ++i) {
2055 fprintf(file, ", ");
2057 clang_getCompletionAnnotation(completion_result->CompletionString, i);
2058 fprintf(file, "\"%s\"", clang_getCString(Annotation));
2059 clang_disposeString(Annotation);
2064 if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
2065 ParentName = clang_getCompletionParent(completion_result->CompletionString,
2067 if (ParentKind != CXCursor_NotImplemented) {
2068 CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
2069 fprintf(file, " (parent: %s '%s')",
2070 clang_getCString(KindSpelling),
2071 clang_getCString(ParentName));
2072 clang_disposeString(KindSpelling);
2074 clang_disposeString(ParentName);
2077 BriefComment = clang_getCompletionBriefComment(
2078 completion_result->CompletionString);
2079 BriefCommentCString = clang_getCString(BriefComment);
2080 if (BriefCommentCString && *BriefCommentCString != '\0') {
2081 fprintf(file, "(brief comment: %s)", BriefCommentCString);
2083 clang_disposeString(BriefComment);
2085 fprintf(file, "\n");
2088 void print_completion_contexts(unsigned long long contexts, FILE *file) {
2089 fprintf(file, "Completion contexts:\n");
2090 if (contexts == CXCompletionContext_Unknown) {
2091 fprintf(file, "Unknown\n");
2093 if (contexts & CXCompletionContext_AnyType) {
2094 fprintf(file, "Any type\n");
2096 if (contexts & CXCompletionContext_AnyValue) {
2097 fprintf(file, "Any value\n");
2099 if (contexts & CXCompletionContext_ObjCObjectValue) {
2100 fprintf(file, "Objective-C object value\n");
2102 if (contexts & CXCompletionContext_ObjCSelectorValue) {
2103 fprintf(file, "Objective-C selector value\n");
2105 if (contexts & CXCompletionContext_CXXClassTypeValue) {
2106 fprintf(file, "C++ class type value\n");
2108 if (contexts & CXCompletionContext_DotMemberAccess) {
2109 fprintf(file, "Dot member access\n");
2111 if (contexts & CXCompletionContext_ArrowMemberAccess) {
2112 fprintf(file, "Arrow member access\n");
2114 if (contexts & CXCompletionContext_ObjCPropertyAccess) {
2115 fprintf(file, "Objective-C property access\n");
2117 if (contexts & CXCompletionContext_EnumTag) {
2118 fprintf(file, "Enum tag\n");
2120 if (contexts & CXCompletionContext_UnionTag) {
2121 fprintf(file, "Union tag\n");
2123 if (contexts & CXCompletionContext_StructTag) {
2124 fprintf(file, "Struct tag\n");
2126 if (contexts & CXCompletionContext_ClassTag) {
2127 fprintf(file, "Class name\n");
2129 if (contexts & CXCompletionContext_Namespace) {
2130 fprintf(file, "Namespace or namespace alias\n");
2132 if (contexts & CXCompletionContext_NestedNameSpecifier) {
2133 fprintf(file, "Nested name specifier\n");
2135 if (contexts & CXCompletionContext_ObjCInterface) {
2136 fprintf(file, "Objective-C interface\n");
2138 if (contexts & CXCompletionContext_ObjCProtocol) {
2139 fprintf(file, "Objective-C protocol\n");
2141 if (contexts & CXCompletionContext_ObjCCategory) {
2142 fprintf(file, "Objective-C category\n");
2144 if (contexts & CXCompletionContext_ObjCInstanceMessage) {
2145 fprintf(file, "Objective-C instance method\n");
2147 if (contexts & CXCompletionContext_ObjCClassMessage) {
2148 fprintf(file, "Objective-C class method\n");
2150 if (contexts & CXCompletionContext_ObjCSelectorName) {
2151 fprintf(file, "Objective-C selector name\n");
2153 if (contexts & CXCompletionContext_MacroName) {
2154 fprintf(file, "Macro name\n");
2156 if (contexts & CXCompletionContext_NaturalLanguage) {
2157 fprintf(file, "Natural language\n");
2161 int perform_code_completion(int argc, const char **argv, int timing_only) {
2162 const char *input = argv[1];
2168 struct CXUnsavedFile *unsaved_files = 0;
2169 int num_unsaved_files = 0;
2170 CXCodeCompleteResults *results = 0;
2171 enum CXErrorCode Err;
2172 CXTranslationUnit TU;
2173 unsigned I, Repeats = 1;
2174 unsigned completionOptions = clang_defaultCodeCompleteOptions();
2176 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
2177 completionOptions |= CXCodeComplete_IncludeCodePatterns;
2178 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
2179 completionOptions |= CXCodeComplete_IncludeBriefComments;
2182 input += strlen("-code-completion-timing=");
2184 input += strlen("-code-completion-at=");
2186 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
2190 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
2193 CIdx = clang_createIndex(0, 0);
2195 if (getenv("CINDEXTEST_EDITING"))
2198 Err = clang_parseTranslationUnit2(CIdx, 0,
2199 argv + num_unsaved_files + 2,
2200 argc - num_unsaved_files - 2,
2201 0, 0, getDefaultParsingOptions(), &TU);
2202 if (Err != CXError_Success) {
2203 fprintf(stderr, "Unable to load translation unit!\n");
2204 describeLibclangFailure(Err);
2208 Err = clang_reparseTranslationUnit(TU, 0, 0,
2209 clang_defaultReparseOptions(TU));
2211 if (Err != CXError_Success) {
2212 fprintf(stderr, "Unable to reparse translation unit!\n");
2213 describeLibclangFailure(Err);
2214 clang_disposeTranslationUnit(TU);
2218 for (I = 0; I != Repeats; ++I) {
2219 results = clang_codeCompleteAt(TU, filename, line, column,
2220 unsaved_files, num_unsaved_files,
2223 fprintf(stderr, "Unable to perform code completion!\n");
2227 clang_disposeCodeCompleteResults(results);
2231 unsigned i, n = results->NumResults, containerIsIncomplete = 0;
2232 unsigned long long contexts;
2233 enum CXCursorKind containerKind;
2234 CXString objCSelector;
2235 const char *selectorString;
2237 /* Sort the code-completion results based on the typed text. */
2238 clang_sortCodeCompletionResults(results->Results, results->NumResults);
2240 for (i = 0; i != n; ++i)
2241 print_completion_result(results->Results + i, stdout);
2243 n = clang_codeCompleteGetNumDiagnostics(results);
2244 for (i = 0; i != n; ++i) {
2245 CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
2246 PrintDiagnostic(diag);
2247 clang_disposeDiagnostic(diag);
2250 contexts = clang_codeCompleteGetContexts(results);
2251 print_completion_contexts(contexts, stdout);
2253 containerKind = clang_codeCompleteGetContainerKind(results,
2254 &containerIsIncomplete);
2256 if (containerKind != CXCursor_InvalidCode) {
2257 /* We have found a container */
2258 CXString containerUSR, containerKindSpelling;
2259 containerKindSpelling = clang_getCursorKindSpelling(containerKind);
2260 printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
2261 clang_disposeString(containerKindSpelling);
2263 if (containerIsIncomplete) {
2264 printf("Container is incomplete\n");
2267 printf("Container is complete\n");
2270 containerUSR = clang_codeCompleteGetContainerUSR(results);
2271 printf("Container USR: %s\n", clang_getCString(containerUSR));
2272 clang_disposeString(containerUSR);
2275 objCSelector = clang_codeCompleteGetObjCSelector(results);
2276 selectorString = clang_getCString(objCSelector);
2277 if (selectorString && strlen(selectorString) > 0) {
2278 printf("Objective-C selector: %s\n", selectorString);
2280 clang_disposeString(objCSelector);
2282 clang_disposeCodeCompleteResults(results);
2284 clang_disposeTranslationUnit(TU);
2285 clang_disposeIndex(CIdx);
2288 free_remapped_files(unsaved_files, num_unsaved_files);
2297 } CursorSourceLocation;
2299 typedef void (*cursor_handler_t)(CXCursor cursor);
2301 static int inspect_cursor_at(int argc, const char **argv,
2302 const char *locations_flag,
2303 cursor_handler_t handler) {
2306 struct CXUnsavedFile *unsaved_files = 0;
2307 int num_unsaved_files = 0;
2308 enum CXErrorCode Err;
2309 CXTranslationUnit TU;
2311 CursorSourceLocation *Locations = 0;
2312 unsigned NumLocations = 0, Loc;
2313 unsigned Repeats = 1;
2316 /* Count the number of locations. */
2317 while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
2320 /* Parse the locations. */
2321 assert(NumLocations > 0 && "Unable to count locations?");
2322 Locations = (CursorSourceLocation *)malloc(
2323 NumLocations * sizeof(CursorSourceLocation));
2324 for (Loc = 0; Loc < NumLocations; ++Loc) {
2325 const char *input = argv[Loc + 1] + strlen(locations_flag);
2326 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2327 &Locations[Loc].line,
2328 &Locations[Loc].column, 0, 0)))
2332 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
2333 &num_unsaved_files))
2336 if (getenv("CINDEXTEST_EDITING"))
2339 /* Parse the translation unit. When we're testing clang_getCursor() after
2340 reparsing, don't remap unsaved files until the second parse. */
2341 CIdx = clang_createIndex(1, 1);
2342 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2343 argv + num_unsaved_files + 1 + NumLocations,
2344 argc - num_unsaved_files - 2 - NumLocations,
2346 Repeats > 1? 0 : num_unsaved_files,
2347 getDefaultParsingOptions(), &TU);
2348 if (Err != CXError_Success) {
2349 fprintf(stderr, "unable to parse input\n");
2350 describeLibclangFailure(Err);
2354 if (checkForErrors(TU) != 0)
2357 for (I = 0; I != Repeats; ++I) {
2359 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2360 clang_defaultReparseOptions(TU));
2361 if (Err != CXError_Success) {
2362 describeLibclangFailure(Err);
2363 clang_disposeTranslationUnit(TU);
2368 if (checkForErrors(TU) != 0)
2371 for (Loc = 0; Loc < NumLocations; ++Loc) {
2372 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2376 Cursor = clang_getCursor(TU,
2377 clang_getLocation(TU, file, Locations[Loc].line,
2378 Locations[Loc].column));
2380 if (checkForErrors(TU) != 0)
2383 if (I + 1 == Repeats) {
2385 free(Locations[Loc].filename);
2390 PrintDiagnostics(TU);
2391 clang_disposeTranslationUnit(TU);
2392 clang_disposeIndex(CIdx);
2394 free_remapped_files(unsaved_files, num_unsaved_files);
2398 static void inspect_print_cursor(CXCursor Cursor) {
2399 CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
2400 CXCompletionString completionString = clang_getCursorCompletionString(
2402 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2405 unsigned line, column;
2406 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2407 printf("%d:%d ", line, column);
2408 PrintCursor(Cursor, NULL);
2409 PrintCursorExtent(Cursor);
2410 Spelling = clang_getCursorSpelling(Cursor);
2411 cspell = clang_getCString(Spelling);
2412 if (cspell && strlen(cspell) != 0) {
2413 unsigned pieceIndex;
2414 printf(" Spelling=%s (", cspell);
2415 for (pieceIndex = 0; ; ++pieceIndex) {
2416 CXSourceRange range =
2417 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2418 if (clang_Range_isNull(range))
2420 PrintRange(range, 0);
2424 clang_disposeString(Spelling);
2425 if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
2426 printf(" Selector index=%d",
2427 clang_Cursor_getObjCSelectorIndex(Cursor));
2428 if (clang_Cursor_isDynamicCall(Cursor))
2429 printf(" Dynamic-call");
2430 if (Cursor.kind == CXCursor_ObjCMessageExpr) {
2431 CXType T = clang_Cursor_getReceiverType(Cursor);
2432 CXString S = clang_getTypeKindSpelling(T.kind);
2433 printf(" Receiver-type=%s", clang_getCString(S));
2434 clang_disposeString(S);
2438 CXModule mod = clang_Cursor_getModule(Cursor);
2440 CXString name, astFilename;
2441 unsigned i, numHeaders;
2443 astFile = clang_Module_getASTFile(mod);
2444 astFilename = clang_getFileName(astFile);
2445 name = clang_Module_getFullName(mod);
2446 numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
2447 printf(" ModuleName=%s (%s) system=%d Headers(%d):",
2448 clang_getCString(name), clang_getCString(astFilename),
2449 clang_Module_isSystem(mod), numHeaders);
2450 clang_disposeString(name);
2451 clang_disposeString(astFilename);
2452 for (i = 0; i < numHeaders; ++i) {
2453 CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
2454 CXString filename = clang_getFileName(file);
2455 printf("\n%s", clang_getCString(filename));
2456 clang_disposeString(filename);
2461 if (completionString != NULL) {
2462 printf("\nCompletion string: ");
2463 print_completion_string(completionString, stdout);
2468 static void display_evaluate_results(CXEvalResult result) {
2469 switch (clang_EvalResult_getKind(result)) {
2472 printf("Kind: Int, ");
2473 if (clang_EvalResult_isUnsignedInt(result)) {
2474 unsigned long long val = clang_EvalResult_getAsUnsigned(result);
2475 printf("unsigned, Value: %llu", val);
2477 long long val = clang_EvalResult_getAsLongLong(result);
2478 printf("Value: %lld", val);
2484 double val = clang_EvalResult_getAsDouble(result);
2485 printf("Kind: Float , Value: %f", val);
2488 case CXEval_ObjCStrLiteral:
2490 const char* str = clang_EvalResult_getAsStr(result);
2491 printf("Kind: ObjCString , Value: %s", str);
2494 case CXEval_StrLiteral:
2496 const char* str = clang_EvalResult_getAsStr(result);
2497 printf("Kind: CString , Value: %s", str);
2502 const char* str = clang_EvalResult_getAsStr(result);
2503 printf("Kind: CFString , Value: %s", str);
2507 printf("Unexposed");
2512 static void inspect_evaluate_cursor(CXCursor Cursor) {
2513 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2516 unsigned line, column;
2519 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2520 printf("%d:%d ", line, column);
2521 PrintCursor(Cursor, NULL);
2522 PrintCursorExtent(Cursor);
2523 Spelling = clang_getCursorSpelling(Cursor);
2524 cspell = clang_getCString(Spelling);
2525 if (cspell && strlen(cspell) != 0) {
2526 unsigned pieceIndex;
2527 printf(" Spelling=%s (", cspell);
2528 for (pieceIndex = 0; ; ++pieceIndex) {
2529 CXSourceRange range =
2530 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2531 if (clang_Range_isNull(range))
2533 PrintRange(range, 0);
2537 clang_disposeString(Spelling);
2539 ER = clang_Cursor_Evaluate(Cursor);
2541 printf("Not Evaluatable");
2543 display_evaluate_results(ER);
2544 clang_EvalResult_dispose(ER);
2549 static void inspect_macroinfo_cursor(CXCursor Cursor) {
2550 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
2553 unsigned line, column;
2554 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2555 printf("%d:%d ", line, column);
2556 PrintCursor(Cursor, NULL);
2557 PrintCursorExtent(Cursor);
2558 Spelling = clang_getCursorSpelling(Cursor);
2559 cspell = clang_getCString(Spelling);
2560 if (cspell && strlen(cspell) != 0) {
2561 unsigned pieceIndex;
2562 printf(" Spelling=%s (", cspell);
2563 for (pieceIndex = 0; ; ++pieceIndex) {
2564 CXSourceRange range =
2565 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
2566 if (clang_Range_isNull(range))
2568 PrintRange(range, 0);
2572 clang_disposeString(Spelling);
2574 if (clang_Cursor_isMacroBuiltin(Cursor)) {
2575 printf("[builtin macro]");
2576 } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
2577 printf("[function macro]");
2582 static enum CXVisitorResult findFileRefsVisit(void *context,
2583 CXCursor cursor, CXSourceRange range) {
2584 if (clang_Range_isNull(range))
2585 return CXVisit_Continue;
2587 PrintCursor(cursor, NULL);
2588 PrintRange(range, "");
2590 return CXVisit_Continue;
2593 static int find_file_refs_at(int argc, const char **argv) {
2596 struct CXUnsavedFile *unsaved_files = 0;
2597 int num_unsaved_files = 0;
2598 enum CXErrorCode Err;
2599 CXTranslationUnit TU;
2601 CursorSourceLocation *Locations = 0;
2602 unsigned NumLocations = 0, Loc;
2603 unsigned Repeats = 1;
2606 /* Count the number of locations. */
2607 while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
2610 /* Parse the locations. */
2611 assert(NumLocations > 0 && "Unable to count locations?");
2612 Locations = (CursorSourceLocation *)malloc(
2613 NumLocations * sizeof(CursorSourceLocation));
2614 for (Loc = 0; Loc < NumLocations; ++Loc) {
2615 const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
2616 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2617 &Locations[Loc].line,
2618 &Locations[Loc].column, 0, 0)))
2622 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
2623 &num_unsaved_files))
2626 if (getenv("CINDEXTEST_EDITING"))
2629 /* Parse the translation unit. When we're testing clang_getCursor() after
2630 reparsing, don't remap unsaved files until the second parse. */
2631 CIdx = clang_createIndex(1, 1);
2632 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2633 argv + num_unsaved_files + 1 + NumLocations,
2634 argc - num_unsaved_files - 2 - NumLocations,
2636 Repeats > 1? 0 : num_unsaved_files,
2637 getDefaultParsingOptions(), &TU);
2638 if (Err != CXError_Success) {
2639 fprintf(stderr, "unable to parse input\n");
2640 describeLibclangFailure(Err);
2641 clang_disposeTranslationUnit(TU);
2645 if (checkForErrors(TU) != 0)
2648 for (I = 0; I != Repeats; ++I) {
2650 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2651 clang_defaultReparseOptions(TU));
2652 if (Err != CXError_Success) {
2653 describeLibclangFailure(Err);
2654 clang_disposeTranslationUnit(TU);
2659 if (checkForErrors(TU) != 0)
2662 for (Loc = 0; Loc < NumLocations; ++Loc) {
2663 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2667 Cursor = clang_getCursor(TU,
2668 clang_getLocation(TU, file, Locations[Loc].line,
2669 Locations[Loc].column));
2671 if (checkForErrors(TU) != 0)
2674 if (I + 1 == Repeats) {
2675 CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
2676 PrintCursor(Cursor, NULL);
2678 clang_findReferencesInFile(Cursor, file, visitor);
2679 free(Locations[Loc].filename);
2681 if (checkForErrors(TU) != 0)
2687 PrintDiagnostics(TU);
2688 clang_disposeTranslationUnit(TU);
2689 clang_disposeIndex(CIdx);
2691 free_remapped_files(unsaved_files, num_unsaved_files);
2695 static enum CXVisitorResult findFileIncludesVisit(void *context,
2696 CXCursor cursor, CXSourceRange range) {
2697 PrintCursor(cursor, NULL);
2698 PrintRange(range, "");
2700 return CXVisit_Continue;
2703 static int find_file_includes_in(int argc, const char **argv) {
2705 struct CXUnsavedFile *unsaved_files = 0;
2706 int num_unsaved_files = 0;
2707 enum CXErrorCode Err;
2708 CXTranslationUnit TU;
2709 const char **Filenames = 0;
2710 unsigned NumFilenames = 0;
2711 unsigned Repeats = 1;
2714 /* Count the number of locations. */
2715 while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
2718 /* Parse the locations. */
2719 assert(NumFilenames > 0 && "Unable to count filenames?");
2720 Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
2721 for (I = 0; I < NumFilenames; ++I) {
2722 const char *input = argv[I + 1] + strlen("-file-includes-in=");
2723 /* Copy the file name. */
2724 Filenames[I] = input;
2727 if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
2728 &num_unsaved_files))
2731 if (getenv("CINDEXTEST_EDITING"))
2734 /* Parse the translation unit. When we're testing clang_getCursor() after
2735 reparsing, don't remap unsaved files until the second parse. */
2736 CIdx = clang_createIndex(1, 1);
2737 Err = clang_parseTranslationUnit2(
2738 CIdx, argv[argc - 1],
2739 argv + num_unsaved_files + 1 + NumFilenames,
2740 argc - num_unsaved_files - 2 - NumFilenames,
2742 Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU);
2744 if (Err != CXError_Success) {
2745 fprintf(stderr, "unable to parse input\n");
2746 describeLibclangFailure(Err);
2747 clang_disposeTranslationUnit(TU);
2751 if (checkForErrors(TU) != 0)
2754 for (I = 0; I != Repeats; ++I) {
2756 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2757 clang_defaultReparseOptions(TU));
2758 if (Err != CXError_Success) {
2759 describeLibclangFailure(Err);
2760 clang_disposeTranslationUnit(TU);
2765 if (checkForErrors(TU) != 0)
2768 for (FI = 0; FI < NumFilenames; ++FI) {
2769 CXFile file = clang_getFile(TU, Filenames[FI]);
2773 if (checkForErrors(TU) != 0)
2776 if (I + 1 == Repeats) {
2777 CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
2778 clang_findIncludesInFile(TU, file, visitor);
2780 if (checkForErrors(TU) != 0)
2786 PrintDiagnostics(TU);
2787 clang_disposeTranslationUnit(TU);
2788 clang_disposeIndex(CIdx);
2789 free((void *)Filenames);
2790 free_remapped_files(unsaved_files, num_unsaved_files);
2794 #define MAX_IMPORTED_ASTFILES 200
2799 } ImportedASTFilesData;
2801 static ImportedASTFilesData *importedASTs_create() {
2802 ImportedASTFilesData *p;
2803 p = malloc(sizeof(ImportedASTFilesData));
2804 p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
2809 static void importedASTs_dispose(ImportedASTFilesData *p) {
2814 for (i = 0; i < p->num_files; ++i)
2815 free(p->filenames[i]);
2820 static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
2823 for (i = 0; i < p->num_files; ++i)
2824 if (strcmp(file, p->filenames[i]) == 0)
2826 assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
2827 p->filenames[p->num_files++] = strdup(file);
2830 typedef struct IndexDataStringList_ {
2831 struct IndexDataStringList_ *next;
2832 char data[1]; /* Dynamically sized. */
2833 } IndexDataStringList;
2836 const char *check_prefix;
2837 int first_check_printed;
2840 const char *main_filename;
2841 ImportedASTFilesData *importedASTs;
2842 IndexDataStringList *strings;
2843 CXTranslationUnit TU;
2846 static void free_client_data(IndexData *index_data) {
2847 IndexDataStringList *node = index_data->strings;
2849 IndexDataStringList *next = node->next;
2853 index_data->strings = NULL;
2856 static void printCheck(IndexData *data) {
2857 if (data->check_prefix) {
2858 if (data->first_check_printed) {
2859 printf("// %s-NEXT: ", data->check_prefix);
2861 printf("// %s : ", data->check_prefix);
2862 data->first_check_printed = 1;
2867 static void printCXIndexFile(CXIdxClientFile file) {
2868 CXString filename = clang_getFileName((CXFile)file);
2869 printf("%s", clang_getCString(filename));
2870 clang_disposeString(filename);
2873 static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
2874 IndexData *index_data;
2877 CXIdxClientFile file;
2878 unsigned line, column;
2881 index_data = (IndexData *)client_data;
2882 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
2884 printf("<invalid>");
2888 printf("<no idxfile>");
2891 filename = clang_getFileName((CXFile)file);
2892 cname = clang_getCString(filename);
2893 if (strcmp(cname, index_data->main_filename) == 0)
2897 clang_disposeString(filename);
2900 printCXIndexFile(file);
2903 printf("%d:%d", line, column);
2906 static unsigned digitCount(unsigned val) {
2916 static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
2917 const CXIdxEntityInfo *info,
2919 IndexData *index_data;
2920 IndexDataStringList *node;
2923 CXIdxClientFile file;
2924 unsigned line, column;
2928 name = "<anon-tag>";
2930 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
2933 (IndexDataStringList *)malloc(sizeof(IndexDataStringList) + strlen(name) +
2934 digitCount(line) + digitCount(column) + 2);
2935 newStr = node->data;
2936 sprintf(newStr, "%s:%d:%d", name, line, column);
2938 /* Remember string so it can be freed later. */
2939 index_data = (IndexData *)client_data;
2940 node->next = index_data->strings;
2941 index_data->strings = node;
2943 return (CXIdxClientContainer)newStr;
2946 static void printCXIndexContainer(const CXIdxContainerInfo *info) {
2947 CXIdxClientContainer container;
2948 container = clang_index_getClientContainer(info);
2950 printf("[<<NULL>>]");
2952 printf("[%s]", (const char *)container);
2955 static const char *getEntityKindString(CXIdxEntityKind kind) {
2957 case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
2958 case CXIdxEntity_Typedef: return "typedef";
2959 case CXIdxEntity_Function: return "function";
2960 case CXIdxEntity_Variable: return "variable";
2961 case CXIdxEntity_Field: return "field";
2962 case CXIdxEntity_EnumConstant: return "enumerator";
2963 case CXIdxEntity_ObjCClass: return "objc-class";
2964 case CXIdxEntity_ObjCProtocol: return "objc-protocol";
2965 case CXIdxEntity_ObjCCategory: return "objc-category";
2966 case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
2967 case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
2968 case CXIdxEntity_ObjCProperty: return "objc-property";
2969 case CXIdxEntity_ObjCIvar: return "objc-ivar";
2970 case CXIdxEntity_Enum: return "enum";
2971 case CXIdxEntity_Struct: return "struct";
2972 case CXIdxEntity_Union: return "union";
2973 case CXIdxEntity_CXXClass: return "c++-class";
2974 case CXIdxEntity_CXXNamespace: return "namespace";
2975 case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
2976 case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
2977 case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
2978 case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
2979 case CXIdxEntity_CXXConstructor: return "constructor";
2980 case CXIdxEntity_CXXDestructor: return "destructor";
2981 case CXIdxEntity_CXXConversionFunction: return "conversion-func";
2982 case CXIdxEntity_CXXTypeAlias: return "type-alias";
2983 case CXIdxEntity_CXXInterface: return "c++-__interface";
2985 assert(0 && "Garbage entity kind");
2989 static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
2991 case CXIdxEntity_NonTemplate: return "";
2992 case CXIdxEntity_Template: return "-template";
2993 case CXIdxEntity_TemplatePartialSpecialization:
2994 return "-template-partial-spec";
2995 case CXIdxEntity_TemplateSpecialization: return "-template-spec";
2997 assert(0 && "Garbage entity kind");
3001 static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
3003 case CXIdxEntityLang_None: return "<none>";
3004 case CXIdxEntityLang_C: return "C";
3005 case CXIdxEntityLang_ObjC: return "ObjC";
3006 case CXIdxEntityLang_CXX: return "C++";
3008 assert(0 && "Garbage language kind");
3012 static void printEntityInfo(const char *cb,
3013 CXClientData client_data,
3014 const CXIdxEntityInfo *info) {
3016 IndexData *index_data;
3018 index_data = (IndexData *)client_data;
3019 printCheck(index_data);
3022 printf("%s: <<NULL>>", cb);
3028 name = "<anon-tag>";
3030 printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
3031 getEntityTemplateKindString(info->templateKind));
3032 printf(" | name: %s", name);
3033 printf(" | USR: %s", info->USR);
3034 printf(" | lang: %s", getEntityLanguageString(info->lang));
3036 for (i = 0; i != info->numAttributes; ++i) {
3037 const CXIdxAttrInfo *Attr = info->attributes[i];
3038 printf(" <attribute>: ");
3039 PrintCursor(Attr->cursor, NULL);
3043 static void printBaseClassInfo(CXClientData client_data,
3044 const CXIdxBaseClassInfo *info) {
3045 printEntityInfo(" <base>", client_data, info->base);
3046 printf(" | cursor: ");
3047 PrintCursor(info->cursor, NULL);
3049 printCXIndexLoc(info->loc, client_data);
3052 static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
3053 CXClientData client_data) {
3055 for (i = 0; i < ProtoInfo->numProtocols; ++i) {
3056 printEntityInfo(" <protocol>", client_data,
3057 ProtoInfo->protocols[i]->protocol);
3058 printf(" | cursor: ");
3059 PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
3061 printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
3066 static void index_diagnostic(CXClientData client_data,
3067 CXDiagnosticSet diagSet, void *reserved) {
3070 unsigned numDiags, i;
3072 IndexData *index_data;
3073 index_data = (IndexData *)client_data;
3074 printCheck(index_data);
3076 numDiags = clang_getNumDiagnosticsInSet(diagSet);
3077 for (i = 0; i != numDiags; ++i) {
3078 diag = clang_getDiagnosticInSet(diagSet, i);
3079 str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
3080 cstr = clang_getCString(str);
3081 printf("[diagnostic]: %s\n", cstr);
3082 clang_disposeString(str);
3084 if (getenv("CINDEXTEST_FAILONERROR") &&
3085 clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
3086 index_data->fail_for_error = 1;
3091 static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
3092 CXFile file, void *reserved) {
3093 IndexData *index_data;
3096 index_data = (IndexData *)client_data;
3097 printCheck(index_data);
3099 filename = clang_getFileName(file);
3100 index_data->main_filename = clang_getCString(filename);
3101 clang_disposeString(filename);
3103 printf("[enteredMainFile]: ");
3104 printCXIndexFile((CXIdxClientFile)file);
3107 return (CXIdxClientFile)file;
3110 static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
3111 const CXIdxIncludedFileInfo *info) {
3112 IndexData *index_data;
3114 index_data = (IndexData *)client_data;
3115 printCheck(index_data);
3117 printf("[ppIncludedFile]: ");
3118 printCXIndexFile((CXIdxClientFile)info->file);
3119 printf(" | name: \"%s\"", info->filename);
3120 printf(" | hash loc: ");
3121 printCXIndexLoc(info->hashLoc, client_data);
3122 printf(" | isImport: %d | isAngled: %d | isModule: %d",
3123 info->isImport, info->isAngled, info->isModuleImport);
3125 Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
3127 CXString str = clang_Module_getFullName(Mod);
3128 const char *cstr = clang_getCString(str);
3129 printf(" | module: %s", cstr);
3130 clang_disposeString(str);
3135 return (CXIdxClientFile)info->file;
3138 static CXIdxClientFile index_importedASTFile(CXClientData client_data,
3139 const CXIdxImportedASTFileInfo *info) {
3140 IndexData *index_data;
3141 index_data = (IndexData *)client_data;
3142 printCheck(index_data);
3144 if (index_data->importedASTs) {
3145 CXString filename = clang_getFileName(info->file);
3146 importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
3147 clang_disposeString(filename);
3150 printf("[importedASTFile]: ");
3151 printCXIndexFile((CXIdxClientFile)info->file);
3153 CXString name = clang_Module_getFullName(info->module);
3155 printCXIndexLoc(info->loc, client_data);
3156 printf(" | name: \"%s\"", clang_getCString(name));
3157 printf(" | isImplicit: %d\n", info->isImplicit);
3158 clang_disposeString(name);
3160 /* PCH file, the rest are not relevant. */
3164 return (CXIdxClientFile)info->file;
3167 static CXIdxClientContainer
3168 index_startedTranslationUnit(CXClientData client_data, void *reserved) {
3169 IndexData *index_data;
3170 index_data = (IndexData *)client_data;
3171 printCheck(index_data);
3173 printf("[startedTranslationUnit]\n");
3174 return (CXIdxClientContainer)"TU";
3177 static void index_indexDeclaration(CXClientData client_data,
3178 const CXIdxDeclInfo *info) {
3179 IndexData *index_data;
3180 const CXIdxObjCCategoryDeclInfo *CatInfo;
3181 const CXIdxObjCInterfaceDeclInfo *InterInfo;
3182 const CXIdxObjCProtocolRefListInfo *ProtoInfo;
3183 const CXIdxObjCPropertyDeclInfo *PropInfo;
3184 const CXIdxCXXClassDeclInfo *CXXClassInfo;
3186 index_data = (IndexData *)client_data;
3188 printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
3189 printf(" | cursor: ");
3190 PrintCursor(info->cursor, NULL);
3192 printCXIndexLoc(info->loc, client_data);
3193 printf(" | semantic-container: ");
3194 printCXIndexContainer(info->semanticContainer);
3195 printf(" | lexical-container: ");
3196 printCXIndexContainer(info->lexicalContainer);
3197 printf(" | isRedecl: %d", info->isRedeclaration);
3198 printf(" | isDef: %d", info->isDefinition);
3199 if (info->flags & CXIdxDeclFlag_Skipped) {
3200 assert(!info->isContainer);
3201 printf(" | isContainer: skipped");
3203 printf(" | isContainer: %d", info->isContainer);
3205 printf(" | isImplicit: %d\n", info->isImplicit);
3207 for (i = 0; i != info->numAttributes; ++i) {
3208 const CXIdxAttrInfo *Attr = info->attributes[i];
3209 printf(" <attribute>: ");
3210 PrintCursor(Attr->cursor, NULL);
3214 if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
3215 const char *kindName = 0;
3216 CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
3218 case CXIdxObjCContainer_ForwardRef:
3219 kindName = "forward-ref"; break;
3220 case CXIdxObjCContainer_Interface:
3221 kindName = "interface"; break;
3222 case CXIdxObjCContainer_Implementation:
3223 kindName = "implementation"; break;
3225 printCheck(index_data);
3226 printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
3229 if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
3230 printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
3231 CatInfo->objcClass);
3232 printf(" | cursor: ");
3233 PrintCursor(CatInfo->classCursor, NULL);
3235 printCXIndexLoc(CatInfo->classLoc, client_data);
3239 if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
3240 if (InterInfo->superInfo) {
3241 printBaseClassInfo(client_data, InterInfo->superInfo);
3246 if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
3247 printProtocolList(ProtoInfo, client_data);
3250 if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
3251 if (PropInfo->getter) {
3252 printEntityInfo(" <getter>", client_data, PropInfo->getter);
3255 if (PropInfo->setter) {
3256 printEntityInfo(" <setter>", client_data, PropInfo->setter);
3261 if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
3262 for (i = 0; i != CXXClassInfo->numBases; ++i) {
3263 printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
3268 if (info->declAsContainer)
3269 clang_index_setClientContainer(
3270 info->declAsContainer,
3271 makeClientContainer(client_data, info->entityInfo, info->loc));
3274 static void index_indexEntityReference(CXClientData client_data,
3275 const CXIdxEntityRefInfo *info) {
3276 printEntityInfo("[indexEntityReference]", client_data,
3277 info->referencedEntity);
3278 printf(" | cursor: ");
3279 PrintCursor(info->cursor, NULL);
3281 printCXIndexLoc(info->loc, client_data);
3282 printEntityInfo(" | <parent>:", client_data, info->parentEntity);
3283 printf(" | container: ");
3284 printCXIndexContainer(info->container);
3285 printf(" | refkind: ");
3286 switch (info->kind) {
3287 case CXIdxEntityRef_Direct: printf("direct"); break;
3288 case CXIdxEntityRef_Implicit: printf("implicit"); break;
3293 static int index_abortQuery(CXClientData client_data, void *reserved) {
3294 IndexData *index_data;
3295 index_data = (IndexData *)client_data;
3296 return index_data->abort;
3299 static IndexerCallbacks IndexCB = {
3302 index_enteredMainFile,
3303 index_ppIncludedFile,
3304 index_importedASTFile,
3305 index_startedTranslationUnit,
3306 index_indexDeclaration,
3307 index_indexEntityReference
3310 static unsigned getIndexOptions(void) {
3311 unsigned index_opts;
3313 if (getenv("CINDEXTEST_SUPPRESSREFS"))
3314 index_opts |= CXIndexOpt_SuppressRedundantRefs;
3315 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
3316 index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
3317 if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
3318 index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
3323 static int index_compile_args(int num_args, const char **args,
3324 CXIndexAction idxAction,
3325 ImportedASTFilesData *importedASTs,
3326 const char *check_prefix) {
3327 IndexData index_data;
3328 unsigned index_opts;
3331 if (num_args == 0) {
3332 fprintf(stderr, "no compiler arguments\n");
3336 index_data.check_prefix = check_prefix;
3337 index_data.first_check_printed = 0;
3338 index_data.fail_for_error = 0;
3339 index_data.abort = 0;
3340 index_data.main_filename = "";
3341 index_data.importedASTs = importedASTs;
3342 index_data.strings = NULL;
3343 index_data.TU = NULL;
3345 index_opts = getIndexOptions();
3346 result = clang_indexSourceFile(idxAction, &index_data,
3347 &IndexCB,sizeof(IndexCB), index_opts,
3348 0, args, num_args, 0, 0, 0,
3349 getDefaultParsingOptions());
3350 if (result != CXError_Success)
3351 describeLibclangFailure(result);
3353 if (index_data.fail_for_error)
3356 free_client_data(&index_data);
3360 static int index_ast_file(const char *ast_file,
3362 CXIndexAction idxAction,
3363 ImportedASTFilesData *importedASTs,
3364 const char *check_prefix) {
3365 CXTranslationUnit TU;
3366 IndexData index_data;
3367 unsigned index_opts;
3370 if (!CreateTranslationUnit(Idx, ast_file, &TU))
3373 index_data.check_prefix = check_prefix;
3374 index_data.first_check_printed = 0;
3375 index_data.fail_for_error = 0;
3376 index_data.abort = 0;
3377 index_data.main_filename = "";
3378 index_data.importedASTs = importedASTs;
3379 index_data.strings = NULL;
3382 index_opts = getIndexOptions();
3383 result = clang_indexTranslationUnit(idxAction, &index_data,
3384 &IndexCB,sizeof(IndexCB),
3386 if (index_data.fail_for_error)
3389 clang_disposeTranslationUnit(TU);
3390 free_client_data(&index_data);
3394 static int index_file(int argc, const char **argv, int full) {
3395 const char *check_prefix;
3397 CXIndexAction idxAction;
3398 ImportedASTFilesData *importedASTs;
3403 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3404 check_prefix = argv[0] + strlen("-check-prefix=");
3410 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3411 /* displayDiagnostics=*/1))) {
3412 fprintf(stderr, "Could not create Index\n");
3415 idxAction = clang_IndexAction_create(Idx);
3418 importedASTs = importedASTs_create();
3420 result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
3426 for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
3427 result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
3428 importedASTs, check_prefix);
3433 importedASTs_dispose(importedASTs);
3434 clang_IndexAction_dispose(idxAction);
3435 clang_disposeIndex(Idx);
3439 static int index_tu(int argc, const char **argv) {
3440 const char *check_prefix;
3442 CXIndexAction idxAction;
3447 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3448 check_prefix = argv[0] + strlen("-check-prefix=");
3454 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3455 /* displayDiagnostics=*/1))) {
3456 fprintf(stderr, "Could not create Index\n");
3459 idxAction = clang_IndexAction_create(Idx);
3461 result = index_ast_file(argv[0], Idx, idxAction,
3462 /*importedASTs=*/0, check_prefix);
3464 clang_IndexAction_dispose(idxAction);
3465 clang_disposeIndex(Idx);
3469 static int index_compile_db(int argc, const char **argv) {
3470 const char *check_prefix;
3472 CXIndexAction idxAction;
3477 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3478 check_prefix = argv[0] + strlen("-check-prefix=");
3485 fprintf(stderr, "no compilation database\n");
3489 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
3490 /* displayDiagnostics=*/1))) {
3491 fprintf(stderr, "Could not create Index\n");
3494 idxAction = clang_IndexAction_create(Idx);
3497 const char *database = argv[0];
3498 CXCompilationDatabase db = 0;
3499 CXCompileCommands CCmds = 0;
3500 CXCompileCommand CCmd;
3501 CXCompilationDatabase_Error ec;
3503 #define MAX_COMPILE_ARGS 512
3504 CXString cxargs[MAX_COMPILE_ARGS];
3505 const char *args[MAX_COMPILE_ARGS];
3509 int i, a, numCmds, numArgs;
3511 len = strlen(database);
3512 tmp = (char *) malloc(len+1);
3513 memcpy(tmp, database, len+1);
3514 buildDir = dirname(tmp);
3516 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
3520 if (ec!=CXCompilationDatabase_NoError) {
3521 printf("unexpected error %d code while loading compilation database\n", ec);
3526 if (chdir(buildDir) != 0) {
3527 printf("Could not chdir to %s\n", buildDir);
3532 CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
3534 printf("compilation db is empty\n");
3539 numCmds = clang_CompileCommands_getSize(CCmds);
3542 fprintf(stderr, "should not get an empty compileCommand set\n");
3547 for (i=0; i<numCmds && errorCode == 0; ++i) {
3548 CCmd = clang_CompileCommands_getCommand(CCmds, i);
3550 wd = clang_CompileCommand_getDirectory(CCmd);
3551 if (chdir(clang_getCString(wd)) != 0) {
3552 printf("Could not chdir to %s\n", clang_getCString(wd));
3556 clang_disposeString(wd);
3558 numArgs = clang_CompileCommand_getNumArgs(CCmd);
3559 if (numArgs > MAX_COMPILE_ARGS){
3560 fprintf(stderr, "got more compile arguments than maximum\n");
3564 for (a=0; a<numArgs; ++a) {
3565 cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
3566 args[a] = clang_getCString(cxargs[a]);
3569 errorCode = index_compile_args(numArgs, args, idxAction,
3570 /*importedASTs=*/0, check_prefix);
3572 for (a=0; a<numArgs; ++a)
3573 clang_disposeString(cxargs[a]);
3576 printf("database loading failed with error code %d.\n", ec);
3581 clang_CompileCommands_dispose(CCmds);
3582 clang_CompilationDatabase_dispose(db);
3587 clang_IndexAction_dispose(idxAction);
3588 clang_disposeIndex(Idx);
3592 int perform_token_annotation(int argc, const char **argv) {
3593 const char *input = argv[1];
3595 unsigned line, second_line;
3596 unsigned column, second_column;
3598 CXTranslationUnit TU = 0;
3600 struct CXUnsavedFile *unsaved_files = 0;
3601 int num_unsaved_files = 0;
3603 unsigned num_tokens;
3604 CXSourceRange range;
3605 CXSourceLocation startLoc, endLoc;
3607 CXCursor *cursors = 0;
3608 CXSourceRangeList *skipped_ranges = 0;
3609 enum CXErrorCode Err;
3612 input += strlen("-test-annotate-tokens=");
3613 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
3614 &second_line, &second_column)))
3617 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
3622 CIdx = clang_createIndex(0, 1);
3623 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
3624 argv + num_unsaved_files + 2,
3625 argc - num_unsaved_files - 3,
3628 getDefaultParsingOptions(), &TU);
3629 if (Err != CXError_Success) {
3630 fprintf(stderr, "unable to parse input\n");
3631 describeLibclangFailure(Err);
3632 clang_disposeIndex(CIdx);
3634 free_remapped_files(unsaved_files, num_unsaved_files);
3639 if (checkForErrors(TU) != 0) {
3644 if (getenv("CINDEXTEST_EDITING")) {
3645 for (i = 0; i < 5; ++i) {
3646 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
3647 clang_defaultReparseOptions(TU));
3648 if (Err != CXError_Success) {
3649 fprintf(stderr, "Unable to reparse translation unit!\n");
3650 describeLibclangFailure(Err);
3657 if (checkForErrors(TU) != 0) {
3662 file = clang_getFile(TU, filename);
3664 fprintf(stderr, "file %s is not in this translation unit\n", filename);
3669 startLoc = clang_getLocation(TU, file, line, column);
3670 if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
3671 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
3677 endLoc = clang_getLocation(TU, file, second_line, second_column);
3678 if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
3679 fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
3680 second_line, second_column);
3685 range = clang_getRange(startLoc, endLoc);
3686 clang_tokenize(TU, range, &tokens, &num_tokens);
3688 if (checkForErrors(TU) != 0) {
3693 cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
3694 clang_annotateTokens(TU, tokens, num_tokens, cursors);
3696 if (checkForErrors(TU) != 0) {
3701 skipped_ranges = clang_getSkippedRanges(TU, file);
3702 for (i = 0; i != skipped_ranges->count; ++i) {
3703 unsigned start_line, start_column, end_line, end_column;
3704 clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
3705 0, &start_line, &start_column, 0);
3706 clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
3707 0, &end_line, &end_column, 0);
3708 printf("Skipping: ");
3709 PrintExtent(stdout, start_line, start_column, end_line, end_column);
3712 clang_disposeSourceRangeList(skipped_ranges);
3714 for (i = 0; i != num_tokens; ++i) {
3715 const char *kind = "<unknown>";
3716 CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
3717 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
3718 unsigned start_line, start_column, end_line, end_column;
3720 switch (clang_getTokenKind(tokens[i])) {
3721 case CXToken_Punctuation: kind = "Punctuation"; break;
3722 case CXToken_Keyword: kind = "Keyword"; break;
3723 case CXToken_Identifier: kind = "Identifier"; break;
3724 case CXToken_Literal: kind = "Literal"; break;
3725 case CXToken_Comment: kind = "Comment"; break;
3727 clang_getSpellingLocation(clang_getRangeStart(extent),
3728 0, &start_line, &start_column, 0);
3729 clang_getSpellingLocation(clang_getRangeEnd(extent),
3730 0, &end_line, &end_column, 0);
3731 printf("%s: \"%s\" ", kind, clang_getCString(spelling));
3732 clang_disposeString(spelling);
3733 PrintExtent(stdout, start_line, start_column, end_line, end_column);
3734 if (!clang_isInvalid(cursors[i].kind)) {
3736 PrintCursor(cursors[i], NULL);
3741 clang_disposeTokens(TU, tokens, num_tokens);
3744 PrintDiagnostics(TU);
3745 clang_disposeTranslationUnit(TU);
3746 clang_disposeIndex(CIdx);
3748 free_remapped_files(unsaved_files, num_unsaved_files);
3753 perform_test_compilation_db(const char *database, int argc, const char **argv) {
3754 CXCompilationDatabase db;
3755 CXCompileCommands CCmds;
3756 CXCompileCommand CCmd;
3757 CXCompilationDatabase_Error ec;
3764 int i, j, a, numCmds, numArgs;
3766 len = strlen(database);
3767 tmp = (char *) malloc(len+1);
3768 memcpy(tmp, database, len+1);
3769 buildDir = dirname(tmp);
3771 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
3775 if (ec!=CXCompilationDatabase_NoError) {
3776 printf("unexpected error %d code while loading compilation database\n", ec);
3781 for (i=0; i<argc && errorCode==0; ) {
3782 if (strcmp(argv[i],"lookup")==0){
3783 CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
3786 printf("file %s not found in compilation db\n", argv[i+1]);
3791 numCmds = clang_CompileCommands_getSize(CCmds);
3794 fprintf(stderr, "should not get an empty compileCommand set for file"
3795 " '%s'\n", argv[i+1]);
3800 for (j=0; j<numCmds; ++j) {
3801 CCmd = clang_CompileCommands_getCommand(CCmds, j);
3803 wd = clang_CompileCommand_getDirectory(CCmd);
3804 printf("workdir:'%s'", clang_getCString(wd));
3805 clang_disposeString(wd);
3807 printf(" cmdline:'");
3808 numArgs = clang_CompileCommand_getNumArgs(CCmd);
3809 for (a=0; a<numArgs; ++a) {
3811 arg = clang_CompileCommand_getArg(CCmd, a);
3812 printf("%s", clang_getCString(arg));
3813 clang_disposeString(arg);
3818 clang_CompileCommands_dispose(CCmds);
3823 clang_CompilationDatabase_dispose(db);
3825 printf("database loading failed with error code %d.\n", ec);
3835 /******************************************************************************/
3837 /******************************************************************************/
3839 static int insufficient_usr(const char *kind, const char *usage) {
3840 fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
3844 static unsigned isUSR(const char *s) {
3845 return s[0] == 'c' && s[1] == ':';
3848 static int not_usr(const char *s, const char *arg) {
3849 fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
3853 static void print_usr(CXString usr) {
3854 const char *s = clang_getCString(usr);
3856 clang_disposeString(usr);
3859 static void display_usrs() {
3860 fprintf(stderr, "-print-usrs options:\n"
3861 " ObjCCategory <class name> <category name>\n"
3862 " ObjCClass <class name>\n"
3863 " ObjCIvar <ivar name> <class USR>\n"
3864 " ObjCMethod <selector> [0=class method|1=instance method] "
3866 " ObjCProperty <property name> <class USR>\n"
3867 " ObjCProtocol <protocol name>\n");
3870 int print_usrs(const char **I, const char **E) {
3872 const char *kind = *I;
3873 unsigned len = strlen(kind);
3876 if (memcmp(kind, "ObjCIvar", 8) == 0) {
3878 return insufficient_usr(kind, "<ivar name> <class USR>");
3880 return not_usr("<class USR>", I[2]);
3883 x.data = (void*) I[2];
3884 x.private_flags = 0;
3885 print_usr(clang_constructUSR_ObjCIvar(I[1], x));
3893 if (memcmp(kind, "ObjCClass", 9) == 0) {
3895 return insufficient_usr(kind, "<class name>");
3896 print_usr(clang_constructUSR_ObjCClass(I[1]));
3902 if (memcmp(kind, "ObjCMethod", 10) == 0) {
3904 return insufficient_usr(kind, "<method selector> "
3905 "[0=class method|1=instance method] <class USR>");
3907 return not_usr("<class USR>", I[3]);
3910 x.data = (void*) I[3];
3911 x.private_flags = 0;
3912 print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
3919 if (memcmp(kind, "ObjCCategory", 12) == 0) {
3921 return insufficient_usr(kind, "<class name> <category name>");
3922 print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
3926 if (memcmp(kind, "ObjCProtocol", 12) == 0) {
3928 return insufficient_usr(kind, "<protocol name>");
3929 print_usr(clang_constructUSR_ObjCProtocol(I[1]));
3933 if (memcmp(kind, "ObjCProperty", 12) == 0) {
3935 return insufficient_usr(kind, "<property name> <class USR>");
3937 return not_usr("<class USR>", I[2]);
3940 x.data = (void*) I[2];
3941 x.private_flags = 0;
3942 print_usr(clang_constructUSR_ObjCProperty(I[1], x));
3955 fprintf(stderr, "Invalid USR kind: %s\n", *I);
3962 int print_usrs_file(const char *file_name) {
3964 const char *args[128];
3965 unsigned numChars = 0;
3967 FILE *fp = fopen(file_name, "r");
3969 fprintf(stderr, "error: cannot open '%s'\n", file_name);
3973 /* This code is not really all that safe, but it works fine for testing. */
3983 line[numChars] = '\0';
3986 if (line[0] == '/' && line[1] == '/')
3989 s = strtok(line, " ");
3995 if (print_usrs(&args[0], &args[i]))
3999 line[numChars++] = c;
4006 /******************************************************************************/
4007 /* Command line processing. */
4008 /******************************************************************************/
4009 int write_pch_file(const char *filename, int argc, const char *argv[]) {
4011 CXTranslationUnit TU;
4012 struct CXUnsavedFile *unsaved_files = 0;
4013 int num_unsaved_files = 0;
4014 enum CXErrorCode Err;
4017 Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
4019 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
4020 clang_disposeIndex(Idx);
4024 Err = clang_parseTranslationUnit2(
4025 Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files,
4026 unsaved_files, num_unsaved_files,
4027 CXTranslationUnit_Incomplete |
4028 CXTranslationUnit_DetailedPreprocessingRecord |
4029 CXTranslationUnit_ForSerialization,
4031 if (Err != CXError_Success) {
4032 fprintf(stderr, "Unable to load translation unit!\n");
4033 describeLibclangFailure(Err);
4034 free_remapped_files(unsaved_files, num_unsaved_files);
4035 clang_disposeTranslationUnit(TU);
4036 clang_disposeIndex(Idx);
4040 switch (clang_saveTranslationUnit(TU, filename,
4041 clang_defaultSaveOptions(TU))) {
4042 case CXSaveError_None:
4045 case CXSaveError_TranslationErrors:
4046 fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
4051 case CXSaveError_InvalidTU:
4052 fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
4057 case CXSaveError_Unknown:
4059 fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
4064 clang_disposeTranslationUnit(TU);
4065 free_remapped_files(unsaved_files, num_unsaved_files);
4066 clang_disposeIndex(Idx);
4070 /******************************************************************************/
4071 /* Serialized diagnostics. */
4072 /******************************************************************************/
4074 static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
4076 case CXLoadDiag_CannotLoad: return "Cannot Load File";
4077 case CXLoadDiag_None: break;
4078 case CXLoadDiag_Unknown: return "Unknown";
4079 case CXLoadDiag_InvalidFile: return "Invalid File";
4084 static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
4086 case CXDiagnostic_Note: return "note";
4087 case CXDiagnostic_Error: return "error";
4088 case CXDiagnostic_Fatal: return "fatal";
4089 case CXDiagnostic_Ignored: return "ignored";
4090 case CXDiagnostic_Warning: return "warning";
4095 static void printIndent(unsigned indent) {
4098 fprintf(stderr, "+");
4100 while (indent > 0) {
4101 fprintf(stderr, "-");
4106 static void printLocation(CXSourceLocation L) {
4109 unsigned line, column, offset;
4111 clang_getExpansionLocation(L, &File, &line, &column, &offset);
4112 FileName = clang_getFileName(File);
4114 fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
4115 clang_disposeString(FileName);
4118 static void printRanges(CXDiagnostic D, unsigned indent) {
4119 unsigned i, n = clang_getDiagnosticNumRanges(D);
4121 for (i = 0; i < n; ++i) {
4122 CXSourceLocation Start, End;
4123 CXSourceRange SR = clang_getDiagnosticRange(D, i);
4124 Start = clang_getRangeStart(SR);
4125 End = clang_getRangeEnd(SR);
4127 printIndent(indent);
4128 fprintf(stderr, "Range: ");
4129 printLocation(Start);
4130 fprintf(stderr, " ");
4132 fprintf(stderr, "\n");
4136 static void printFixIts(CXDiagnostic D, unsigned indent) {
4137 unsigned i, n = clang_getDiagnosticNumFixIts(D);
4138 fprintf(stderr, "Number FIXITs = %d\n", n);
4139 for (i = 0 ; i < n; ++i) {
4140 CXSourceRange ReplacementRange;
4142 text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
4144 printIndent(indent);
4145 fprintf(stderr, "FIXIT: (");
4146 printLocation(clang_getRangeStart(ReplacementRange));
4147 fprintf(stderr, " - ");
4148 printLocation(clang_getRangeEnd(ReplacementRange));
4149 fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
4150 clang_disposeString(text);
4154 static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
4160 n = clang_getNumDiagnosticsInSet(Diags);
4161 for (i = 0; i < n; ++i) {
4162 CXSourceLocation DiagLoc;
4165 CXString FileName, DiagSpelling, DiagOption, DiagCat;
4166 unsigned line, column, offset;
4167 const char *DiagOptionStr = 0, *DiagCatStr = 0;
4169 D = clang_getDiagnosticInSet(Diags, i);
4170 DiagLoc = clang_getDiagnosticLocation(D);
4171 clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
4172 FileName = clang_getFileName(File);
4173 DiagSpelling = clang_getDiagnosticSpelling(D);
4175 printIndent(indent);
4177 fprintf(stderr, "%s:%d:%d: %s: %s",
4178 clang_getCString(FileName),
4181 getSeverityString(clang_getDiagnosticSeverity(D)),
4182 clang_getCString(DiagSpelling));
4184 DiagOption = clang_getDiagnosticOption(D, 0);
4185 DiagOptionStr = clang_getCString(DiagOption);
4186 if (DiagOptionStr) {
4187 fprintf(stderr, " [%s]", DiagOptionStr);
4190 DiagCat = clang_getDiagnosticCategoryText(D);
4191 DiagCatStr = clang_getCString(DiagCat);
4193 fprintf(stderr, " [%s]", DiagCatStr);
4196 fprintf(stderr, "\n");
4198 printRanges(D, indent);
4199 printFixIts(D, indent);
4201 /* Print subdiagnostics. */
4202 printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
4204 clang_disposeString(FileName);
4205 clang_disposeString(DiagSpelling);
4206 clang_disposeString(DiagOption);
4207 clang_disposeString(DiagCat);
4211 static int read_diagnostics(const char *filename) {
4212 enum CXLoadDiag_Error error;
4213 CXString errorString;
4214 CXDiagnosticSet Diags = 0;
4216 Diags = clang_loadDiagnostics(filename, &error, &errorString);
4218 fprintf(stderr, "Trouble deserializing file (%s): %s\n",
4219 getDiagnosticCodeStr(error),
4220 clang_getCString(errorString));
4221 clang_disposeString(errorString);
4225 printDiagnosticSet(Diags, 0);
4226 fprintf(stderr, "Number of diagnostics: %d\n",
4227 clang_getNumDiagnosticsInSet(Diags));
4228 clang_disposeDiagnosticSet(Diags);
4232 static int perform_print_build_session_timestamp(void) {
4233 printf("%lld\n", clang_getBuildSessionTimestamp());
4237 /******************************************************************************/
4238 /* Command line processing. */
4239 /******************************************************************************/
4241 static CXCursorVisitor GetVisitor(const char *s) {
4243 return FilteredPrintingVisitor;
4244 if (strcmp(s, "-usrs") == 0)
4246 if (strncmp(s, "-memory-usage", 13) == 0)
4247 return GetVisitor(s + 13);
4251 static void print_usage(void) {
4253 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
4254 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
4255 " c-index-test -cursor-at=<site> <compiler arguments>\n"
4256 " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
4257 " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
4258 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
4259 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
4261 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4262 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4263 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
4264 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
4265 " c-index-test -test-file-scan <AST file> <source file> "
4266 "[FileCheck prefix]\n");
4268 " c-index-test -test-load-tu <AST file> <symbol filter> "
4269 "[FileCheck prefix]\n"
4270 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
4271 "[FileCheck prefix]\n"
4272 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
4274 " c-index-test -test-load-source-memory-usage "
4275 "<symbol filter> {<args>}*\n"
4276 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
4278 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
4279 " c-index-test -test-load-source-usrs-memory-usage "
4280 "<symbol filter> {<args>}*\n"
4281 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
4282 " c-index-test -test-inclusion-stack-source {<args>}*\n"
4283 " c-index-test -test-inclusion-stack-tu <AST file>\n");
4285 " c-index-test -test-print-linkage-source {<args>}*\n"
4286 " c-index-test -test-print-visibility {<args>}*\n"
4287 " c-index-test -test-print-type {<args>}*\n"
4288 " c-index-test -test-print-type-size {<args>}*\n"
4289 " c-index-test -test-print-bitwidth {<args>}*\n"
4290 " c-index-test -test-print-type-declaration {<args>}*\n"
4291 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
4292 " c-index-test -print-usr-file <file>\n"
4293 " c-index-test -write-pch <file> <compiler arguments>\n");
4295 " c-index-test -compilation-db [lookup <filename>] database\n");
4297 " c-index-test -print-build-session-timestamp\n");
4299 " c-index-test -read-diagnostics <file>\n\n");
4301 " <symbol filter> values:\n%s",
4302 " all - load all symbols, including those from PCH\n"
4303 " local - load all symbols except those in PCH\n"
4304 " category - only load ObjC categories (non-PCH)\n"
4305 " interface - only load ObjC interfaces (non-PCH)\n"
4306 " protocol - only load ObjC protocols (non-PCH)\n"
4307 " function - only load functions (non-PCH)\n"
4308 " typedef - only load typdefs (non-PCH)\n"
4309 " scan-function - scan function bodies (non-PCH)\n\n");
4314 int cindextest_main(int argc, const char **argv) {
4315 clang_enableStackTraces();
4316 if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
4317 return read_diagnostics(argv[2]);
4318 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
4319 return perform_code_completion(argc, argv, 0);
4320 if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
4321 return perform_code_completion(argc, argv, 1);
4322 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
4323 return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
4324 if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
4325 return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
4326 inspect_evaluate_cursor);
4327 if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
4328 return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
4329 inspect_macroinfo_cursor);
4330 if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
4331 return find_file_refs_at(argc, argv);
4332 if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
4333 return find_file_includes_in(argc, argv);
4334 if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
4335 return index_file(argc - 2, argv + 2, /*full=*/0);
4336 if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
4337 return index_file(argc - 2, argv + 2, /*full=*/1);
4338 if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
4339 return index_tu(argc - 2, argv + 2);
4340 if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
4341 return index_compile_db(argc - 2, argv + 2);
4342 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
4343 CXCursorVisitor I = GetVisitor(argv[1] + 13);
4345 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
4348 else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
4349 CXCursorVisitor I = GetVisitor(argv[1] + 25);
4351 int trials = atoi(argv[2]);
4352 return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
4356 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
4357 CXCursorVisitor I = GetVisitor(argv[1] + 17);
4359 PostVisitTU postVisit = 0;
4360 if (strstr(argv[1], "-memory-usage"))
4361 postVisit = PrintMemoryUsage;
4364 return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
4367 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
4368 return perform_file_scan(argv[2], argv[3],
4369 argc >= 5 ? argv[4] : 0);
4370 else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
4371 return perform_token_annotation(argc, argv);
4372 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
4373 return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
4374 PrintInclusionStack);
4375 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
4376 return perform_test_load_tu(argv[2], "all", NULL, NULL,
4377 PrintInclusionStack);
4378 else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
4379 return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
4381 else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0)
4382 return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility,
4384 else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
4385 return perform_test_load_source(argc - 2, argv + 2, "all",
4387 else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
4388 return perform_test_load_source(argc - 2, argv + 2, "all",
4390 else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
4391 return perform_test_load_source(argc - 2, argv + 2, "all",
4392 PrintTypeDeclaration, 0);
4393 else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
4394 return perform_test_load_source(argc - 2, argv + 2, "all",
4396 else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
4397 return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
4398 else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
4399 return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
4400 else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
4402 return print_usrs(argv + 2, argv + argc);
4408 else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
4409 return print_usrs_file(argv[2]);
4410 else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
4411 return write_pch_file(argv[2], argc - 3, argv + 3);
4412 else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
4413 return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
4414 else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
4415 return perform_print_build_session_timestamp();
4423 /* We intentionally run in a separate thread to ensure we at least minimal
4424 * testing of a multithreaded environment (for example, having a reduced stack
4427 typedef struct thread_info {
4428 int (*main_func)(int argc, const char **argv);
4433 void thread_runner(void *client_data_v) {
4434 thread_info *client_data = client_data_v;
4435 client_data->result = client_data->main_func(client_data->argc,
4439 static void flush_atexit(void) {
4440 /* stdout, and surprisingly even stderr, are not always flushed on process
4441 * and thread exit, particularly when the system is under heavy load. */
4446 int main(int argc, const char **argv) {
4447 thread_info client_data;
4449 atexit(flush_atexit);
4451 #ifdef CLANG_HAVE_LIBXML
4455 client_data.main_func = cindextest_main;
4456 client_data.argc = argc;
4457 client_data.argv = argv;
4459 if (argc > 1 && strcmp(argv[1], "core") == 0)
4460 client_data.main_func = indextest_core_main;
4462 if (getenv("CINDEXTEST_NOTHREADS"))
4463 return client_data.main_func(client_data.argc, client_data.argv);
4465 clang_executeOnThread(thread_runner, &client_data, 0);
4466 return client_data.result;