3 #include "clang-c/BuildSystem.h"
4 #include "clang-c/CXCompilationDatabase.h"
5 #include "clang-c/CXErrorCode.h"
6 #include "clang-c/CXSourceLocation.h"
7 #include "clang-c/CXString.h"
8 #include "clang-c/Documentation.h"
9 #include "clang-c/Index.h"
10 #include "clang/Config/config.h"
17 #ifdef CLANG_HAVE_LIBXML
18 #include <libxml/parser.h>
19 #include <libxml/relaxng.h>
20 #include <libxml/xmlerror.h>
29 extern int indextest_core_main(int argc
, const char **argv
);
30 extern int indextest_perform_shell_execution(const char *command_line
);
32 /******************************************************************************/
33 /* Utility functions. */
34 /******************************************************************************/
37 char *basename(const char* path
)
39 char* base1
= (char*)strrchr(path
, '/');
40 char* base2
= (char*)strrchr(path
, '\\');
42 return((base1
> base2
) ? base1
+ 1 : base2
+ 1);
50 char *dirname(char* path
)
52 char* base1
= (char*)strrchr(path
, '/');
53 char* base2
= (char*)strrchr(path
, '\\');
67 extern char *basename(const char *);
68 extern char *dirname(char *);
71 CXIndex
createIndexWithInvocationEmissionPath(int ExcludeDeclarationsFromPCH
,
72 int DisplayDiagnostics
) {
76 memset(&Opts
, 0, sizeof(Opts
));
77 Opts
.Size
= sizeof(CXIndexOptions
);
78 Opts
.ExcludeDeclarationsFromPCH
= ExcludeDeclarationsFromPCH
;
79 Opts
.DisplayDiagnostics
= DisplayDiagnostics
;
80 Opts
.InvocationEmissionPath
= getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
82 Idx
= clang_createIndexWithOptions(&Opts
);
85 "clang_createIndexWithOptions() failed. "
86 "CINDEX_VERSION_MINOR = %d, sizeof(CXIndexOptions) = %u\n",
87 CINDEX_VERSION_MINOR
, Opts
.Size
);
92 /** Return the default parsing options. */
93 static unsigned getDefaultParsingOptions(void) {
94 unsigned options
= CXTranslationUnit_DetailedPreprocessingRecord
;
96 if (getenv("CINDEXTEST_EDITING"))
97 options
|= clang_defaultEditingTranslationUnitOptions();
98 if (getenv("CINDEXTEST_COMPLETION_CACHING"))
99 options
|= CXTranslationUnit_CacheCompletionResults
;
100 if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
101 options
&= ~CXTranslationUnit_CacheCompletionResults
;
102 if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
103 options
|= CXTranslationUnit_SkipFunctionBodies
;
104 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
105 options
|= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
;
106 if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
107 options
|= CXTranslationUnit_CreatePreambleOnFirstParse
;
108 if (getenv("CINDEXTEST_KEEP_GOING"))
109 options
|= CXTranslationUnit_KeepGoing
;
110 if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
111 options
|= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble
;
112 if (getenv("CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES"))
113 options
|= CXTranslationUnit_IncludeAttributedTypes
;
114 if (getenv("CINDEXTEST_VISIT_IMPLICIT_ATTRIBUTES"))
115 options
|= CXTranslationUnit_VisitImplicitAttributes
;
116 if (getenv("CINDEXTEST_IGNORE_NONERRORS_FROM_INCLUDED_FILES"))
117 options
|= CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles
;
122 static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy
) {
125 enum CXPrintingPolicyProperty property
;
127 struct Mapping mappings
[] = {
128 {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation
},
129 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS",
130 CXPrintingPolicy_SuppressSpecifiers
},
131 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
132 CXPrintingPolicy_SuppressTagKeyword
},
133 {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
134 CXPrintingPolicy_IncludeTagDefinition
},
135 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
136 CXPrintingPolicy_SuppressScope
},
137 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
138 CXPrintingPolicy_SuppressUnwrittenScope
},
139 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS",
140 CXPrintingPolicy_SuppressInitializers
},
141 {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN",
142 CXPrintingPolicy_ConstantArraySizeAsWritten
},
143 {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS",
144 CXPrintingPolicy_AnonymousTagLocations
},
145 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME",
146 CXPrintingPolicy_SuppressStrongLifetime
},
147 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS",
148 CXPrintingPolicy_SuppressLifetimeQualifiers
},
149 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS",
150 CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors
},
151 {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool
},
152 {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict
},
153 {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof
},
154 {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF",
155 CXPrintingPolicy_UnderscoreAlignof
},
156 {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS",
157 CXPrintingPolicy_UseVoidForZeroParams
},
158 {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput
},
159 {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION",
160 CXPrintingPolicy_PolishForDeclaration
},
161 {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half
},
162 {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar
},
163 {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES",
164 CXPrintingPolicy_IncludeNewlines
},
165 {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING",
166 CXPrintingPolicy_MSVCFormatting
},
167 {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN",
168 CXPrintingPolicy_ConstantsAsWritten
},
169 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE",
170 CXPrintingPolicy_SuppressImplicitBase
},
171 {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME",
172 CXPrintingPolicy_FullyQualifiedName
},
176 for (i
= 0; i
< sizeof(mappings
) / sizeof(struct Mapping
); i
++) {
177 char *value
= getenv(mappings
[i
].name
);
179 clang_PrintingPolicy_setProperty(Policy
, mappings
[i
].property
,
180 (unsigned)strtoul(value
, 0L, 10));
185 /** Returns 0 in case of success, non-zero in case of a failure. */
186 static int checkForErrors(CXTranslationUnit TU
);
188 static void describeLibclangFailure(enum CXErrorCode Err
) {
190 case CXError_Success
:
191 fprintf(stderr
, "Success\n");
194 case CXError_Failure
:
195 fprintf(stderr
, "Failure (no details available)\n");
198 case CXError_Crashed
:
199 fprintf(stderr
, "Failure: libclang crashed\n");
202 case CXError_InvalidArguments
:
203 fprintf(stderr
, "Failure: invalid arguments passed to a libclang routine\n");
206 case CXError_ASTReadError
:
207 fprintf(stderr
, "Failure: AST deserialization error occurred\n");
212 static void PrintExtent(FILE *out
, unsigned begin_line
, unsigned begin_column
,
213 unsigned end_line
, unsigned end_column
) {
214 fprintf(out
, "[%d:%d - %d:%d]", begin_line
, begin_column
,
215 end_line
, end_column
);
218 static unsigned CreateTranslationUnit(CXIndex Idx
, const char *file
,
219 CXTranslationUnit
*TU
) {
220 enum CXErrorCode Err
= clang_createTranslationUnit2(Idx
, file
, TU
);
221 if (Err
!= CXError_Success
) {
222 fprintf(stderr
, "Unable to load translation unit from '%s'!\n", file
);
223 describeLibclangFailure(Err
);
230 void free_remapped_files(struct CXUnsavedFile
*unsaved_files
,
231 int num_unsaved_files
) {
233 for (i
= 0; i
!= num_unsaved_files
; ++i
) {
235 #pragma GCC diagnostic push
236 #pragma GCC diagnostic ignored "-Wcast-qual"
238 free((char *)unsaved_files
[i
].Filename
);
239 free((char *)unsaved_files
[i
].Contents
);
241 #pragma GCC diagnostic pop
247 static int parse_remapped_files_with_opt(const char *opt_name
,
248 int argc
, const char **argv
,
250 struct CXUnsavedFile
**unsaved_files
,
251 int *num_unsaved_files
) {
254 int prefix_len
= strlen(opt_name
);
257 *num_unsaved_files
= 0;
259 /* Count the number of remapped files. */
260 for (arg
= start_arg
; arg
< argc
; ++arg
) {
261 if (strncmp(argv
[arg
], opt_name
, prefix_len
))
264 assert(*num_unsaved_files
< (int)(sizeof(arg_indices
)/sizeof(int)));
265 arg_indices
[*num_unsaved_files
] = arg
;
266 ++*num_unsaved_files
;
269 if (*num_unsaved_files
== 0)
273 = (struct CXUnsavedFile
*)malloc(sizeof(struct CXUnsavedFile
) *
275 assert(*unsaved_files
);
276 for (i
= 0; i
!= *num_unsaved_files
; ++i
) {
277 struct CXUnsavedFile
*unsaved
= *unsaved_files
+ i
;
278 const char *arg_string
= argv
[arg_indices
[i
]] + prefix_len
;
283 const char *sep
= strchr(arg_string
, ',');
286 "error: %sfrom:to argument is missing comma\n", opt_name
);
287 free_remapped_files(*unsaved_files
, i
);
289 *num_unsaved_files
= 0;
293 /* Open the file that we're remapping to. */
294 to_file
= fopen(sep
+ 1, "rb");
296 fprintf(stderr
, "error: cannot open file %s that we are remapping to\n",
298 free_remapped_files(*unsaved_files
, i
);
300 *num_unsaved_files
= 0;
304 /* Determine the length of the file we're remapping to. */
305 fseek(to_file
, 0, SEEK_END
);
306 unsaved
->Length
= ftell(to_file
);
307 fseek(to_file
, 0, SEEK_SET
);
309 /* Read the contents of the file we're remapping to. */
310 contents
= (char *)malloc(unsaved
->Length
+ 1);
312 if (fread(contents
, 1, unsaved
->Length
, to_file
) != unsaved
->Length
) {
313 fprintf(stderr
, "error: unexpected %s reading 'to' file %s\n",
314 (feof(to_file
) ? "EOF" : "error"), sep
+ 1);
316 free_remapped_files(*unsaved_files
, i
);
319 *num_unsaved_files
= 0;
322 contents
[unsaved
->Length
] = 0;
323 unsaved
->Contents
= contents
;
325 /* Close the file. */
328 /* Copy the file name that we're remapping from. */
329 filename_len
= sep
- arg_string
;
330 filename
= (char *)malloc(filename_len
+ 1);
332 memcpy(filename
, arg_string
, filename_len
);
333 filename
[filename_len
] = 0;
334 unsaved
->Filename
= filename
;
340 static int parse_remapped_files(int argc
, const char **argv
, int start_arg
,
341 struct CXUnsavedFile
**unsaved_files
,
342 int *num_unsaved_files
) {
343 return parse_remapped_files_with_opt("-remap-file=", argc
, argv
, start_arg
,
344 unsaved_files
, num_unsaved_files
);
347 static int parse_remapped_files_with_try(int try_idx
,
348 int argc
, const char **argv
,
350 struct CXUnsavedFile
**unsaved_files
,
351 int *num_unsaved_files
) {
352 struct CXUnsavedFile
*unsaved_files_no_try_idx
;
353 int num_unsaved_files_no_try_idx
;
354 struct CXUnsavedFile
*unsaved_files_try_idx
;
355 int num_unsaved_files_try_idx
;
359 ret
= parse_remapped_files(argc
, argv
, start_arg
,
360 &unsaved_files_no_try_idx
, &num_unsaved_files_no_try_idx
);
364 sprintf(opt_name
, "-remap-file-%d=", try_idx
);
365 ret
= parse_remapped_files_with_opt(opt_name
, argc
, argv
, start_arg
,
366 &unsaved_files_try_idx
, &num_unsaved_files_try_idx
);
370 if (num_unsaved_files_no_try_idx
== 0) {
371 *unsaved_files
= unsaved_files_try_idx
;
372 *num_unsaved_files
= num_unsaved_files_try_idx
;
375 if (num_unsaved_files_try_idx
== 0) {
376 *unsaved_files
= unsaved_files_no_try_idx
;
377 *num_unsaved_files
= num_unsaved_files_no_try_idx
;
381 *num_unsaved_files
= num_unsaved_files_no_try_idx
+ num_unsaved_files_try_idx
;
383 = (struct CXUnsavedFile
*)realloc(unsaved_files_no_try_idx
,
384 sizeof(struct CXUnsavedFile
) *
386 assert(*unsaved_files
);
387 memcpy(*unsaved_files
+ num_unsaved_files_no_try_idx
,
388 unsaved_files_try_idx
, sizeof(struct CXUnsavedFile
) *
389 num_unsaved_files_try_idx
);
390 free(unsaved_files_try_idx
);
394 static const char *parse_comments_schema(int argc
, const char **argv
) {
395 const char *CommentsSchemaArg
= "-comments-xml-schema=";
396 const char *CommentSchemaFile
= NULL
;
399 return CommentSchemaFile
;
401 if (!strncmp(argv
[0], CommentsSchemaArg
, strlen(CommentsSchemaArg
)))
402 CommentSchemaFile
= argv
[0] + strlen(CommentsSchemaArg
);
404 return CommentSchemaFile
;
407 /******************************************************************************/
408 /* Pretty-printing. */
409 /******************************************************************************/
411 static const char *FileCheckPrefix
= "CHECK";
413 static void PrintCString(const char *CStr
) {
414 if (CStr
!= NULL
&& CStr
[0] != '\0') {
415 for ( ; *CStr
; ++CStr
) {
416 const char C
= *CStr
;
418 case '\n': printf("\\n"); break;
419 case '\r': printf("\\r"); break;
420 case '\t': printf("\\t"); break;
421 case '\v': printf("\\v"); break;
422 case '\f': printf("\\f"); break;
423 default: putchar(C
); break;
429 static void PrintCStringWithPrefix(const char *Prefix
, const char *CStr
) {
430 printf(" %s=[", Prefix
);
435 static void PrintCXStringAndDispose(CXString Str
) {
436 PrintCString(clang_getCString(Str
));
437 clang_disposeString(Str
);
440 static void PrintCXStringWithPrefix(const char *Prefix
, CXString Str
) {
441 PrintCStringWithPrefix(Prefix
, clang_getCString(Str
));
444 static void PrintCXStringWithPrefixAndDispose(const char *Prefix
,
446 PrintCStringWithPrefix(Prefix
, clang_getCString(Str
));
447 clang_disposeString(Str
);
450 static void PrintRange(CXSourceRange R
, const char *str
) {
451 CXFile begin_file
, end_file
;
452 unsigned begin_line
, begin_column
, end_line
, end_column
;
454 clang_getSpellingLocation(clang_getRangeStart(R
),
455 &begin_file
, &begin_line
, &begin_column
, 0);
456 clang_getSpellingLocation(clang_getRangeEnd(R
),
457 &end_file
, &end_line
, &end_column
, 0);
458 if (!begin_file
|| !end_file
)
463 PrintExtent(stdout
, begin_line
, begin_column
, end_line
, end_column
);
466 static enum DisplayType
{
467 DisplayType_Spelling
,
468 DisplayType_DisplayName
,
470 } wanted_display_type
= DisplayType_Spelling
;
472 static void printVersion(const char *Prefix
, CXVersion Version
) {
473 if (Version
.Major
< 0)
475 printf("%s%d", Prefix
, Version
.Major
);
477 if (Version
.Minor
< 0)
479 printf(".%d", Version
.Minor
);
481 if (Version
.Subminor
< 0)
483 printf(".%d", Version
.Subminor
);
486 struct CommentASTDumpingContext
{
490 static void DumpCXCommentInternal(struct CommentASTDumpingContext
*Ctx
,
494 enum CXCommentKind Kind
= clang_Comment_getKind(Comment
);
497 for (i
= 0, e
= Ctx
->IndentLevel
; i
!= e
; ++i
)
503 printf("CXComment_Null");
506 printf("CXComment_Text");
507 PrintCXStringWithPrefixAndDispose("Text",
508 clang_TextComment_getText(Comment
));
509 if (clang_Comment_isWhitespace(Comment
))
510 printf(" IsWhitespace");
511 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
512 printf(" HasTrailingNewline");
514 case CXComment_InlineCommand
:
515 printf("CXComment_InlineCommand");
516 PrintCXStringWithPrefixAndDispose(
518 clang_InlineCommandComment_getCommandName(Comment
));
519 switch (clang_InlineCommandComment_getRenderKind(Comment
)) {
520 case CXCommentInlineCommandRenderKind_Normal
:
521 printf(" RenderNormal");
523 case CXCommentInlineCommandRenderKind_Bold
:
524 printf(" RenderBold");
526 case CXCommentInlineCommandRenderKind_Monospaced
:
527 printf(" RenderMonospaced");
529 case CXCommentInlineCommandRenderKind_Emphasized
:
530 printf(" RenderEmphasized");
532 case CXCommentInlineCommandRenderKind_Anchor
:
533 printf(" RenderAnchor");
536 for (i
= 0, e
= clang_InlineCommandComment_getNumArgs(Comment
);
538 printf(" Arg[%u]=", i
);
539 PrintCXStringAndDispose(
540 clang_InlineCommandComment_getArgText(Comment
, i
));
542 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
543 printf(" HasTrailingNewline");
545 case CXComment_HTMLStartTag
: {
547 printf("CXComment_HTMLStartTag");
548 PrintCXStringWithPrefixAndDispose(
550 clang_HTMLTagComment_getTagName(Comment
));
551 NumAttrs
= clang_HTMLStartTag_getNumAttrs(Comment
);
554 for (i
= 0; i
!= NumAttrs
; ++i
) {
556 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment
, i
));
558 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment
, i
));
561 if (clang_HTMLStartTagComment_isSelfClosing(Comment
))
562 printf(" SelfClosing");
563 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
564 printf(" HasTrailingNewline");
567 case CXComment_HTMLEndTag
:
568 printf("CXComment_HTMLEndTag");
569 PrintCXStringWithPrefixAndDispose(
571 clang_HTMLTagComment_getTagName(Comment
));
572 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
573 printf(" HasTrailingNewline");
575 case CXComment_Paragraph
:
576 printf("CXComment_Paragraph");
577 if (clang_Comment_isWhitespace(Comment
))
578 printf(" IsWhitespace");
580 case CXComment_BlockCommand
:
581 printf("CXComment_BlockCommand");
582 PrintCXStringWithPrefixAndDispose(
584 clang_BlockCommandComment_getCommandName(Comment
));
585 for (i
= 0, e
= clang_BlockCommandComment_getNumArgs(Comment
);
587 printf(" Arg[%u]=", i
);
588 PrintCXStringAndDispose(
589 clang_BlockCommandComment_getArgText(Comment
, i
));
592 case CXComment_ParamCommand
:
593 printf("CXComment_ParamCommand");
594 switch (clang_ParamCommandComment_getDirection(Comment
)) {
595 case CXCommentParamPassDirection_In
:
598 case CXCommentParamPassDirection_Out
:
601 case CXCommentParamPassDirection_InOut
:
605 if (clang_ParamCommandComment_isDirectionExplicit(Comment
))
606 printf(" explicitly");
608 printf(" implicitly");
609 PrintCXStringWithPrefixAndDispose(
611 clang_ParamCommandComment_getParamName(Comment
));
612 if (clang_ParamCommandComment_isParamIndexValid(Comment
))
613 printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment
));
615 printf(" ParamIndex=Invalid");
617 case CXComment_TParamCommand
:
618 printf("CXComment_TParamCommand");
619 PrintCXStringWithPrefixAndDispose(
621 clang_TParamCommandComment_getParamName(Comment
));
622 if (clang_TParamCommandComment_isParamPositionValid(Comment
)) {
623 printf(" ParamPosition={");
624 for (i
= 0, e
= clang_TParamCommandComment_getDepth(Comment
);
626 printf("%u", clang_TParamCommandComment_getIndex(Comment
, i
));
632 printf(" ParamPosition=Invalid");
634 case CXComment_VerbatimBlockCommand
:
635 printf("CXComment_VerbatimBlockCommand");
636 PrintCXStringWithPrefixAndDispose(
638 clang_BlockCommandComment_getCommandName(Comment
));
640 case CXComment_VerbatimBlockLine
:
641 printf("CXComment_VerbatimBlockLine");
642 PrintCXStringWithPrefixAndDispose(
644 clang_VerbatimBlockLineComment_getText(Comment
));
646 case CXComment_VerbatimLine
:
647 printf("CXComment_VerbatimLine");
648 PrintCXStringWithPrefixAndDispose(
650 clang_VerbatimLineComment_getText(Comment
));
652 case CXComment_FullComment
:
653 printf("CXComment_FullComment");
656 if (Kind
!= CXComment_Null
) {
657 const unsigned NumChildren
= clang_Comment_getNumChildren(Comment
);
659 for (i
= 0; i
!= NumChildren
; ++i
) {
660 printf("\n// %s: ", FileCheckPrefix
);
661 DumpCXCommentInternal(Ctx
, clang_Comment_getChild(Comment
, i
));
668 static void DumpCXComment(CXComment Comment
) {
669 struct CommentASTDumpingContext Ctx
;
671 printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix
, FileCheckPrefix
);
672 DumpCXCommentInternal(&Ctx
, Comment
);
676 static void ValidateCommentXML(const char *Str
, const char *CommentSchemaFile
) {
677 #ifdef CLANG_HAVE_LIBXML
678 xmlRelaxNGParserCtxtPtr RNGParser
;
679 xmlRelaxNGPtr Schema
;
681 xmlRelaxNGValidCtxtPtr ValidationCtxt
;
684 if (!CommentSchemaFile
)
687 RNGParser
= xmlRelaxNGNewParserCtxt(CommentSchemaFile
);
689 printf(" libXMLError");
692 Schema
= xmlRelaxNGParse(RNGParser
);
694 Doc
= xmlParseDoc((const xmlChar
*) Str
);
697 xmlErrorPtr Error
= xmlGetLastError();
698 printf(" CommentXMLInvalid [not well-formed XML: %s]", Error
->message
);
702 ValidationCtxt
= xmlRelaxNGNewValidCtxt(Schema
);
703 status
= xmlRelaxNGValidateDoc(ValidationCtxt
, Doc
);
705 printf(" CommentXMLValid");
706 else if (status
> 0) {
707 xmlErrorPtr Error
= xmlGetLastError();
708 printf(" CommentXMLInvalid [not valid XML: %s]", Error
->message
);
710 printf(" libXMLError");
712 xmlRelaxNGFreeValidCtxt(ValidationCtxt
);
714 xmlRelaxNGFree(Schema
);
715 xmlRelaxNGFreeParserCtxt(RNGParser
);
719 static void PrintCursorComments(CXCursor Cursor
,
720 const char *CommentSchemaFile
) {
723 const char *RawCommentCString
;
724 CXString BriefComment
;
725 const char *BriefCommentCString
;
727 RawComment
= clang_Cursor_getRawCommentText(Cursor
);
728 RawCommentCString
= clang_getCString(RawComment
);
729 if (RawCommentCString
!= NULL
&& RawCommentCString
[0] != '\0') {
730 PrintCStringWithPrefix("RawComment", RawCommentCString
);
731 PrintRange(clang_Cursor_getCommentRange(Cursor
), "RawCommentRange");
733 BriefComment
= clang_Cursor_getBriefCommentText(Cursor
);
734 BriefCommentCString
= clang_getCString(BriefComment
);
735 if (BriefCommentCString
!= NULL
&& BriefCommentCString
[0] != '\0')
736 PrintCStringWithPrefix("BriefComment", BriefCommentCString
);
737 clang_disposeString(BriefComment
);
739 clang_disposeString(RawComment
);
743 CXComment Comment
= clang_Cursor_getParsedComment(Cursor
);
744 if (clang_Comment_getKind(Comment
) != CXComment_Null
) {
745 PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
746 clang_FullComment_getAsHTML(Comment
));
749 XML
= clang_FullComment_getAsXML(Comment
);
750 PrintCXStringWithPrefix("FullCommentAsXML", XML
);
751 ValidateCommentXML(clang_getCString(XML
), CommentSchemaFile
);
752 clang_disposeString(XML
);
755 DumpCXComment(Comment
);
765 static int lineCol_cmp(const void *p1
, const void *p2
) {
766 const LineCol
*lhs
= p1
;
767 const LineCol
*rhs
= p2
;
768 if (lhs
->line
!= rhs
->line
)
769 return (int)lhs
->line
- (int)rhs
->line
;
770 return (int)lhs
->col
- (int)rhs
->col
;
773 static CXString
CursorToText(CXCursor Cursor
) {
775 switch (wanted_display_type
) {
776 case DisplayType_Spelling
:
777 return clang_getCursorSpelling(Cursor
);
778 case DisplayType_DisplayName
:
779 return clang_getCursorDisplayName(Cursor
);
780 case DisplayType_Pretty
: {
781 CXPrintingPolicy Policy
= clang_getCursorPrintingPolicy(Cursor
);
782 ModifyPrintingPolicyAccordingToEnv(Policy
);
783 text
= clang_getCursorPrettyPrinted(Cursor
, Policy
);
784 clang_PrintingPolicy_dispose(Policy
);
788 assert(0 && "unknown display type"); /* no llvm_unreachable in C. */
789 /* Set to NULL to prevent uninitialized variable warnings. */
791 text
.private_flags
= 0;
795 static void PrintCursor(CXCursor Cursor
, const char *CommentSchemaFile
) {
796 CXTranslationUnit TU
= clang_Cursor_getTranslationUnit(Cursor
);
797 if (clang_isInvalid(Cursor
.kind
)) {
798 CXString ks
= clang_getCursorKindSpelling(Cursor
.kind
);
799 printf("Invalid Cursor => %s", clang_getCString(ks
));
800 clang_disposeString(ks
);
805 unsigned line
, column
;
806 CXCursor SpecializationOf
;
807 CXCursor
*overridden
;
808 unsigned num_overridden
;
809 unsigned RefNameRangeNr
;
810 CXSourceRange CursorExtent
;
811 CXSourceRange RefNameRange
;
812 int AlwaysUnavailable
;
813 int AlwaysDeprecated
;
814 CXString UnavailableMessage
;
815 CXString DeprecatedMessage
;
816 CXPlatformAvailability PlatformAvailability
[2];
817 int NumPlatformAvailability
;
820 ks
= clang_getCursorKindSpelling(Cursor
.kind
);
821 string
= CursorToText(Cursor
);
822 printf("%s=%s", clang_getCString(ks
),
823 clang_getCString(string
));
824 clang_disposeString(ks
);
825 clang_disposeString(string
);
827 Referenced
= clang_getCursorReferenced(Cursor
);
828 if (!clang_equalCursors(Referenced
, clang_getNullCursor())) {
829 if (clang_getCursorKind(Referenced
) == CXCursor_OverloadedDeclRef
) {
830 unsigned I
, N
= clang_getNumOverloadedDecls(Referenced
);
832 for (I
= 0; I
!= N
; ++I
) {
833 CXCursor Ovl
= clang_getOverloadedDecl(Referenced
, I
);
834 CXSourceLocation Loc
;
838 Loc
= clang_getCursorLocation(Ovl
);
839 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
840 printf("%d:%d", line
, column
);
844 CXSourceLocation Loc
= clang_getCursorLocation(Referenced
);
845 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
846 printf(":%d:%d", line
, column
);
849 if (clang_getCursorKind(Referenced
) == CXCursor_TypedefDecl
) {
850 CXType T
= clang_getCursorType(Referenced
);
851 if (clang_Type_isTransparentTagTypedef(T
)) {
852 CXType Underlying
= clang_getTypedefDeclUnderlyingType(Referenced
);
853 CXString S
= clang_getTypeSpelling(Underlying
);
854 printf(" (Transparent: %s)", clang_getCString(S
));
855 clang_disposeString(S
);
860 if (clang_isCursorDefinition(Cursor
))
861 printf(" (Definition)");
863 switch (clang_getCursorAvailability(Cursor
)) {
864 case CXAvailability_Available
:
867 case CXAvailability_Deprecated
:
868 printf(" (deprecated)");
871 case CXAvailability_NotAvailable
:
872 printf(" (unavailable)");
875 case CXAvailability_NotAccessible
:
876 printf(" (inaccessible)");
880 NumPlatformAvailability
881 = clang_getCursorPlatformAvailability(Cursor
,
886 PlatformAvailability
, 2);
887 if (AlwaysUnavailable
) {
888 printf(" (always unavailable: \"%s\")",
889 clang_getCString(UnavailableMessage
));
890 } else if (AlwaysDeprecated
) {
891 printf(" (always deprecated: \"%s\")",
892 clang_getCString(DeprecatedMessage
));
894 for (I
= 0; I
!= NumPlatformAvailability
; ++I
) {
898 printf(" (%s", clang_getCString(PlatformAvailability
[I
].Platform
));
899 if (PlatformAvailability
[I
].Unavailable
)
900 printf(", unavailable");
902 printVersion(", introduced=", PlatformAvailability
[I
].Introduced
);
903 printVersion(", deprecated=", PlatformAvailability
[I
].Deprecated
);
904 printVersion(", obsoleted=", PlatformAvailability
[I
].Obsoleted
);
906 if (clang_getCString(PlatformAvailability
[I
].Message
)[0])
907 printf(", message=\"%s\"",
908 clang_getCString(PlatformAvailability
[I
].Message
));
912 for (I
= 0; I
!= NumPlatformAvailability
; ++I
) {
915 clang_disposeCXPlatformAvailability(PlatformAvailability
+ I
);
918 clang_disposeString(DeprecatedMessage
);
919 clang_disposeString(UnavailableMessage
);
921 if (clang_CXXConstructor_isDefaultConstructor(Cursor
))
922 printf(" (default constructor)");
924 if (clang_CXXConstructor_isMoveConstructor(Cursor
))
925 printf(" (move constructor)");
926 if (clang_CXXConstructor_isCopyConstructor(Cursor
))
927 printf(" (copy constructor)");
928 if (clang_CXXConstructor_isConvertingConstructor(Cursor
))
929 printf(" (converting constructor)");
930 if (clang_CXXField_isMutable(Cursor
))
931 printf(" (mutable)");
932 if (clang_CXXMethod_isDefaulted(Cursor
))
933 printf(" (defaulted)");
934 if (clang_CXXMethod_isDeleted(Cursor
))
935 printf(" (deleted)");
936 if (clang_CXXMethod_isStatic(Cursor
))
938 if (clang_CXXMethod_isVirtual(Cursor
))
939 printf(" (virtual)");
940 if (clang_CXXMethod_isConst(Cursor
))
942 if (clang_CXXMethod_isPureVirtual(Cursor
))
944 if (clang_CXXMethod_isCopyAssignmentOperator(Cursor
))
945 printf(" (copy-assignment operator)");
946 if (clang_CXXMethod_isMoveAssignmentOperator(Cursor
))
947 printf(" (move-assignment operator)");
948 if (clang_CXXMethod_isExplicit(Cursor
))
949 printf(" (explicit)");
950 if (clang_CXXRecord_isAbstract(Cursor
))
951 printf(" (abstract)");
952 if (clang_EnumDecl_isScoped(Cursor
))
954 if (clang_Cursor_isVariadic(Cursor
))
955 printf(" (variadic)");
956 if (clang_Cursor_isObjCOptional(Cursor
))
957 printf(" (@optional)");
958 if (clang_isInvalidDeclaration(Cursor
))
959 printf(" (invalid)");
961 switch (clang_getCursorExceptionSpecificationType(Cursor
))
963 case CXCursor_ExceptionSpecificationKind_None
:
966 case CXCursor_ExceptionSpecificationKind_DynamicNone
:
967 printf(" (noexcept dynamic none)");
970 case CXCursor_ExceptionSpecificationKind_Dynamic
:
971 printf(" (noexcept dynamic)");
974 case CXCursor_ExceptionSpecificationKind_MSAny
:
975 printf(" (noexcept dynamic any)");
978 case CXCursor_ExceptionSpecificationKind_BasicNoexcept
:
979 printf(" (noexcept)");
982 case CXCursor_ExceptionSpecificationKind_ComputedNoexcept
:
983 printf(" (computed-noexcept)");
986 case CXCursor_ExceptionSpecificationKind_Unevaluated
:
987 case CXCursor_ExceptionSpecificationKind_Uninstantiated
:
988 case CXCursor_ExceptionSpecificationKind_Unparsed
:
996 if (clang_Cursor_isExternalSymbol(Cursor
, &language
, &definedIn
,
998 printf(" (external lang: %s, defined: %s, gen: %d)",
999 clang_getCString(language
), clang_getCString(definedIn
), generated
);
1000 clang_disposeString(language
);
1001 clang_disposeString(definedIn
);
1005 if (Cursor
.kind
== CXCursor_IBOutletCollectionAttr
) {
1007 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor
));
1008 CXString S
= clang_getTypeKindSpelling(T
.kind
);
1009 printf(" [IBOutletCollection=%s]", clang_getCString(S
));
1010 clang_disposeString(S
);
1013 if (Cursor
.kind
== CXCursor_CXXBaseSpecifier
) {
1014 enum CX_CXXAccessSpecifier access
= clang_getCXXAccessSpecifier(Cursor
);
1015 unsigned isVirtual
= clang_isVirtualBase(Cursor
);
1016 const char *accessStr
= 0;
1019 case CX_CXXInvalidAccessSpecifier
:
1020 accessStr
= "invalid"; break;
1022 accessStr
= "public"; break;
1023 case CX_CXXProtected
:
1024 accessStr
= "protected"; break;
1026 accessStr
= "private"; break;
1029 printf(" [access=%s isVirtual=%s]", accessStr
,
1030 isVirtual
? "true" : "false");
1033 SpecializationOf
= clang_getSpecializedCursorTemplate(Cursor
);
1034 if (!clang_equalCursors(SpecializationOf
, clang_getNullCursor())) {
1035 CXSourceLocation Loc
= clang_getCursorLocation(SpecializationOf
);
1036 CXString Name
= clang_getCursorSpelling(SpecializationOf
);
1037 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1038 printf(" [Specialization of %s:%d:%d]",
1039 clang_getCString(Name
), line
, column
);
1040 clang_disposeString(Name
);
1042 if (Cursor
.kind
== CXCursor_FunctionDecl
1043 || Cursor
.kind
== CXCursor_StructDecl
1044 || Cursor
.kind
== CXCursor_ClassDecl
1045 || Cursor
.kind
== CXCursor_ClassTemplatePartialSpecialization
) {
1046 /* Collect the template parameter kinds from the base template. */
1047 int NumTemplateArgs
= clang_Cursor_getNumTemplateArguments(Cursor
);
1049 if (NumTemplateArgs
< 0) {
1050 printf(" [no template arg info]");
1052 for (I
= 0; I
< NumTemplateArgs
; I
++) {
1053 enum CXTemplateArgumentKind TAK
=
1054 clang_Cursor_getTemplateArgumentKind(Cursor
, I
);
1056 case CXTemplateArgumentKind_Type
:
1058 CXType T
= clang_Cursor_getTemplateArgumentType(Cursor
, I
);
1059 CXString S
= clang_getTypeSpelling(T
);
1060 printf(" [Template arg %d: kind: %d, type: %s]",
1061 I
, TAK
, clang_getCString(S
));
1062 clang_disposeString(S
);
1065 case CXTemplateArgumentKind_Integral
:
1066 printf(" [Template arg %d: kind: %d, intval: %lld]",
1067 I
, TAK
, clang_Cursor_getTemplateArgumentValue(Cursor
, I
));
1070 printf(" [Template arg %d: kind: %d]\n", I
, TAK
);
1076 clang_getOverriddenCursors(Cursor
, &overridden
, &num_overridden
);
1077 if (num_overridden
) {
1079 LineCol lineCols
[50];
1080 assert(num_overridden
<= 50);
1081 printf(" [Overrides ");
1082 for (I
= 0; I
!= num_overridden
; ++I
) {
1083 CXSourceLocation Loc
= clang_getCursorLocation(overridden
[I
]);
1084 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1085 lineCols
[I
].line
= line
;
1086 lineCols
[I
].col
= column
;
1088 /* Make the order of the override list deterministic. */
1089 qsort(lineCols
, num_overridden
, sizeof(LineCol
), lineCol_cmp
);
1090 for (I
= 0; I
!= num_overridden
; ++I
) {
1093 printf("@%d:%d", lineCols
[I
].line
, lineCols
[I
].col
);
1096 clang_disposeOverriddenCursors(overridden
);
1099 if (Cursor
.kind
== CXCursor_InclusionDirective
) {
1100 CXFile File
= clang_getIncludedFile(Cursor
);
1101 CXString Included
= clang_getFileName(File
);
1102 const char *IncludedString
= clang_getCString(Included
);
1103 printf(" (%s)", IncludedString
? IncludedString
: "(null)");
1104 clang_disposeString(Included
);
1106 if (clang_isFileMultipleIncludeGuarded(TU
, File
))
1107 printf(" [multi-include guarded]");
1110 CursorExtent
= clang_getCursorExtent(Cursor
);
1111 RefNameRange
= clang_getCursorReferenceNameRange(Cursor
,
1112 CXNameRange_WantQualifier
1113 | CXNameRange_WantSinglePiece
1114 | CXNameRange_WantTemplateArgs
,
1116 if (!clang_equalRanges(CursorExtent
, RefNameRange
))
1117 PrintRange(RefNameRange
, "SingleRefName");
1119 for (RefNameRangeNr
= 0; 1; RefNameRangeNr
++) {
1120 RefNameRange
= clang_getCursorReferenceNameRange(Cursor
,
1121 CXNameRange_WantQualifier
1122 | CXNameRange_WantTemplateArgs
,
1124 if (clang_equalRanges(clang_getNullRange(), RefNameRange
))
1126 if (!clang_equalRanges(CursorExtent
, RefNameRange
))
1127 PrintRange(RefNameRange
, "RefName");
1130 PrintCursorComments(Cursor
, CommentSchemaFile
);
1133 unsigned PropAttrs
= clang_Cursor_getObjCPropertyAttributes(Cursor
, 0);
1134 if (PropAttrs
!= CXObjCPropertyAttr_noattr
) {
1136 #define PRINT_PROP_ATTR(A) \
1137 if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
1138 PRINT_PROP_ATTR(readonly
);
1139 PRINT_PROP_ATTR(getter
);
1140 PRINT_PROP_ATTR(assign
);
1141 PRINT_PROP_ATTR(readwrite
);
1142 PRINT_PROP_ATTR(retain
);
1143 PRINT_PROP_ATTR(copy
);
1144 PRINT_PROP_ATTR(nonatomic
);
1145 PRINT_PROP_ATTR(setter
);
1146 PRINT_PROP_ATTR(atomic
);
1147 PRINT_PROP_ATTR(weak
);
1148 PRINT_PROP_ATTR(strong
);
1149 PRINT_PROP_ATTR(unsafe_unretained
);
1150 PRINT_PROP_ATTR(class);
1155 if (Cursor
.kind
== CXCursor_ObjCPropertyDecl
) {
1156 CXString Name
= clang_Cursor_getObjCPropertyGetterName(Cursor
);
1157 CXString Spelling
= clang_getCursorSpelling(Cursor
);
1158 const char *CName
= clang_getCString(Name
);
1159 const char *CSpelling
= clang_getCString(Spelling
);
1160 if (CName
&& strcmp(CName
, CSpelling
)) {
1161 printf(" (getter=%s)", CName
);
1163 clang_disposeString(Spelling
);
1164 clang_disposeString(Name
);
1167 if (Cursor
.kind
== CXCursor_ObjCPropertyDecl
) {
1168 CXString Name
= clang_Cursor_getObjCPropertySetterName(Cursor
);
1169 CXString Spelling
= clang_getCursorSpelling(Cursor
);
1170 const char *CName
= clang_getCString(Name
);
1171 const char *CSpelling
= clang_getCString(Spelling
);
1172 char *DefaultSetter
= malloc(strlen(CSpelling
) + 5);
1173 sprintf(DefaultSetter
, "set%s:", CSpelling
);
1174 DefaultSetter
[3] &= ~(1 << 5); /* Make uppercase */
1175 if (CName
&& strcmp(CName
, DefaultSetter
)) {
1176 printf(" (setter=%s)", CName
);
1178 free(DefaultSetter
);
1179 clang_disposeString(Spelling
);
1180 clang_disposeString(Name
);
1184 unsigned QT
= clang_Cursor_getObjCDeclQualifiers(Cursor
);
1185 if (QT
!= CXObjCDeclQualifier_None
) {
1187 #define PRINT_OBJC_QUAL(A) \
1188 if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
1189 PRINT_OBJC_QUAL(In
);
1190 PRINT_OBJC_QUAL(Inout
);
1191 PRINT_OBJC_QUAL(Out
);
1192 PRINT_OBJC_QUAL(Bycopy
);
1193 PRINT_OBJC_QUAL(Byref
);
1194 PRINT_OBJC_QUAL(Oneway
);
1201 static const char* GetCursorSource(CXCursor Cursor
) {
1202 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
1205 clang_getExpansionLocation(Loc
, &file
, 0, 0, 0);
1206 source
= clang_getFileName(file
);
1207 if (!clang_getCString(source
)) {
1208 clang_disposeString(source
);
1209 return "<invalid loc>";
1212 const char *b
= basename(clang_getCString(source
));
1213 clang_disposeString(source
);
1218 static CXString
createCXString(const char *CS
) {
1220 Str
.data
= (const void *) CS
;
1221 Str
.private_flags
= 0;
1225 /******************************************************************************/
1227 /******************************************************************************/
1229 typedef void (*PostVisitTU
)(CXTranslationUnit
);
1231 void PrintDiagnostic(CXDiagnostic Diagnostic
) {
1235 unsigned display_opts
= CXDiagnostic_DisplaySourceLocation
1236 | CXDiagnostic_DisplayColumn
| CXDiagnostic_DisplaySourceRanges
1237 | CXDiagnostic_DisplayOption
;
1238 unsigned i
, num_fixits
;
1240 if (clang_getDiagnosticSeverity(Diagnostic
) == CXDiagnostic_Ignored
)
1243 Msg
= clang_formatDiagnostic(Diagnostic
, display_opts
);
1244 fprintf(stderr
, "%s\n", clang_getCString(Msg
));
1245 clang_disposeString(Msg
);
1247 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic
),
1252 num_fixits
= clang_getDiagnosticNumFixIts(Diagnostic
);
1253 fprintf(stderr
, "Number FIX-ITs = %d\n", num_fixits
);
1254 for (i
= 0; i
!= num_fixits
; ++i
) {
1255 CXSourceRange range
;
1256 CXString insertion_text
= clang_getDiagnosticFixIt(Diagnostic
, i
, &range
);
1257 CXSourceLocation start
= clang_getRangeStart(range
);
1258 CXSourceLocation end
= clang_getRangeEnd(range
);
1259 unsigned start_line
, start_column
, end_line
, end_column
;
1260 CXFile start_file
, end_file
;
1261 clang_getSpellingLocation(start
, &start_file
, &start_line
,
1263 clang_getSpellingLocation(end
, &end_file
, &end_line
, &end_column
, 0);
1264 if (clang_equalLocations(start
, end
)) {
1266 if (start_file
== file
)
1267 fprintf(out
, "FIX-IT: Insert \"%s\" at %d:%d\n",
1268 clang_getCString(insertion_text
), start_line
, start_column
);
1269 } else if (strcmp(clang_getCString(insertion_text
), "") == 0) {
1271 if (start_file
== file
&& end_file
== file
) {
1272 fprintf(out
, "FIX-IT: Remove ");
1273 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
1278 if (start_file
== end_file
) {
1279 fprintf(out
, "FIX-IT: Replace ");
1280 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
1281 fprintf(out
, " with \"%s\"\n", clang_getCString(insertion_text
));
1284 clang_disposeString(insertion_text
);
1288 void PrintDiagnosticSet(CXDiagnosticSet Set
) {
1289 int i
= 0, n
= clang_getNumDiagnosticsInSet(Set
);
1290 for ( ; i
!= n
; ++i
) {
1291 CXDiagnostic Diag
= clang_getDiagnosticInSet(Set
, i
);
1292 CXDiagnosticSet ChildDiags
= clang_getChildDiagnostics(Diag
);
1293 PrintDiagnostic(Diag
);
1295 PrintDiagnosticSet(ChildDiags
);
1299 void PrintDiagnostics(CXTranslationUnit TU
) {
1300 CXDiagnosticSet TUSet
= clang_getDiagnosticSetFromTU(TU
);
1301 PrintDiagnosticSet(TUSet
);
1302 clang_disposeDiagnosticSet(TUSet
);
1305 void PrintMemoryUsage(CXTranslationUnit TU
) {
1306 unsigned long total
= 0;
1308 CXTUResourceUsage usage
= clang_getCXTUResourceUsage(TU
);
1309 fprintf(stderr
, "Memory usage:\n");
1310 for (i
= 0 ; i
!= usage
.numEntries
; ++i
) {
1311 const char *name
= clang_getTUResourceUsageName(usage
.entries
[i
].kind
);
1312 unsigned long amount
= usage
.entries
[i
].amount
;
1314 fprintf(stderr
, " %s : %ld bytes (%f MBytes)\n", name
, amount
,
1315 ((double) amount
)/(1024*1024));
1317 fprintf(stderr
, " TOTAL = %ld bytes (%f MBytes)\n", total
,
1318 ((double) total
)/(1024*1024));
1319 clang_disposeCXTUResourceUsage(usage
);
1322 /******************************************************************************/
1323 /* Logic for testing traversal. */
1324 /******************************************************************************/
1326 static void PrintCursorExtent(CXCursor C
) {
1327 CXSourceRange extent
= clang_getCursorExtent(C
);
1328 PrintRange(extent
, "Extent");
1331 /* Data used by the visitors. */
1333 CXTranslationUnit TU
;
1334 enum CXCursorKind
*Filter
;
1335 const char *CommentSchemaFile
;
1339 enum CXChildVisitResult
FilteredPrintingVisitor(CXCursor Cursor
,
1341 CXClientData ClientData
) {
1342 VisitorData
*Data
= (VisitorData
*)ClientData
;
1343 if (!Data
->Filter
|| (Cursor
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
1344 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
1345 unsigned line
, column
;
1346 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1347 printf("// %s: %s:%d:%d: ", FileCheckPrefix
,
1348 GetCursorSource(Cursor
), line
, column
);
1349 PrintCursor(Cursor
, Data
->CommentSchemaFile
);
1350 PrintCursorExtent(Cursor
);
1351 if (clang_isDeclaration(Cursor
.kind
)) {
1352 enum CX_CXXAccessSpecifier access
= clang_getCXXAccessSpecifier(Cursor
);
1353 const char *accessStr
= 0;
1356 case CX_CXXInvalidAccessSpecifier
: break;
1358 accessStr
= "public"; break;
1359 case CX_CXXProtected
:
1360 accessStr
= "protected"; break;
1362 accessStr
= "private"; break;
1366 printf(" [access=%s]", accessStr
);
1369 return CXChildVisit_Recurse
;
1372 return CXChildVisit_Continue
;
1375 static enum CXChildVisitResult
FunctionScanVisitor(CXCursor Cursor
,
1377 CXClientData ClientData
) {
1378 const char *startBuf
, *endBuf
;
1379 unsigned startLine
, startColumn
, endLine
, endColumn
, curLine
, curColumn
;
1381 VisitorData
*Data
= (VisitorData
*)ClientData
;
1383 if (Cursor
.kind
!= CXCursor_FunctionDecl
||
1384 !clang_isCursorDefinition(Cursor
))
1385 return CXChildVisit_Continue
;
1387 clang_getDefinitionSpellingAndExtent(Cursor
, &startBuf
, &endBuf
,
1388 &startLine
, &startColumn
,
1389 &endLine
, &endColumn
);
1390 /* Probe the entire body, looking for both decls and refs. */
1391 curLine
= startLine
;
1392 curColumn
= startColumn
;
1394 while (startBuf
< endBuf
) {
1395 CXSourceLocation Loc
;
1399 if (*startBuf
== '\n') {
1403 } else if (*startBuf
!= '\t')
1406 Loc
= clang_getCursorLocation(Cursor
);
1407 clang_getSpellingLocation(Loc
, &file
, 0, 0, 0);
1409 source
= clang_getFileName(file
);
1410 if (clang_getCString(source
)) {
1411 CXSourceLocation RefLoc
1412 = clang_getLocation(Data
->TU
, file
, curLine
, curColumn
);
1413 Ref
= clang_getCursor(Data
->TU
, RefLoc
);
1414 if (Ref
.kind
== CXCursor_NoDeclFound
) {
1415 /* Nothing found here; that's fine. */
1416 } else if (Ref
.kind
!= CXCursor_FunctionDecl
) {
1417 printf("// %s: %s:%d:%d: ", FileCheckPrefix
, GetCursorSource(Ref
),
1418 curLine
, curColumn
);
1419 PrintCursor(Ref
, Data
->CommentSchemaFile
);
1423 clang_disposeString(source
);
1427 return CXChildVisit_Continue
;
1430 /******************************************************************************/
1432 /******************************************************************************/
1434 enum CXChildVisitResult
USRVisitor(CXCursor C
, CXCursor parent
,
1435 CXClientData ClientData
) {
1436 VisitorData
*Data
= (VisitorData
*)ClientData
;
1437 if (!Data
->Filter
|| (C
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
1438 CXString USR
= clang_getCursorUSR(C
);
1439 const char *cstr
= clang_getCString(USR
);
1440 if (!cstr
|| cstr
[0] == '\0') {
1441 clang_disposeString(USR
);
1442 return CXChildVisit_Recurse
;
1444 printf("// %s: %s %s", FileCheckPrefix
, GetCursorSource(C
), cstr
);
1446 PrintCursorExtent(C
);
1448 clang_disposeString(USR
);
1450 return CXChildVisit_Recurse
;
1453 return CXChildVisit_Continue
;
1456 /******************************************************************************/
1457 /* Inclusion stack testing. */
1458 /******************************************************************************/
1460 void InclusionVisitor(CXFile includedFile
, CXSourceLocation
*includeStack
,
1461 unsigned includeStackLen
, CXClientData data
) {
1466 fname
= clang_getFileName(includedFile
);
1467 printf("file: %s\nincluded by:\n", clang_getCString(fname
));
1468 clang_disposeString(fname
);
1470 for (i
= 0; i
< includeStackLen
; ++i
) {
1471 CXFile includingFile
;
1472 unsigned line
, column
;
1473 clang_getSpellingLocation(includeStack
[i
], &includingFile
, &line
,
1475 fname
= clang_getFileName(includingFile
);
1476 printf(" %s:%d:%d\n", clang_getCString(fname
), line
, column
);
1477 clang_disposeString(fname
);
1482 void PrintInclusionStack(CXTranslationUnit TU
) {
1483 clang_getInclusions(TU
, InclusionVisitor
, NULL
);
1486 /******************************************************************************/
1487 /* Linkage testing. */
1488 /******************************************************************************/
1490 static enum CXChildVisitResult
PrintLinkage(CXCursor cursor
, CXCursor p
,
1492 const char *linkage
= 0;
1494 if (clang_isInvalid(clang_getCursorKind(cursor
)))
1495 return CXChildVisit_Recurse
;
1497 switch (clang_getCursorLinkage(cursor
)) {
1498 case CXLinkage_Invalid
: break;
1499 case CXLinkage_NoLinkage
: linkage
= "NoLinkage"; break;
1500 case CXLinkage_Internal
: linkage
= "Internal"; break;
1501 case CXLinkage_UniqueExternal
: linkage
= "UniqueExternal"; break;
1502 case CXLinkage_External
: linkage
= "External"; break;
1506 PrintCursor(cursor
, NULL
);
1507 printf("linkage=%s\n", linkage
);
1510 return CXChildVisit_Recurse
;
1513 /******************************************************************************/
1514 /* Visibility testing. */
1515 /******************************************************************************/
1517 static enum CXChildVisitResult
PrintVisibility(CXCursor cursor
, CXCursor p
,
1519 const char *visibility
= 0;
1521 if (clang_isInvalid(clang_getCursorKind(cursor
)))
1522 return CXChildVisit_Recurse
;
1524 switch (clang_getCursorVisibility(cursor
)) {
1525 case CXVisibility_Invalid
: break;
1526 case CXVisibility_Hidden
: visibility
= "Hidden"; break;
1527 case CXVisibility_Protected
: visibility
= "Protected"; break;
1528 case CXVisibility_Default
: visibility
= "Default"; break;
1532 PrintCursor(cursor
, NULL
);
1533 printf("visibility=%s\n", visibility
);
1536 return CXChildVisit_Recurse
;
1539 /******************************************************************************/
1540 /* Typekind testing. */
1541 /******************************************************************************/
1543 static void PrintTypeAndTypeKind(CXType T
, const char *Format
) {
1544 CXString TypeSpelling
, TypeKindSpelling
;
1546 TypeSpelling
= clang_getTypeSpelling(T
);
1547 TypeKindSpelling
= clang_getTypeKindSpelling(T
.kind
);
1549 clang_getCString(TypeSpelling
),
1550 clang_getCString(TypeKindSpelling
));
1551 clang_disposeString(TypeSpelling
);
1552 clang_disposeString(TypeKindSpelling
);
1555 static enum CXVisitorResult
FieldVisitor(CXCursor C
,
1556 CXClientData client_data
) {
1557 (*(int *) client_data
)+=1;
1558 return CXVisit_Continue
;
1561 static void PrintTypeTemplateArgs(CXType T
, const char *Format
) {
1562 int NumTArgs
= clang_Type_getNumTemplateArguments(T
);
1563 if (NumTArgs
!= -1 && NumTArgs
!= 0) {
1566 printf(Format
, NumTArgs
);
1567 for (i
= 0; i
< NumTArgs
; ++i
) {
1568 TArg
= clang_Type_getTemplateArgumentAsType(T
, i
);
1569 if (TArg
.kind
!= CXType_Invalid
) {
1570 PrintTypeAndTypeKind(TArg
, " [type=%s] [typekind=%s]");
1573 /* Ensure that the returned type is invalid when indexing off-by-one. */
1574 TArg
= clang_Type_getTemplateArgumentAsType(T
, i
);
1575 assert(TArg
.kind
== CXType_Invalid
);
1580 static void PrintNullabilityKind(CXType T
, const char *Format
) {
1581 enum CXTypeNullabilityKind N
= clang_Type_getNullability(T
);
1583 const char *nullability
= 0;
1585 case CXTypeNullability_NonNull
:
1586 nullability
= "nonnull";
1588 case CXTypeNullability_Nullable
:
1589 nullability
= "nullable";
1591 case CXTypeNullability_NullableResult
:
1592 nullability
= "nullable_result";
1594 case CXTypeNullability_Unspecified
:
1595 nullability
= "unspecified";
1597 case CXTypeNullability_Invalid
:
1602 printf(Format
, nullability
);
1606 static enum CXChildVisitResult
PrintType(CXCursor cursor
, CXCursor p
,
1608 if (!clang_isInvalid(clang_getCursorKind(cursor
))) {
1609 CXType T
= clang_getCursorType(cursor
);
1610 CXType PT
= clang_getPointeeType(T
);
1611 enum CXRefQualifierKind RQ
= clang_Type_getCXXRefQualifier(T
);
1612 PrintCursor(cursor
, NULL
);
1613 PrintTypeAndTypeKind(T
, " [type=%s] [typekind=%s]");
1614 PrintNullabilityKind(T
, " [nullability=%s]");
1615 if (clang_isConstQualifiedType(T
))
1617 if (clang_isVolatileQualifiedType(T
))
1618 printf(" volatile");
1619 if (clang_isRestrictQualifiedType(T
))
1620 printf(" restrict");
1621 if (RQ
== CXRefQualifier_LValue
)
1622 printf(" lvalue-ref-qualifier");
1623 if (RQ
== CXRefQualifier_RValue
)
1624 printf(" rvalue-ref-qualifier");
1625 /* Print the template argument types if they exist. */
1626 PrintTypeTemplateArgs(T
, " [templateargs/%d=");
1627 /* Print the canonical type if it is different. */
1629 CXType CT
= clang_getCanonicalType(T
);
1630 if (!clang_equalTypes(T
, CT
)) {
1631 PrintTypeAndTypeKind(CT
, " [canonicaltype=%s] [canonicaltypekind=%s]");
1632 PrintTypeTemplateArgs(CT
, " [canonicaltemplateargs/%d=");
1635 /* Print the value type if it exists. */
1637 CXType VT
= clang_Type_getValueType(T
);
1638 if (VT
.kind
!= CXType_Invalid
)
1639 PrintTypeAndTypeKind(VT
, " [valuetype=%s] [valuetypekind=%s]");
1641 /* Print the modified type if it exists. */
1643 CXType MT
= clang_Type_getModifiedType(T
);
1644 if (MT
.kind
!= CXType_Invalid
) {
1645 PrintTypeAndTypeKind(MT
, " [modifiedtype=%s] [modifiedtypekind=%s]");
1648 /* Print the return type if it exists. */
1650 CXType RT
= clang_getCursorResultType(cursor
);
1651 if (RT
.kind
!= CXType_Invalid
) {
1652 PrintTypeAndTypeKind(RT
, " [resulttype=%s] [resulttypekind=%s]");
1654 PrintNullabilityKind(RT
, " [resultnullability=%s]");
1656 /* Print the argument types if they exist. */
1658 int NumArgs
= clang_Cursor_getNumArguments(cursor
);
1659 if (NumArgs
!= -1 && NumArgs
!= 0) {
1662 for (i
= 0; i
< NumArgs
; ++i
) {
1663 CXType T
= clang_getCursorType(clang_Cursor_getArgument(cursor
, i
));
1664 if (T
.kind
!= CXType_Invalid
) {
1665 PrintTypeAndTypeKind(T
, " [%s] [%s]");
1666 PrintNullabilityKind(T
, " [%s]");
1672 /* Print ObjC base types, type arguments, and protocol list if available. */
1674 CXType BT
= clang_Type_getObjCObjectBaseType(PT
);
1675 if (BT
.kind
!= CXType_Invalid
) {
1676 PrintTypeAndTypeKind(BT
, " [basetype=%s] [basekind=%s]");
1680 unsigned NumTypeArgs
= clang_Type_getNumObjCTypeArgs(PT
);
1681 if (NumTypeArgs
> 0) {
1683 printf(" [typeargs=");
1684 for (i
= 0; i
< NumTypeArgs
; ++i
) {
1685 CXType TA
= clang_Type_getObjCTypeArg(PT
, i
);
1686 if (TA
.kind
!= CXType_Invalid
) {
1687 PrintTypeAndTypeKind(TA
, " [%s] [%s]");
1694 unsigned NumProtocols
= clang_Type_getNumObjCProtocolRefs(PT
);
1695 if (NumProtocols
> 0) {
1697 printf(" [protocols=");
1698 for (i
= 0; i
< NumProtocols
; ++i
) {
1699 CXCursor P
= clang_Type_getObjCProtocolDecl(PT
, i
);
1700 if (!clang_isInvalid(clang_getCursorKind(P
))) {
1701 PrintCursor(P
, NULL
);
1707 /* Print if this is a non-POD type. */
1708 printf(" [isPOD=%d]", clang_isPODType(T
));
1709 /* Print the pointee type. */
1711 if (PT
.kind
!= CXType_Invalid
) {
1712 PrintTypeAndTypeKind(PT
, " [pointeetype=%s] [pointeekind=%s]");
1715 /* Print the number of fields if they exist. */
1718 if (clang_Type_visitFields(T
, FieldVisitor
, &numFields
)){
1719 if (numFields
!= 0) {
1720 printf(" [nbFields=%d]", numFields
);
1725 /* Print if it is an anonymous record or namespace. */
1727 unsigned isAnon
= clang_Cursor_isAnonymous(cursor
);
1729 printf(" [isAnon=%d]", isAnon
);
1733 /* Print if it is an anonymous record decl */
1735 unsigned isAnonRecDecl
= clang_Cursor_isAnonymousRecordDecl(cursor
);
1736 printf(" [isAnonRecDecl=%d]", isAnonRecDecl
);
1739 /* Print if it is an inline namespace decl */
1741 unsigned isInlineNamespace
= clang_Cursor_isInlineNamespace(cursor
);
1742 if (isInlineNamespace
!= 0)
1743 printf(" [isInlineNamespace=%d]", isInlineNamespace
);
1748 return CXChildVisit_Recurse
;
1751 static void PrintSingleTypeSize(CXType T
, const char *TypeKindFormat
,
1752 const char *SizeFormat
,
1753 const char *AlignFormat
) {
1754 PrintTypeAndTypeKind(T
, TypeKindFormat
);
1755 /* Print the type sizeof if applicable. */
1757 long long Size
= clang_Type_getSizeOf(T
);
1758 if (Size
>= 0 || Size
< -1 ) {
1759 printf(SizeFormat
, Size
);
1762 /* Print the type alignof if applicable. */
1764 long long Align
= clang_Type_getAlignOf(T
);
1765 if (Align
>= 0 || Align
< -1) {
1766 printf(AlignFormat
, Align
);
1770 /* Print the return type if it exists. */
1772 CXType RT
= clang_getResultType(T
);
1773 if (RT
.kind
!= CXType_Invalid
)
1774 PrintSingleTypeSize(RT
, " [resulttype=%s] [resulttypekind=%s]",
1775 " [resultsizeof=%lld]", " [resultalignof=%lld]");
1779 static enum CXChildVisitResult
PrintTypeSize(CXCursor cursor
, CXCursor p
,
1782 enum CXCursorKind K
= clang_getCursorKind(cursor
);
1783 if (clang_isInvalid(K
))
1784 return CXChildVisit_Recurse
;
1785 T
= clang_getCursorType(cursor
);
1786 PrintCursor(cursor
, NULL
);
1787 PrintSingleTypeSize(T
, " [type=%s] [typekind=%s]", " [sizeof=%lld]",
1789 /* Print the record field offset if applicable. */
1791 CXString FieldSpelling
= clang_getCursorSpelling(cursor
);
1792 const char *FieldName
= clang_getCString(FieldSpelling
);
1793 /* recurse to get the first parent record that is not anonymous. */
1794 unsigned RecordIsAnonymous
= 0;
1795 if (clang_getCursorKind(cursor
) == CXCursor_FieldDecl
) {
1797 CXCursor Parent
= p
;
1800 Parent
= clang_getCursorSemanticParent(Record
);
1801 RecordIsAnonymous
= clang_Cursor_isAnonymous(Record
);
1802 /* Recurse as long as the parent is a CXType_Record and the Record
1804 } while ( clang_getCursorType(Parent
).kind
== CXType_Record
&&
1805 RecordIsAnonymous
> 0);
1807 long long Offset
= clang_Type_getOffsetOf(clang_getCursorType(Record
),
1809 long long Offset2
= clang_Cursor_getOffsetOfField(cursor
);
1810 if (Offset
== Offset2
){
1811 printf(" [offsetof=%lld]", Offset
);
1813 /* Offsets will be different in anonymous records. */
1814 printf(" [offsetof=%lld/%lld]", Offset
, Offset2
);
1818 clang_disposeString(FieldSpelling
);
1820 /* Print if its a bitfield */
1822 int IsBitfield
= clang_Cursor_isBitField(cursor
);
1824 printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor
));
1829 return CXChildVisit_Recurse
;
1832 /******************************************************************************/
1833 /* Mangling testing. */
1834 /******************************************************************************/
1836 static enum CXChildVisitResult
PrintMangledName(CXCursor cursor
, CXCursor p
,
1838 CXString MangledName
;
1839 if (clang_isUnexposed(clang_getCursorKind(cursor
)))
1840 return CXChildVisit_Recurse
;
1841 PrintCursor(cursor
, NULL
);
1842 MangledName
= clang_Cursor_getMangling(cursor
);
1843 printf(" [mangled=%s]\n", clang_getCString(MangledName
));
1844 clang_disposeString(MangledName
);
1845 return CXChildVisit_Continue
;
1848 static enum CXChildVisitResult
PrintManglings(CXCursor cursor
, CXCursor p
,
1851 CXStringSet
*Manglings
= NULL
;
1852 if (clang_isUnexposed(clang_getCursorKind(cursor
)))
1853 return CXChildVisit_Recurse
;
1854 if (!clang_isDeclaration(clang_getCursorKind(cursor
)))
1855 return CXChildVisit_Recurse
;
1856 if (clang_getCursorKind(cursor
) == CXCursor_ParmDecl
)
1857 return CXChildVisit_Continue
;
1858 PrintCursor(cursor
, NULL
);
1859 Manglings
= clang_Cursor_getCXXManglings(cursor
);
1861 for (I
= 0, E
= Manglings
->Count
; I
< E
; ++I
)
1862 printf(" [mangled=%s]", clang_getCString(Manglings
->Strings
[I
]));
1863 clang_disposeStringSet(Manglings
);
1866 Manglings
= clang_Cursor_getObjCManglings(cursor
);
1868 for (I
= 0, E
= Manglings
->Count
; I
< E
; ++I
)
1869 printf(" [mangled=%s]", clang_getCString(Manglings
->Strings
[I
]));
1870 clang_disposeStringSet(Manglings
);
1873 return CXChildVisit_Recurse
;
1876 static enum CXChildVisitResult
1877 PrintSingleSymbolSGFs(CXCursor cursor
, CXCursor parent
, CXClientData data
) {
1878 CXString SGFData
= clang_getSymbolGraphForCursor(cursor
);
1879 const char *SGF
= clang_getCString(SGFData
);
1881 printf("%s\n", SGF
);
1883 clang_disposeString(SGFData
);
1885 return CXChildVisit_Recurse
;
1888 /******************************************************************************/
1889 /* Bitwidth testing. */
1890 /******************************************************************************/
1892 static enum CXChildVisitResult
PrintBitWidth(CXCursor cursor
, CXCursor p
,
1895 if (clang_getCursorKind(cursor
) != CXCursor_FieldDecl
)
1896 return CXChildVisit_Recurse
;
1898 Bitwidth
= clang_getFieldDeclBitWidth(cursor
);
1899 if (Bitwidth
>= 0) {
1900 PrintCursor(cursor
, NULL
);
1901 printf(" bitwidth=%d\n", Bitwidth
);
1904 return CXChildVisit_Recurse
;
1907 /******************************************************************************/
1908 /* Type declaration testing */
1909 /******************************************************************************/
1911 static enum CXChildVisitResult
PrintTypeDeclaration(CXCursor cursor
, CXCursor p
,
1913 CXCursor typeDeclaration
= clang_getTypeDeclaration(clang_getCursorType(cursor
));
1915 if (clang_isDeclaration(typeDeclaration
.kind
)) {
1916 PrintCursor(cursor
, NULL
);
1917 PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration
), " [typedeclaration=%s] [typekind=%s]\n");
1920 return CXChildVisit_Recurse
;
1923 /******************************************************************************/
1924 /* Declaration attributes testing */
1925 /******************************************************************************/
1927 static enum CXChildVisitResult
PrintDeclAttributes(CXCursor cursor
, CXCursor p
,
1929 if (clang_isDeclaration(cursor
.kind
)) {
1931 PrintCursor(cursor
, NULL
);
1932 return CXChildVisit_Recurse
;
1933 } else if (clang_isAttribute(cursor
.kind
)) {
1935 PrintCursor(cursor
, NULL
);
1937 return CXChildVisit_Continue
;
1940 /******************************************************************************/
1941 /* Target information testing. */
1942 /******************************************************************************/
1944 static int print_target_info(int argc
, const char **argv
) {
1946 CXTranslationUnit TU
;
1947 CXTargetInfo TargetInfo
;
1949 const char *FileName
;
1950 enum CXErrorCode Err
;
1954 fprintf(stderr
, "No filename specified\n");
1960 Idx
= clang_createIndex(0, 1);
1961 Err
= clang_parseTranslationUnit2(Idx
, FileName
, argv
, argc
, NULL
, 0,
1962 getDefaultParsingOptions(), &TU
);
1963 if (Err
!= CXError_Success
) {
1964 fprintf(stderr
, "Couldn't parse translation unit!\n");
1965 describeLibclangFailure(Err
);
1966 clang_disposeIndex(Idx
);
1970 TargetInfo
= clang_getTranslationUnitTargetInfo(TU
);
1972 Triple
= clang_TargetInfo_getTriple(TargetInfo
);
1973 printf("TargetTriple: %s\n", clang_getCString(Triple
));
1974 clang_disposeString(Triple
);
1976 PointerWidth
= clang_TargetInfo_getPointerWidth(TargetInfo
);
1977 printf("PointerWidth: %d\n", PointerWidth
);
1979 clang_TargetInfo_dispose(TargetInfo
);
1980 clang_disposeTranslationUnit(TU
);
1981 clang_disposeIndex(Idx
);
1985 /******************************************************************************/
1986 /* Loading ASTs/source. */
1987 /******************************************************************************/
1989 static int perform_test_load(CXIndex Idx
, CXTranslationUnit TU
,
1990 const char *filter
, const char *prefix
,
1991 CXCursorVisitor Visitor
,
1993 const char *CommentSchemaFile
) {
1996 FileCheckPrefix
= prefix
;
1999 enum CXCursorKind K
= CXCursor_NotImplemented
;
2000 enum CXCursorKind
*ck
= &K
;
2003 /* Perform some simple filtering. */
2004 if (!strcmp(filter
, "all") || !strcmp(filter
, "local")) ck
= NULL
;
2005 else if (!strcmp(filter
, "all-display") ||
2006 !strcmp(filter
, "local-display")) {
2008 wanted_display_type
= DisplayType_DisplayName
;
2010 else if (!strcmp(filter
, "all-pretty") ||
2011 !strcmp(filter
, "local-pretty")) {
2013 wanted_display_type
= DisplayType_Pretty
;
2015 else if (!strcmp(filter
, "none")) K
= (enum CXCursorKind
) ~0;
2016 else if (!strcmp(filter
, "category")) K
= CXCursor_ObjCCategoryDecl
;
2017 else if (!strcmp(filter
, "interface")) K
= CXCursor_ObjCInterfaceDecl
;
2018 else if (!strcmp(filter
, "protocol")) K
= CXCursor_ObjCProtocolDecl
;
2019 else if (!strcmp(filter
, "function")) K
= CXCursor_FunctionDecl
;
2020 else if (!strcmp(filter
, "typedef")) K
= CXCursor_TypedefDecl
;
2021 else if (!strcmp(filter
, "scan-function")) Visitor
= FunctionScanVisitor
;
2023 fprintf(stderr
, "Unknown filter for -test-load-tu: %s\n", filter
);
2029 Data
.CommentSchemaFile
= CommentSchemaFile
;
2030 clang_visitChildren(clang_getTranslationUnitCursor(TU
), Visitor
, &Data
);
2036 PrintDiagnostics(TU
);
2037 if (checkForErrors(TU
) != 0) {
2038 clang_disposeTranslationUnit(TU
);
2042 clang_disposeTranslationUnit(TU
);
2046 int perform_test_load_tu(const char *file
, const char *filter
,
2047 const char *prefix
, CXCursorVisitor Visitor
,
2050 CXTranslationUnit TU
;
2052 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
2053 !strcmp(filter
, "local") ? 1 : 0,
2054 /* displayDiagnostics=*/1);
2056 if (!CreateTranslationUnit(Idx
, file
, &TU
)) {
2057 clang_disposeIndex(Idx
);
2061 result
= perform_test_load(Idx
, TU
, filter
, prefix
, Visitor
, PV
, NULL
);
2062 clang_disposeIndex(Idx
);
2066 int perform_test_load_source(int argc
, const char **argv
,
2067 const char *filter
, CXCursorVisitor Visitor
,
2070 CXTranslationUnit TU
;
2071 const char *CommentSchemaFile
;
2072 struct CXUnsavedFile
*unsaved_files
= 0;
2073 int num_unsaved_files
= 0;
2074 enum CXErrorCode Err
;
2076 unsigned Repeats
= 0;
2080 createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */
2081 (!strcmp(filter
, "local") ||
2082 !strcmp(filter
, "local-display") ||
2083 !strcmp(filter
, "local-pretty"))
2086 /* displayDiagnostics=*/1);
2090 if ((CommentSchemaFile
= parse_comments_schema(argc
, argv
))) {
2095 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
2096 clang_disposeIndex(Idx
);
2100 if (getenv("CINDEXTEST_EDITING"))
2103 Err
= clang_parseTranslationUnit2(Idx
, 0,
2104 argv
+ num_unsaved_files
,
2105 argc
- num_unsaved_files
,
2106 unsaved_files
, num_unsaved_files
,
2107 getDefaultParsingOptions(), &TU
);
2108 if (Err
!= CXError_Success
) {
2109 fprintf(stderr
, "Unable to load translation unit!\n");
2110 describeLibclangFailure(Err
);
2111 free_remapped_files(unsaved_files
, num_unsaved_files
);
2112 clang_disposeIndex(Idx
);
2116 for (I
= 0; I
!= Repeats
; ++I
) {
2117 if (checkForErrors(TU
) != 0)
2121 clang_suspendTranslationUnit(TU
);
2123 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
2124 clang_defaultReparseOptions(TU
));
2125 if (Err
!= CXError_Success
) {
2126 describeLibclangFailure(Err
);
2127 free_remapped_files(unsaved_files
, num_unsaved_files
);
2128 clang_disposeIndex(Idx
);
2134 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
,
2136 free_remapped_files(unsaved_files
, num_unsaved_files
);
2137 clang_disposeIndex(Idx
);
2141 int perform_test_reparse_source(int argc
, const char **argv
, int trials
,
2142 const char *filter
, CXCursorVisitor Visitor
,
2145 CXTranslationUnit TU
;
2146 struct CXUnsavedFile
*unsaved_files
= 0;
2147 int num_unsaved_files
= 0;
2148 int compiler_arg_idx
= 0;
2149 enum CXErrorCode Err
;
2152 int execute_after_trial
= 0;
2153 const char *execute_command
= NULL
;
2154 int remap_after_trial
= 0;
2157 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
2158 !strcmp(filter
, "local") ? 1 : 0,
2159 /* displayDiagnostics=*/1);
2161 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
2162 clang_disposeIndex(Idx
);
2166 for (i
= 0; i
< argc
; ++i
) {
2167 if (strcmp(argv
[i
], "--") == 0)
2171 compiler_arg_idx
= i
+1;
2172 if (num_unsaved_files
> compiler_arg_idx
)
2173 compiler_arg_idx
= num_unsaved_files
;
2175 /* Load the initial translation unit -- we do this without honoring remapped
2176 * files, so that we have a way to test results after changing the source. */
2177 Err
= clang_parseTranslationUnit2(Idx
, 0,
2178 argv
+ compiler_arg_idx
,
2179 argc
- compiler_arg_idx
,
2180 0, 0, getDefaultParsingOptions(), &TU
);
2181 if (Err
!= CXError_Success
) {
2182 fprintf(stderr
, "Unable to load translation unit!\n");
2183 describeLibclangFailure(Err
);
2184 free_remapped_files(unsaved_files
, num_unsaved_files
);
2185 clang_disposeIndex(Idx
);
2189 if (checkForErrors(TU
) != 0)
2192 if (getenv("CINDEXTEST_EXECUTE_COMMAND")) {
2193 execute_command
= getenv("CINDEXTEST_EXECUTE_COMMAND");
2195 if (getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL")) {
2196 execute_after_trial
=
2197 strtol(getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL"), &endptr
, 10);
2200 if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
2202 strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr
, 10);
2205 for (trial
= 0; trial
< trials
; ++trial
) {
2206 if (execute_command
&& trial
== execute_after_trial
) {
2207 result
= indextest_perform_shell_execution(execute_command
);
2212 free_remapped_files(unsaved_files
, num_unsaved_files
);
2213 if (parse_remapped_files_with_try(trial
, argc
, argv
, 0,
2214 &unsaved_files
, &num_unsaved_files
)) {
2215 clang_disposeTranslationUnit(TU
);
2216 clang_disposeIndex(Idx
);
2220 Err
= clang_reparseTranslationUnit(
2222 trial
>= remap_after_trial
? num_unsaved_files
: 0,
2223 trial
>= remap_after_trial
? unsaved_files
: 0,
2224 clang_defaultReparseOptions(TU
));
2225 if (Err
!= CXError_Success
) {
2226 fprintf(stderr
, "Unable to reparse translation unit!\n");
2227 describeLibclangFailure(Err
);
2228 clang_disposeTranslationUnit(TU
);
2229 free_remapped_files(unsaved_files
, num_unsaved_files
);
2230 clang_disposeIndex(Idx
);
2234 if (checkForErrors(TU
) != 0)
2238 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
, NULL
);
2240 free_remapped_files(unsaved_files
, num_unsaved_files
);
2241 clang_disposeIndex(Idx
);
2245 static int perform_single_file_parse(const char *filename
) {
2247 CXTranslationUnit TU
;
2248 enum CXErrorCode Err
;
2251 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1,
2252 /* displayDiagnostics=*/1);
2254 Err
= clang_parseTranslationUnit2(Idx
, filename
,
2255 /*command_line_args=*/NULL
,
2256 /*num_command_line_args=*/0,
2257 /*unsaved_files=*/NULL
,
2258 /*num_unsaved_files=*/0,
2259 CXTranslationUnit_SingleFileParse
, &TU
);
2260 if (Err
!= CXError_Success
) {
2261 fprintf(stderr
, "Unable to load translation unit!\n");
2262 describeLibclangFailure(Err
);
2263 clang_disposeIndex(Idx
);
2267 result
= perform_test_load(Idx
, TU
, /*filter=*/"all", /*prefix=*/NULL
, FilteredPrintingVisitor
, /*PostVisit=*/NULL
,
2268 /*CommentSchemaFile=*/NULL
);
2269 clang_disposeIndex(Idx
);
2273 static int perform_file_retain_excluded_cb(const char *filename
) {
2275 CXTranslationUnit TU
;
2276 enum CXErrorCode Err
;
2279 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1,
2280 /* displayDiagnostics=*/1);
2282 Err
= clang_parseTranslationUnit2(Idx
, filename
,
2283 /*command_line_args=*/NULL
,
2284 /*num_command_line_args=*/0,
2285 /*unsaved_files=*/NULL
,
2286 /*num_unsaved_files=*/0,
2287 CXTranslationUnit_RetainExcludedConditionalBlocks
, &TU
);
2288 if (Err
!= CXError_Success
) {
2289 fprintf(stderr
, "Unable to load translation unit!\n");
2290 describeLibclangFailure(Err
);
2291 clang_disposeIndex(Idx
);
2295 result
= perform_test_load(Idx
, TU
, /*filter=*/"all", /*prefix=*/NULL
, FilteredPrintingVisitor
, /*PostVisit=*/NULL
,
2296 /*CommentSchemaFile=*/NULL
);
2297 clang_disposeIndex(Idx
);
2301 /******************************************************************************/
2302 /* Logic for testing clang_getCursor(). */
2303 /******************************************************************************/
2305 static void print_cursor_file_scan(CXTranslationUnit TU
, CXCursor cursor
,
2306 unsigned start_line
, unsigned start_col
,
2307 unsigned end_line
, unsigned end_col
,
2308 const char *prefix
) {
2309 printf("// %s: ", FileCheckPrefix
);
2311 printf("-%s", prefix
);
2312 PrintExtent(stdout
, start_line
, start_col
, end_line
, end_col
);
2314 PrintCursor(cursor
, NULL
);
2318 static int perform_file_scan(const char *ast_file
, const char *source_file
,
2319 const char *prefix
) {
2321 CXTranslationUnit TU
;
2323 CXCursor prevCursor
= clang_getNullCursor();
2325 unsigned line
= 1, col
= 1;
2326 unsigned start_line
= 1, start_col
= 1;
2328 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
2329 /* displayDiagnostics=*/1))) {
2330 fprintf(stderr
, "Could not create Index\n");
2334 if (!CreateTranslationUnit(Idx
, ast_file
, &TU
))
2337 if ((fp
= fopen(source_file
, "r")) == NULL
) {
2338 fprintf(stderr
, "Could not open '%s'\n", source_file
);
2339 clang_disposeTranslationUnit(TU
);
2343 file
= clang_getFile(TU
, source_file
);
2354 /* Check the cursor at this position, and dump the previous one if we have
2355 * found something new.
2357 cursor
= clang_getCursor(TU
, clang_getLocation(TU
, file
, line
, col
));
2358 if ((c
== EOF
|| !clang_equalCursors(cursor
, prevCursor
)) &&
2359 prevCursor
.kind
!= CXCursor_InvalidFile
) {
2360 print_cursor_file_scan(TU
, prevCursor
, start_line
, start_col
,
2368 prevCursor
= cursor
;
2372 clang_disposeTranslationUnit(TU
);
2373 clang_disposeIndex(Idx
);
2377 /******************************************************************************/
2378 /* Logic for testing clang code completion. */
2379 /******************************************************************************/
2381 /* Parse file:line:column from the input string. Returns 0 on success, non-zero
2382 on failure. If successful, the pointer *filename will contain newly-allocated
2383 memory (that will be owned by the caller) to store the file name. */
2384 int parse_file_line_column(const char *input
, char **filename
, unsigned *line
,
2385 unsigned *column
, unsigned *second_line
,
2386 unsigned *second_column
) {
2387 /* Find the second colon. */
2388 const char *last_colon
= strrchr(input
, ':');
2389 unsigned values
[4], i
;
2390 unsigned num_values
= (second_line
&& second_column
)? 4 : 2;
2393 if (!last_colon
|| last_colon
== input
) {
2394 if (num_values
== 4)
2395 fprintf(stderr
, "could not parse filename:line:column:line:column in "
2398 fprintf(stderr
, "could not parse filename:line:column in '%s'\n", input
);
2402 for (i
= 0; i
!= num_values
; ++i
) {
2403 const char *prev_colon
;
2405 /* Parse the next line or column. */
2406 values
[num_values
- i
- 1] = strtol(last_colon
+ 1, &endptr
, 10);
2407 if (*endptr
!= 0 && *endptr
!= ':') {
2408 fprintf(stderr
, "could not parse %s in '%s'\n",
2409 (i
% 2 ? "column" : "line"), input
);
2413 if (i
+ 1 == num_values
)
2416 /* Find the previous colon. */
2417 prev_colon
= last_colon
- 1;
2418 while (prev_colon
!= input
&& *prev_colon
!= ':')
2420 if (prev_colon
== input
) {
2421 fprintf(stderr
, "could not parse %s in '%s'\n",
2422 (i
% 2 == 0? "column" : "line"), input
);
2426 last_colon
= prev_colon
;
2430 *column
= values
[1];
2432 if (second_line
&& second_column
) {
2433 *second_line
= values
[2];
2434 *second_column
= values
[3];
2437 /* Copy the file name. */
2438 *filename
= (char*)malloc(last_colon
- input
+ 1);
2440 memcpy(*filename
, input
, last_colon
- input
);
2441 (*filename
)[last_colon
- input
] = 0;
2446 clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind
) {
2448 case CXCompletionChunk_Optional
: return "Optional";
2449 case CXCompletionChunk_TypedText
: return "TypedText";
2450 case CXCompletionChunk_Text
: return "Text";
2451 case CXCompletionChunk_Placeholder
: return "Placeholder";
2452 case CXCompletionChunk_Informative
: return "Informative";
2453 case CXCompletionChunk_CurrentParameter
: return "CurrentParameter";
2454 case CXCompletionChunk_LeftParen
: return "LeftParen";
2455 case CXCompletionChunk_RightParen
: return "RightParen";
2456 case CXCompletionChunk_LeftBracket
: return "LeftBracket";
2457 case CXCompletionChunk_RightBracket
: return "RightBracket";
2458 case CXCompletionChunk_LeftBrace
: return "LeftBrace";
2459 case CXCompletionChunk_RightBrace
: return "RightBrace";
2460 case CXCompletionChunk_LeftAngle
: return "LeftAngle";
2461 case CXCompletionChunk_RightAngle
: return "RightAngle";
2462 case CXCompletionChunk_Comma
: return "Comma";
2463 case CXCompletionChunk_ResultType
: return "ResultType";
2464 case CXCompletionChunk_Colon
: return "Colon";
2465 case CXCompletionChunk_SemiColon
: return "SemiColon";
2466 case CXCompletionChunk_Equal
: return "Equal";
2467 case CXCompletionChunk_HorizontalSpace
: return "HorizontalSpace";
2468 case CXCompletionChunk_VerticalSpace
: return "VerticalSpace";
2474 static int checkForErrors(CXTranslationUnit TU
) {
2479 if (!getenv("CINDEXTEST_FAILONERROR"))
2482 Num
= clang_getNumDiagnostics(TU
);
2483 for (i
= 0; i
!= Num
; ++i
) {
2484 Diag
= clang_getDiagnostic(TU
, i
);
2485 if (clang_getDiagnosticSeverity(Diag
) >= CXDiagnostic_Error
) {
2486 DiagStr
= clang_formatDiagnostic(Diag
,
2487 clang_defaultDiagnosticDisplayOptions());
2488 fprintf(stderr
, "%s\n", clang_getCString(DiagStr
));
2489 clang_disposeString(DiagStr
);
2490 clang_disposeDiagnostic(Diag
);
2493 clang_disposeDiagnostic(Diag
);
2499 static void print_completion_string(CXCompletionString completion_string
,
2503 N
= clang_getNumCompletionChunks(completion_string
);
2504 for (I
= 0; I
!= N
; ++I
) {
2507 enum CXCompletionChunkKind Kind
2508 = clang_getCompletionChunkKind(completion_string
, I
);
2510 if (Kind
== CXCompletionChunk_Optional
) {
2511 fprintf(file
, "{Optional ");
2512 print_completion_string(
2513 clang_getCompletionChunkCompletionString(completion_string
, I
),
2519 if (Kind
== CXCompletionChunk_VerticalSpace
) {
2520 fprintf(file
, "{VerticalSpace }");
2524 text
= clang_getCompletionChunkText(completion_string
, I
);
2525 cstr
= clang_getCString(text
);
2526 fprintf(file
, "{%s %s}",
2527 clang_getCompletionChunkKindSpelling(Kind
),
2529 clang_disposeString(text
);
2534 static void print_line_column(CXSourceLocation location
, FILE *file
) {
2535 unsigned line
, column
;
2536 clang_getExpansionLocation(location
, NULL
, &line
, &column
, NULL
);
2537 fprintf(file
, "%d:%d", line
, column
);
2540 static void print_token_range(CXTranslationUnit translation_unit
,
2541 CXSourceLocation start
, FILE *file
) {
2542 CXToken
*token
= clang_getToken(translation_unit
, start
);
2545 if (token
!= NULL
) {
2546 CXSourceRange token_range
= clang_getTokenExtent(translation_unit
, *token
);
2547 print_line_column(clang_getRangeStart(token_range
), file
);
2549 print_line_column(clang_getRangeEnd(token_range
), file
);
2550 clang_disposeTokens(translation_unit
, token
, 1);
2556 static void print_completion_result(CXTranslationUnit translation_unit
,
2557 CXCodeCompleteResults
*completion_results
,
2560 CXCompletionResult
*completion_result
= completion_results
->Results
+ index
;
2561 CXString ks
= clang_getCursorKindSpelling(completion_result
->CursorKind
);
2562 unsigned annotationCount
;
2563 enum CXCursorKind ParentKind
;
2564 CXString ParentName
;
2565 CXString BriefComment
;
2566 CXString Annotation
;
2567 const char *BriefCommentCString
;
2570 fprintf(file
, "%s:", clang_getCString(ks
));
2571 clang_disposeString(ks
);
2573 print_completion_string(completion_result
->CompletionString
, file
);
2574 fprintf(file
, " (%u)",
2575 clang_getCompletionPriority(completion_result
->CompletionString
));
2576 switch (clang_getCompletionAvailability(completion_result
->CompletionString
)){
2577 case CXAvailability_Available
:
2580 case CXAvailability_Deprecated
:
2581 fprintf(file
, " (deprecated)");
2584 case CXAvailability_NotAvailable
:
2585 fprintf(file
, " (unavailable)");
2588 case CXAvailability_NotAccessible
:
2589 fprintf(file
, " (inaccessible)");
2593 annotationCount
= clang_getCompletionNumAnnotations(
2594 completion_result
->CompletionString
);
2595 if (annotationCount
) {
2597 fprintf(file
, " (");
2598 for (i
= 0; i
< annotationCount
; ++i
) {
2600 fprintf(file
, ", ");
2602 clang_getCompletionAnnotation(completion_result
->CompletionString
, i
);
2603 fprintf(file
, "\"%s\"", clang_getCString(Annotation
));
2604 clang_disposeString(Annotation
);
2609 if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
2610 ParentName
= clang_getCompletionParent(completion_result
->CompletionString
,
2612 if (ParentKind
!= CXCursor_NotImplemented
) {
2613 CXString KindSpelling
= clang_getCursorKindSpelling(ParentKind
);
2614 fprintf(file
, " (parent: %s '%s')",
2615 clang_getCString(KindSpelling
),
2616 clang_getCString(ParentName
));
2617 clang_disposeString(KindSpelling
);
2619 clang_disposeString(ParentName
);
2622 BriefComment
= clang_getCompletionBriefComment(
2623 completion_result
->CompletionString
);
2624 BriefCommentCString
= clang_getCString(BriefComment
);
2625 if (BriefCommentCString
&& *BriefCommentCString
!= '\0') {
2626 fprintf(file
, "(brief comment: %s)", BriefCommentCString
);
2628 clang_disposeString(BriefComment
);
2630 for (i
= 0; i
< clang_getCompletionNumFixIts(completion_results
, index
);
2632 CXSourceRange correction_range
;
2633 CXString FixIt
= clang_getCompletionFixIt(completion_results
, index
, i
,
2635 fprintf(file
, " (requires fix-it: ");
2636 print_token_range(translation_unit
, clang_getRangeStart(correction_range
),
2638 fprintf(file
, " to \"%s\")", clang_getCString(FixIt
));
2639 clang_disposeString(FixIt
);
2642 fprintf(file
, "\n");
2645 void print_completion_contexts(unsigned long long contexts
, FILE *file
) {
2646 fprintf(file
, "Completion contexts:\n");
2647 if (contexts
== CXCompletionContext_Unknown
) {
2648 fprintf(file
, "Unknown\n");
2650 if (contexts
& CXCompletionContext_AnyType
) {
2651 fprintf(file
, "Any type\n");
2653 if (contexts
& CXCompletionContext_AnyValue
) {
2654 fprintf(file
, "Any value\n");
2656 if (contexts
& CXCompletionContext_ObjCObjectValue
) {
2657 fprintf(file
, "Objective-C object value\n");
2659 if (contexts
& CXCompletionContext_ObjCSelectorValue
) {
2660 fprintf(file
, "Objective-C selector value\n");
2662 if (contexts
& CXCompletionContext_CXXClassTypeValue
) {
2663 fprintf(file
, "C++ class type value\n");
2665 if (contexts
& CXCompletionContext_DotMemberAccess
) {
2666 fprintf(file
, "Dot member access\n");
2668 if (contexts
& CXCompletionContext_ArrowMemberAccess
) {
2669 fprintf(file
, "Arrow member access\n");
2671 if (contexts
& CXCompletionContext_ObjCPropertyAccess
) {
2672 fprintf(file
, "Objective-C property access\n");
2674 if (contexts
& CXCompletionContext_EnumTag
) {
2675 fprintf(file
, "Enum tag\n");
2677 if (contexts
& CXCompletionContext_UnionTag
) {
2678 fprintf(file
, "Union tag\n");
2680 if (contexts
& CXCompletionContext_StructTag
) {
2681 fprintf(file
, "Struct tag\n");
2683 if (contexts
& CXCompletionContext_ClassTag
) {
2684 fprintf(file
, "Class name\n");
2686 if (contexts
& CXCompletionContext_Namespace
) {
2687 fprintf(file
, "Namespace or namespace alias\n");
2689 if (contexts
& CXCompletionContext_NestedNameSpecifier
) {
2690 fprintf(file
, "Nested name specifier\n");
2692 if (contexts
& CXCompletionContext_ObjCInterface
) {
2693 fprintf(file
, "Objective-C interface\n");
2695 if (contexts
& CXCompletionContext_ObjCProtocol
) {
2696 fprintf(file
, "Objective-C protocol\n");
2698 if (contexts
& CXCompletionContext_ObjCCategory
) {
2699 fprintf(file
, "Objective-C category\n");
2701 if (contexts
& CXCompletionContext_ObjCInstanceMessage
) {
2702 fprintf(file
, "Objective-C instance method\n");
2704 if (contexts
& CXCompletionContext_ObjCClassMessage
) {
2705 fprintf(file
, "Objective-C class method\n");
2707 if (contexts
& CXCompletionContext_ObjCSelectorName
) {
2708 fprintf(file
, "Objective-C selector name\n");
2710 if (contexts
& CXCompletionContext_MacroName
) {
2711 fprintf(file
, "Macro name\n");
2713 if (contexts
& CXCompletionContext_NaturalLanguage
) {
2714 fprintf(file
, "Natural language\n");
2718 int perform_code_completion(int argc
, const char **argv
, int timing_only
) {
2719 const char *input
= argv
[1];
2725 struct CXUnsavedFile
*unsaved_files
= 0;
2726 int num_unsaved_files
= 0;
2727 CXCodeCompleteResults
*results
= 0;
2728 enum CXErrorCode Err
;
2729 CXTranslationUnit TU
;
2730 unsigned I
, Repeats
= 1;
2731 unsigned completionOptions
= clang_defaultCodeCompleteOptions();
2733 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
2734 completionOptions
|= CXCodeComplete_IncludeCodePatterns
;
2735 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
2736 completionOptions
|= CXCodeComplete_IncludeBriefComments
;
2737 if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
2738 completionOptions
|= CXCodeComplete_SkipPreamble
;
2739 if (getenv("CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
2740 completionOptions
|= CXCodeComplete_IncludeCompletionsWithFixIts
;
2743 input
+= strlen("-code-completion-timing=");
2745 input
+= strlen("-code-completion-at=");
2747 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
2751 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
))
2754 CIdx
= createIndexWithInvocationEmissionPath(0, 0);
2758 if (getenv("CINDEXTEST_EDITING"))
2761 Err
= clang_parseTranslationUnit2(CIdx
, 0,
2762 argv
+ num_unsaved_files
+ 2,
2763 argc
- num_unsaved_files
- 2,
2764 0, 0, getDefaultParsingOptions(), &TU
);
2765 if (Err
!= CXError_Success
) {
2766 fprintf(stderr
, "Unable to load translation unit!\n");
2767 describeLibclangFailure(Err
);
2771 Err
= clang_reparseTranslationUnit(TU
, 0, 0,
2772 clang_defaultReparseOptions(TU
));
2774 if (Err
!= CXError_Success
) {
2775 fprintf(stderr
, "Unable to reparse translation unit!\n");
2776 describeLibclangFailure(Err
);
2777 clang_disposeTranslationUnit(TU
);
2781 for (I
= 0; I
!= Repeats
; ++I
) {
2782 results
= clang_codeCompleteAt(TU
, filename
, line
, column
,
2783 unsaved_files
, num_unsaved_files
,
2786 fprintf(stderr
, "Unable to perform code completion!\n");
2790 clang_disposeCodeCompleteResults(results
);
2794 unsigned i
, n
= results
->NumResults
, containerIsIncomplete
= 0;
2795 unsigned long long contexts
;
2796 enum CXCursorKind containerKind
;
2797 CXString objCSelector
;
2798 const char *selectorString
;
2800 /* Sort the code-completion results based on the typed text. */
2801 clang_sortCodeCompletionResults(results
->Results
, results
->NumResults
);
2803 for (i
= 0; i
!= n
; ++i
)
2804 print_completion_result(TU
, results
, i
, stdout
);
2806 n
= clang_codeCompleteGetNumDiagnostics(results
);
2807 for (i
= 0; i
!= n
; ++i
) {
2808 CXDiagnostic diag
= clang_codeCompleteGetDiagnostic(results
, i
);
2809 PrintDiagnostic(diag
);
2810 clang_disposeDiagnostic(diag
);
2813 contexts
= clang_codeCompleteGetContexts(results
);
2814 print_completion_contexts(contexts
, stdout
);
2816 containerKind
= clang_codeCompleteGetContainerKind(results
,
2817 &containerIsIncomplete
);
2819 if (containerKind
!= CXCursor_InvalidCode
) {
2820 /* We have found a container */
2821 CXString containerUSR
, containerKindSpelling
;
2822 containerKindSpelling
= clang_getCursorKindSpelling(containerKind
);
2823 printf("Container Kind: %s\n", clang_getCString(containerKindSpelling
));
2824 clang_disposeString(containerKindSpelling
);
2826 if (containerIsIncomplete
) {
2827 printf("Container is incomplete\n");
2830 printf("Container is complete\n");
2833 containerUSR
= clang_codeCompleteGetContainerUSR(results
);
2834 printf("Container USR: %s\n", clang_getCString(containerUSR
));
2835 clang_disposeString(containerUSR
);
2838 objCSelector
= clang_codeCompleteGetObjCSelector(results
);
2839 selectorString
= clang_getCString(objCSelector
);
2840 if (selectorString
&& strlen(selectorString
) > 0) {
2841 printf("Objective-C selector: %s\n", selectorString
);
2843 clang_disposeString(objCSelector
);
2845 clang_disposeCodeCompleteResults(results
);
2847 clang_disposeTranslationUnit(TU
);
2848 clang_disposeIndex(CIdx
);
2851 free_remapped_files(unsaved_files
, num_unsaved_files
);
2860 } CursorSourceLocation
;
2862 typedef void (*cursor_handler_t
)(CXCursor cursor
);
2864 static int inspect_cursor_at(int argc
, const char **argv
,
2865 const char *locations_flag
,
2866 cursor_handler_t handler
) {
2869 struct CXUnsavedFile
*unsaved_files
= 0;
2870 int num_unsaved_files
= 0;
2871 enum CXErrorCode Err
;
2872 CXTranslationUnit TU
;
2874 CursorSourceLocation
*Locations
= 0;
2875 unsigned NumLocations
= 0, Loc
;
2876 unsigned Repeats
= 1;
2879 /* Count the number of locations. */
2880 while (strstr(argv
[NumLocations
+1], locations_flag
) == argv
[NumLocations
+1])
2883 /* Parse the locations. */
2884 assert(NumLocations
> 0 && "Unable to count locations?");
2885 Locations
= (CursorSourceLocation
*)malloc(
2886 NumLocations
* sizeof(CursorSourceLocation
));
2888 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
2889 const char *input
= argv
[Loc
+ 1] + strlen(locations_flag
);
2890 if ((errorCode
= parse_file_line_column(input
, &Locations
[Loc
].filename
,
2891 &Locations
[Loc
].line
,
2892 &Locations
[Loc
].column
, 0, 0)))
2896 if (parse_remapped_files(argc
, argv
, NumLocations
+ 1, &unsaved_files
,
2897 &num_unsaved_files
))
2900 if (getenv("CINDEXTEST_EDITING"))
2903 /* Parse the translation unit. When we're testing clang_getCursor() after
2904 reparsing, don't remap unsaved files until the second parse. */
2905 CIdx
= clang_createIndex(1, 1);
2906 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
2907 argv
+ num_unsaved_files
+ 1 + NumLocations
,
2908 argc
- num_unsaved_files
- 2 - NumLocations
,
2910 Repeats
> 1? 0 : num_unsaved_files
,
2911 getDefaultParsingOptions(), &TU
);
2912 if (Err
!= CXError_Success
) {
2913 fprintf(stderr
, "unable to parse input\n");
2914 describeLibclangFailure(Err
);
2918 if (checkForErrors(TU
) != 0)
2921 for (I
= 0; I
!= Repeats
; ++I
) {
2923 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
2924 clang_defaultReparseOptions(TU
));
2925 if (Err
!= CXError_Success
) {
2926 describeLibclangFailure(Err
);
2927 clang_disposeTranslationUnit(TU
);
2932 if (checkForErrors(TU
) != 0)
2935 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
2936 CXFile file
= clang_getFile(TU
, Locations
[Loc
].filename
);
2940 Cursor
= clang_getCursor(TU
,
2941 clang_getLocation(TU
, file
, Locations
[Loc
].line
,
2942 Locations
[Loc
].column
));
2944 if (checkForErrors(TU
) != 0)
2947 if (I
+ 1 == Repeats
) {
2949 free(Locations
[Loc
].filename
);
2954 PrintDiagnostics(TU
);
2955 clang_disposeTranslationUnit(TU
);
2956 clang_disposeIndex(CIdx
);
2958 free_remapped_files(unsaved_files
, num_unsaved_files
);
2962 static void inspect_print_cursor(CXCursor Cursor
) {
2963 CXTranslationUnit TU
= clang_Cursor_getTranslationUnit(Cursor
);
2964 CXCompletionString completionString
= clang_getCursorCompletionString(
2966 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
2969 unsigned line
, column
;
2970 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
2971 printf("%d:%d ", line
, column
);
2972 PrintCursor(Cursor
, NULL
);
2973 PrintCursorExtent(Cursor
);
2974 Spelling
= clang_getCursorSpelling(Cursor
);
2975 cspell
= clang_getCString(Spelling
);
2976 if (cspell
&& strlen(cspell
) != 0) {
2977 unsigned pieceIndex
;
2978 printf(" Spelling=%s (", cspell
);
2979 for (pieceIndex
= 0; ; ++pieceIndex
) {
2980 CXSourceRange range
=
2981 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
2982 if (clang_Range_isNull(range
))
2984 PrintRange(range
, 0);
2988 clang_disposeString(Spelling
);
2989 if (clang_Cursor_getObjCSelectorIndex(Cursor
) != -1)
2990 printf(" Selector index=%d",
2991 clang_Cursor_getObjCSelectorIndex(Cursor
));
2992 if (clang_Cursor_isDynamicCall(Cursor
))
2993 printf(" Dynamic-call");
2994 if (Cursor
.kind
== CXCursor_ObjCMessageExpr
||
2995 Cursor
.kind
== CXCursor_MemberRefExpr
) {
2996 CXType T
= clang_Cursor_getReceiverType(Cursor
);
2997 if (T
.kind
!= CXType_Invalid
) {
2998 CXString S
= clang_getTypeKindSpelling(T
.kind
);
2999 printf(" Receiver-type=%s", clang_getCString(S
));
3000 clang_disposeString(S
);
3005 CXModule mod
= clang_Cursor_getModule(Cursor
);
3007 CXString name
, astFilename
;
3008 unsigned i
, numHeaders
;
3010 astFile
= clang_Module_getASTFile(mod
);
3011 astFilename
= clang_getFileName(astFile
);
3012 name
= clang_Module_getFullName(mod
);
3013 numHeaders
= clang_Module_getNumTopLevelHeaders(TU
, mod
);
3014 printf(" ModuleName=%s (%s) system=%d Headers(%d):",
3015 clang_getCString(name
), clang_getCString(astFilename
),
3016 clang_Module_isSystem(mod
), numHeaders
);
3017 clang_disposeString(name
);
3018 clang_disposeString(astFilename
);
3019 for (i
= 0; i
< numHeaders
; ++i
) {
3020 CXFile file
= clang_Module_getTopLevelHeader(TU
, mod
, i
);
3021 CXString filename
= clang_getFileName(file
);
3022 printf("\n%s", clang_getCString(filename
));
3023 clang_disposeString(filename
);
3028 if (completionString
!= NULL
) {
3029 printf("\nCompletion string: ");
3030 print_completion_string(completionString
, stdout
);
3035 static void display_evaluate_results(CXEvalResult result
) {
3036 switch (clang_EvalResult_getKind(result
)) {
3039 printf("Kind: Int, ");
3040 if (clang_EvalResult_isUnsignedInt(result
)) {
3041 unsigned long long val
= clang_EvalResult_getAsUnsigned(result
);
3042 printf("unsigned, Value: %llu", val
);
3044 long long val
= clang_EvalResult_getAsLongLong(result
);
3045 printf("Value: %lld", val
);
3051 double val
= clang_EvalResult_getAsDouble(result
);
3052 printf("Kind: Float , Value: %f", val
);
3055 case CXEval_ObjCStrLiteral
:
3057 const char* str
= clang_EvalResult_getAsStr(result
);
3058 printf("Kind: ObjCString , Value: %s", str
);
3061 case CXEval_StrLiteral
:
3063 const char* str
= clang_EvalResult_getAsStr(result
);
3064 printf("Kind: CString , Value: %s", str
);
3069 const char* str
= clang_EvalResult_getAsStr(result
);
3070 printf("Kind: CFString , Value: %s", str
);
3074 printf("Unexposed");
3079 static void inspect_evaluate_cursor(CXCursor Cursor
) {
3080 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
3083 unsigned line
, column
;
3086 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
3087 printf("%d:%d ", line
, column
);
3088 PrintCursor(Cursor
, NULL
);
3089 PrintCursorExtent(Cursor
);
3090 Spelling
= clang_getCursorSpelling(Cursor
);
3091 cspell
= clang_getCString(Spelling
);
3092 if (cspell
&& strlen(cspell
) != 0) {
3093 unsigned pieceIndex
;
3094 printf(" Spelling=%s (", cspell
);
3095 for (pieceIndex
= 0; ; ++pieceIndex
) {
3096 CXSourceRange range
=
3097 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
3098 if (clang_Range_isNull(range
))
3100 PrintRange(range
, 0);
3104 clang_disposeString(Spelling
);
3106 ER
= clang_Cursor_Evaluate(Cursor
);
3108 printf("Not Evaluatable");
3110 display_evaluate_results(ER
);
3111 clang_EvalResult_dispose(ER
);
3116 static void inspect_macroinfo_cursor(CXCursor Cursor
) {
3117 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
3120 unsigned line
, column
;
3121 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
3122 printf("%d:%d ", line
, column
);
3123 PrintCursor(Cursor
, NULL
);
3124 PrintCursorExtent(Cursor
);
3125 Spelling
= clang_getCursorSpelling(Cursor
);
3126 cspell
= clang_getCString(Spelling
);
3127 if (cspell
&& strlen(cspell
) != 0) {
3128 unsigned pieceIndex
;
3129 printf(" Spelling=%s (", cspell
);
3130 for (pieceIndex
= 0; ; ++pieceIndex
) {
3131 CXSourceRange range
=
3132 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
3133 if (clang_Range_isNull(range
))
3135 PrintRange(range
, 0);
3139 clang_disposeString(Spelling
);
3141 if (clang_Cursor_isMacroBuiltin(Cursor
)) {
3142 printf("[builtin macro]");
3143 } else if (clang_Cursor_isMacroFunctionLike(Cursor
)) {
3144 printf("[function macro]");
3149 static enum CXVisitorResult
findFileRefsVisit(void *context
,
3150 CXCursor cursor
, CXSourceRange range
) {
3151 if (clang_Range_isNull(range
))
3152 return CXVisit_Continue
;
3154 PrintCursor(cursor
, NULL
);
3155 PrintRange(range
, "");
3157 return CXVisit_Continue
;
3160 static int find_file_refs_at(int argc
, const char **argv
) {
3163 struct CXUnsavedFile
*unsaved_files
= 0;
3164 int num_unsaved_files
= 0;
3165 enum CXErrorCode Err
;
3166 CXTranslationUnit TU
;
3168 CursorSourceLocation
*Locations
= 0;
3169 unsigned NumLocations
= 0, Loc
;
3170 unsigned Repeats
= 1;
3173 /* Count the number of locations. */
3174 while (strstr(argv
[NumLocations
+1], "-file-refs-at=") == argv
[NumLocations
+1])
3177 /* Parse the locations. */
3178 assert(NumLocations
> 0 && "Unable to count locations?");
3179 Locations
= (CursorSourceLocation
*)malloc(
3180 NumLocations
* sizeof(CursorSourceLocation
));
3182 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
3183 const char *input
= argv
[Loc
+ 1] + strlen("-file-refs-at=");
3184 if ((errorCode
= parse_file_line_column(input
, &Locations
[Loc
].filename
,
3185 &Locations
[Loc
].line
,
3186 &Locations
[Loc
].column
, 0, 0)))
3190 if (parse_remapped_files(argc
, argv
, NumLocations
+ 1, &unsaved_files
,
3191 &num_unsaved_files
))
3194 if (getenv("CINDEXTEST_EDITING"))
3197 /* Parse the translation unit. When we're testing clang_getCursor() after
3198 reparsing, don't remap unsaved files until the second parse. */
3199 CIdx
= clang_createIndex(1, 1);
3200 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
3201 argv
+ num_unsaved_files
+ 1 + NumLocations
,
3202 argc
- num_unsaved_files
- 2 - NumLocations
,
3204 Repeats
> 1? 0 : num_unsaved_files
,
3205 getDefaultParsingOptions(), &TU
);
3206 if (Err
!= CXError_Success
) {
3207 fprintf(stderr
, "unable to parse input\n");
3208 describeLibclangFailure(Err
);
3209 clang_disposeTranslationUnit(TU
);
3213 if (checkForErrors(TU
) != 0)
3216 for (I
= 0; I
!= Repeats
; ++I
) {
3218 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
3219 clang_defaultReparseOptions(TU
));
3220 if (Err
!= CXError_Success
) {
3221 describeLibclangFailure(Err
);
3222 clang_disposeTranslationUnit(TU
);
3227 if (checkForErrors(TU
) != 0)
3230 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
3231 CXFile file
= clang_getFile(TU
, Locations
[Loc
].filename
);
3235 Cursor
= clang_getCursor(TU
,
3236 clang_getLocation(TU
, file
, Locations
[Loc
].line
,
3237 Locations
[Loc
].column
));
3239 if (checkForErrors(TU
) != 0)
3242 if (I
+ 1 == Repeats
) {
3243 CXCursorAndRangeVisitor visitor
= { 0, findFileRefsVisit
};
3244 PrintCursor(Cursor
, NULL
);
3246 clang_findReferencesInFile(Cursor
, file
, visitor
);
3247 free(Locations
[Loc
].filename
);
3249 if (checkForErrors(TU
) != 0)
3255 PrintDiagnostics(TU
);
3256 clang_disposeTranslationUnit(TU
);
3257 clang_disposeIndex(CIdx
);
3259 free_remapped_files(unsaved_files
, num_unsaved_files
);
3263 static enum CXVisitorResult
findFileIncludesVisit(void *context
,
3264 CXCursor cursor
, CXSourceRange range
) {
3265 PrintCursor(cursor
, NULL
);
3266 PrintRange(range
, "");
3268 return CXVisit_Continue
;
3271 static int find_file_includes_in(int argc
, const char **argv
) {
3273 struct CXUnsavedFile
*unsaved_files
= 0;
3274 int num_unsaved_files
= 0;
3275 enum CXErrorCode Err
;
3276 CXTranslationUnit TU
;
3277 const char **Filenames
= 0;
3278 unsigned NumFilenames
= 0;
3279 unsigned Repeats
= 1;
3282 /* Count the number of locations. */
3283 while (strstr(argv
[NumFilenames
+1], "-file-includes-in=") == argv
[NumFilenames
+1])
3286 /* Parse the locations. */
3287 assert(NumFilenames
> 0 && "Unable to count filenames?");
3288 Filenames
= (const char **)malloc(NumFilenames
* sizeof(const char *));
3290 for (I
= 0; I
< NumFilenames
; ++I
) {
3291 const char *input
= argv
[I
+ 1] + strlen("-file-includes-in=");
3292 /* Copy the file name. */
3293 Filenames
[I
] = input
;
3296 if (parse_remapped_files(argc
, argv
, NumFilenames
+ 1, &unsaved_files
,
3297 &num_unsaved_files
))
3300 if (getenv("CINDEXTEST_EDITING"))
3303 /* Parse the translation unit. When we're testing clang_getCursor() after
3304 reparsing, don't remap unsaved files until the second parse. */
3305 CIdx
= clang_createIndex(1, 1);
3306 Err
= clang_parseTranslationUnit2(
3307 CIdx
, argv
[argc
- 1],
3308 argv
+ num_unsaved_files
+ 1 + NumFilenames
,
3309 argc
- num_unsaved_files
- 2 - NumFilenames
,
3311 Repeats
> 1 ? 0 : num_unsaved_files
, getDefaultParsingOptions(), &TU
);
3313 if (Err
!= CXError_Success
) {
3314 fprintf(stderr
, "unable to parse input\n");
3315 describeLibclangFailure(Err
);
3316 clang_disposeTranslationUnit(TU
);
3320 if (checkForErrors(TU
) != 0)
3323 for (I
= 0; I
!= Repeats
; ++I
) {
3325 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
3326 clang_defaultReparseOptions(TU
));
3327 if (Err
!= CXError_Success
) {
3328 describeLibclangFailure(Err
);
3329 clang_disposeTranslationUnit(TU
);
3334 if (checkForErrors(TU
) != 0)
3337 for (FI
= 0; FI
< NumFilenames
; ++FI
) {
3338 CXFile file
= clang_getFile(TU
, Filenames
[FI
]);
3342 if (checkForErrors(TU
) != 0)
3345 if (I
+ 1 == Repeats
) {
3346 CXCursorAndRangeVisitor visitor
= { 0, findFileIncludesVisit
};
3347 clang_findIncludesInFile(TU
, file
, visitor
);
3349 if (checkForErrors(TU
) != 0)
3355 PrintDiagnostics(TU
);
3356 clang_disposeTranslationUnit(TU
);
3357 clang_disposeIndex(CIdx
);
3358 free((void *)Filenames
);
3359 free_remapped_files(unsaved_files
, num_unsaved_files
);
3363 #define MAX_IMPORTED_ASTFILES 200
3368 } ImportedASTFilesData
;
3370 static ImportedASTFilesData
*importedASTs_create(void) {
3371 ImportedASTFilesData
*p
;
3372 p
= malloc(sizeof(ImportedASTFilesData
));
3374 p
->filenames
= malloc(MAX_IMPORTED_ASTFILES
* sizeof(const char *));
3375 assert(p
->filenames
);
3380 static void importedASTs_dispose(ImportedASTFilesData
*p
) {
3385 for (i
= 0; i
< p
->num_files
; ++i
)
3386 free(p
->filenames
[i
]);
3391 static void importedASTS_insert(ImportedASTFilesData
*p
, const char *file
) {
3394 for (i
= 0; i
< p
->num_files
; ++i
)
3395 if (strcmp(file
, p
->filenames
[i
]) == 0)
3397 assert(p
->num_files
+ 1 < MAX_IMPORTED_ASTFILES
);
3398 p
->filenames
[p
->num_files
++] = strdup(file
);
3401 typedef struct IndexDataStringList_
{
3402 struct IndexDataStringList_
*next
;
3403 char data
[1]; /* Dynamically sized. */
3404 } IndexDataStringList
;
3407 const char *check_prefix
;
3408 int first_check_printed
;
3411 CXString main_filename
;
3412 ImportedASTFilesData
*importedASTs
;
3413 IndexDataStringList
*strings
;
3414 CXTranslationUnit TU
;
3417 static void free_client_data(IndexData
*index_data
) {
3418 IndexDataStringList
*node
= index_data
->strings
;
3420 IndexDataStringList
*next
= node
->next
;
3424 index_data
->strings
= NULL
;
3427 static void printCheck(IndexData
*data
) {
3428 if (data
->check_prefix
) {
3429 if (data
->first_check_printed
) {
3430 printf("// %s-NEXT: ", data
->check_prefix
);
3432 printf("// %s : ", data
->check_prefix
);
3433 data
->first_check_printed
= 1;
3438 static void printCXIndexFile(CXIdxClientFile file
) {
3439 CXString filename
= clang_getFileName((CXFile
)file
);
3440 printf("%s", clang_getCString(filename
));
3441 clang_disposeString(filename
);
3444 static void printCXIndexLoc(CXIdxLoc loc
, CXClientData client_data
) {
3445 IndexData
*index_data
;
3448 CXIdxClientFile file
;
3449 unsigned line
, column
;
3450 const char *main_filename
;
3453 index_data
= (IndexData
*)client_data
;
3454 clang_indexLoc_getFileLocation(loc
, &file
, 0, &line
, &column
, 0);
3456 printf("<invalid>");
3460 printf("<no idxfile>");
3463 filename
= clang_getFileName((CXFile
)file
);
3464 cname
= clang_getCString(filename
);
3465 main_filename
= clang_getCString(index_data
->main_filename
);
3466 if (strcmp(cname
, main_filename
) == 0)
3470 clang_disposeString(filename
);
3473 printCXIndexFile(file
);
3476 printf("%d:%d", line
, column
);
3479 static unsigned digitCount(unsigned val
) {
3489 static CXIdxClientContainer
makeClientContainer(CXClientData
*client_data
,
3490 const CXIdxEntityInfo
*info
,
3492 IndexData
*index_data
;
3493 IndexDataStringList
*node
;
3496 CXIdxClientFile file
;
3497 unsigned line
, column
;
3501 name
= "<anon-tag>";
3503 clang_indexLoc_getFileLocation(loc
, &file
, 0, &line
, &column
, 0);
3506 (IndexDataStringList
*)malloc(sizeof(IndexDataStringList
) + strlen(name
) +
3507 digitCount(line
) + digitCount(column
) + 2);
3509 newStr
= node
->data
;
3510 sprintf(newStr
, "%s:%d:%d", name
, line
, column
);
3512 /* Remember string so it can be freed later. */
3513 index_data
= (IndexData
*)client_data
;
3514 node
->next
= index_data
->strings
;
3515 index_data
->strings
= node
;
3517 return (CXIdxClientContainer
)newStr
;
3520 static void printCXIndexContainer(const CXIdxContainerInfo
*info
) {
3521 CXIdxClientContainer container
;
3522 container
= clang_index_getClientContainer(info
);
3524 printf("[<<NULL>>]");
3526 printf("[%s]", (const char *)container
);
3529 static const char *getEntityKindString(CXIdxEntityKind kind
) {
3531 case CXIdxEntity_Unexposed
: return "<<UNEXPOSED>>";
3532 case CXIdxEntity_Typedef
: return "typedef";
3533 case CXIdxEntity_Function
: return "function";
3534 case CXIdxEntity_Variable
: return "variable";
3535 case CXIdxEntity_Field
: return "field";
3536 case CXIdxEntity_EnumConstant
: return "enumerator";
3537 case CXIdxEntity_ObjCClass
: return "objc-class";
3538 case CXIdxEntity_ObjCProtocol
: return "objc-protocol";
3539 case CXIdxEntity_ObjCCategory
: return "objc-category";
3540 case CXIdxEntity_ObjCInstanceMethod
: return "objc-instance-method";
3541 case CXIdxEntity_ObjCClassMethod
: return "objc-class-method";
3542 case CXIdxEntity_ObjCProperty
: return "objc-property";
3543 case CXIdxEntity_ObjCIvar
: return "objc-ivar";
3544 case CXIdxEntity_Enum
: return "enum";
3545 case CXIdxEntity_Struct
: return "struct";
3546 case CXIdxEntity_Union
: return "union";
3547 case CXIdxEntity_CXXClass
: return "c++-class";
3548 case CXIdxEntity_CXXNamespace
: return "namespace";
3549 case CXIdxEntity_CXXNamespaceAlias
: return "namespace-alias";
3550 case CXIdxEntity_CXXStaticVariable
: return "c++-static-var";
3551 case CXIdxEntity_CXXStaticMethod
: return "c++-static-method";
3552 case CXIdxEntity_CXXInstanceMethod
: return "c++-instance-method";
3553 case CXIdxEntity_CXXConstructor
: return "constructor";
3554 case CXIdxEntity_CXXDestructor
: return "destructor";
3555 case CXIdxEntity_CXXConversionFunction
: return "conversion-func";
3556 case CXIdxEntity_CXXTypeAlias
: return "type-alias";
3557 case CXIdxEntity_CXXInterface
: return "c++-__interface";
3558 case CXIdxEntity_CXXConcept
:
3561 assert(0 && "Garbage entity kind");
3565 static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind
) {
3567 case CXIdxEntity_NonTemplate
: return "";
3568 case CXIdxEntity_Template
: return "-template";
3569 case CXIdxEntity_TemplatePartialSpecialization
:
3570 return "-template-partial-spec";
3571 case CXIdxEntity_TemplateSpecialization
: return "-template-spec";
3573 assert(0 && "Garbage entity kind");
3577 static const char *getEntityLanguageString(CXIdxEntityLanguage kind
) {
3579 case CXIdxEntityLang_None
: return "<none>";
3580 case CXIdxEntityLang_C
: return "C";
3581 case CXIdxEntityLang_ObjC
: return "ObjC";
3582 case CXIdxEntityLang_CXX
: return "C++";
3583 case CXIdxEntityLang_Swift
: return "Swift";
3585 assert(0 && "Garbage language kind");
3589 static void printEntityInfo(const char *cb
,
3590 CXClientData client_data
,
3591 const CXIdxEntityInfo
*info
) {
3593 IndexData
*index_data
;
3595 index_data
= (IndexData
*)client_data
;
3596 printCheck(index_data
);
3599 printf("%s: <<NULL>>", cb
);
3605 name
= "<anon-tag>";
3607 printf("%s: kind: %s%s", cb
, getEntityKindString(info
->kind
),
3608 getEntityTemplateKindString(info
->templateKind
));
3609 printf(" | name: %s", name
);
3610 printf(" | USR: %s", info
->USR
);
3611 printf(" | lang: %s", getEntityLanguageString(info
->lang
));
3613 for (i
= 0; i
!= info
->numAttributes
; ++i
) {
3614 const CXIdxAttrInfo
*Attr
= info
->attributes
[i
];
3615 printf(" <attribute>: ");
3616 PrintCursor(Attr
->cursor
, NULL
);
3620 static void printBaseClassInfo(CXClientData client_data
,
3621 const CXIdxBaseClassInfo
*info
) {
3622 printEntityInfo(" <base>", client_data
, info
->base
);
3623 printf(" | cursor: ");
3624 PrintCursor(info
->cursor
, NULL
);
3626 printCXIndexLoc(info
->loc
, client_data
);
3629 static void printProtocolList(const CXIdxObjCProtocolRefListInfo
*ProtoInfo
,
3630 CXClientData client_data
) {
3632 for (i
= 0; i
< ProtoInfo
->numProtocols
; ++i
) {
3633 printEntityInfo(" <protocol>", client_data
,
3634 ProtoInfo
->protocols
[i
]->protocol
);
3635 printf(" | cursor: ");
3636 PrintCursor(ProtoInfo
->protocols
[i
]->cursor
, NULL
);
3638 printCXIndexLoc(ProtoInfo
->protocols
[i
]->loc
, client_data
);
3643 static void printSymbolRole(CXSymbolRole role
) {
3644 if (role
& CXSymbolRole_Declaration
)
3646 if (role
& CXSymbolRole_Definition
)
3648 if (role
& CXSymbolRole_Reference
)
3650 if (role
& CXSymbolRole_Read
)
3652 if (role
& CXSymbolRole_Write
)
3654 if (role
& CXSymbolRole_Call
)
3656 if (role
& CXSymbolRole_Dynamic
)
3658 if (role
& CXSymbolRole_AddressOf
)
3660 if (role
& CXSymbolRole_Implicit
)
3661 printf(" implicit");
3664 static void index_diagnostic(CXClientData client_data
,
3665 CXDiagnosticSet diagSet
, void *reserved
) {
3668 unsigned numDiags
, i
;
3670 IndexData
*index_data
;
3671 index_data
= (IndexData
*)client_data
;
3672 printCheck(index_data
);
3674 numDiags
= clang_getNumDiagnosticsInSet(diagSet
);
3675 for (i
= 0; i
!= numDiags
; ++i
) {
3676 diag
= clang_getDiagnosticInSet(diagSet
, i
);
3677 str
= clang_formatDiagnostic(diag
, clang_defaultDiagnosticDisplayOptions());
3678 cstr
= clang_getCString(str
);
3679 printf("[diagnostic]: %s\n", cstr
);
3680 clang_disposeString(str
);
3682 if (getenv("CINDEXTEST_FAILONERROR") &&
3683 clang_getDiagnosticSeverity(diag
) >= CXDiagnostic_Error
) {
3684 index_data
->fail_for_error
= 1;
3689 static CXIdxClientFile
index_enteredMainFile(CXClientData client_data
,
3690 CXFile file
, void *reserved
) {
3691 IndexData
*index_data
;
3693 index_data
= (IndexData
*)client_data
;
3694 printCheck(index_data
);
3696 index_data
->main_filename
= clang_getFileName(file
);
3698 printf("[enteredMainFile]: ");
3699 printCXIndexFile((CXIdxClientFile
)file
);
3702 return (CXIdxClientFile
)file
;
3705 static CXIdxClientFile
index_ppIncludedFile(CXClientData client_data
,
3706 const CXIdxIncludedFileInfo
*info
) {
3707 IndexData
*index_data
;
3709 index_data
= (IndexData
*)client_data
;
3710 printCheck(index_data
);
3712 printf("[ppIncludedFile]: ");
3713 printCXIndexFile((CXIdxClientFile
)info
->file
);
3714 printf(" | name: \"%s\"", info
->filename
);
3715 printf(" | hash loc: ");
3716 printCXIndexLoc(info
->hashLoc
, client_data
);
3717 printf(" | isImport: %d | isAngled: %d | isModule: %d",
3718 info
->isImport
, info
->isAngled
, info
->isModuleImport
);
3720 Mod
= clang_getModuleForFile(index_data
->TU
, (CXFile
)info
->file
);
3722 CXString str
= clang_Module_getFullName(Mod
);
3723 const char *cstr
= clang_getCString(str
);
3724 printf(" | module: %s", cstr
);
3725 clang_disposeString(str
);
3730 return (CXIdxClientFile
)info
->file
;
3733 static CXIdxClientFile
index_importedASTFile(CXClientData client_data
,
3734 const CXIdxImportedASTFileInfo
*info
) {
3735 IndexData
*index_data
;
3736 index_data
= (IndexData
*)client_data
;
3737 printCheck(index_data
);
3739 if (index_data
->importedASTs
) {
3740 CXString filename
= clang_getFileName(info
->file
);
3741 importedASTS_insert(index_data
->importedASTs
, clang_getCString(filename
));
3742 clang_disposeString(filename
);
3745 printf("[importedASTFile]: ");
3746 printCXIndexFile((CXIdxClientFile
)info
->file
);
3748 CXString name
= clang_Module_getFullName(info
->module
);
3750 printCXIndexLoc(info
->loc
, client_data
);
3751 printf(" | name: \"%s\"", clang_getCString(name
));
3752 printf(" | isImplicit: %d\n", info
->isImplicit
);
3753 clang_disposeString(name
);
3755 /* PCH file, the rest are not relevant. */
3759 return (CXIdxClientFile
)info
->file
;
3762 static CXIdxClientContainer
3763 index_startedTranslationUnit(CXClientData client_data
, void *reserved
) {
3764 IndexData
*index_data
;
3765 index_data
= (IndexData
*)client_data
;
3766 printCheck(index_data
);
3768 printf("[startedTranslationUnit]\n");
3770 #pragma GCC diagnostic push
3771 #pragma GCC diagnostic ignored "-Wcast-qual"
3773 return (CXIdxClientContainer
)"TU";
3775 #pragma GCC diagnostic pop
3779 static void index_indexDeclaration(CXClientData client_data
,
3780 const CXIdxDeclInfo
*info
) {
3781 IndexData
*index_data
;
3782 const CXIdxObjCCategoryDeclInfo
*CatInfo
;
3783 const CXIdxObjCInterfaceDeclInfo
*InterInfo
;
3784 const CXIdxObjCProtocolRefListInfo
*ProtoInfo
;
3785 const CXIdxObjCPropertyDeclInfo
*PropInfo
;
3786 const CXIdxCXXClassDeclInfo
*CXXClassInfo
;
3788 index_data
= (IndexData
*)client_data
;
3790 printEntityInfo("[indexDeclaration]", client_data
, info
->entityInfo
);
3791 printf(" | cursor: ");
3792 PrintCursor(info
->cursor
, NULL
);
3794 printCXIndexLoc(info
->loc
, client_data
);
3795 printf(" | semantic-container: ");
3796 printCXIndexContainer(info
->semanticContainer
);
3797 printf(" | lexical-container: ");
3798 printCXIndexContainer(info
->lexicalContainer
);
3799 printf(" | isRedecl: %d", info
->isRedeclaration
);
3800 printf(" | isDef: %d", info
->isDefinition
);
3801 if (info
->flags
& CXIdxDeclFlag_Skipped
) {
3802 assert(!info
->isContainer
);
3803 printf(" | isContainer: skipped");
3805 printf(" | isContainer: %d", info
->isContainer
);
3807 printf(" | isImplicit: %d\n", info
->isImplicit
);
3809 for (i
= 0; i
!= info
->numAttributes
; ++i
) {
3810 const CXIdxAttrInfo
*Attr
= info
->attributes
[i
];
3811 printf(" <attribute>: ");
3812 PrintCursor(Attr
->cursor
, NULL
);
3816 if (clang_index_isEntityObjCContainerKind(info
->entityInfo
->kind
)) {
3817 const char *kindName
= 0;
3818 CXIdxObjCContainerKind K
= clang_index_getObjCContainerDeclInfo(info
)->kind
;
3820 case CXIdxObjCContainer_ForwardRef
:
3821 kindName
= "forward-ref"; break;
3822 case CXIdxObjCContainer_Interface
:
3823 kindName
= "interface"; break;
3824 case CXIdxObjCContainer_Implementation
:
3825 kindName
= "implementation"; break;
3827 printCheck(index_data
);
3828 printf(" <ObjCContainerInfo>: kind: %s\n", kindName
);
3831 if ((CatInfo
= clang_index_getObjCCategoryDeclInfo(info
))) {
3832 printEntityInfo(" <ObjCCategoryInfo>: class", client_data
,
3833 CatInfo
->objcClass
);
3834 printf(" | cursor: ");
3835 PrintCursor(CatInfo
->classCursor
, NULL
);
3837 printCXIndexLoc(CatInfo
->classLoc
, client_data
);
3841 if ((InterInfo
= clang_index_getObjCInterfaceDeclInfo(info
))) {
3842 if (InterInfo
->superInfo
) {
3843 printBaseClassInfo(client_data
, InterInfo
->superInfo
);
3848 if ((ProtoInfo
= clang_index_getObjCProtocolRefListInfo(info
))) {
3849 printProtocolList(ProtoInfo
, client_data
);
3852 if ((PropInfo
= clang_index_getObjCPropertyDeclInfo(info
))) {
3853 if (PropInfo
->getter
) {
3854 printEntityInfo(" <getter>", client_data
, PropInfo
->getter
);
3857 if (PropInfo
->setter
) {
3858 printEntityInfo(" <setter>", client_data
, PropInfo
->setter
);
3863 if ((CXXClassInfo
= clang_index_getCXXClassDeclInfo(info
))) {
3864 for (i
= 0; i
!= CXXClassInfo
->numBases
; ++i
) {
3865 printBaseClassInfo(client_data
, CXXClassInfo
->bases
[i
]);
3870 if (info
->declAsContainer
)
3871 clang_index_setClientContainer(
3872 info
->declAsContainer
,
3873 makeClientContainer(client_data
, info
->entityInfo
, info
->loc
));
3876 static void index_indexEntityReference(CXClientData client_data
,
3877 const CXIdxEntityRefInfo
*info
) {
3878 printEntityInfo("[indexEntityReference]", client_data
,
3879 info
->referencedEntity
);
3880 printf(" | cursor: ");
3881 PrintCursor(info
->cursor
, NULL
);
3883 printCXIndexLoc(info
->loc
, client_data
);
3884 printEntityInfo(" | <parent>:", client_data
, info
->parentEntity
);
3885 printf(" | container: ");
3886 printCXIndexContainer(info
->container
);
3887 printf(" | refkind: ");
3888 switch (info
->kind
) {
3889 case CXIdxEntityRef_Direct
: printf("direct"); break;
3890 case CXIdxEntityRef_Implicit
: printf("implicit"); break;
3893 printSymbolRole(info
->role
);
3897 static int index_abortQuery(CXClientData client_data
, void *reserved
) {
3898 IndexData
*index_data
;
3899 index_data
= (IndexData
*)client_data
;
3900 return index_data
->abort
;
3903 static IndexerCallbacks IndexCB
= {
3906 index_enteredMainFile
,
3907 index_ppIncludedFile
,
3908 index_importedASTFile
,
3909 index_startedTranslationUnit
,
3910 index_indexDeclaration
,
3911 index_indexEntityReference
3914 static unsigned getIndexOptions(void) {
3915 unsigned index_opts
;
3917 if (getenv("CINDEXTEST_SUPPRESSREFS"))
3918 index_opts
|= CXIndexOpt_SuppressRedundantRefs
;
3919 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
3920 index_opts
|= CXIndexOpt_IndexFunctionLocalSymbols
;
3921 if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
3922 index_opts
|= CXIndexOpt_SkipParsedBodiesInSession
;
3923 if (getenv("CINDEXTEST_INDEXIMPLICITTEMPLATEINSTANTIATIONS"))
3924 index_opts
|= CXIndexOpt_IndexImplicitTemplateInstantiations
;
3929 static int index_compile_args(int num_args
, const char **args
,
3930 CXIndexAction idxAction
,
3931 ImportedASTFilesData
*importedASTs
,
3932 const char *check_prefix
) {
3933 IndexData index_data
;
3934 unsigned index_opts
;
3937 if (num_args
== 0) {
3938 fprintf(stderr
, "no compiler arguments\n");
3942 index_data
.check_prefix
= check_prefix
;
3943 index_data
.first_check_printed
= 0;
3944 index_data
.fail_for_error
= 0;
3945 index_data
.abort
= 0;
3946 index_data
.main_filename
= createCXString("");
3947 index_data
.importedASTs
= importedASTs
;
3948 index_data
.strings
= NULL
;
3949 index_data
.TU
= NULL
;
3951 index_opts
= getIndexOptions();
3952 result
= clang_indexSourceFile(idxAction
, &index_data
,
3953 &IndexCB
,sizeof(IndexCB
), index_opts
,
3954 0, args
, num_args
, 0, 0, 0,
3955 getDefaultParsingOptions());
3956 if (result
!= CXError_Success
)
3957 describeLibclangFailure(result
);
3959 if (index_data
.fail_for_error
)
3962 clang_disposeString(index_data
.main_filename
);
3963 free_client_data(&index_data
);
3967 static int index_ast_file(const char *ast_file
,
3969 CXIndexAction idxAction
,
3970 ImportedASTFilesData
*importedASTs
,
3971 const char *check_prefix
) {
3972 CXTranslationUnit TU
;
3973 IndexData index_data
;
3974 unsigned index_opts
;
3977 if (!CreateTranslationUnit(Idx
, ast_file
, &TU
))
3980 index_data
.check_prefix
= check_prefix
;
3981 index_data
.first_check_printed
= 0;
3982 index_data
.fail_for_error
= 0;
3983 index_data
.abort
= 0;
3984 index_data
.main_filename
= createCXString("");
3985 index_data
.importedASTs
= importedASTs
;
3986 index_data
.strings
= NULL
;
3989 index_opts
= getIndexOptions();
3990 result
= clang_indexTranslationUnit(idxAction
, &index_data
,
3991 &IndexCB
,sizeof(IndexCB
),
3993 if (index_data
.fail_for_error
)
3996 clang_disposeTranslationUnit(TU
);
3997 clang_disposeString(index_data
.main_filename
);
3998 free_client_data(&index_data
);
4002 static int index_file(int argc
, const char **argv
, int full
) {
4003 const char *check_prefix
;
4005 CXIndexAction idxAction
;
4006 ImportedASTFilesData
*importedASTs
;
4011 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4012 check_prefix
= argv
[0] + strlen("-check-prefix=");
4018 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4019 /* displayDiagnostics=*/1))) {
4020 fprintf(stderr
, "Could not create Index\n");
4023 idxAction
= clang_IndexAction_create(Idx
);
4026 importedASTs
= importedASTs_create();
4028 result
= index_compile_args(argc
, argv
, idxAction
, importedASTs
, check_prefix
);
4034 for (i
= 0; i
< importedASTs
->num_files
&& result
== 0; ++i
) {
4035 result
= index_ast_file(importedASTs
->filenames
[i
], Idx
, idxAction
,
4036 importedASTs
, check_prefix
);
4041 importedASTs_dispose(importedASTs
);
4042 clang_IndexAction_dispose(idxAction
);
4043 clang_disposeIndex(Idx
);
4047 static int index_tu(int argc
, const char **argv
) {
4048 const char *check_prefix
;
4050 CXIndexAction idxAction
;
4055 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4056 check_prefix
= argv
[0] + strlen("-check-prefix=");
4062 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4063 /* displayDiagnostics=*/1))) {
4064 fprintf(stderr
, "Could not create Index\n");
4067 idxAction
= clang_IndexAction_create(Idx
);
4069 result
= index_ast_file(argv
[0], Idx
, idxAction
,
4070 /*importedASTs=*/0, check_prefix
);
4072 clang_IndexAction_dispose(idxAction
);
4073 clang_disposeIndex(Idx
);
4077 static int index_compile_db(int argc
, const char **argv
) {
4078 const char *check_prefix
;
4080 CXIndexAction idxAction
;
4085 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4086 check_prefix
= argv
[0] + strlen("-check-prefix=");
4093 fprintf(stderr
, "no compilation database\n");
4097 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4098 /* displayDiagnostics=*/1))) {
4099 fprintf(stderr
, "Could not create Index\n");
4102 idxAction
= clang_IndexAction_create(Idx
);
4105 const char *database
= argv
[0];
4106 CXCompilationDatabase db
= 0;
4107 CXCompileCommands CCmds
= 0;
4108 CXCompileCommand CCmd
;
4109 CXCompilationDatabase_Error ec
;
4111 #define MAX_COMPILE_ARGS 512
4112 CXString cxargs
[MAX_COMPILE_ARGS
];
4113 const char *args
[MAX_COMPILE_ARGS
];
4117 int i
, a
, numCmds
, numArgs
;
4119 len
= strlen(database
);
4120 tmp
= (char *) malloc(len
+1);
4122 memcpy(tmp
, database
, len
+1);
4123 buildDir
= dirname(tmp
);
4125 db
= clang_CompilationDatabase_fromDirectory(buildDir
, &ec
);
4129 if (ec
!=CXCompilationDatabase_NoError
) {
4130 printf("unexpected error %d code while loading compilation database\n", ec
);
4135 if (chdir(buildDir
) != 0) {
4136 printf("Could not chdir to %s\n", buildDir
);
4141 CCmds
= clang_CompilationDatabase_getAllCompileCommands(db
);
4143 printf("compilation db is empty\n");
4148 numCmds
= clang_CompileCommands_getSize(CCmds
);
4151 fprintf(stderr
, "should not get an empty compileCommand set\n");
4156 for (i
=0; i
<numCmds
&& errorCode
== 0; ++i
) {
4157 CCmd
= clang_CompileCommands_getCommand(CCmds
, i
);
4159 wd
= clang_CompileCommand_getDirectory(CCmd
);
4160 if (chdir(clang_getCString(wd
)) != 0) {
4161 printf("Could not chdir to %s\n", clang_getCString(wd
));
4165 clang_disposeString(wd
);
4167 numArgs
= clang_CompileCommand_getNumArgs(CCmd
);
4168 if (numArgs
> MAX_COMPILE_ARGS
){
4169 fprintf(stderr
, "got more compile arguments than maximum\n");
4173 for (a
=0; a
<numArgs
; ++a
) {
4174 cxargs
[a
] = clang_CompileCommand_getArg(CCmd
, a
);
4175 args
[a
] = clang_getCString(cxargs
[a
]);
4178 errorCode
= index_compile_args(numArgs
, args
, idxAction
,
4179 /*importedASTs=*/0, check_prefix
);
4181 for (a
=0; a
<numArgs
; ++a
)
4182 clang_disposeString(cxargs
[a
]);
4185 printf("database loading failed with error code %d.\n", ec
);
4190 clang_CompileCommands_dispose(CCmds
);
4191 clang_CompilationDatabase_dispose(db
);
4196 clang_IndexAction_dispose(idxAction
);
4197 clang_disposeIndex(Idx
);
4201 int perform_token_annotation(int argc
, const char **argv
) {
4202 const char *input
= argv
[1];
4204 unsigned line
, second_line
;
4205 unsigned column
, second_column
;
4207 CXTranslationUnit TU
= 0;
4209 struct CXUnsavedFile
*unsaved_files
= 0;
4210 int num_unsaved_files
= 0;
4212 unsigned num_tokens
;
4213 CXSourceRange range
;
4214 CXSourceLocation startLoc
, endLoc
;
4216 CXCursor
*cursors
= 0;
4217 CXSourceRangeList
*skipped_ranges
= 0;
4218 enum CXErrorCode Err
;
4221 input
+= strlen("-test-annotate-tokens=");
4222 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
4223 &second_line
, &second_column
)))
4226 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
)) {
4231 CIdx
= clang_createIndex(0, 1);
4232 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
4233 argv
+ num_unsaved_files
+ 2,
4234 argc
- num_unsaved_files
- 3,
4237 getDefaultParsingOptions(), &TU
);
4238 if (Err
!= CXError_Success
) {
4239 fprintf(stderr
, "unable to parse input\n");
4240 describeLibclangFailure(Err
);
4241 clang_disposeIndex(CIdx
);
4243 free_remapped_files(unsaved_files
, num_unsaved_files
);
4248 if (checkForErrors(TU
) != 0) {
4253 if (getenv("CINDEXTEST_EDITING")) {
4254 for (i
= 0; i
< 5; ++i
) {
4255 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
4256 clang_defaultReparseOptions(TU
));
4257 if (Err
!= CXError_Success
) {
4258 fprintf(stderr
, "Unable to reparse translation unit!\n");
4259 describeLibclangFailure(Err
);
4266 if (checkForErrors(TU
) != 0) {
4271 file
= clang_getFile(TU
, filename
);
4273 fprintf(stderr
, "file %s is not in this translation unit\n", filename
);
4278 startLoc
= clang_getLocation(TU
, file
, line
, column
);
4279 if (clang_equalLocations(clang_getNullLocation(), startLoc
)) {
4280 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
, line
,
4286 endLoc
= clang_getLocation(TU
, file
, second_line
, second_column
);
4287 if (clang_equalLocations(clang_getNullLocation(), endLoc
)) {
4288 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
,
4289 second_line
, second_column
);
4294 range
= clang_getRange(startLoc
, endLoc
);
4295 clang_tokenize(TU
, range
, &tokens
, &num_tokens
);
4297 if (checkForErrors(TU
) != 0) {
4302 cursors
= (CXCursor
*)malloc(num_tokens
* sizeof(CXCursor
));
4304 clang_annotateTokens(TU
, tokens
, num_tokens
, cursors
);
4306 if (checkForErrors(TU
) != 0) {
4311 skipped_ranges
= clang_getSkippedRanges(TU
, file
);
4312 for (i
= 0; i
!= skipped_ranges
->count
; ++i
) {
4313 unsigned start_line
, start_column
, end_line
, end_column
;
4314 clang_getSpellingLocation(clang_getRangeStart(skipped_ranges
->ranges
[i
]),
4315 0, &start_line
, &start_column
, 0);
4316 clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges
->ranges
[i
]),
4317 0, &end_line
, &end_column
, 0);
4318 printf("Skipping: ");
4319 PrintExtent(stdout
, start_line
, start_column
, end_line
, end_column
);
4322 clang_disposeSourceRangeList(skipped_ranges
);
4324 for (i
= 0; i
!= num_tokens
; ++i
) {
4325 const char *kind
= "<unknown>";
4326 CXString spelling
= clang_getTokenSpelling(TU
, tokens
[i
]);
4327 CXSourceRange extent
= clang_getTokenExtent(TU
, tokens
[i
]);
4328 unsigned start_line
, start_column
, end_line
, end_column
;
4330 switch (clang_getTokenKind(tokens
[i
])) {
4331 case CXToken_Punctuation
: kind
= "Punctuation"; break;
4332 case CXToken_Keyword
: kind
= "Keyword"; break;
4333 case CXToken_Identifier
: kind
= "Identifier"; break;
4334 case CXToken_Literal
: kind
= "Literal"; break;
4335 case CXToken_Comment
: kind
= "Comment"; break;
4337 clang_getSpellingLocation(clang_getRangeStart(extent
),
4338 0, &start_line
, &start_column
, 0);
4339 clang_getSpellingLocation(clang_getRangeEnd(extent
),
4340 0, &end_line
, &end_column
, 0);
4341 printf("%s: \"%s\" ", kind
, clang_getCString(spelling
));
4342 clang_disposeString(spelling
);
4343 PrintExtent(stdout
, start_line
, start_column
, end_line
, end_column
);
4344 if (!clang_isInvalid(cursors
[i
].kind
)) {
4346 PrintCursor(cursors
[i
], NULL
);
4351 clang_disposeTokens(TU
, tokens
, num_tokens
);
4354 PrintDiagnostics(TU
);
4355 clang_disposeTranslationUnit(TU
);
4356 clang_disposeIndex(CIdx
);
4358 free_remapped_files(unsaved_files
, num_unsaved_files
);
4363 perform_test_compilation_db(const char *database
, int argc
, const char **argv
) {
4364 CXCompilationDatabase db
;
4365 CXCompileCommands CCmds
;
4366 CXCompileCommand CCmd
;
4367 CXCompilationDatabase_Error ec
;
4374 int i
, j
, a
, numCmds
, numArgs
;
4376 len
= strlen(database
);
4377 tmp
= (char *) malloc(len
+1);
4379 memcpy(tmp
, database
, len
+1);
4380 buildDir
= dirname(tmp
);
4382 db
= clang_CompilationDatabase_fromDirectory(buildDir
, &ec
);
4386 if (ec
!=CXCompilationDatabase_NoError
) {
4387 printf("unexpected error %d code while loading compilation database\n", ec
);
4392 for (i
=0; i
<argc
&& errorCode
==0; ) {
4393 if (strcmp(argv
[i
],"lookup")==0){
4394 CCmds
= clang_CompilationDatabase_getCompileCommands(db
, argv
[i
+1]);
4397 printf("file %s not found in compilation db\n", argv
[i
+1]);
4402 numCmds
= clang_CompileCommands_getSize(CCmds
);
4405 fprintf(stderr
, "should not get an empty compileCommand set for file"
4406 " '%s'\n", argv
[i
+1]);
4411 for (j
=0; j
<numCmds
; ++j
) {
4412 CCmd
= clang_CompileCommands_getCommand(CCmds
, j
);
4414 wd
= clang_CompileCommand_getDirectory(CCmd
);
4415 printf("workdir:'%s'", clang_getCString(wd
));
4416 clang_disposeString(wd
);
4418 printf(" cmdline:'");
4419 numArgs
= clang_CompileCommand_getNumArgs(CCmd
);
4420 for (a
=0; a
<numArgs
; ++a
) {
4422 arg
= clang_CompileCommand_getArg(CCmd
, a
);
4423 printf("%s", clang_getCString(arg
));
4424 clang_disposeString(arg
);
4429 clang_CompileCommands_dispose(CCmds
);
4434 clang_CompilationDatabase_dispose(db
);
4436 printf("database loading failed with error code %d.\n", ec
);
4446 /******************************************************************************/
4448 /******************************************************************************/
4450 static int insufficient_usr(const char *kind
, const char *usage
) {
4451 fprintf(stderr
, "USR for '%s' requires: %s\n", kind
, usage
);
4455 static unsigned isUSR(const char *s
) {
4456 return s
[0] == 'c' && s
[1] == ':';
4459 static int not_usr(const char *s
, const char *arg
) {
4460 fprintf(stderr
, "'%s' argument ('%s') is not a USR\n", s
, arg
);
4464 static void print_usr(CXString usr
) {
4465 const char *s
= clang_getCString(usr
);
4467 clang_disposeString(usr
);
4470 static void display_usrs(void) {
4471 fprintf(stderr
, "-print-usrs options:\n"
4472 " ObjCCategory <class name> <category name>\n"
4473 " ObjCClass <class name>\n"
4474 " ObjCIvar <ivar name> <class USR>\n"
4475 " ObjCMethod <selector> [0=class method|1=instance method] "
4477 " ObjCProperty <property name> <class USR>\n"
4478 " ObjCProtocol <protocol name>\n");
4481 int print_usrs(const char **I
, const char **E
) {
4483 const char *kind
= *I
;
4484 unsigned len
= strlen(kind
);
4487 if (memcmp(kind
, "ObjCIvar", 8) == 0) {
4489 return insufficient_usr(kind
, "<ivar name> <class USR>");
4491 return not_usr("<class USR>", I
[2]);
4493 CXString x
= createCXString(I
[2]);
4494 print_usr(clang_constructUSR_ObjCIvar(I
[1], x
));
4502 if (memcmp(kind
, "ObjCClass", 9) == 0) {
4504 return insufficient_usr(kind
, "<class name>");
4505 print_usr(clang_constructUSR_ObjCClass(I
[1]));
4511 if (memcmp(kind
, "ObjCMethod", 10) == 0) {
4513 return insufficient_usr(kind
, "<method selector> "
4514 "[0=class method|1=instance method] <class USR>");
4516 return not_usr("<class USR>", I
[3]);
4518 CXString x
= createCXString(I
[3]);
4519 print_usr(clang_constructUSR_ObjCMethod(I
[1], atoi(I
[2]), x
));
4526 if (memcmp(kind
, "ObjCCategory", 12) == 0) {
4528 return insufficient_usr(kind
, "<class name> <category name>");
4529 print_usr(clang_constructUSR_ObjCCategory(I
[1], I
[2]));
4533 if (memcmp(kind
, "ObjCProtocol", 12) == 0) {
4535 return insufficient_usr(kind
, "<protocol name>");
4536 print_usr(clang_constructUSR_ObjCProtocol(I
[1]));
4540 if (memcmp(kind
, "ObjCProperty", 12) == 0) {
4542 return insufficient_usr(kind
, "<property name> <class USR>");
4544 return not_usr("<class USR>", I
[2]);
4546 CXString x
= createCXString(I
[2]);
4547 print_usr(clang_constructUSR_ObjCProperty(I
[1], x
));
4560 fprintf(stderr
, "Invalid USR kind: %s\n", *I
);
4567 int print_usrs_file(const char *file_name
) {
4569 const char *args
[128];
4570 unsigned numChars
= 0;
4572 FILE *fp
= fopen(file_name
, "r");
4574 fprintf(stderr
, "error: cannot open '%s'\n", file_name
);
4578 /* This code is not really all that safe, but it works fine for testing. */
4588 line
[numChars
] = '\0';
4591 if (line
[0] == '/' && line
[1] == '/')
4594 s
= strtok(line
, " ");
4600 if (print_usrs(&args
[0], &args
[i
]))
4604 line
[numChars
++] = c
;
4611 /******************************************************************************/
4612 /* Command line processing. */
4613 /******************************************************************************/
4614 int write_pch_file(const char *filename
, int argc
, const char *argv
[]) {
4616 CXTranslationUnit TU
;
4617 struct CXUnsavedFile
*unsaved_files
= 0;
4618 int num_unsaved_files
= 0;
4619 enum CXErrorCode Err
;
4622 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
4624 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
4625 clang_disposeIndex(Idx
);
4629 Err
= clang_parseTranslationUnit2(
4630 Idx
, 0, argv
+ num_unsaved_files
, argc
- num_unsaved_files
,
4631 unsaved_files
, num_unsaved_files
,
4632 CXTranslationUnit_Incomplete
|
4633 CXTranslationUnit_DetailedPreprocessingRecord
|
4634 CXTranslationUnit_ForSerialization
,
4636 if (Err
!= CXError_Success
) {
4637 fprintf(stderr
, "Unable to load translation unit!\n");
4638 describeLibclangFailure(Err
);
4639 free_remapped_files(unsaved_files
, num_unsaved_files
);
4640 clang_disposeTranslationUnit(TU
);
4641 clang_disposeIndex(Idx
);
4645 switch (clang_saveTranslationUnit(TU
, filename
,
4646 clang_defaultSaveOptions(TU
))) {
4647 case CXSaveError_None
:
4650 case CXSaveError_TranslationErrors
:
4651 fprintf(stderr
, "Unable to write PCH file %s: translation errors\n",
4656 case CXSaveError_InvalidTU
:
4657 fprintf(stderr
, "Unable to write PCH file %s: invalid translation unit\n",
4662 case CXSaveError_Unknown
:
4664 fprintf(stderr
, "Unable to write PCH file %s: unknown error \n", filename
);
4669 clang_disposeTranslationUnit(TU
);
4670 free_remapped_files(unsaved_files
, num_unsaved_files
);
4671 clang_disposeIndex(Idx
);
4675 /******************************************************************************/
4676 /* Serialized diagnostics. */
4677 /******************************************************************************/
4679 static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error
) {
4681 case CXLoadDiag_CannotLoad
: return "Cannot Load File";
4682 case CXLoadDiag_None
: break;
4683 case CXLoadDiag_Unknown
: return "Unknown";
4684 case CXLoadDiag_InvalidFile
: return "Invalid File";
4689 static const char *getSeverityString(enum CXDiagnosticSeverity severity
) {
4691 case CXDiagnostic_Note
: return "note";
4692 case CXDiagnostic_Error
: return "error";
4693 case CXDiagnostic_Fatal
: return "fatal";
4694 case CXDiagnostic_Ignored
: return "ignored";
4695 case CXDiagnostic_Warning
: return "warning";
4700 static void printIndent(unsigned indent
) {
4703 fprintf(stderr
, "+");
4705 while (indent
> 0) {
4706 fprintf(stderr
, "-");
4711 static void printLocation(CXSourceLocation L
) {
4714 unsigned line
, column
, offset
;
4716 clang_getExpansionLocation(L
, &File
, &line
, &column
, &offset
);
4717 FileName
= clang_getFileName(File
);
4719 fprintf(stderr
, "%s:%d:%d", clang_getCString(FileName
), line
, column
);
4720 clang_disposeString(FileName
);
4723 static void printRanges(CXDiagnostic D
, unsigned indent
) {
4724 unsigned i
, n
= clang_getDiagnosticNumRanges(D
);
4726 for (i
= 0; i
< n
; ++i
) {
4727 CXSourceLocation Start
, End
;
4728 CXSourceRange SR
= clang_getDiagnosticRange(D
, i
);
4729 Start
= clang_getRangeStart(SR
);
4730 End
= clang_getRangeEnd(SR
);
4732 printIndent(indent
);
4733 fprintf(stderr
, "Range: ");
4734 printLocation(Start
);
4735 fprintf(stderr
, " ");
4737 fprintf(stderr
, "\n");
4741 static void printFixIts(CXDiagnostic D
, unsigned indent
) {
4742 unsigned i
, n
= clang_getDiagnosticNumFixIts(D
);
4743 fprintf(stderr
, "Number FIXITs = %d\n", n
);
4744 for (i
= 0 ; i
< n
; ++i
) {
4745 CXSourceRange ReplacementRange
;
4747 text
= clang_getDiagnosticFixIt(D
, i
, &ReplacementRange
);
4749 printIndent(indent
);
4750 fprintf(stderr
, "FIXIT: (");
4751 printLocation(clang_getRangeStart(ReplacementRange
));
4752 fprintf(stderr
, " - ");
4753 printLocation(clang_getRangeEnd(ReplacementRange
));
4754 fprintf(stderr
, "): \"%s\"\n", clang_getCString(text
));
4755 clang_disposeString(text
);
4759 static void printDiagnosticSet(CXDiagnosticSet Diags
, unsigned indent
) {
4765 n
= clang_getNumDiagnosticsInSet(Diags
);
4766 for (i
= 0; i
< n
; ++i
) {
4767 CXSourceLocation DiagLoc
;
4770 CXString FileName
, DiagSpelling
, DiagOption
, DiagCat
;
4771 unsigned line
, column
, offset
;
4772 const char *FileNameStr
= 0, *DiagOptionStr
= 0, *DiagCatStr
= 0;
4774 D
= clang_getDiagnosticInSet(Diags
, i
);
4775 DiagLoc
= clang_getDiagnosticLocation(D
);
4776 clang_getExpansionLocation(DiagLoc
, &File
, &line
, &column
, &offset
);
4777 FileName
= clang_getFileName(File
);
4778 FileNameStr
= clang_getCString(FileName
);
4779 DiagSpelling
= clang_getDiagnosticSpelling(D
);
4781 printIndent(indent
);
4783 fprintf(stderr
, "%s:%d:%d: %s: %s",
4784 FileNameStr
? FileNameStr
: "(null)",
4787 getSeverityString(clang_getDiagnosticSeverity(D
)),
4788 clang_getCString(DiagSpelling
));
4790 DiagOption
= clang_getDiagnosticOption(D
, 0);
4791 DiagOptionStr
= clang_getCString(DiagOption
);
4792 if (DiagOptionStr
) {
4793 fprintf(stderr
, " [%s]", DiagOptionStr
);
4796 DiagCat
= clang_getDiagnosticCategoryText(D
);
4797 DiagCatStr
= clang_getCString(DiagCat
);
4799 fprintf(stderr
, " [%s]", DiagCatStr
);
4802 fprintf(stderr
, "\n");
4804 printRanges(D
, indent
);
4805 printFixIts(D
, indent
);
4807 /* Print subdiagnostics. */
4808 printDiagnosticSet(clang_getChildDiagnostics(D
), indent
+2);
4810 clang_disposeString(FileName
);
4811 clang_disposeString(DiagSpelling
);
4812 clang_disposeString(DiagOption
);
4813 clang_disposeString(DiagCat
);
4817 static int read_diagnostics(const char *filename
) {
4818 enum CXLoadDiag_Error error
;
4819 CXString errorString
;
4820 CXDiagnosticSet Diags
= 0;
4822 Diags
= clang_loadDiagnostics(filename
, &error
, &errorString
);
4824 fprintf(stderr
, "Trouble deserializing file (%s): %s\n",
4825 getDiagnosticCodeStr(error
),
4826 clang_getCString(errorString
));
4827 clang_disposeString(errorString
);
4831 printDiagnosticSet(Diags
, 0);
4832 fprintf(stderr
, "Number of diagnostics: %d\n",
4833 clang_getNumDiagnosticsInSet(Diags
));
4834 clang_disposeDiagnosticSet(Diags
);
4838 static int perform_print_build_session_timestamp(void) {
4839 printf("%lld\n", clang_getBuildSessionTimestamp());
4843 static int perform_test_single_symbol_sgf(const char *input
, int argc
,
4844 const char *argv
[]) {
4846 CXTranslationUnit TU
;
4848 struct CXUnsavedFile
*unsaved_files
= 0;
4849 int num_unsaved_files
= 0;
4850 enum CXErrorCode Err
;
4855 usr
= input
+ strlen("-single-symbol-sgf-for=");
4857 Idx
= createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */ 1,
4858 /* displayDiagnostics=*/0);
4862 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
4867 Err
= clang_parseTranslationUnit2(
4868 Idx
, 0, argv
+ num_unsaved_files
, argc
- num_unsaved_files
, unsaved_files
,
4869 num_unsaved_files
, getDefaultParsingOptions(), &TU
);
4870 if (Err
!= CXError_Success
) {
4871 fprintf(stderr
, "Unable to load translation unit!\n");
4872 describeLibclangFailure(Err
);
4874 goto free_remapped_files
;
4877 Err
= clang_createAPISet(TU
, &API
);
4878 if (Err
!= CXError_Success
) {
4880 "Unable to create API Set for API information extraction!\n");
4885 SGF
= clang_getSymbolGraphForUSR(usr
, API
);
4886 printf("%s", clang_getCString(SGF
));
4888 clang_disposeString(SGF
);
4889 clang_disposeAPISet(API
);
4891 clang_disposeTranslationUnit(TU
);
4892 free_remapped_files
:
4893 free_remapped_files(unsaved_files
, num_unsaved_files
);
4895 clang_disposeIndex(Idx
);
4899 static void inspect_single_symbol_sgf_cursor(CXCursor Cursor
) {
4900 CXSourceLocation CursorLoc
;
4903 unsigned line
, column
;
4904 CursorLoc
= clang_getCursorLocation(Cursor
);
4905 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
4907 SGFData
= clang_getSymbolGraphForCursor(Cursor
);
4908 SGF
= clang_getCString(SGFData
);
4910 printf("%d:%d: %s\n", line
, column
, SGF
);
4912 clang_disposeString(SGFData
);
4915 /******************************************************************************/
4916 /* Command line processing. */
4917 /******************************************************************************/
4919 static CXCursorVisitor
GetVisitor(const char *s
) {
4921 return FilteredPrintingVisitor
;
4922 if (strcmp(s
, "-usrs") == 0)
4924 if (strncmp(s
, "-memory-usage", 13) == 0)
4925 return GetVisitor(s
+ 13);
4929 static void print_usage(void) {
4931 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
4932 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
4933 " c-index-test -cursor-at=<site> <compiler arguments>\n"
4934 " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
4935 " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
4936 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
4937 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
4939 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4940 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4941 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
4942 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
4943 " c-index-test -test-file-scan <AST file> <source file> "
4944 "[FileCheck prefix]\n");
4946 " c-index-test -test-load-tu <AST file> <symbol filter> "
4947 "[FileCheck prefix]\n"
4948 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
4949 "[FileCheck prefix]\n"
4950 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
4952 " c-index-test -test-load-source-memory-usage "
4953 "<symbol filter> {<args>}*\n"
4954 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
4956 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
4957 " c-index-test -test-load-source-usrs-memory-usage "
4958 "<symbol filter> {<args>}*\n"
4959 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
4960 " c-index-test -test-inclusion-stack-source {<args>}*\n"
4961 " c-index-test -test-inclusion-stack-tu <AST file>\n");
4963 " c-index-test -test-print-linkage-source {<args>}*\n"
4964 " c-index-test -test-print-visibility {<args>}*\n"
4965 " c-index-test -test-print-type {<args>}*\n"
4966 " c-index-test -test-print-type-size {<args>}*\n"
4967 " c-index-test -test-print-bitwidth {<args>}*\n"
4968 " c-index-test -test-print-target-info {<args>}*\n"
4969 " c-index-test -test-print-type-declaration {<args>}*\n"
4970 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
4971 " c-index-test -print-usr-file <file>\n");
4973 " c-index-test -single-symbol-sgfs <symbol filter> {<args>*}\n"
4974 " c-index-test -single-symbol-sgf-at=<site> {<args>*}\n"
4975 " c-index-test -single-symbol-sgf-for=<usr> {<args>}*\n");
4977 " c-index-test -write-pch <file> <compiler arguments>\n"
4978 " c-index-test -compilation-db [lookup <filename>] database\n");
4980 " c-index-test -print-build-session-timestamp\n");
4982 " c-index-test -read-diagnostics <file>\n\n");
4984 " <symbol filter> values:\n%s",
4985 " all - load all symbols, including those from PCH\n"
4986 " local - load all symbols except those in PCH\n"
4987 " category - only load ObjC categories (non-PCH)\n"
4988 " interface - only load ObjC interfaces (non-PCH)\n"
4989 " protocol - only load ObjC protocols (non-PCH)\n"
4990 " function - only load functions (non-PCH)\n"
4991 " typedef - only load typdefs (non-PCH)\n"
4992 " scan-function - scan function bodies (non-PCH)\n\n");
4997 int cindextest_main(int argc
, const char **argv
) {
4998 clang_enableStackTraces();
4999 if (argc
> 2 && strcmp(argv
[1], "-read-diagnostics") == 0)
5000 return read_diagnostics(argv
[2]);
5001 if (argc
> 2 && strstr(argv
[1], "-code-completion-at=") == argv
[1])
5002 return perform_code_completion(argc
, argv
, 0);
5003 if (argc
> 2 && strstr(argv
[1], "-code-completion-timing=") == argv
[1])
5004 return perform_code_completion(argc
, argv
, 1);
5005 if (argc
> 2 && strstr(argv
[1], "-cursor-at=") == argv
[1])
5006 return inspect_cursor_at(argc
, argv
, "-cursor-at=", inspect_print_cursor
);
5007 if (argc
> 2 && strstr(argv
[1], "-evaluate-cursor-at=") == argv
[1])
5008 return inspect_cursor_at(argc
, argv
, "-evaluate-cursor-at=",
5009 inspect_evaluate_cursor
);
5010 if (argc
> 2 && strstr(argv
[1], "-get-macro-info-cursor-at=") == argv
[1])
5011 return inspect_cursor_at(argc
, argv
, "-get-macro-info-cursor-at=",
5012 inspect_macroinfo_cursor
);
5013 if (argc
> 2 && strstr(argv
[1], "-file-refs-at=") == argv
[1])
5014 return find_file_refs_at(argc
, argv
);
5015 if (argc
> 2 && strstr(argv
[1], "-file-includes-in=") == argv
[1])
5016 return find_file_includes_in(argc
, argv
);
5017 if (argc
> 2 && strcmp(argv
[1], "-index-file") == 0)
5018 return index_file(argc
- 2, argv
+ 2, /*full=*/0);
5019 if (argc
> 2 && strcmp(argv
[1], "-index-file-full") == 0)
5020 return index_file(argc
- 2, argv
+ 2, /*full=*/1);
5021 if (argc
> 2 && strcmp(argv
[1], "-index-tu") == 0)
5022 return index_tu(argc
- 2, argv
+ 2);
5023 if (argc
> 2 && strcmp(argv
[1], "-index-compile-db") == 0)
5024 return index_compile_db(argc
- 2, argv
+ 2);
5025 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-tu", 13) == 0) {
5026 CXCursorVisitor I
= GetVisitor(argv
[1] + 13);
5028 return perform_test_load_tu(argv
[2], argv
[3], argc
>= 5 ? argv
[4] : 0, I
,
5031 else if (argc
>= 5 && strncmp(argv
[1], "-test-load-source-reparse", 25) == 0){
5032 CXCursorVisitor I
= GetVisitor(argv
[1] + 25);
5034 int trials
= atoi(argv
[2]);
5035 return perform_test_reparse_source(argc
- 4, argv
+ 4, trials
, argv
[3], I
,
5039 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-source", 17) == 0) {
5040 CXCursorVisitor I
= GetVisitor(argv
[1] + 17);
5042 PostVisitTU postVisit
= 0;
5043 if (strstr(argv
[1], "-memory-usage"))
5044 postVisit
= PrintMemoryUsage
;
5047 return perform_test_load_source(argc
- 3, argv
+ 3, argv
[2], I
,
5050 else if (argc
>= 3 && strcmp(argv
[1], "-single-file-parse") == 0)
5051 return perform_single_file_parse(argv
[2]);
5052 else if (argc
>= 3 && strcmp(argv
[1], "-retain-excluded-conditional-blocks") == 0)
5053 return perform_file_retain_excluded_cb(argv
[2]);
5054 else if (argc
>= 4 && strcmp(argv
[1], "-test-file-scan") == 0)
5055 return perform_file_scan(argv
[2], argv
[3],
5056 argc
>= 5 ? argv
[4] : 0);
5057 else if (argc
> 2 && strstr(argv
[1], "-test-annotate-tokens=") == argv
[1])
5058 return perform_token_annotation(argc
, argv
);
5059 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-source") == 0)
5060 return perform_test_load_source(argc
- 2, argv
+ 2, "all", NULL
,
5061 PrintInclusionStack
);
5062 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-tu") == 0)
5063 return perform_test_load_tu(argv
[2], "all", NULL
, NULL
,
5064 PrintInclusionStack
);
5065 else if (argc
> 2 && strcmp(argv
[1], "-test-print-linkage-source") == 0)
5066 return perform_test_load_source(argc
- 2, argv
+ 2, "all", PrintLinkage
,
5068 else if (argc
> 2 && strcmp(argv
[1], "-test-print-visibility") == 0)
5069 return perform_test_load_source(argc
- 2, argv
+ 2, "all", PrintVisibility
,
5071 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type") == 0)
5072 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5074 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type-size") == 0)
5075 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5077 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type-declaration") == 0)
5078 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5079 PrintTypeDeclaration
, 0);
5080 else if (argc
> 2 && strcmp(argv
[1], "-test-print-decl-attributes") == 0)
5081 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5082 PrintDeclAttributes
, 0);
5083 else if (argc
> 2 && strcmp(argv
[1], "-test-print-bitwidth") == 0)
5084 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5086 else if (argc
> 2 && strcmp(argv
[1], "-test-print-mangle") == 0)
5087 return perform_test_load_tu(argv
[2], "all", NULL
, PrintMangledName
, NULL
);
5088 else if (argc
> 2 && strcmp(argv
[1], "-test-print-manglings") == 0)
5089 return perform_test_load_tu(argv
[2], "all", NULL
, PrintManglings
, NULL
);
5090 else if (argc
> 2 && strcmp(argv
[1], "-test-print-target-info") == 0)
5091 return print_target_info(argc
- 2, argv
+ 2);
5092 else if (argc
> 1 && strcmp(argv
[1], "-print-usr") == 0) {
5094 return print_usrs(argv
+ 2, argv
+ argc
);
5100 else if (argc
> 2 && strcmp(argv
[1], "-print-usr-file") == 0)
5101 return print_usrs_file(argv
[2]);
5102 else if (argc
> 2 && strcmp(argv
[1], "-write-pch") == 0)
5103 return write_pch_file(argv
[2], argc
- 3, argv
+ 3);
5104 else if (argc
> 2 && strcmp(argv
[1], "-compilation-db") == 0)
5105 return perform_test_compilation_db(argv
[argc
-1], argc
- 3, argv
+ 2);
5106 else if (argc
== 2 && strcmp(argv
[1], "-print-build-session-timestamp") == 0)
5107 return perform_print_build_session_timestamp();
5108 else if (argc
> 3 && strcmp(argv
[1], "-single-symbol-sgfs") == 0)
5109 return perform_test_load_source(argc
- 3, argv
+ 3, argv
[2],
5110 PrintSingleSymbolSGFs
, NULL
);
5111 else if (argc
> 2 && strstr(argv
[1], "-single-symbol-sgf-at=") == argv
[1])
5112 return inspect_cursor_at(
5113 argc
, argv
, "-single-symbol-sgf-at=", inspect_single_symbol_sgf_cursor
);
5114 else if (argc
> 2 && strstr(argv
[1], "-single-symbol-sgf-for=") == argv
[1])
5115 return perform_test_single_symbol_sgf(argv
[1], argc
- 2, argv
+ 2);
5123 /* We intentionally run in a separate thread to ensure we at least minimal
5124 * testing of a multithreaded environment (for example, having a reduced stack
5127 typedef struct thread_info
{
5128 int (*main_func
)(int argc
, const char **argv
);
5133 void thread_runner(void *client_data_v
) {
5134 thread_info
*client_data
= client_data_v
;
5135 client_data
->result
= client_data
->main_func(client_data
->argc
,
5139 static void flush_atexit(void) {
5140 /* stdout, and surprisingly even stderr, are not always flushed on process
5141 * and thread exit, particularly when the system is under heavy load. */
5146 int main(int argc
, const char **argv
) {
5147 thread_info client_data
;
5149 atexit(flush_atexit
);
5151 #ifdef CLANG_HAVE_LIBXML
5155 if (argc
> 1 && strcmp(argv
[1], "core") == 0)
5156 return indextest_core_main(argc
, argv
);
5158 client_data
.main_func
= cindextest_main
;
5159 client_data
.argc
= argc
;
5160 client_data
.argv
= argv
;
5162 if (getenv("CINDEXTEST_NOTHREADS"))
5163 return client_data
.main_func(client_data
.argc
, client_data
.argv
);
5165 clang_executeOnThread(thread_runner
, &client_data
, 0);
5166 return client_data
.result
;