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"
11 #include "llvm/Support/AutoConvert.h"
18 #ifdef CLANG_HAVE_LIBXML
19 #include <libxml/parser.h>
20 #include <libxml/relaxng.h>
21 #include <libxml/xmlerror.h>
30 extern int indextest_core_main(int argc
, const char **argv
);
31 extern int indextest_perform_shell_execution(const char *command_line
);
33 /******************************************************************************/
34 /* Utility functions. */
35 /******************************************************************************/
38 char *basename(const char* path
)
40 char* base1
= (char*)strrchr(path
, '/');
41 char* base2
= (char*)strrchr(path
, '\\');
43 return((base1
> base2
) ? base1
+ 1 : base2
+ 1);
51 char *dirname(char* path
)
53 char* base1
= (char*)strrchr(path
, '/');
54 char* base2
= (char*)strrchr(path
, '\\');
68 extern char *basename(const char *);
69 extern char *dirname(char *);
72 CXIndex
createIndexWithInvocationEmissionPath(int ExcludeDeclarationsFromPCH
,
73 int DisplayDiagnostics
) {
77 memset(&Opts
, 0, sizeof(Opts
));
78 Opts
.Size
= sizeof(CXIndexOptions
);
79 Opts
.ExcludeDeclarationsFromPCH
= ExcludeDeclarationsFromPCH
;
80 Opts
.DisplayDiagnostics
= DisplayDiagnostics
;
81 Opts
.InvocationEmissionPath
= getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
83 Idx
= clang_createIndexWithOptions(&Opts
);
86 "clang_createIndexWithOptions() failed. "
87 "CINDEX_VERSION_MINOR = %d, sizeof(CXIndexOptions) = %u\n",
88 CINDEX_VERSION_MINOR
, Opts
.Size
);
93 /** Return the default parsing options. */
94 static unsigned getDefaultParsingOptions(void) {
95 unsigned options
= CXTranslationUnit_DetailedPreprocessingRecord
;
97 if (getenv("CINDEXTEST_EDITING"))
98 options
|= clang_defaultEditingTranslationUnitOptions();
99 if (getenv("CINDEXTEST_COMPLETION_CACHING"))
100 options
|= CXTranslationUnit_CacheCompletionResults
;
101 if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
102 options
&= ~CXTranslationUnit_CacheCompletionResults
;
103 if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
104 options
|= CXTranslationUnit_SkipFunctionBodies
;
105 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
106 options
|= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion
;
107 if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
108 options
|= CXTranslationUnit_CreatePreambleOnFirstParse
;
109 if (getenv("CINDEXTEST_KEEP_GOING"))
110 options
|= CXTranslationUnit_KeepGoing
;
111 if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
112 options
|= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble
;
113 if (getenv("CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES"))
114 options
|= CXTranslationUnit_IncludeAttributedTypes
;
115 if (getenv("CINDEXTEST_VISIT_IMPLICIT_ATTRIBUTES"))
116 options
|= CXTranslationUnit_VisitImplicitAttributes
;
117 if (getenv("CINDEXTEST_IGNORE_NONERRORS_FROM_INCLUDED_FILES"))
118 options
|= CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles
;
123 static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy
) {
126 enum CXPrintingPolicyProperty property
;
128 struct Mapping mappings
[] = {
129 {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation
},
130 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS",
131 CXPrintingPolicy_SuppressSpecifiers
},
132 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
133 CXPrintingPolicy_SuppressTagKeyword
},
134 {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
135 CXPrintingPolicy_IncludeTagDefinition
},
136 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
137 CXPrintingPolicy_SuppressScope
},
138 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
139 CXPrintingPolicy_SuppressUnwrittenScope
},
140 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS",
141 CXPrintingPolicy_SuppressInitializers
},
142 {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN",
143 CXPrintingPolicy_ConstantArraySizeAsWritten
},
144 {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS",
145 CXPrintingPolicy_AnonymousTagLocations
},
146 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME",
147 CXPrintingPolicy_SuppressStrongLifetime
},
148 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS",
149 CXPrintingPolicy_SuppressLifetimeQualifiers
},
150 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS",
151 CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors
},
152 {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool
},
153 {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict
},
154 {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof
},
155 {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF",
156 CXPrintingPolicy_UnderscoreAlignof
},
157 {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS",
158 CXPrintingPolicy_UseVoidForZeroParams
},
159 {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput
},
160 {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION",
161 CXPrintingPolicy_PolishForDeclaration
},
162 {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half
},
163 {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar
},
164 {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES",
165 CXPrintingPolicy_IncludeNewlines
},
166 {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING",
167 CXPrintingPolicy_MSVCFormatting
},
168 {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN",
169 CXPrintingPolicy_ConstantsAsWritten
},
170 {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE",
171 CXPrintingPolicy_SuppressImplicitBase
},
172 {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME",
173 CXPrintingPolicy_FullyQualifiedName
},
177 for (i
= 0; i
< sizeof(mappings
) / sizeof(struct Mapping
); i
++) {
178 char *value
= getenv(mappings
[i
].name
);
180 clang_PrintingPolicy_setProperty(Policy
, mappings
[i
].property
,
181 (unsigned)strtoul(value
, 0L, 10));
186 /** Returns 0 in case of success, non-zero in case of a failure. */
187 static int checkForErrors(CXTranslationUnit TU
);
189 static void describeLibclangFailure(enum CXErrorCode Err
) {
191 case CXError_Success
:
192 fprintf(stderr
, "Success\n");
195 case CXError_Failure
:
196 fprintf(stderr
, "Failure (no details available)\n");
199 case CXError_Crashed
:
200 fprintf(stderr
, "Failure: libclang crashed\n");
203 case CXError_InvalidArguments
:
204 fprintf(stderr
, "Failure: invalid arguments passed to a libclang routine\n");
207 case CXError_ASTReadError
:
208 fprintf(stderr
, "Failure: AST deserialization error occurred\n");
213 static void PrintExtent(FILE *out
, unsigned begin_line
, unsigned begin_column
,
214 unsigned end_line
, unsigned end_column
) {
215 fprintf(out
, "[%d:%d - %d:%d]", begin_line
, begin_column
,
216 end_line
, end_column
);
219 static unsigned CreateTranslationUnit(CXIndex Idx
, const char *file
,
220 CXTranslationUnit
*TU
) {
221 enum CXErrorCode Err
= clang_createTranslationUnit2(Idx
, file
, TU
);
222 if (Err
!= CXError_Success
) {
223 fprintf(stderr
, "Unable to load translation unit from '%s'!\n", file
);
224 describeLibclangFailure(Err
);
231 void free_remapped_files(struct CXUnsavedFile
*unsaved_files
,
232 int num_unsaved_files
) {
234 for (i
= 0; i
!= num_unsaved_files
; ++i
) {
236 #pragma GCC diagnostic push
237 #pragma GCC diagnostic ignored "-Wcast-qual"
239 free((char *)unsaved_files
[i
].Filename
);
240 free((char *)unsaved_files
[i
].Contents
);
242 #pragma GCC diagnostic pop
248 static int parse_remapped_files_with_opt(const char *opt_name
,
249 int argc
, const char **argv
,
251 struct CXUnsavedFile
**unsaved_files
,
252 int *num_unsaved_files
) {
255 int prefix_len
= strlen(opt_name
);
258 *num_unsaved_files
= 0;
260 /* Count the number of remapped files. */
261 for (arg
= start_arg
; arg
< argc
; ++arg
) {
262 if (strncmp(argv
[arg
], opt_name
, prefix_len
))
265 assert(*num_unsaved_files
< (int)(sizeof(arg_indices
)/sizeof(int)));
266 arg_indices
[*num_unsaved_files
] = arg
;
267 ++*num_unsaved_files
;
270 if (*num_unsaved_files
== 0)
274 = (struct CXUnsavedFile
*)malloc(sizeof(struct CXUnsavedFile
) *
276 assert(*unsaved_files
);
277 for (i
= 0; i
!= *num_unsaved_files
; ++i
) {
278 struct CXUnsavedFile
*unsaved
= *unsaved_files
+ i
;
279 const char *arg_string
= argv
[arg_indices
[i
]] + prefix_len
;
284 const char *sep
= strchr(arg_string
, ',');
287 "error: %sfrom:to argument is missing comma\n", opt_name
);
288 free_remapped_files(*unsaved_files
, i
);
290 *num_unsaved_files
= 0;
294 /* Open the file that we're remapping to. */
295 to_file
= fopen(sep
+ 1, "rb");
297 fprintf(stderr
, "error: cannot open file %s that we are remapping to\n",
299 free_remapped_files(*unsaved_files
, i
);
301 *num_unsaved_files
= 0;
305 /* Determine the length of the file we're remapping to. */
306 fseek(to_file
, 0, SEEK_END
);
307 unsaved
->Length
= ftell(to_file
);
308 fseek(to_file
, 0, SEEK_SET
);
310 /* Read the contents of the file we're remapping to. */
311 contents
= (char *)malloc(unsaved
->Length
+ 1);
313 if (fread(contents
, 1, unsaved
->Length
, to_file
) != unsaved
->Length
) {
314 fprintf(stderr
, "error: unexpected %s reading 'to' file %s\n",
315 (feof(to_file
) ? "EOF" : "error"), sep
+ 1);
317 free_remapped_files(*unsaved_files
, i
);
320 *num_unsaved_files
= 0;
323 contents
[unsaved
->Length
] = 0;
324 unsaved
->Contents
= contents
;
326 /* Close the file. */
329 /* Copy the file name that we're remapping from. */
330 filename_len
= sep
- arg_string
;
331 filename
= (char *)malloc(filename_len
+ 1);
333 memcpy(filename
, arg_string
, filename_len
);
334 filename
[filename_len
] = 0;
335 unsaved
->Filename
= filename
;
341 static int parse_remapped_files(int argc
, const char **argv
, int start_arg
,
342 struct CXUnsavedFile
**unsaved_files
,
343 int *num_unsaved_files
) {
344 return parse_remapped_files_with_opt("-remap-file=", argc
, argv
, start_arg
,
345 unsaved_files
, num_unsaved_files
);
348 static int parse_remapped_files_with_try(int try_idx
,
349 int argc
, const char **argv
,
351 struct CXUnsavedFile
**unsaved_files
,
352 int *num_unsaved_files
) {
353 struct CXUnsavedFile
*unsaved_files_no_try_idx
;
354 int num_unsaved_files_no_try_idx
;
355 struct CXUnsavedFile
*unsaved_files_try_idx
;
356 int num_unsaved_files_try_idx
;
360 ret
= parse_remapped_files(argc
, argv
, start_arg
,
361 &unsaved_files_no_try_idx
, &num_unsaved_files_no_try_idx
);
365 sprintf(opt_name
, "-remap-file-%d=", try_idx
);
366 ret
= parse_remapped_files_with_opt(opt_name
, argc
, argv
, start_arg
,
367 &unsaved_files_try_idx
, &num_unsaved_files_try_idx
);
371 if (num_unsaved_files_no_try_idx
== 0) {
372 *unsaved_files
= unsaved_files_try_idx
;
373 *num_unsaved_files
= num_unsaved_files_try_idx
;
376 if (num_unsaved_files_try_idx
== 0) {
377 *unsaved_files
= unsaved_files_no_try_idx
;
378 *num_unsaved_files
= num_unsaved_files_no_try_idx
;
382 *num_unsaved_files
= num_unsaved_files_no_try_idx
+ num_unsaved_files_try_idx
;
384 = (struct CXUnsavedFile
*)realloc(unsaved_files_no_try_idx
,
385 sizeof(struct CXUnsavedFile
) *
387 assert(*unsaved_files
);
388 memcpy(*unsaved_files
+ num_unsaved_files_no_try_idx
,
389 unsaved_files_try_idx
, sizeof(struct CXUnsavedFile
) *
390 num_unsaved_files_try_idx
);
391 free(unsaved_files_try_idx
);
395 static const char *parse_comments_schema(int argc
, const char **argv
) {
396 const char *CommentsSchemaArg
= "-comments-xml-schema=";
397 const char *CommentSchemaFile
= NULL
;
400 return CommentSchemaFile
;
402 if (!strncmp(argv
[0], CommentsSchemaArg
, strlen(CommentsSchemaArg
)))
403 CommentSchemaFile
= argv
[0] + strlen(CommentsSchemaArg
);
405 return CommentSchemaFile
;
408 /******************************************************************************/
409 /* Pretty-printing. */
410 /******************************************************************************/
412 static const char *FileCheckPrefix
= "CHECK";
414 static void PrintCString(const char *CStr
) {
415 if (CStr
!= NULL
&& CStr
[0] != '\0') {
416 for ( ; *CStr
; ++CStr
) {
417 const char C
= *CStr
;
419 case '\n': printf("\\n"); break;
420 case '\r': printf("\\r"); break;
421 case '\t': printf("\\t"); break;
422 case '\v': printf("\\v"); break;
423 case '\f': printf("\\f"); break;
424 default: putchar(C
); break;
430 static void PrintCStringWithPrefix(const char *Prefix
, const char *CStr
) {
431 printf(" %s=[", Prefix
);
436 static void PrintCXStringAndDispose(CXString Str
) {
437 PrintCString(clang_getCString(Str
));
438 clang_disposeString(Str
);
441 static void PrintCXStringWithPrefix(const char *Prefix
, CXString Str
) {
442 PrintCStringWithPrefix(Prefix
, clang_getCString(Str
));
445 static void PrintCXStringWithPrefixAndDispose(const char *Prefix
,
447 PrintCStringWithPrefix(Prefix
, clang_getCString(Str
));
448 clang_disposeString(Str
);
451 static void PrintRange(CXSourceRange R
, const char *str
) {
452 CXFile begin_file
, end_file
;
453 unsigned begin_line
, begin_column
, end_line
, end_column
;
455 clang_getSpellingLocation(clang_getRangeStart(R
),
456 &begin_file
, &begin_line
, &begin_column
, 0);
457 clang_getSpellingLocation(clang_getRangeEnd(R
),
458 &end_file
, &end_line
, &end_column
, 0);
459 if (!begin_file
|| !end_file
)
464 PrintExtent(stdout
, begin_line
, begin_column
, end_line
, end_column
);
467 static enum DisplayType
{
468 DisplayType_Spelling
,
469 DisplayType_DisplayName
,
471 } wanted_display_type
= DisplayType_Spelling
;
473 static void printVersion(const char *Prefix
, CXVersion Version
) {
474 if (Version
.Major
< 0)
476 printf("%s%d", Prefix
, Version
.Major
);
478 if (Version
.Minor
< 0)
480 printf(".%d", Version
.Minor
);
482 if (Version
.Subminor
< 0)
484 printf(".%d", Version
.Subminor
);
487 struct CommentASTDumpingContext
{
491 static void DumpCXCommentInternal(struct CommentASTDumpingContext
*Ctx
,
495 enum CXCommentKind Kind
= clang_Comment_getKind(Comment
);
498 for (i
= 0, e
= Ctx
->IndentLevel
; i
!= e
; ++i
)
504 printf("CXComment_Null");
507 printf("CXComment_Text");
508 PrintCXStringWithPrefixAndDispose("Text",
509 clang_TextComment_getText(Comment
));
510 if (clang_Comment_isWhitespace(Comment
))
511 printf(" IsWhitespace");
512 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
513 printf(" HasTrailingNewline");
515 case CXComment_InlineCommand
:
516 printf("CXComment_InlineCommand");
517 PrintCXStringWithPrefixAndDispose(
519 clang_InlineCommandComment_getCommandName(Comment
));
520 switch (clang_InlineCommandComment_getRenderKind(Comment
)) {
521 case CXCommentInlineCommandRenderKind_Normal
:
522 printf(" RenderNormal");
524 case CXCommentInlineCommandRenderKind_Bold
:
525 printf(" RenderBold");
527 case CXCommentInlineCommandRenderKind_Monospaced
:
528 printf(" RenderMonospaced");
530 case CXCommentInlineCommandRenderKind_Emphasized
:
531 printf(" RenderEmphasized");
533 case CXCommentInlineCommandRenderKind_Anchor
:
534 printf(" RenderAnchor");
537 for (i
= 0, e
= clang_InlineCommandComment_getNumArgs(Comment
);
539 printf(" Arg[%u]=", i
);
540 PrintCXStringAndDispose(
541 clang_InlineCommandComment_getArgText(Comment
, i
));
543 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
544 printf(" HasTrailingNewline");
546 case CXComment_HTMLStartTag
: {
548 printf("CXComment_HTMLStartTag");
549 PrintCXStringWithPrefixAndDispose(
551 clang_HTMLTagComment_getTagName(Comment
));
552 NumAttrs
= clang_HTMLStartTag_getNumAttrs(Comment
);
555 for (i
= 0; i
!= NumAttrs
; ++i
) {
557 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment
, i
));
559 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment
, i
));
562 if (clang_HTMLStartTagComment_isSelfClosing(Comment
))
563 printf(" SelfClosing");
564 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
565 printf(" HasTrailingNewline");
568 case CXComment_HTMLEndTag
:
569 printf("CXComment_HTMLEndTag");
570 PrintCXStringWithPrefixAndDispose(
572 clang_HTMLTagComment_getTagName(Comment
));
573 if (clang_InlineContentComment_hasTrailingNewline(Comment
))
574 printf(" HasTrailingNewline");
576 case CXComment_Paragraph
:
577 printf("CXComment_Paragraph");
578 if (clang_Comment_isWhitespace(Comment
))
579 printf(" IsWhitespace");
581 case CXComment_BlockCommand
:
582 printf("CXComment_BlockCommand");
583 PrintCXStringWithPrefixAndDispose(
585 clang_BlockCommandComment_getCommandName(Comment
));
586 for (i
= 0, e
= clang_BlockCommandComment_getNumArgs(Comment
);
588 printf(" Arg[%u]=", i
);
589 PrintCXStringAndDispose(
590 clang_BlockCommandComment_getArgText(Comment
, i
));
593 case CXComment_ParamCommand
:
594 printf("CXComment_ParamCommand");
595 switch (clang_ParamCommandComment_getDirection(Comment
)) {
596 case CXCommentParamPassDirection_In
:
599 case CXCommentParamPassDirection_Out
:
602 case CXCommentParamPassDirection_InOut
:
606 if (clang_ParamCommandComment_isDirectionExplicit(Comment
))
607 printf(" explicitly");
609 printf(" implicitly");
610 PrintCXStringWithPrefixAndDispose(
612 clang_ParamCommandComment_getParamName(Comment
));
613 if (clang_ParamCommandComment_isParamIndexValid(Comment
))
614 printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment
));
616 printf(" ParamIndex=Invalid");
618 case CXComment_TParamCommand
:
619 printf("CXComment_TParamCommand");
620 PrintCXStringWithPrefixAndDispose(
622 clang_TParamCommandComment_getParamName(Comment
));
623 if (clang_TParamCommandComment_isParamPositionValid(Comment
)) {
624 printf(" ParamPosition={");
625 for (i
= 0, e
= clang_TParamCommandComment_getDepth(Comment
);
627 printf("%u", clang_TParamCommandComment_getIndex(Comment
, i
));
633 printf(" ParamPosition=Invalid");
635 case CXComment_VerbatimBlockCommand
:
636 printf("CXComment_VerbatimBlockCommand");
637 PrintCXStringWithPrefixAndDispose(
639 clang_BlockCommandComment_getCommandName(Comment
));
641 case CXComment_VerbatimBlockLine
:
642 printf("CXComment_VerbatimBlockLine");
643 PrintCXStringWithPrefixAndDispose(
645 clang_VerbatimBlockLineComment_getText(Comment
));
647 case CXComment_VerbatimLine
:
648 printf("CXComment_VerbatimLine");
649 PrintCXStringWithPrefixAndDispose(
651 clang_VerbatimLineComment_getText(Comment
));
653 case CXComment_FullComment
:
654 printf("CXComment_FullComment");
657 if (Kind
!= CXComment_Null
) {
658 const unsigned NumChildren
= clang_Comment_getNumChildren(Comment
);
660 for (i
= 0; i
!= NumChildren
; ++i
) {
661 printf("\n// %s: ", FileCheckPrefix
);
662 DumpCXCommentInternal(Ctx
, clang_Comment_getChild(Comment
, i
));
669 static void DumpCXComment(CXComment Comment
) {
670 struct CommentASTDumpingContext Ctx
;
672 printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix
, FileCheckPrefix
);
673 DumpCXCommentInternal(&Ctx
, Comment
);
677 static void ValidateCommentXML(const char *Str
, const char *CommentSchemaFile
) {
678 #ifdef CLANG_HAVE_LIBXML
679 xmlRelaxNGParserCtxtPtr RNGParser
;
680 xmlRelaxNGPtr Schema
;
682 xmlRelaxNGValidCtxtPtr ValidationCtxt
;
685 if (!CommentSchemaFile
)
688 RNGParser
= xmlRelaxNGNewParserCtxt(CommentSchemaFile
);
690 printf(" libXMLError");
693 Schema
= xmlRelaxNGParse(RNGParser
);
695 Doc
= xmlParseDoc((const xmlChar
*) Str
);
698 xmlErrorPtr Error
= xmlGetLastError();
699 printf(" CommentXMLInvalid [not well-formed XML: %s]", Error
->message
);
703 ValidationCtxt
= xmlRelaxNGNewValidCtxt(Schema
);
704 status
= xmlRelaxNGValidateDoc(ValidationCtxt
, Doc
);
706 printf(" CommentXMLValid");
707 else if (status
> 0) {
708 xmlErrorPtr Error
= xmlGetLastError();
709 printf(" CommentXMLInvalid [not valid XML: %s]", Error
->message
);
711 printf(" libXMLError");
713 xmlRelaxNGFreeValidCtxt(ValidationCtxt
);
715 xmlRelaxNGFree(Schema
);
716 xmlRelaxNGFreeParserCtxt(RNGParser
);
720 static void PrintCursorComments(CXCursor Cursor
,
721 const char *CommentSchemaFile
) {
724 const char *RawCommentCString
;
725 CXString BriefComment
;
726 const char *BriefCommentCString
;
728 RawComment
= clang_Cursor_getRawCommentText(Cursor
);
729 RawCommentCString
= clang_getCString(RawComment
);
730 if (RawCommentCString
!= NULL
&& RawCommentCString
[0] != '\0') {
731 PrintCStringWithPrefix("RawComment", RawCommentCString
);
732 PrintRange(clang_Cursor_getCommentRange(Cursor
), "RawCommentRange");
734 BriefComment
= clang_Cursor_getBriefCommentText(Cursor
);
735 BriefCommentCString
= clang_getCString(BriefComment
);
736 if (BriefCommentCString
!= NULL
&& BriefCommentCString
[0] != '\0')
737 PrintCStringWithPrefix("BriefComment", BriefCommentCString
);
738 clang_disposeString(BriefComment
);
740 clang_disposeString(RawComment
);
744 CXComment Comment
= clang_Cursor_getParsedComment(Cursor
);
745 if (clang_Comment_getKind(Comment
) != CXComment_Null
) {
746 PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
747 clang_FullComment_getAsHTML(Comment
));
750 XML
= clang_FullComment_getAsXML(Comment
);
751 PrintCXStringWithPrefix("FullCommentAsXML", XML
);
752 ValidateCommentXML(clang_getCString(XML
), CommentSchemaFile
);
753 clang_disposeString(XML
);
756 DumpCXComment(Comment
);
766 static int lineCol_cmp(const void *p1
, const void *p2
) {
767 const LineCol
*lhs
= p1
;
768 const LineCol
*rhs
= p2
;
769 if (lhs
->line
!= rhs
->line
)
770 return (int)lhs
->line
- (int)rhs
->line
;
771 return (int)lhs
->col
- (int)rhs
->col
;
774 static CXString
CursorToText(CXCursor Cursor
) {
776 switch (wanted_display_type
) {
777 case DisplayType_Spelling
:
778 return clang_getCursorSpelling(Cursor
);
779 case DisplayType_DisplayName
:
780 return clang_getCursorDisplayName(Cursor
);
781 case DisplayType_Pretty
: {
782 CXPrintingPolicy Policy
= clang_getCursorPrintingPolicy(Cursor
);
783 ModifyPrintingPolicyAccordingToEnv(Policy
);
784 text
= clang_getCursorPrettyPrinted(Cursor
, Policy
);
785 clang_PrintingPolicy_dispose(Policy
);
789 assert(0 && "unknown display type"); /* no llvm_unreachable in C. */
790 /* Set to NULL to prevent uninitialized variable warnings. */
792 text
.private_flags
= 0;
796 static void PrintCursor(CXCursor Cursor
, const char *CommentSchemaFile
) {
797 CXTranslationUnit TU
= clang_Cursor_getTranslationUnit(Cursor
);
798 if (clang_isInvalid(Cursor
.kind
)) {
799 CXString ks
= clang_getCursorKindSpelling(Cursor
.kind
);
800 printf("Invalid Cursor => %s", clang_getCString(ks
));
801 clang_disposeString(ks
);
806 unsigned line
, column
;
807 CXCursor SpecializationOf
;
808 CXCursor
*overridden
;
809 unsigned num_overridden
;
810 unsigned RefNameRangeNr
;
811 CXSourceRange CursorExtent
;
812 CXSourceRange RefNameRange
;
813 int AlwaysUnavailable
;
814 int AlwaysDeprecated
;
815 CXString UnavailableMessage
;
816 CXString DeprecatedMessage
;
817 CXPlatformAvailability PlatformAvailability
[2];
818 int NumPlatformAvailability
;
821 ks
= clang_getCursorKindSpelling(Cursor
.kind
);
822 string
= CursorToText(Cursor
);
823 printf("%s=%s", clang_getCString(ks
),
824 clang_getCString(string
));
825 clang_disposeString(ks
);
826 clang_disposeString(string
);
828 Referenced
= clang_getCursorReferenced(Cursor
);
829 if (!clang_equalCursors(Referenced
, clang_getNullCursor())) {
830 if (clang_getCursorKind(Referenced
) == CXCursor_OverloadedDeclRef
) {
831 unsigned I
, N
= clang_getNumOverloadedDecls(Referenced
);
833 for (I
= 0; I
!= N
; ++I
) {
834 CXCursor Ovl
= clang_getOverloadedDecl(Referenced
, I
);
835 CXSourceLocation Loc
;
839 Loc
= clang_getCursorLocation(Ovl
);
840 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
841 printf("%d:%d", line
, column
);
845 CXSourceLocation Loc
= clang_getCursorLocation(Referenced
);
846 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
847 printf(":%d:%d", line
, column
);
850 if (clang_getCursorKind(Referenced
) == CXCursor_TypedefDecl
) {
851 CXType T
= clang_getCursorType(Referenced
);
852 if (clang_Type_isTransparentTagTypedef(T
)) {
853 CXType Underlying
= clang_getTypedefDeclUnderlyingType(Referenced
);
854 CXString S
= clang_getTypeSpelling(Underlying
);
855 printf(" (Transparent: %s)", clang_getCString(S
));
856 clang_disposeString(S
);
861 if (clang_isCursorDefinition(Cursor
))
862 printf(" (Definition)");
864 switch (clang_getCursorAvailability(Cursor
)) {
865 case CXAvailability_Available
:
868 case CXAvailability_Deprecated
:
869 printf(" (deprecated)");
872 case CXAvailability_NotAvailable
:
873 printf(" (unavailable)");
876 case CXAvailability_NotAccessible
:
877 printf(" (inaccessible)");
881 NumPlatformAvailability
882 = clang_getCursorPlatformAvailability(Cursor
,
887 PlatformAvailability
, 2);
888 if (AlwaysUnavailable
) {
889 printf(" (always unavailable: \"%s\")",
890 clang_getCString(UnavailableMessage
));
891 } else if (AlwaysDeprecated
) {
892 printf(" (always deprecated: \"%s\")",
893 clang_getCString(DeprecatedMessage
));
895 for (I
= 0; I
!= NumPlatformAvailability
; ++I
) {
899 printf(" (%s", clang_getCString(PlatformAvailability
[I
].Platform
));
900 if (PlatformAvailability
[I
].Unavailable
)
901 printf(", unavailable");
903 printVersion(", introduced=", PlatformAvailability
[I
].Introduced
);
904 printVersion(", deprecated=", PlatformAvailability
[I
].Deprecated
);
905 printVersion(", obsoleted=", PlatformAvailability
[I
].Obsoleted
);
907 if (clang_getCString(PlatformAvailability
[I
].Message
)[0])
908 printf(", message=\"%s\"",
909 clang_getCString(PlatformAvailability
[I
].Message
));
913 for (I
= 0; I
!= NumPlatformAvailability
; ++I
) {
916 clang_disposeCXPlatformAvailability(PlatformAvailability
+ I
);
919 clang_disposeString(DeprecatedMessage
);
920 clang_disposeString(UnavailableMessage
);
922 if (clang_CXXConstructor_isDefaultConstructor(Cursor
))
923 printf(" (default constructor)");
925 if (clang_CXXConstructor_isMoveConstructor(Cursor
))
926 printf(" (move constructor)");
927 if (clang_CXXConstructor_isCopyConstructor(Cursor
))
928 printf(" (copy constructor)");
929 if (clang_CXXConstructor_isConvertingConstructor(Cursor
))
930 printf(" (converting constructor)");
931 if (clang_CXXField_isMutable(Cursor
))
932 printf(" (mutable)");
933 if (clang_CXXMethod_isDefaulted(Cursor
))
934 printf(" (defaulted)");
935 if (clang_CXXMethod_isDeleted(Cursor
))
936 printf(" (deleted)");
937 if (clang_CXXMethod_isStatic(Cursor
))
939 if (clang_CXXMethod_isVirtual(Cursor
))
940 printf(" (virtual)");
941 if (clang_CXXMethod_isConst(Cursor
))
943 if (clang_CXXMethod_isPureVirtual(Cursor
))
945 if (clang_CXXMethod_isCopyAssignmentOperator(Cursor
))
946 printf(" (copy-assignment operator)");
947 if (clang_CXXMethod_isMoveAssignmentOperator(Cursor
))
948 printf(" (move-assignment operator)");
949 if (clang_CXXMethod_isExplicit(Cursor
))
950 printf(" (explicit)");
951 if (clang_CXXRecord_isAbstract(Cursor
))
952 printf(" (abstract)");
953 if (clang_EnumDecl_isScoped(Cursor
))
955 if (clang_Cursor_isVariadic(Cursor
))
956 printf(" (variadic)");
957 if (clang_Cursor_isObjCOptional(Cursor
))
958 printf(" (@optional)");
959 if (clang_isInvalidDeclaration(Cursor
))
960 printf(" (invalid)");
962 switch (clang_getCursorExceptionSpecificationType(Cursor
))
964 case CXCursor_ExceptionSpecificationKind_None
:
967 case CXCursor_ExceptionSpecificationKind_DynamicNone
:
968 printf(" (noexcept dynamic none)");
971 case CXCursor_ExceptionSpecificationKind_Dynamic
:
972 printf(" (noexcept dynamic)");
975 case CXCursor_ExceptionSpecificationKind_MSAny
:
976 printf(" (noexcept dynamic any)");
979 case CXCursor_ExceptionSpecificationKind_BasicNoexcept
:
980 printf(" (noexcept)");
983 case CXCursor_ExceptionSpecificationKind_ComputedNoexcept
:
984 printf(" (computed-noexcept)");
987 case CXCursor_ExceptionSpecificationKind_Unevaluated
:
988 case CXCursor_ExceptionSpecificationKind_Uninstantiated
:
989 case CXCursor_ExceptionSpecificationKind_Unparsed
:
997 if (clang_Cursor_isExternalSymbol(Cursor
, &language
, &definedIn
,
999 printf(" (external lang: %s, defined: %s, gen: %d)",
1000 clang_getCString(language
), clang_getCString(definedIn
), generated
);
1001 clang_disposeString(language
);
1002 clang_disposeString(definedIn
);
1006 if (Cursor
.kind
== CXCursor_IBOutletCollectionAttr
) {
1008 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor
));
1009 CXString S
= clang_getTypeKindSpelling(T
.kind
);
1010 printf(" [IBOutletCollection=%s]", clang_getCString(S
));
1011 clang_disposeString(S
);
1014 if (Cursor
.kind
== CXCursor_CXXBaseSpecifier
) {
1015 enum CX_CXXAccessSpecifier access
= clang_getCXXAccessSpecifier(Cursor
);
1016 unsigned isVirtual
= clang_isVirtualBase(Cursor
);
1017 const char *accessStr
= 0;
1020 case CX_CXXInvalidAccessSpecifier
:
1021 accessStr
= "invalid"; break;
1023 accessStr
= "public"; break;
1024 case CX_CXXProtected
:
1025 accessStr
= "protected"; break;
1027 accessStr
= "private"; break;
1030 printf(" [access=%s isVirtual=%s]", accessStr
,
1031 isVirtual
? "true" : "false");
1034 SpecializationOf
= clang_getSpecializedCursorTemplate(Cursor
);
1035 if (!clang_equalCursors(SpecializationOf
, clang_getNullCursor())) {
1036 CXSourceLocation Loc
= clang_getCursorLocation(SpecializationOf
);
1037 CXString Name
= clang_getCursorSpelling(SpecializationOf
);
1038 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1039 printf(" [Specialization of %s:%d:%d]",
1040 clang_getCString(Name
), line
, column
);
1041 clang_disposeString(Name
);
1043 if (Cursor
.kind
== CXCursor_FunctionDecl
1044 || Cursor
.kind
== CXCursor_StructDecl
1045 || Cursor
.kind
== CXCursor_ClassDecl
1046 || Cursor
.kind
== CXCursor_ClassTemplatePartialSpecialization
) {
1047 /* Collect the template parameter kinds from the base template. */
1048 int NumTemplateArgs
= clang_Cursor_getNumTemplateArguments(Cursor
);
1050 if (NumTemplateArgs
< 0) {
1051 printf(" [no template arg info]");
1053 for (I
= 0; I
< NumTemplateArgs
; I
++) {
1054 enum CXTemplateArgumentKind TAK
=
1055 clang_Cursor_getTemplateArgumentKind(Cursor
, I
);
1057 case CXTemplateArgumentKind_Type
:
1059 CXType T
= clang_Cursor_getTemplateArgumentType(Cursor
, I
);
1060 CXString S
= clang_getTypeSpelling(T
);
1061 printf(" [Template arg %d: kind: %d, type: %s]",
1062 I
, TAK
, clang_getCString(S
));
1063 clang_disposeString(S
);
1066 case CXTemplateArgumentKind_Integral
:
1067 printf(" [Template arg %d: kind: %d, intval: %lld]",
1068 I
, TAK
, clang_Cursor_getTemplateArgumentValue(Cursor
, I
));
1071 printf(" [Template arg %d: kind: %d]\n", I
, TAK
);
1077 clang_getOverriddenCursors(Cursor
, &overridden
, &num_overridden
);
1078 if (num_overridden
) {
1080 LineCol lineCols
[50];
1081 assert(num_overridden
<= 50);
1082 printf(" [Overrides ");
1083 for (I
= 0; I
!= num_overridden
; ++I
) {
1084 CXSourceLocation Loc
= clang_getCursorLocation(overridden
[I
]);
1085 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1086 lineCols
[I
].line
= line
;
1087 lineCols
[I
].col
= column
;
1089 /* Make the order of the override list deterministic. */
1090 qsort(lineCols
, num_overridden
, sizeof(LineCol
), lineCol_cmp
);
1091 for (I
= 0; I
!= num_overridden
; ++I
) {
1094 printf("@%d:%d", lineCols
[I
].line
, lineCols
[I
].col
);
1097 clang_disposeOverriddenCursors(overridden
);
1100 if (Cursor
.kind
== CXCursor_InclusionDirective
) {
1101 CXFile File
= clang_getIncludedFile(Cursor
);
1102 CXString Included
= clang_getFileName(File
);
1103 const char *IncludedString
= clang_getCString(Included
);
1104 printf(" (%s)", IncludedString
? IncludedString
: "(null)");
1105 clang_disposeString(Included
);
1107 if (clang_isFileMultipleIncludeGuarded(TU
, File
))
1108 printf(" [multi-include guarded]");
1111 CursorExtent
= clang_getCursorExtent(Cursor
);
1112 RefNameRange
= clang_getCursorReferenceNameRange(Cursor
,
1113 CXNameRange_WantQualifier
1114 | CXNameRange_WantSinglePiece
1115 | CXNameRange_WantTemplateArgs
,
1117 if (!clang_equalRanges(CursorExtent
, RefNameRange
))
1118 PrintRange(RefNameRange
, "SingleRefName");
1120 for (RefNameRangeNr
= 0; 1; RefNameRangeNr
++) {
1121 RefNameRange
= clang_getCursorReferenceNameRange(Cursor
,
1122 CXNameRange_WantQualifier
1123 | CXNameRange_WantTemplateArgs
,
1125 if (clang_equalRanges(clang_getNullRange(), RefNameRange
))
1127 if (!clang_equalRanges(CursorExtent
, RefNameRange
))
1128 PrintRange(RefNameRange
, "RefName");
1131 PrintCursorComments(Cursor
, CommentSchemaFile
);
1134 unsigned PropAttrs
= clang_Cursor_getObjCPropertyAttributes(Cursor
, 0);
1135 if (PropAttrs
!= CXObjCPropertyAttr_noattr
) {
1137 #define PRINT_PROP_ATTR(A) \
1138 if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
1139 PRINT_PROP_ATTR(readonly
);
1140 PRINT_PROP_ATTR(getter
);
1141 PRINT_PROP_ATTR(assign
);
1142 PRINT_PROP_ATTR(readwrite
);
1143 PRINT_PROP_ATTR(retain
);
1144 PRINT_PROP_ATTR(copy
);
1145 PRINT_PROP_ATTR(nonatomic
);
1146 PRINT_PROP_ATTR(setter
);
1147 PRINT_PROP_ATTR(atomic
);
1148 PRINT_PROP_ATTR(weak
);
1149 PRINT_PROP_ATTR(strong
);
1150 PRINT_PROP_ATTR(unsafe_unretained
);
1151 PRINT_PROP_ATTR(class);
1156 if (Cursor
.kind
== CXCursor_ObjCPropertyDecl
) {
1157 CXString Name
= clang_Cursor_getObjCPropertyGetterName(Cursor
);
1158 CXString Spelling
= clang_getCursorSpelling(Cursor
);
1159 const char *CName
= clang_getCString(Name
);
1160 const char *CSpelling
= clang_getCString(Spelling
);
1161 if (CName
&& strcmp(CName
, CSpelling
)) {
1162 printf(" (getter=%s)", CName
);
1164 clang_disposeString(Spelling
);
1165 clang_disposeString(Name
);
1168 if (Cursor
.kind
== CXCursor_ObjCPropertyDecl
) {
1169 CXString Name
= clang_Cursor_getObjCPropertySetterName(Cursor
);
1170 CXString Spelling
= clang_getCursorSpelling(Cursor
);
1171 const char *CName
= clang_getCString(Name
);
1172 const char *CSpelling
= clang_getCString(Spelling
);
1173 char *DefaultSetter
= malloc(strlen(CSpelling
) + 5);
1174 sprintf(DefaultSetter
, "set%s:", CSpelling
);
1175 DefaultSetter
[3] &= ~(1 << 5); /* Make uppercase */
1176 if (CName
&& strcmp(CName
, DefaultSetter
)) {
1177 printf(" (setter=%s)", CName
);
1179 free(DefaultSetter
);
1180 clang_disposeString(Spelling
);
1181 clang_disposeString(Name
);
1185 unsigned QT
= clang_Cursor_getObjCDeclQualifiers(Cursor
);
1186 if (QT
!= CXObjCDeclQualifier_None
) {
1188 #define PRINT_OBJC_QUAL(A) \
1189 if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
1190 PRINT_OBJC_QUAL(In
);
1191 PRINT_OBJC_QUAL(Inout
);
1192 PRINT_OBJC_QUAL(Out
);
1193 PRINT_OBJC_QUAL(Bycopy
);
1194 PRINT_OBJC_QUAL(Byref
);
1195 PRINT_OBJC_QUAL(Oneway
);
1202 static const char* GetCursorSource(CXCursor Cursor
) {
1203 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
1206 clang_getExpansionLocation(Loc
, &file
, 0, 0, 0);
1207 source
= clang_getFileName(file
);
1208 if (!clang_getCString(source
)) {
1209 clang_disposeString(source
);
1210 return "<invalid loc>";
1213 const char *b
= basename(clang_getCString(source
));
1214 clang_disposeString(source
);
1219 static CXString
createCXString(const char *CS
) {
1221 Str
.data
= (const void *) CS
;
1222 Str
.private_flags
= 0;
1226 /******************************************************************************/
1228 /******************************************************************************/
1230 typedef void (*PostVisitTU
)(CXTranslationUnit
);
1232 void PrintDiagnostic(CXDiagnostic Diagnostic
) {
1236 unsigned display_opts
= CXDiagnostic_DisplaySourceLocation
1237 | CXDiagnostic_DisplayColumn
| CXDiagnostic_DisplaySourceRanges
1238 | CXDiagnostic_DisplayOption
;
1239 unsigned i
, num_fixits
;
1241 if (clang_getDiagnosticSeverity(Diagnostic
) == CXDiagnostic_Ignored
)
1244 Msg
= clang_formatDiagnostic(Diagnostic
, display_opts
);
1245 fprintf(stderr
, "%s\n", clang_getCString(Msg
));
1246 clang_disposeString(Msg
);
1248 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic
),
1253 num_fixits
= clang_getDiagnosticNumFixIts(Diagnostic
);
1254 fprintf(stderr
, "Number FIX-ITs = %d\n", num_fixits
);
1255 for (i
= 0; i
!= num_fixits
; ++i
) {
1256 CXSourceRange range
;
1257 CXString insertion_text
= clang_getDiagnosticFixIt(Diagnostic
, i
, &range
);
1258 CXSourceLocation start
= clang_getRangeStart(range
);
1259 CXSourceLocation end
= clang_getRangeEnd(range
);
1260 unsigned start_line
, start_column
, end_line
, end_column
;
1261 CXFile start_file
, end_file
;
1262 clang_getSpellingLocation(start
, &start_file
, &start_line
,
1264 clang_getSpellingLocation(end
, &end_file
, &end_line
, &end_column
, 0);
1265 if (clang_equalLocations(start
, end
)) {
1267 if (start_file
== file
)
1268 fprintf(out
, "FIX-IT: Insert \"%s\" at %d:%d\n",
1269 clang_getCString(insertion_text
), start_line
, start_column
);
1270 } else if (strcmp(clang_getCString(insertion_text
), "") == 0) {
1272 if (start_file
== file
&& end_file
== file
) {
1273 fprintf(out
, "FIX-IT: Remove ");
1274 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
1279 if (start_file
== end_file
) {
1280 fprintf(out
, "FIX-IT: Replace ");
1281 PrintExtent(out
, start_line
, start_column
, end_line
, end_column
);
1282 fprintf(out
, " with \"%s\"\n", clang_getCString(insertion_text
));
1285 clang_disposeString(insertion_text
);
1289 void PrintDiagnosticSet(CXDiagnosticSet Set
) {
1290 int i
= 0, n
= clang_getNumDiagnosticsInSet(Set
);
1291 for ( ; i
!= n
; ++i
) {
1292 CXDiagnostic Diag
= clang_getDiagnosticInSet(Set
, i
);
1293 CXDiagnosticSet ChildDiags
= clang_getChildDiagnostics(Diag
);
1294 PrintDiagnostic(Diag
);
1296 PrintDiagnosticSet(ChildDiags
);
1300 void PrintDiagnostics(CXTranslationUnit TU
) {
1301 CXDiagnosticSet TUSet
= clang_getDiagnosticSetFromTU(TU
);
1302 PrintDiagnosticSet(TUSet
);
1303 clang_disposeDiagnosticSet(TUSet
);
1306 void PrintMemoryUsage(CXTranslationUnit TU
) {
1307 unsigned long total
= 0;
1309 CXTUResourceUsage usage
= clang_getCXTUResourceUsage(TU
);
1310 fprintf(stderr
, "Memory usage:\n");
1311 for (i
= 0 ; i
!= usage
.numEntries
; ++i
) {
1312 const char *name
= clang_getTUResourceUsageName(usage
.entries
[i
].kind
);
1313 unsigned long amount
= usage
.entries
[i
].amount
;
1315 fprintf(stderr
, " %s : %ld bytes (%f MBytes)\n", name
, amount
,
1316 ((double) amount
)/(1024*1024));
1318 fprintf(stderr
, " TOTAL = %ld bytes (%f MBytes)\n", total
,
1319 ((double) total
)/(1024*1024));
1320 clang_disposeCXTUResourceUsage(usage
);
1323 /******************************************************************************/
1324 /* Logic for testing traversal. */
1325 /******************************************************************************/
1327 static void PrintCursorExtent(CXCursor C
) {
1328 CXSourceRange extent
= clang_getCursorExtent(C
);
1329 PrintRange(extent
, "Extent");
1332 /* Data used by the visitors. */
1334 CXTranslationUnit TU
;
1335 enum CXCursorKind
*Filter
;
1336 const char *CommentSchemaFile
;
1340 enum CXChildVisitResult
FilteredPrintingVisitor(CXCursor Cursor
,
1342 CXClientData ClientData
) {
1343 VisitorData
*Data
= (VisitorData
*)ClientData
;
1344 if (!Data
->Filter
|| (Cursor
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
1345 CXSourceLocation Loc
= clang_getCursorLocation(Cursor
);
1346 unsigned line
, column
;
1347 clang_getSpellingLocation(Loc
, 0, &line
, &column
, 0);
1348 printf("// %s: %s:%d:%d: ", FileCheckPrefix
,
1349 GetCursorSource(Cursor
), line
, column
);
1350 PrintCursor(Cursor
, Data
->CommentSchemaFile
);
1351 PrintCursorExtent(Cursor
);
1352 if (clang_isDeclaration(Cursor
.kind
)) {
1353 enum CX_CXXAccessSpecifier access
= clang_getCXXAccessSpecifier(Cursor
);
1354 const char *accessStr
= 0;
1357 case CX_CXXInvalidAccessSpecifier
: break;
1359 accessStr
= "public"; break;
1360 case CX_CXXProtected
:
1361 accessStr
= "protected"; break;
1363 accessStr
= "private"; break;
1367 printf(" [access=%s]", accessStr
);
1370 return CXChildVisit_Recurse
;
1373 return CXChildVisit_Continue
;
1376 static enum CXChildVisitResult
FunctionScanVisitor(CXCursor Cursor
,
1378 CXClientData ClientData
) {
1379 const char *startBuf
, *endBuf
;
1380 unsigned startLine
, startColumn
, endLine
, endColumn
, curLine
, curColumn
;
1382 VisitorData
*Data
= (VisitorData
*)ClientData
;
1384 if (Cursor
.kind
!= CXCursor_FunctionDecl
||
1385 !clang_isCursorDefinition(Cursor
))
1386 return CXChildVisit_Continue
;
1388 clang_getDefinitionSpellingAndExtent(Cursor
, &startBuf
, &endBuf
,
1389 &startLine
, &startColumn
,
1390 &endLine
, &endColumn
);
1391 /* Probe the entire body, looking for both decls and refs. */
1392 curLine
= startLine
;
1393 curColumn
= startColumn
;
1395 while (startBuf
< endBuf
) {
1396 CXSourceLocation Loc
;
1400 if (*startBuf
== '\n') {
1404 } else if (*startBuf
!= '\t')
1407 Loc
= clang_getCursorLocation(Cursor
);
1408 clang_getSpellingLocation(Loc
, &file
, 0, 0, 0);
1410 source
= clang_getFileName(file
);
1411 if (clang_getCString(source
)) {
1412 CXSourceLocation RefLoc
1413 = clang_getLocation(Data
->TU
, file
, curLine
, curColumn
);
1414 Ref
= clang_getCursor(Data
->TU
, RefLoc
);
1415 if (Ref
.kind
== CXCursor_NoDeclFound
) {
1416 /* Nothing found here; that's fine. */
1417 } else if (Ref
.kind
!= CXCursor_FunctionDecl
) {
1418 printf("// %s: %s:%d:%d: ", FileCheckPrefix
, GetCursorSource(Ref
),
1419 curLine
, curColumn
);
1420 PrintCursor(Ref
, Data
->CommentSchemaFile
);
1424 clang_disposeString(source
);
1428 return CXChildVisit_Continue
;
1431 /******************************************************************************/
1433 /******************************************************************************/
1435 enum CXChildVisitResult
USRVisitor(CXCursor C
, CXCursor parent
,
1436 CXClientData ClientData
) {
1437 VisitorData
*Data
= (VisitorData
*)ClientData
;
1438 if (!Data
->Filter
|| (C
.kind
== *(enum CXCursorKind
*)Data
->Filter
)) {
1439 CXString USR
= clang_getCursorUSR(C
);
1440 const char *cstr
= clang_getCString(USR
);
1441 if (!cstr
|| cstr
[0] == '\0') {
1442 clang_disposeString(USR
);
1443 return CXChildVisit_Recurse
;
1445 printf("// %s: %s %s", FileCheckPrefix
, GetCursorSource(C
), cstr
);
1447 PrintCursorExtent(C
);
1449 clang_disposeString(USR
);
1451 return CXChildVisit_Recurse
;
1454 return CXChildVisit_Continue
;
1457 /******************************************************************************/
1458 /* Inclusion stack testing. */
1459 /******************************************************************************/
1461 void InclusionVisitor(CXFile includedFile
, CXSourceLocation
*includeStack
,
1462 unsigned includeStackLen
, CXClientData data
) {
1467 fname
= clang_getFileName(includedFile
);
1468 printf("file: %s\nincluded by:\n", clang_getCString(fname
));
1469 clang_disposeString(fname
);
1471 for (i
= 0; i
< includeStackLen
; ++i
) {
1472 CXFile includingFile
;
1473 unsigned line
, column
;
1474 clang_getSpellingLocation(includeStack
[i
], &includingFile
, &line
,
1476 fname
= clang_getFileName(includingFile
);
1477 printf(" %s:%d:%d\n", clang_getCString(fname
), line
, column
);
1478 clang_disposeString(fname
);
1483 void PrintInclusionStack(CXTranslationUnit TU
) {
1484 clang_getInclusions(TU
, InclusionVisitor
, NULL
);
1487 /******************************************************************************/
1488 /* Linkage testing. */
1489 /******************************************************************************/
1491 static enum CXChildVisitResult
PrintLinkage(CXCursor cursor
, CXCursor p
,
1493 const char *linkage
= 0;
1495 if (clang_isInvalid(clang_getCursorKind(cursor
)))
1496 return CXChildVisit_Recurse
;
1498 switch (clang_getCursorLinkage(cursor
)) {
1499 case CXLinkage_Invalid
: break;
1500 case CXLinkage_NoLinkage
: linkage
= "NoLinkage"; break;
1501 case CXLinkage_Internal
: linkage
= "Internal"; break;
1502 case CXLinkage_UniqueExternal
: linkage
= "UniqueExternal"; break;
1503 case CXLinkage_External
: linkage
= "External"; break;
1507 PrintCursor(cursor
, NULL
);
1508 printf("linkage=%s\n", linkage
);
1511 return CXChildVisit_Recurse
;
1514 /******************************************************************************/
1515 /* Visibility testing. */
1516 /******************************************************************************/
1518 static enum CXChildVisitResult
PrintVisibility(CXCursor cursor
, CXCursor p
,
1520 const char *visibility
= 0;
1522 if (clang_isInvalid(clang_getCursorKind(cursor
)))
1523 return CXChildVisit_Recurse
;
1525 switch (clang_getCursorVisibility(cursor
)) {
1526 case CXVisibility_Invalid
: break;
1527 case CXVisibility_Hidden
: visibility
= "Hidden"; break;
1528 case CXVisibility_Protected
: visibility
= "Protected"; break;
1529 case CXVisibility_Default
: visibility
= "Default"; break;
1533 PrintCursor(cursor
, NULL
);
1534 printf("visibility=%s\n", visibility
);
1537 return CXChildVisit_Recurse
;
1540 /******************************************************************************/
1541 /* Typekind testing. */
1542 /******************************************************************************/
1544 static void PrintTypeAndTypeKind(CXType T
, const char *Format
) {
1545 CXString TypeSpelling
, TypeKindSpelling
;
1547 TypeSpelling
= clang_getTypeSpelling(T
);
1548 TypeKindSpelling
= clang_getTypeKindSpelling(T
.kind
);
1550 clang_getCString(TypeSpelling
),
1551 clang_getCString(TypeKindSpelling
));
1552 clang_disposeString(TypeSpelling
);
1553 clang_disposeString(TypeKindSpelling
);
1556 static enum CXVisitorResult
FieldVisitor(CXCursor C
,
1557 CXClientData client_data
) {
1558 (*(int *) client_data
)+=1;
1559 return CXVisit_Continue
;
1562 static void PrintTypeTemplateArgs(CXType T
, const char *Format
) {
1563 int NumTArgs
= clang_Type_getNumTemplateArguments(T
);
1564 if (NumTArgs
!= -1 && NumTArgs
!= 0) {
1567 printf(Format
, NumTArgs
);
1568 for (i
= 0; i
< NumTArgs
; ++i
) {
1569 TArg
= clang_Type_getTemplateArgumentAsType(T
, i
);
1570 if (TArg
.kind
!= CXType_Invalid
) {
1571 PrintTypeAndTypeKind(TArg
, " [type=%s] [typekind=%s]");
1574 /* Ensure that the returned type is invalid when indexing off-by-one. */
1575 TArg
= clang_Type_getTemplateArgumentAsType(T
, i
);
1576 assert(TArg
.kind
== CXType_Invalid
);
1581 static void PrintNullabilityKind(CXType T
, const char *Format
) {
1582 enum CXTypeNullabilityKind N
= clang_Type_getNullability(T
);
1584 const char *nullability
= 0;
1586 case CXTypeNullability_NonNull
:
1587 nullability
= "nonnull";
1589 case CXTypeNullability_Nullable
:
1590 nullability
= "nullable";
1592 case CXTypeNullability_NullableResult
:
1593 nullability
= "nullable_result";
1595 case CXTypeNullability_Unspecified
:
1596 nullability
= "unspecified";
1598 case CXTypeNullability_Invalid
:
1603 printf(Format
, nullability
);
1607 static enum CXChildVisitResult
PrintType(CXCursor cursor
, CXCursor p
,
1609 if (!clang_isInvalid(clang_getCursorKind(cursor
))) {
1610 CXType T
= clang_getCursorType(cursor
);
1611 CXType PT
= clang_getPointeeType(T
);
1612 enum CXRefQualifierKind RQ
= clang_Type_getCXXRefQualifier(T
);
1613 PrintCursor(cursor
, NULL
);
1614 PrintTypeAndTypeKind(T
, " [type=%s] [typekind=%s]");
1615 PrintNullabilityKind(T
, " [nullability=%s]");
1616 if (clang_isConstQualifiedType(T
))
1618 if (clang_isVolatileQualifiedType(T
))
1619 printf(" volatile");
1620 if (clang_isRestrictQualifiedType(T
))
1621 printf(" restrict");
1622 if (RQ
== CXRefQualifier_LValue
)
1623 printf(" lvalue-ref-qualifier");
1624 if (RQ
== CXRefQualifier_RValue
)
1625 printf(" rvalue-ref-qualifier");
1626 /* Print the template argument types if they exist. */
1627 PrintTypeTemplateArgs(T
, " [templateargs/%d=");
1628 /* Print the canonical type if it is different. */
1630 CXType CT
= clang_getCanonicalType(T
);
1631 if (!clang_equalTypes(T
, CT
)) {
1632 PrintTypeAndTypeKind(CT
, " [canonicaltype=%s] [canonicaltypekind=%s]");
1633 PrintTypeTemplateArgs(CT
, " [canonicaltemplateargs/%d=");
1636 /* Print the value type if it exists. */
1638 CXType VT
= clang_Type_getValueType(T
);
1639 if (VT
.kind
!= CXType_Invalid
)
1640 PrintTypeAndTypeKind(VT
, " [valuetype=%s] [valuetypekind=%s]");
1642 /* Print the modified type if it exists. */
1644 CXType MT
= clang_Type_getModifiedType(T
);
1645 if (MT
.kind
!= CXType_Invalid
) {
1646 PrintTypeAndTypeKind(MT
, " [modifiedtype=%s] [modifiedtypekind=%s]");
1649 /* Print the return type if it exists. */
1651 CXType RT
= clang_getCursorResultType(cursor
);
1652 if (RT
.kind
!= CXType_Invalid
) {
1653 PrintTypeAndTypeKind(RT
, " [resulttype=%s] [resulttypekind=%s]");
1655 PrintNullabilityKind(RT
, " [resultnullability=%s]");
1657 /* Print the argument types if they exist. */
1659 int NumArgs
= clang_Cursor_getNumArguments(cursor
);
1660 if (NumArgs
!= -1 && NumArgs
!= 0) {
1663 for (i
= 0; i
< NumArgs
; ++i
) {
1664 CXType T
= clang_getCursorType(clang_Cursor_getArgument(cursor
, i
));
1665 if (T
.kind
!= CXType_Invalid
) {
1666 PrintTypeAndTypeKind(T
, " [%s] [%s]");
1667 PrintNullabilityKind(T
, " [%s]");
1673 /* Print ObjC base types, type arguments, and protocol list if available. */
1675 CXType BT
= clang_Type_getObjCObjectBaseType(PT
);
1676 if (BT
.kind
!= CXType_Invalid
) {
1677 PrintTypeAndTypeKind(BT
, " [basetype=%s] [basekind=%s]");
1681 unsigned NumTypeArgs
= clang_Type_getNumObjCTypeArgs(PT
);
1682 if (NumTypeArgs
> 0) {
1684 printf(" [typeargs=");
1685 for (i
= 0; i
< NumTypeArgs
; ++i
) {
1686 CXType TA
= clang_Type_getObjCTypeArg(PT
, i
);
1687 if (TA
.kind
!= CXType_Invalid
) {
1688 PrintTypeAndTypeKind(TA
, " [%s] [%s]");
1695 unsigned NumProtocols
= clang_Type_getNumObjCProtocolRefs(PT
);
1696 if (NumProtocols
> 0) {
1698 printf(" [protocols=");
1699 for (i
= 0; i
< NumProtocols
; ++i
) {
1700 CXCursor P
= clang_Type_getObjCProtocolDecl(PT
, i
);
1701 if (!clang_isInvalid(clang_getCursorKind(P
))) {
1702 PrintCursor(P
, NULL
);
1708 /* Print if this is a non-POD type. */
1709 printf(" [isPOD=%d]", clang_isPODType(T
));
1710 /* Print the pointee type. */
1712 if (PT
.kind
!= CXType_Invalid
) {
1713 PrintTypeAndTypeKind(PT
, " [pointeetype=%s] [pointeekind=%s]");
1716 /* Print the number of fields if they exist. */
1719 if (clang_Type_visitFields(T
, FieldVisitor
, &numFields
)){
1720 if (numFields
!= 0) {
1721 printf(" [nbFields=%d]", numFields
);
1726 /* Print if it is an anonymous record or namespace. */
1728 unsigned isAnon
= clang_Cursor_isAnonymous(cursor
);
1730 printf(" [isAnon=%d]", isAnon
);
1734 /* Print if it is an anonymous record decl */
1736 unsigned isAnonRecDecl
= clang_Cursor_isAnonymousRecordDecl(cursor
);
1737 printf(" [isAnonRecDecl=%d]", isAnonRecDecl
);
1740 /* Print if it is an inline namespace decl */
1742 unsigned isInlineNamespace
= clang_Cursor_isInlineNamespace(cursor
);
1743 if (isInlineNamespace
!= 0)
1744 printf(" [isInlineNamespace=%d]", isInlineNamespace
);
1749 return CXChildVisit_Recurse
;
1752 static void PrintSingleTypeSize(CXType T
, const char *TypeKindFormat
,
1753 const char *SizeFormat
,
1754 const char *AlignFormat
) {
1755 PrintTypeAndTypeKind(T
, TypeKindFormat
);
1756 /* Print the type sizeof if applicable. */
1758 long long Size
= clang_Type_getSizeOf(T
);
1759 if (Size
>= 0 || Size
< -1 ) {
1760 printf(SizeFormat
, Size
);
1763 /* Print the type alignof if applicable. */
1765 long long Align
= clang_Type_getAlignOf(T
);
1766 if (Align
>= 0 || Align
< -1) {
1767 printf(AlignFormat
, Align
);
1771 /* Print the return type if it exists. */
1773 CXType RT
= clang_getResultType(T
);
1774 if (RT
.kind
!= CXType_Invalid
)
1775 PrintSingleTypeSize(RT
, " [resulttype=%s] [resulttypekind=%s]",
1776 " [resultsizeof=%lld]", " [resultalignof=%lld]");
1780 static enum CXChildVisitResult
PrintTypeSize(CXCursor cursor
, CXCursor p
,
1783 enum CXCursorKind K
= clang_getCursorKind(cursor
);
1784 if (clang_isInvalid(K
))
1785 return CXChildVisit_Recurse
;
1786 T
= clang_getCursorType(cursor
);
1787 PrintCursor(cursor
, NULL
);
1788 PrintSingleTypeSize(T
, " [type=%s] [typekind=%s]", " [sizeof=%lld]",
1790 /* Print the record field offset if applicable. */
1792 CXString FieldSpelling
= clang_getCursorSpelling(cursor
);
1793 const char *FieldName
= clang_getCString(FieldSpelling
);
1794 /* recurse to get the first parent record that is not anonymous. */
1795 unsigned RecordIsAnonymous
= 0;
1796 if (clang_getCursorKind(cursor
) == CXCursor_FieldDecl
) {
1798 CXCursor Parent
= p
;
1801 Parent
= clang_getCursorSemanticParent(Record
);
1802 RecordIsAnonymous
= clang_Cursor_isAnonymous(Record
);
1803 /* Recurse as long as the parent is a CXType_Record and the Record
1805 } while ( clang_getCursorType(Parent
).kind
== CXType_Record
&&
1806 RecordIsAnonymous
> 0);
1808 long long Offset
= clang_Type_getOffsetOf(clang_getCursorType(Record
),
1810 long long Offset2
= clang_Cursor_getOffsetOfField(cursor
);
1811 if (Offset
== Offset2
){
1812 printf(" [offsetof=%lld]", Offset
);
1814 /* Offsets will be different in anonymous records. */
1815 printf(" [offsetof=%lld/%lld]", Offset
, Offset2
);
1819 clang_disposeString(FieldSpelling
);
1821 /* Print if its a bitfield */
1823 int IsBitfield
= clang_Cursor_isBitField(cursor
);
1825 printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor
));
1830 return CXChildVisit_Recurse
;
1833 /******************************************************************************/
1834 /* Mangling testing. */
1835 /******************************************************************************/
1837 static enum CXChildVisitResult
PrintMangledName(CXCursor cursor
, CXCursor p
,
1839 CXString MangledName
;
1840 if (clang_isUnexposed(clang_getCursorKind(cursor
)))
1841 return CXChildVisit_Recurse
;
1842 if (clang_getCursorKind(cursor
) == CXCursor_LinkageSpec
)
1843 return CXChildVisit_Recurse
;
1844 PrintCursor(cursor
, NULL
);
1845 MangledName
= clang_Cursor_getMangling(cursor
);
1846 printf(" [mangled=%s]\n", clang_getCString(MangledName
));
1847 clang_disposeString(MangledName
);
1848 return CXChildVisit_Continue
;
1851 static enum CXChildVisitResult
PrintManglings(CXCursor cursor
, CXCursor p
,
1854 CXStringSet
*Manglings
= NULL
;
1855 if (clang_isUnexposed(clang_getCursorKind(cursor
)))
1856 return CXChildVisit_Recurse
;
1857 if (!clang_isDeclaration(clang_getCursorKind(cursor
)))
1858 return CXChildVisit_Recurse
;
1859 if (clang_getCursorKind(cursor
) == CXCursor_LinkageSpec
)
1860 return CXChildVisit_Recurse
;
1861 if (clang_getCursorKind(cursor
) == CXCursor_ParmDecl
)
1862 return CXChildVisit_Continue
;
1863 PrintCursor(cursor
, NULL
);
1864 Manglings
= clang_Cursor_getCXXManglings(cursor
);
1866 for (I
= 0, E
= Manglings
->Count
; I
< E
; ++I
)
1867 printf(" [mangled=%s]", clang_getCString(Manglings
->Strings
[I
]));
1868 clang_disposeStringSet(Manglings
);
1871 Manglings
= clang_Cursor_getObjCManglings(cursor
);
1873 for (I
= 0, E
= Manglings
->Count
; I
< E
; ++I
)
1874 printf(" [mangled=%s]", clang_getCString(Manglings
->Strings
[I
]));
1875 clang_disposeStringSet(Manglings
);
1878 return CXChildVisit_Recurse
;
1881 static enum CXChildVisitResult
1882 PrintSingleSymbolSGFs(CXCursor cursor
, CXCursor parent
, CXClientData data
) {
1883 CXString SGFData
= clang_getSymbolGraphForCursor(cursor
);
1884 const char *SGF
= clang_getCString(SGFData
);
1886 printf("%s\n", SGF
);
1888 clang_disposeString(SGFData
);
1890 return CXChildVisit_Recurse
;
1893 /******************************************************************************/
1894 /* Bitwidth testing. */
1895 /******************************************************************************/
1897 static enum CXChildVisitResult
PrintBitWidth(CXCursor cursor
, CXCursor p
,
1900 if (clang_getCursorKind(cursor
) != CXCursor_FieldDecl
)
1901 return CXChildVisit_Recurse
;
1903 Bitwidth
= clang_getFieldDeclBitWidth(cursor
);
1904 if (Bitwidth
>= 0) {
1905 PrintCursor(cursor
, NULL
);
1906 printf(" bitwidth=%d\n", Bitwidth
);
1909 return CXChildVisit_Recurse
;
1912 /******************************************************************************/
1913 /* Type declaration testing */
1914 /******************************************************************************/
1916 static enum CXChildVisitResult
PrintTypeDeclaration(CXCursor cursor
, CXCursor p
,
1918 CXCursor typeDeclaration
= clang_getTypeDeclaration(clang_getCursorType(cursor
));
1920 if (clang_isDeclaration(typeDeclaration
.kind
)) {
1921 PrintCursor(cursor
, NULL
);
1922 PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration
), " [typedeclaration=%s] [typekind=%s]\n");
1925 return CXChildVisit_Recurse
;
1928 /******************************************************************************/
1929 /* Declaration attributes testing */
1930 /******************************************************************************/
1932 static enum CXChildVisitResult
PrintDeclAttributes(CXCursor cursor
, CXCursor p
,
1934 if (clang_isDeclaration(cursor
.kind
)) {
1936 PrintCursor(cursor
, NULL
);
1937 return CXChildVisit_Recurse
;
1938 } else if (clang_isAttribute(cursor
.kind
)) {
1940 PrintCursor(cursor
, NULL
);
1942 return CXChildVisit_Continue
;
1945 /******************************************************************************/
1946 /* Target information testing. */
1947 /******************************************************************************/
1949 static int print_target_info(int argc
, const char **argv
) {
1951 CXTranslationUnit TU
;
1952 CXTargetInfo TargetInfo
;
1954 const char *FileName
;
1955 enum CXErrorCode Err
;
1959 fprintf(stderr
, "No filename specified\n");
1965 Idx
= clang_createIndex(0, 1);
1966 Err
= clang_parseTranslationUnit2(Idx
, FileName
, argv
, argc
, NULL
, 0,
1967 getDefaultParsingOptions(), &TU
);
1968 if (Err
!= CXError_Success
) {
1969 fprintf(stderr
, "Couldn't parse translation unit!\n");
1970 describeLibclangFailure(Err
);
1971 clang_disposeIndex(Idx
);
1975 TargetInfo
= clang_getTranslationUnitTargetInfo(TU
);
1977 Triple
= clang_TargetInfo_getTriple(TargetInfo
);
1978 printf("TargetTriple: %s\n", clang_getCString(Triple
));
1979 clang_disposeString(Triple
);
1981 PointerWidth
= clang_TargetInfo_getPointerWidth(TargetInfo
);
1982 printf("PointerWidth: %d\n", PointerWidth
);
1984 clang_TargetInfo_dispose(TargetInfo
);
1985 clang_disposeTranslationUnit(TU
);
1986 clang_disposeIndex(Idx
);
1990 /******************************************************************************/
1991 /* Loading ASTs/source. */
1992 /******************************************************************************/
1994 static int perform_test_load(CXIndex Idx
, CXTranslationUnit TU
,
1995 const char *filter
, const char *prefix
,
1996 CXCursorVisitor Visitor
,
1998 const char *CommentSchemaFile
) {
2001 FileCheckPrefix
= prefix
;
2004 enum CXCursorKind K
= CXCursor_NotImplemented
;
2005 enum CXCursorKind
*ck
= &K
;
2008 /* Perform some simple filtering. */
2009 if (!strcmp(filter
, "all") || !strcmp(filter
, "local")) ck
= NULL
;
2010 else if (!strcmp(filter
, "all-display") ||
2011 !strcmp(filter
, "local-display")) {
2013 wanted_display_type
= DisplayType_DisplayName
;
2015 else if (!strcmp(filter
, "all-pretty") ||
2016 !strcmp(filter
, "local-pretty")) {
2018 wanted_display_type
= DisplayType_Pretty
;
2020 else if (!strcmp(filter
, "none")) K
= (enum CXCursorKind
) ~0;
2021 else if (!strcmp(filter
, "category")) K
= CXCursor_ObjCCategoryDecl
;
2022 else if (!strcmp(filter
, "interface")) K
= CXCursor_ObjCInterfaceDecl
;
2023 else if (!strcmp(filter
, "protocol")) K
= CXCursor_ObjCProtocolDecl
;
2024 else if (!strcmp(filter
, "function")) K
= CXCursor_FunctionDecl
;
2025 else if (!strcmp(filter
, "typedef")) K
= CXCursor_TypedefDecl
;
2026 else if (!strcmp(filter
, "scan-function")) Visitor
= FunctionScanVisitor
;
2028 fprintf(stderr
, "Unknown filter for -test-load-tu: %s\n", filter
);
2034 Data
.CommentSchemaFile
= CommentSchemaFile
;
2035 clang_visitChildren(clang_getTranslationUnitCursor(TU
), Visitor
, &Data
);
2041 PrintDiagnostics(TU
);
2042 if (checkForErrors(TU
) != 0) {
2043 clang_disposeTranslationUnit(TU
);
2047 clang_disposeTranslationUnit(TU
);
2051 int perform_test_load_tu(const char *file
, const char *filter
,
2052 const char *prefix
, CXCursorVisitor Visitor
,
2055 CXTranslationUnit TU
;
2057 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
2058 !strcmp(filter
, "local") ? 1 : 0,
2059 /* displayDiagnostics=*/1);
2061 if (!CreateTranslationUnit(Idx
, file
, &TU
)) {
2062 clang_disposeIndex(Idx
);
2066 result
= perform_test_load(Idx
, TU
, filter
, prefix
, Visitor
, PV
, NULL
);
2067 clang_disposeIndex(Idx
);
2071 int perform_test_load_source(int argc
, const char **argv
,
2072 const char *filter
, CXCursorVisitor Visitor
,
2075 CXTranslationUnit TU
;
2076 const char *CommentSchemaFile
;
2077 struct CXUnsavedFile
*unsaved_files
= 0;
2078 int num_unsaved_files
= 0;
2079 enum CXErrorCode Err
;
2081 unsigned Repeats
= 0;
2085 createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */
2086 (!strcmp(filter
, "local") ||
2087 !strcmp(filter
, "local-display") ||
2088 !strcmp(filter
, "local-pretty"))
2091 /* displayDiagnostics=*/1);
2095 if ((CommentSchemaFile
= parse_comments_schema(argc
, argv
))) {
2100 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
2101 clang_disposeIndex(Idx
);
2105 if (getenv("CINDEXTEST_EDITING"))
2108 Err
= clang_parseTranslationUnit2(Idx
, 0,
2109 argv
+ num_unsaved_files
,
2110 argc
- num_unsaved_files
,
2111 unsaved_files
, num_unsaved_files
,
2112 getDefaultParsingOptions(), &TU
);
2113 if (Err
!= CXError_Success
) {
2114 fprintf(stderr
, "Unable to load translation unit!\n");
2115 describeLibclangFailure(Err
);
2116 free_remapped_files(unsaved_files
, num_unsaved_files
);
2117 clang_disposeIndex(Idx
);
2121 for (I
= 0; I
!= Repeats
; ++I
) {
2122 if (checkForErrors(TU
) != 0)
2126 clang_suspendTranslationUnit(TU
);
2128 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
2129 clang_defaultReparseOptions(TU
));
2130 if (Err
!= CXError_Success
) {
2131 describeLibclangFailure(Err
);
2132 free_remapped_files(unsaved_files
, num_unsaved_files
);
2133 clang_disposeIndex(Idx
);
2139 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
,
2141 free_remapped_files(unsaved_files
, num_unsaved_files
);
2142 clang_disposeIndex(Idx
);
2146 int perform_test_reparse_source(int argc
, const char **argv
, int trials
,
2147 const char *filter
, CXCursorVisitor Visitor
,
2150 CXTranslationUnit TU
;
2151 struct CXUnsavedFile
*unsaved_files
= 0;
2152 int num_unsaved_files
= 0;
2153 int compiler_arg_idx
= 0;
2154 enum CXErrorCode Err
;
2157 int execute_after_trial
= 0;
2158 const char *execute_command
= NULL
;
2159 int remap_after_trial
= 0;
2162 Idx
= clang_createIndex(/* excludeDeclsFromPCH */
2163 !strcmp(filter
, "local") ? 1 : 0,
2164 /* displayDiagnostics=*/1);
2166 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
2167 clang_disposeIndex(Idx
);
2171 for (i
= 0; i
< argc
; ++i
) {
2172 if (strcmp(argv
[i
], "--") == 0)
2176 compiler_arg_idx
= i
+1;
2177 if (num_unsaved_files
> compiler_arg_idx
)
2178 compiler_arg_idx
= num_unsaved_files
;
2180 /* Load the initial translation unit -- we do this without honoring remapped
2181 * files, so that we have a way to test results after changing the source. */
2182 Err
= clang_parseTranslationUnit2(Idx
, 0,
2183 argv
+ compiler_arg_idx
,
2184 argc
- compiler_arg_idx
,
2185 0, 0, getDefaultParsingOptions(), &TU
);
2186 if (Err
!= CXError_Success
) {
2187 fprintf(stderr
, "Unable to load translation unit!\n");
2188 describeLibclangFailure(Err
);
2189 free_remapped_files(unsaved_files
, num_unsaved_files
);
2190 clang_disposeIndex(Idx
);
2194 if (checkForErrors(TU
) != 0)
2197 if (getenv("CINDEXTEST_EXECUTE_COMMAND")) {
2198 execute_command
= getenv("CINDEXTEST_EXECUTE_COMMAND");
2200 if (getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL")) {
2201 execute_after_trial
=
2202 strtol(getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL"), &endptr
, 10);
2205 if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
2207 strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr
, 10);
2210 for (trial
= 0; trial
< trials
; ++trial
) {
2211 if (execute_command
&& trial
== execute_after_trial
) {
2212 result
= indextest_perform_shell_execution(execute_command
);
2217 free_remapped_files(unsaved_files
, num_unsaved_files
);
2218 if (parse_remapped_files_with_try(trial
, argc
, argv
, 0,
2219 &unsaved_files
, &num_unsaved_files
)) {
2220 clang_disposeTranslationUnit(TU
);
2221 clang_disposeIndex(Idx
);
2225 Err
= clang_reparseTranslationUnit(
2227 trial
>= remap_after_trial
? num_unsaved_files
: 0,
2228 trial
>= remap_after_trial
? unsaved_files
: 0,
2229 clang_defaultReparseOptions(TU
));
2230 if (Err
!= CXError_Success
) {
2231 fprintf(stderr
, "Unable to reparse translation unit!\n");
2232 describeLibclangFailure(Err
);
2233 clang_disposeTranslationUnit(TU
);
2234 free_remapped_files(unsaved_files
, num_unsaved_files
);
2235 clang_disposeIndex(Idx
);
2239 if (checkForErrors(TU
) != 0)
2243 result
= perform_test_load(Idx
, TU
, filter
, NULL
, Visitor
, PV
, NULL
);
2245 free_remapped_files(unsaved_files
, num_unsaved_files
);
2246 clang_disposeIndex(Idx
);
2250 static int perform_single_file_parse(const char *filename
) {
2252 CXTranslationUnit TU
;
2253 enum CXErrorCode Err
;
2256 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1,
2257 /* displayDiagnostics=*/1);
2259 Err
= clang_parseTranslationUnit2(Idx
, filename
,
2260 /*command_line_args=*/NULL
,
2261 /*num_command_line_args=*/0,
2262 /*unsaved_files=*/NULL
,
2263 /*num_unsaved_files=*/0,
2264 CXTranslationUnit_SingleFileParse
, &TU
);
2265 if (Err
!= CXError_Success
) {
2266 fprintf(stderr
, "Unable to load translation unit!\n");
2267 describeLibclangFailure(Err
);
2268 clang_disposeIndex(Idx
);
2272 result
= perform_test_load(Idx
, TU
, /*filter=*/"all", /*prefix=*/NULL
, FilteredPrintingVisitor
, /*PostVisit=*/NULL
,
2273 /*CommentSchemaFile=*/NULL
);
2274 clang_disposeIndex(Idx
);
2278 static int perform_file_retain_excluded_cb(const char *filename
) {
2280 CXTranslationUnit TU
;
2281 enum CXErrorCode Err
;
2284 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1,
2285 /* displayDiagnostics=*/1);
2287 Err
= clang_parseTranslationUnit2(Idx
, filename
,
2288 /*command_line_args=*/NULL
,
2289 /*num_command_line_args=*/0,
2290 /*unsaved_files=*/NULL
,
2291 /*num_unsaved_files=*/0,
2292 CXTranslationUnit_RetainExcludedConditionalBlocks
, &TU
);
2293 if (Err
!= CXError_Success
) {
2294 fprintf(stderr
, "Unable to load translation unit!\n");
2295 describeLibclangFailure(Err
);
2296 clang_disposeIndex(Idx
);
2300 result
= perform_test_load(Idx
, TU
, /*filter=*/"all", /*prefix=*/NULL
, FilteredPrintingVisitor
, /*PostVisit=*/NULL
,
2301 /*CommentSchemaFile=*/NULL
);
2302 clang_disposeIndex(Idx
);
2306 /******************************************************************************/
2307 /* Logic for testing clang_getCursor(). */
2308 /******************************************************************************/
2310 static void print_cursor_file_scan(CXTranslationUnit TU
, CXCursor cursor
,
2311 unsigned start_line
, unsigned start_col
,
2312 unsigned end_line
, unsigned end_col
,
2313 const char *prefix
) {
2314 printf("// %s: ", FileCheckPrefix
);
2316 printf("-%s", prefix
);
2317 PrintExtent(stdout
, start_line
, start_col
, end_line
, end_col
);
2319 PrintCursor(cursor
, NULL
);
2323 static int perform_file_scan(const char *ast_file
, const char *source_file
,
2324 const char *prefix
) {
2326 CXTranslationUnit TU
;
2328 CXCursor prevCursor
= clang_getNullCursor();
2330 unsigned line
= 1, col
= 1;
2331 unsigned start_line
= 1, start_col
= 1;
2333 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
2334 /* displayDiagnostics=*/1))) {
2335 fprintf(stderr
, "Could not create Index\n");
2339 if (!CreateTranslationUnit(Idx
, ast_file
, &TU
))
2342 if ((fp
= fopen(source_file
, "r")) == NULL
) {
2343 fprintf(stderr
, "Could not open '%s'\n", source_file
);
2344 clang_disposeTranslationUnit(TU
);
2348 file
= clang_getFile(TU
, source_file
);
2359 /* Check the cursor at this position, and dump the previous one if we have
2360 * found something new.
2362 cursor
= clang_getCursor(TU
, clang_getLocation(TU
, file
, line
, col
));
2363 if ((c
== EOF
|| !clang_equalCursors(cursor
, prevCursor
)) &&
2364 prevCursor
.kind
!= CXCursor_InvalidFile
) {
2365 print_cursor_file_scan(TU
, prevCursor
, start_line
, start_col
,
2373 prevCursor
= cursor
;
2377 clang_disposeTranslationUnit(TU
);
2378 clang_disposeIndex(Idx
);
2382 /******************************************************************************/
2383 /* Logic for testing clang code completion. */
2384 /******************************************************************************/
2386 /* Parse file:line:column from the input string. Returns 0 on success, non-zero
2387 on failure. If successful, the pointer *filename will contain newly-allocated
2388 memory (that will be owned by the caller) to store the file name. */
2389 int parse_file_line_column(const char *input
, char **filename
, unsigned *line
,
2390 unsigned *column
, unsigned *second_line
,
2391 unsigned *second_column
) {
2392 /* Find the second colon. */
2393 const char *last_colon
= strrchr(input
, ':');
2394 unsigned values
[4], i
;
2395 unsigned num_values
= (second_line
&& second_column
)? 4 : 2;
2398 if (!last_colon
|| last_colon
== input
) {
2399 if (num_values
== 4)
2400 fprintf(stderr
, "could not parse filename:line:column:line:column in "
2403 fprintf(stderr
, "could not parse filename:line:column in '%s'\n", input
);
2407 for (i
= 0; i
!= num_values
; ++i
) {
2408 const char *prev_colon
;
2410 /* Parse the next line or column. */
2411 values
[num_values
- i
- 1] = strtol(last_colon
+ 1, &endptr
, 10);
2412 if (*endptr
!= 0 && *endptr
!= ':') {
2413 fprintf(stderr
, "could not parse %s in '%s'\n",
2414 (i
% 2 ? "column" : "line"), input
);
2418 if (i
+ 1 == num_values
)
2421 /* Find the previous colon. */
2422 prev_colon
= last_colon
- 1;
2423 while (prev_colon
!= input
&& *prev_colon
!= ':')
2425 if (prev_colon
== input
) {
2426 fprintf(stderr
, "could not parse %s in '%s'\n",
2427 (i
% 2 == 0? "column" : "line"), input
);
2431 last_colon
= prev_colon
;
2435 *column
= values
[1];
2437 if (second_line
&& second_column
) {
2438 *second_line
= values
[2];
2439 *second_column
= values
[3];
2442 /* Copy the file name. */
2443 *filename
= (char*)malloc(last_colon
- input
+ 1);
2445 memcpy(*filename
, input
, last_colon
- input
);
2446 (*filename
)[last_colon
- input
] = 0;
2451 clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind
) {
2453 case CXCompletionChunk_Optional
: return "Optional";
2454 case CXCompletionChunk_TypedText
: return "TypedText";
2455 case CXCompletionChunk_Text
: return "Text";
2456 case CXCompletionChunk_Placeholder
: return "Placeholder";
2457 case CXCompletionChunk_Informative
: return "Informative";
2458 case CXCompletionChunk_CurrentParameter
: return "CurrentParameter";
2459 case CXCompletionChunk_LeftParen
: return "LeftParen";
2460 case CXCompletionChunk_RightParen
: return "RightParen";
2461 case CXCompletionChunk_LeftBracket
: return "LeftBracket";
2462 case CXCompletionChunk_RightBracket
: return "RightBracket";
2463 case CXCompletionChunk_LeftBrace
: return "LeftBrace";
2464 case CXCompletionChunk_RightBrace
: return "RightBrace";
2465 case CXCompletionChunk_LeftAngle
: return "LeftAngle";
2466 case CXCompletionChunk_RightAngle
: return "RightAngle";
2467 case CXCompletionChunk_Comma
: return "Comma";
2468 case CXCompletionChunk_ResultType
: return "ResultType";
2469 case CXCompletionChunk_Colon
: return "Colon";
2470 case CXCompletionChunk_SemiColon
: return "SemiColon";
2471 case CXCompletionChunk_Equal
: return "Equal";
2472 case CXCompletionChunk_HorizontalSpace
: return "HorizontalSpace";
2473 case CXCompletionChunk_VerticalSpace
: return "VerticalSpace";
2479 static int checkForErrors(CXTranslationUnit TU
) {
2484 if (!getenv("CINDEXTEST_FAILONERROR"))
2487 Num
= clang_getNumDiagnostics(TU
);
2488 for (i
= 0; i
!= Num
; ++i
) {
2489 Diag
= clang_getDiagnostic(TU
, i
);
2490 if (clang_getDiagnosticSeverity(Diag
) >= CXDiagnostic_Error
) {
2491 DiagStr
= clang_formatDiagnostic(Diag
,
2492 clang_defaultDiagnosticDisplayOptions());
2493 fprintf(stderr
, "%s\n", clang_getCString(DiagStr
));
2494 clang_disposeString(DiagStr
);
2495 clang_disposeDiagnostic(Diag
);
2498 clang_disposeDiagnostic(Diag
);
2504 static void print_completion_string(CXCompletionString completion_string
,
2508 N
= clang_getNumCompletionChunks(completion_string
);
2509 for (I
= 0; I
!= N
; ++I
) {
2512 enum CXCompletionChunkKind Kind
2513 = clang_getCompletionChunkKind(completion_string
, I
);
2515 if (Kind
== CXCompletionChunk_Optional
) {
2516 fprintf(file
, "{Optional ");
2517 print_completion_string(
2518 clang_getCompletionChunkCompletionString(completion_string
, I
),
2524 if (Kind
== CXCompletionChunk_VerticalSpace
) {
2525 fprintf(file
, "{VerticalSpace }");
2529 text
= clang_getCompletionChunkText(completion_string
, I
);
2530 cstr
= clang_getCString(text
);
2531 fprintf(file
, "{%s %s}",
2532 clang_getCompletionChunkKindSpelling(Kind
),
2534 clang_disposeString(text
);
2539 static void print_line_column(CXSourceLocation location
, FILE *file
) {
2540 unsigned line
, column
;
2541 clang_getExpansionLocation(location
, NULL
, &line
, &column
, NULL
);
2542 fprintf(file
, "%d:%d", line
, column
);
2545 static void print_token_range(CXTranslationUnit translation_unit
,
2546 CXSourceLocation start
, FILE *file
) {
2547 CXToken
*token
= clang_getToken(translation_unit
, start
);
2550 if (token
!= NULL
) {
2551 CXSourceRange token_range
= clang_getTokenExtent(translation_unit
, *token
);
2552 print_line_column(clang_getRangeStart(token_range
), file
);
2554 print_line_column(clang_getRangeEnd(token_range
), file
);
2555 clang_disposeTokens(translation_unit
, token
, 1);
2561 static void print_completion_result(CXTranslationUnit translation_unit
,
2562 CXCodeCompleteResults
*completion_results
,
2565 CXCompletionResult
*completion_result
= completion_results
->Results
+ index
;
2566 CXString ks
= clang_getCursorKindSpelling(completion_result
->CursorKind
);
2567 unsigned annotationCount
;
2568 enum CXCursorKind ParentKind
;
2569 CXString ParentName
;
2570 CXString BriefComment
;
2571 CXString Annotation
;
2572 const char *BriefCommentCString
;
2575 fprintf(file
, "%s:", clang_getCString(ks
));
2576 clang_disposeString(ks
);
2578 print_completion_string(completion_result
->CompletionString
, file
);
2579 fprintf(file
, " (%u)",
2580 clang_getCompletionPriority(completion_result
->CompletionString
));
2581 switch (clang_getCompletionAvailability(completion_result
->CompletionString
)){
2582 case CXAvailability_Available
:
2585 case CXAvailability_Deprecated
:
2586 fprintf(file
, " (deprecated)");
2589 case CXAvailability_NotAvailable
:
2590 fprintf(file
, " (unavailable)");
2593 case CXAvailability_NotAccessible
:
2594 fprintf(file
, " (inaccessible)");
2598 annotationCount
= clang_getCompletionNumAnnotations(
2599 completion_result
->CompletionString
);
2600 if (annotationCount
) {
2602 fprintf(file
, " (");
2603 for (i
= 0; i
< annotationCount
; ++i
) {
2605 fprintf(file
, ", ");
2607 clang_getCompletionAnnotation(completion_result
->CompletionString
, i
);
2608 fprintf(file
, "\"%s\"", clang_getCString(Annotation
));
2609 clang_disposeString(Annotation
);
2614 if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
2615 ParentName
= clang_getCompletionParent(completion_result
->CompletionString
,
2617 if (ParentKind
!= CXCursor_NotImplemented
) {
2618 CXString KindSpelling
= clang_getCursorKindSpelling(ParentKind
);
2619 fprintf(file
, " (parent: %s '%s')",
2620 clang_getCString(KindSpelling
),
2621 clang_getCString(ParentName
));
2622 clang_disposeString(KindSpelling
);
2624 clang_disposeString(ParentName
);
2627 BriefComment
= clang_getCompletionBriefComment(
2628 completion_result
->CompletionString
);
2629 BriefCommentCString
= clang_getCString(BriefComment
);
2630 if (BriefCommentCString
&& *BriefCommentCString
!= '\0') {
2631 fprintf(file
, "(brief comment: %s)", BriefCommentCString
);
2633 clang_disposeString(BriefComment
);
2635 for (i
= 0; i
< clang_getCompletionNumFixIts(completion_results
, index
);
2637 CXSourceRange correction_range
;
2638 CXString FixIt
= clang_getCompletionFixIt(completion_results
, index
, i
,
2640 fprintf(file
, " (requires fix-it: ");
2641 print_token_range(translation_unit
, clang_getRangeStart(correction_range
),
2643 fprintf(file
, " to \"%s\")", clang_getCString(FixIt
));
2644 clang_disposeString(FixIt
);
2647 fprintf(file
, "\n");
2650 void print_completion_contexts(unsigned long long contexts
, FILE *file
) {
2651 fprintf(file
, "Completion contexts:\n");
2652 if (contexts
== CXCompletionContext_Unknown
) {
2653 fprintf(file
, "Unknown\n");
2655 if (contexts
& CXCompletionContext_AnyType
) {
2656 fprintf(file
, "Any type\n");
2658 if (contexts
& CXCompletionContext_AnyValue
) {
2659 fprintf(file
, "Any value\n");
2661 if (contexts
& CXCompletionContext_ObjCObjectValue
) {
2662 fprintf(file
, "Objective-C object value\n");
2664 if (contexts
& CXCompletionContext_ObjCSelectorValue
) {
2665 fprintf(file
, "Objective-C selector value\n");
2667 if (contexts
& CXCompletionContext_CXXClassTypeValue
) {
2668 fprintf(file
, "C++ class type value\n");
2670 if (contexts
& CXCompletionContext_DotMemberAccess
) {
2671 fprintf(file
, "Dot member access\n");
2673 if (contexts
& CXCompletionContext_ArrowMemberAccess
) {
2674 fprintf(file
, "Arrow member access\n");
2676 if (contexts
& CXCompletionContext_ObjCPropertyAccess
) {
2677 fprintf(file
, "Objective-C property access\n");
2679 if (contexts
& CXCompletionContext_EnumTag
) {
2680 fprintf(file
, "Enum tag\n");
2682 if (contexts
& CXCompletionContext_UnionTag
) {
2683 fprintf(file
, "Union tag\n");
2685 if (contexts
& CXCompletionContext_StructTag
) {
2686 fprintf(file
, "Struct tag\n");
2688 if (contexts
& CXCompletionContext_ClassTag
) {
2689 fprintf(file
, "Class name\n");
2691 if (contexts
& CXCompletionContext_Namespace
) {
2692 fprintf(file
, "Namespace or namespace alias\n");
2694 if (contexts
& CXCompletionContext_NestedNameSpecifier
) {
2695 fprintf(file
, "Nested name specifier\n");
2697 if (contexts
& CXCompletionContext_ObjCInterface
) {
2698 fprintf(file
, "Objective-C interface\n");
2700 if (contexts
& CXCompletionContext_ObjCProtocol
) {
2701 fprintf(file
, "Objective-C protocol\n");
2703 if (contexts
& CXCompletionContext_ObjCCategory
) {
2704 fprintf(file
, "Objective-C category\n");
2706 if (contexts
& CXCompletionContext_ObjCInstanceMessage
) {
2707 fprintf(file
, "Objective-C instance method\n");
2709 if (contexts
& CXCompletionContext_ObjCClassMessage
) {
2710 fprintf(file
, "Objective-C class method\n");
2712 if (contexts
& CXCompletionContext_ObjCSelectorName
) {
2713 fprintf(file
, "Objective-C selector name\n");
2715 if (contexts
& CXCompletionContext_MacroName
) {
2716 fprintf(file
, "Macro name\n");
2718 if (contexts
& CXCompletionContext_NaturalLanguage
) {
2719 fprintf(file
, "Natural language\n");
2723 int perform_code_completion(int argc
, const char **argv
, int timing_only
) {
2724 const char *input
= argv
[1];
2730 struct CXUnsavedFile
*unsaved_files
= 0;
2731 int num_unsaved_files
= 0;
2732 CXCodeCompleteResults
*results
= 0;
2733 enum CXErrorCode Err
;
2734 CXTranslationUnit TU
;
2735 unsigned I
, Repeats
= 1;
2736 unsigned completionOptions
= clang_defaultCodeCompleteOptions();
2738 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
2739 completionOptions
|= CXCodeComplete_IncludeCodePatterns
;
2740 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
2741 completionOptions
|= CXCodeComplete_IncludeBriefComments
;
2742 if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
2743 completionOptions
|= CXCodeComplete_SkipPreamble
;
2744 if (getenv("CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
2745 completionOptions
|= CXCodeComplete_IncludeCompletionsWithFixIts
;
2748 input
+= strlen("-code-completion-timing=");
2750 input
+= strlen("-code-completion-at=");
2752 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
2756 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
))
2759 CIdx
= createIndexWithInvocationEmissionPath(0, 0);
2763 if (getenv("CINDEXTEST_EDITING"))
2766 Err
= clang_parseTranslationUnit2(CIdx
, 0,
2767 argv
+ num_unsaved_files
+ 2,
2768 argc
- num_unsaved_files
- 2,
2769 0, 0, getDefaultParsingOptions(), &TU
);
2770 if (Err
!= CXError_Success
) {
2771 fprintf(stderr
, "Unable to load translation unit!\n");
2772 describeLibclangFailure(Err
);
2776 Err
= clang_reparseTranslationUnit(TU
, 0, 0,
2777 clang_defaultReparseOptions(TU
));
2779 if (Err
!= CXError_Success
) {
2780 fprintf(stderr
, "Unable to reparse translation unit!\n");
2781 describeLibclangFailure(Err
);
2782 clang_disposeTranslationUnit(TU
);
2786 for (I
= 0; I
!= Repeats
; ++I
) {
2787 results
= clang_codeCompleteAt(TU
, filename
, line
, column
,
2788 unsaved_files
, num_unsaved_files
,
2791 fprintf(stderr
, "Unable to perform code completion!\n");
2795 clang_disposeCodeCompleteResults(results
);
2799 unsigned i
, n
= results
->NumResults
, containerIsIncomplete
= 0;
2800 unsigned long long contexts
;
2801 enum CXCursorKind containerKind
;
2802 CXString objCSelector
;
2803 const char *selectorString
;
2805 /* Sort the code-completion results based on the typed text. */
2806 clang_sortCodeCompletionResults(results
->Results
, results
->NumResults
);
2808 for (i
= 0; i
!= n
; ++i
)
2809 print_completion_result(TU
, results
, i
, stdout
);
2811 n
= clang_codeCompleteGetNumDiagnostics(results
);
2812 for (i
= 0; i
!= n
; ++i
) {
2813 CXDiagnostic diag
= clang_codeCompleteGetDiagnostic(results
, i
);
2814 PrintDiagnostic(diag
);
2815 clang_disposeDiagnostic(diag
);
2818 contexts
= clang_codeCompleteGetContexts(results
);
2819 print_completion_contexts(contexts
, stdout
);
2821 containerKind
= clang_codeCompleteGetContainerKind(results
,
2822 &containerIsIncomplete
);
2824 if (containerKind
!= CXCursor_InvalidCode
) {
2825 /* We have found a container */
2826 CXString containerUSR
, containerKindSpelling
;
2827 containerKindSpelling
= clang_getCursorKindSpelling(containerKind
);
2828 printf("Container Kind: %s\n", clang_getCString(containerKindSpelling
));
2829 clang_disposeString(containerKindSpelling
);
2831 if (containerIsIncomplete
) {
2832 printf("Container is incomplete\n");
2835 printf("Container is complete\n");
2838 containerUSR
= clang_codeCompleteGetContainerUSR(results
);
2839 printf("Container USR: %s\n", clang_getCString(containerUSR
));
2840 clang_disposeString(containerUSR
);
2843 objCSelector
= clang_codeCompleteGetObjCSelector(results
);
2844 selectorString
= clang_getCString(objCSelector
);
2845 if (selectorString
&& strlen(selectorString
) > 0) {
2846 printf("Objective-C selector: %s\n", selectorString
);
2848 clang_disposeString(objCSelector
);
2850 clang_disposeCodeCompleteResults(results
);
2852 clang_disposeTranslationUnit(TU
);
2853 clang_disposeIndex(CIdx
);
2856 free_remapped_files(unsaved_files
, num_unsaved_files
);
2865 } CursorSourceLocation
;
2867 typedef void (*cursor_handler_t
)(CXCursor cursor
);
2869 static int inspect_cursor_at(int argc
, const char **argv
,
2870 const char *locations_flag
,
2871 cursor_handler_t handler
) {
2874 struct CXUnsavedFile
*unsaved_files
= 0;
2875 int num_unsaved_files
= 0;
2876 enum CXErrorCode Err
;
2877 CXTranslationUnit TU
;
2879 CursorSourceLocation
*Locations
= 0;
2880 unsigned NumLocations
= 0, Loc
;
2881 unsigned Repeats
= 1;
2884 /* Count the number of locations. */
2885 while (strstr(argv
[NumLocations
+1], locations_flag
) == argv
[NumLocations
+1])
2888 /* Parse the locations. */
2889 assert(NumLocations
> 0 && "Unable to count locations?");
2890 Locations
= (CursorSourceLocation
*)malloc(
2891 NumLocations
* sizeof(CursorSourceLocation
));
2893 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
2894 const char *input
= argv
[Loc
+ 1] + strlen(locations_flag
);
2895 if ((errorCode
= parse_file_line_column(input
, &Locations
[Loc
].filename
,
2896 &Locations
[Loc
].line
,
2897 &Locations
[Loc
].column
, 0, 0)))
2901 if (parse_remapped_files(argc
, argv
, NumLocations
+ 1, &unsaved_files
,
2902 &num_unsaved_files
))
2905 if (getenv("CINDEXTEST_EDITING"))
2908 /* Parse the translation unit. When we're testing clang_getCursor() after
2909 reparsing, don't remap unsaved files until the second parse. */
2910 CIdx
= clang_createIndex(1, 1);
2911 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
2912 argv
+ num_unsaved_files
+ 1 + NumLocations
,
2913 argc
- num_unsaved_files
- 2 - NumLocations
,
2915 Repeats
> 1? 0 : num_unsaved_files
,
2916 getDefaultParsingOptions(), &TU
);
2917 if (Err
!= CXError_Success
) {
2918 fprintf(stderr
, "unable to parse input\n");
2919 describeLibclangFailure(Err
);
2923 if (checkForErrors(TU
) != 0)
2926 for (I
= 0; I
!= Repeats
; ++I
) {
2928 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
2929 clang_defaultReparseOptions(TU
));
2930 if (Err
!= CXError_Success
) {
2931 describeLibclangFailure(Err
);
2932 clang_disposeTranslationUnit(TU
);
2937 if (checkForErrors(TU
) != 0)
2940 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
2941 CXFile file
= clang_getFile(TU
, Locations
[Loc
].filename
);
2945 Cursor
= clang_getCursor(TU
,
2946 clang_getLocation(TU
, file
, Locations
[Loc
].line
,
2947 Locations
[Loc
].column
));
2949 if (checkForErrors(TU
) != 0)
2952 if (I
+ 1 == Repeats
) {
2954 free(Locations
[Loc
].filename
);
2959 PrintDiagnostics(TU
);
2960 clang_disposeTranslationUnit(TU
);
2961 clang_disposeIndex(CIdx
);
2963 free_remapped_files(unsaved_files
, num_unsaved_files
);
2967 static void inspect_print_cursor(CXCursor Cursor
) {
2968 CXTranslationUnit TU
= clang_Cursor_getTranslationUnit(Cursor
);
2969 CXCompletionString completionString
= clang_getCursorCompletionString(
2971 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
2974 unsigned line
, column
;
2975 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
2976 printf("%d:%d ", line
, column
);
2977 PrintCursor(Cursor
, NULL
);
2978 PrintCursorExtent(Cursor
);
2979 Spelling
= clang_getCursorSpelling(Cursor
);
2980 cspell
= clang_getCString(Spelling
);
2981 if (cspell
&& strlen(cspell
) != 0) {
2982 unsigned pieceIndex
;
2983 printf(" Spelling=%s (", cspell
);
2984 for (pieceIndex
= 0; ; ++pieceIndex
) {
2985 CXSourceRange range
=
2986 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
2987 if (clang_Range_isNull(range
))
2989 PrintRange(range
, 0);
2993 clang_disposeString(Spelling
);
2994 if (clang_Cursor_getObjCSelectorIndex(Cursor
) != -1)
2995 printf(" Selector index=%d",
2996 clang_Cursor_getObjCSelectorIndex(Cursor
));
2997 if (clang_Cursor_isDynamicCall(Cursor
))
2998 printf(" Dynamic-call");
2999 if (Cursor
.kind
== CXCursor_ObjCMessageExpr
||
3000 Cursor
.kind
== CXCursor_MemberRefExpr
) {
3001 CXType T
= clang_Cursor_getReceiverType(Cursor
);
3002 if (T
.kind
!= CXType_Invalid
) {
3003 CXString S
= clang_getTypeKindSpelling(T
.kind
);
3004 printf(" Receiver-type=%s", clang_getCString(S
));
3005 clang_disposeString(S
);
3010 CXModule mod
= clang_Cursor_getModule(Cursor
);
3012 CXString name
, astFilename
;
3013 unsigned i
, numHeaders
;
3015 astFile
= clang_Module_getASTFile(mod
);
3016 astFilename
= clang_getFileName(astFile
);
3017 name
= clang_Module_getFullName(mod
);
3018 numHeaders
= clang_Module_getNumTopLevelHeaders(TU
, mod
);
3019 printf(" ModuleName=%s (%s) system=%d Headers(%d):",
3020 clang_getCString(name
), clang_getCString(astFilename
),
3021 clang_Module_isSystem(mod
), numHeaders
);
3022 clang_disposeString(name
);
3023 clang_disposeString(astFilename
);
3024 for (i
= 0; i
< numHeaders
; ++i
) {
3025 CXFile file
= clang_Module_getTopLevelHeader(TU
, mod
, i
);
3026 CXString filename
= clang_getFileName(file
);
3027 printf("\n%s", clang_getCString(filename
));
3028 clang_disposeString(filename
);
3033 if (completionString
!= NULL
) {
3034 printf("\nCompletion string: ");
3035 print_completion_string(completionString
, stdout
);
3040 static void display_evaluate_results(CXEvalResult result
) {
3041 switch (clang_EvalResult_getKind(result
)) {
3044 printf("Kind: Int, ");
3045 if (clang_EvalResult_isUnsignedInt(result
)) {
3046 unsigned long long val
= clang_EvalResult_getAsUnsigned(result
);
3047 printf("unsigned, Value: %llu", val
);
3049 long long val
= clang_EvalResult_getAsLongLong(result
);
3050 printf("Value: %lld", val
);
3056 double val
= clang_EvalResult_getAsDouble(result
);
3057 printf("Kind: Float , Value: %f", val
);
3060 case CXEval_ObjCStrLiteral
:
3062 const char* str
= clang_EvalResult_getAsStr(result
);
3063 printf("Kind: ObjCString , Value: %s", str
);
3066 case CXEval_StrLiteral
:
3068 const char* str
= clang_EvalResult_getAsStr(result
);
3069 printf("Kind: CString , Value: %s", str
);
3074 const char* str
= clang_EvalResult_getAsStr(result
);
3075 printf("Kind: CFString , Value: %s", str
);
3079 printf("Unexposed");
3084 static void inspect_evaluate_cursor(CXCursor Cursor
) {
3085 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
3088 unsigned line
, column
;
3091 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
3092 printf("%d:%d ", line
, column
);
3093 PrintCursor(Cursor
, NULL
);
3094 PrintCursorExtent(Cursor
);
3095 Spelling
= clang_getCursorSpelling(Cursor
);
3096 cspell
= clang_getCString(Spelling
);
3097 if (cspell
&& strlen(cspell
) != 0) {
3098 unsigned pieceIndex
;
3099 printf(" Spelling=%s (", cspell
);
3100 for (pieceIndex
= 0; ; ++pieceIndex
) {
3101 CXSourceRange range
=
3102 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
3103 if (clang_Range_isNull(range
))
3105 PrintRange(range
, 0);
3109 clang_disposeString(Spelling
);
3111 ER
= clang_Cursor_Evaluate(Cursor
);
3113 printf("Not Evaluatable");
3115 display_evaluate_results(ER
);
3116 clang_EvalResult_dispose(ER
);
3121 static void inspect_macroinfo_cursor(CXCursor Cursor
) {
3122 CXSourceLocation CursorLoc
= clang_getCursorLocation(Cursor
);
3125 unsigned line
, column
;
3126 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
3127 printf("%d:%d ", line
, column
);
3128 PrintCursor(Cursor
, NULL
);
3129 PrintCursorExtent(Cursor
);
3130 Spelling
= clang_getCursorSpelling(Cursor
);
3131 cspell
= clang_getCString(Spelling
);
3132 if (cspell
&& strlen(cspell
) != 0) {
3133 unsigned pieceIndex
;
3134 printf(" Spelling=%s (", cspell
);
3135 for (pieceIndex
= 0; ; ++pieceIndex
) {
3136 CXSourceRange range
=
3137 clang_Cursor_getSpellingNameRange(Cursor
, pieceIndex
, 0);
3138 if (clang_Range_isNull(range
))
3140 PrintRange(range
, 0);
3144 clang_disposeString(Spelling
);
3146 if (clang_Cursor_isMacroBuiltin(Cursor
)) {
3147 printf("[builtin macro]");
3148 } else if (clang_Cursor_isMacroFunctionLike(Cursor
)) {
3149 printf("[function macro]");
3154 static enum CXVisitorResult
findFileRefsVisit(void *context
,
3155 CXCursor cursor
, CXSourceRange range
) {
3156 if (clang_Range_isNull(range
))
3157 return CXVisit_Continue
;
3159 PrintCursor(cursor
, NULL
);
3160 PrintRange(range
, "");
3162 return CXVisit_Continue
;
3165 static int find_file_refs_at(int argc
, const char **argv
) {
3168 struct CXUnsavedFile
*unsaved_files
= 0;
3169 int num_unsaved_files
= 0;
3170 enum CXErrorCode Err
;
3171 CXTranslationUnit TU
;
3173 CursorSourceLocation
*Locations
= 0;
3174 unsigned NumLocations
= 0, Loc
;
3175 unsigned Repeats
= 1;
3178 /* Count the number of locations. */
3179 while (strstr(argv
[NumLocations
+1], "-file-refs-at=") == argv
[NumLocations
+1])
3182 /* Parse the locations. */
3183 assert(NumLocations
> 0 && "Unable to count locations?");
3184 Locations
= (CursorSourceLocation
*)malloc(
3185 NumLocations
* sizeof(CursorSourceLocation
));
3187 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
3188 const char *input
= argv
[Loc
+ 1] + strlen("-file-refs-at=");
3189 if ((errorCode
= parse_file_line_column(input
, &Locations
[Loc
].filename
,
3190 &Locations
[Loc
].line
,
3191 &Locations
[Loc
].column
, 0, 0)))
3195 if (parse_remapped_files(argc
, argv
, NumLocations
+ 1, &unsaved_files
,
3196 &num_unsaved_files
))
3199 if (getenv("CINDEXTEST_EDITING"))
3202 /* Parse the translation unit. When we're testing clang_getCursor() after
3203 reparsing, don't remap unsaved files until the second parse. */
3204 CIdx
= clang_createIndex(1, 1);
3205 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
3206 argv
+ num_unsaved_files
+ 1 + NumLocations
,
3207 argc
- num_unsaved_files
- 2 - NumLocations
,
3209 Repeats
> 1? 0 : num_unsaved_files
,
3210 getDefaultParsingOptions(), &TU
);
3211 if (Err
!= CXError_Success
) {
3212 fprintf(stderr
, "unable to parse input\n");
3213 describeLibclangFailure(Err
);
3214 clang_disposeTranslationUnit(TU
);
3218 if (checkForErrors(TU
) != 0)
3221 for (I
= 0; I
!= Repeats
; ++I
) {
3223 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
3224 clang_defaultReparseOptions(TU
));
3225 if (Err
!= CXError_Success
) {
3226 describeLibclangFailure(Err
);
3227 clang_disposeTranslationUnit(TU
);
3232 if (checkForErrors(TU
) != 0)
3235 for (Loc
= 0; Loc
< NumLocations
; ++Loc
) {
3236 CXFile file
= clang_getFile(TU
, Locations
[Loc
].filename
);
3240 Cursor
= clang_getCursor(TU
,
3241 clang_getLocation(TU
, file
, Locations
[Loc
].line
,
3242 Locations
[Loc
].column
));
3244 if (checkForErrors(TU
) != 0)
3247 if (I
+ 1 == Repeats
) {
3248 CXCursorAndRangeVisitor visitor
= { 0, findFileRefsVisit
};
3249 PrintCursor(Cursor
, NULL
);
3251 clang_findReferencesInFile(Cursor
, file
, visitor
);
3252 free(Locations
[Loc
].filename
);
3254 if (checkForErrors(TU
) != 0)
3260 PrintDiagnostics(TU
);
3261 clang_disposeTranslationUnit(TU
);
3262 clang_disposeIndex(CIdx
);
3264 free_remapped_files(unsaved_files
, num_unsaved_files
);
3268 static enum CXVisitorResult
findFileIncludesVisit(void *context
,
3269 CXCursor cursor
, CXSourceRange range
) {
3270 PrintCursor(cursor
, NULL
);
3271 PrintRange(range
, "");
3273 return CXVisit_Continue
;
3276 static int find_file_includes_in(int argc
, const char **argv
) {
3278 struct CXUnsavedFile
*unsaved_files
= 0;
3279 int num_unsaved_files
= 0;
3280 enum CXErrorCode Err
;
3281 CXTranslationUnit TU
;
3282 const char **Filenames
= 0;
3283 unsigned NumFilenames
= 0;
3284 unsigned Repeats
= 1;
3287 /* Count the number of locations. */
3288 while (strstr(argv
[NumFilenames
+1], "-file-includes-in=") == argv
[NumFilenames
+1])
3291 /* Parse the locations. */
3292 assert(NumFilenames
> 0 && "Unable to count filenames?");
3293 Filenames
= (const char **)malloc(NumFilenames
* sizeof(const char *));
3295 for (I
= 0; I
< NumFilenames
; ++I
) {
3296 const char *input
= argv
[I
+ 1] + strlen("-file-includes-in=");
3297 /* Copy the file name. */
3298 Filenames
[I
] = input
;
3301 if (parse_remapped_files(argc
, argv
, NumFilenames
+ 1, &unsaved_files
,
3302 &num_unsaved_files
))
3305 if (getenv("CINDEXTEST_EDITING"))
3308 /* Parse the translation unit. When we're testing clang_getCursor() after
3309 reparsing, don't remap unsaved files until the second parse. */
3310 CIdx
= clang_createIndex(1, 1);
3311 Err
= clang_parseTranslationUnit2(
3312 CIdx
, argv
[argc
- 1],
3313 argv
+ num_unsaved_files
+ 1 + NumFilenames
,
3314 argc
- num_unsaved_files
- 2 - NumFilenames
,
3316 Repeats
> 1 ? 0 : num_unsaved_files
, getDefaultParsingOptions(), &TU
);
3318 if (Err
!= CXError_Success
) {
3319 fprintf(stderr
, "unable to parse input\n");
3320 describeLibclangFailure(Err
);
3321 clang_disposeTranslationUnit(TU
);
3325 if (checkForErrors(TU
) != 0)
3328 for (I
= 0; I
!= Repeats
; ++I
) {
3330 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
3331 clang_defaultReparseOptions(TU
));
3332 if (Err
!= CXError_Success
) {
3333 describeLibclangFailure(Err
);
3334 clang_disposeTranslationUnit(TU
);
3339 if (checkForErrors(TU
) != 0)
3342 for (FI
= 0; FI
< NumFilenames
; ++FI
) {
3343 CXFile file
= clang_getFile(TU
, Filenames
[FI
]);
3347 if (checkForErrors(TU
) != 0)
3350 if (I
+ 1 == Repeats
) {
3351 CXCursorAndRangeVisitor visitor
= { 0, findFileIncludesVisit
};
3352 clang_findIncludesInFile(TU
, file
, visitor
);
3354 if (checkForErrors(TU
) != 0)
3360 PrintDiagnostics(TU
);
3361 clang_disposeTranslationUnit(TU
);
3362 clang_disposeIndex(CIdx
);
3363 free((void *)Filenames
);
3364 free_remapped_files(unsaved_files
, num_unsaved_files
);
3368 #define MAX_IMPORTED_ASTFILES 200
3373 } ImportedASTFilesData
;
3375 static ImportedASTFilesData
*importedASTs_create(void) {
3376 ImportedASTFilesData
*p
;
3377 p
= malloc(sizeof(ImportedASTFilesData
));
3379 p
->filenames
= malloc(MAX_IMPORTED_ASTFILES
* sizeof(const char *));
3380 assert(p
->filenames
);
3385 static void importedASTs_dispose(ImportedASTFilesData
*p
) {
3390 for (i
= 0; i
< p
->num_files
; ++i
)
3391 free(p
->filenames
[i
]);
3396 static void importedASTS_insert(ImportedASTFilesData
*p
, const char *file
) {
3399 for (i
= 0; i
< p
->num_files
; ++i
)
3400 if (strcmp(file
, p
->filenames
[i
]) == 0)
3402 assert(p
->num_files
+ 1 < MAX_IMPORTED_ASTFILES
);
3403 p
->filenames
[p
->num_files
++] = strdup(file
);
3406 typedef struct IndexDataStringList_
{
3407 struct IndexDataStringList_
*next
;
3408 char data
[1]; /* Dynamically sized. */
3409 } IndexDataStringList
;
3412 const char *check_prefix
;
3413 int first_check_printed
;
3416 CXString main_filename
;
3417 ImportedASTFilesData
*importedASTs
;
3418 IndexDataStringList
*strings
;
3419 CXTranslationUnit TU
;
3422 static void free_client_data(IndexData
*index_data
) {
3423 IndexDataStringList
*node
= index_data
->strings
;
3425 IndexDataStringList
*next
= node
->next
;
3429 index_data
->strings
= NULL
;
3432 static void printCheck(IndexData
*data
) {
3433 if (data
->check_prefix
) {
3434 if (data
->first_check_printed
) {
3435 printf("// %s-NEXT: ", data
->check_prefix
);
3437 printf("// %s : ", data
->check_prefix
);
3438 data
->first_check_printed
= 1;
3443 static void printCXIndexFile(CXIdxClientFile file
) {
3444 CXString filename
= clang_getFileName((CXFile
)file
);
3445 printf("%s", clang_getCString(filename
));
3446 clang_disposeString(filename
);
3449 static void printCXIndexLoc(CXIdxLoc loc
, CXClientData client_data
) {
3450 IndexData
*index_data
;
3453 CXIdxClientFile file
;
3454 unsigned line
, column
;
3455 const char *main_filename
;
3458 index_data
= (IndexData
*)client_data
;
3459 clang_indexLoc_getFileLocation(loc
, &file
, 0, &line
, &column
, 0);
3461 printf("<invalid>");
3465 printf("<no idxfile>");
3468 filename
= clang_getFileName((CXFile
)file
);
3469 cname
= clang_getCString(filename
);
3470 main_filename
= clang_getCString(index_data
->main_filename
);
3471 if (strcmp(cname
, main_filename
) == 0)
3475 clang_disposeString(filename
);
3478 printCXIndexFile(file
);
3481 printf("%d:%d", line
, column
);
3484 static unsigned digitCount(unsigned val
) {
3494 static CXIdxClientContainer
makeClientContainer(CXClientData
*client_data
,
3495 const CXIdxEntityInfo
*info
,
3497 IndexData
*index_data
;
3498 IndexDataStringList
*node
;
3501 CXIdxClientFile file
;
3502 unsigned line
, column
;
3506 name
= "<anon-tag>";
3508 clang_indexLoc_getFileLocation(loc
, &file
, 0, &line
, &column
, 0);
3511 (IndexDataStringList
*)malloc(sizeof(IndexDataStringList
) + strlen(name
) +
3512 digitCount(line
) + digitCount(column
) + 2);
3514 newStr
= node
->data
;
3515 sprintf(newStr
, "%s:%d:%d", name
, line
, column
);
3517 /* Remember string so it can be freed later. */
3518 index_data
= (IndexData
*)client_data
;
3519 node
->next
= index_data
->strings
;
3520 index_data
->strings
= node
;
3522 return (CXIdxClientContainer
)newStr
;
3525 static void printCXIndexContainer(const CXIdxContainerInfo
*info
) {
3526 CXIdxClientContainer container
;
3527 container
= clang_index_getClientContainer(info
);
3529 printf("[<<NULL>>]");
3531 printf("[%s]", (const char *)container
);
3534 static const char *getEntityKindString(CXIdxEntityKind kind
) {
3536 case CXIdxEntity_Unexposed
: return "<<UNEXPOSED>>";
3537 case CXIdxEntity_Typedef
: return "typedef";
3538 case CXIdxEntity_Function
: return "function";
3539 case CXIdxEntity_Variable
: return "variable";
3540 case CXIdxEntity_Field
: return "field";
3541 case CXIdxEntity_EnumConstant
: return "enumerator";
3542 case CXIdxEntity_ObjCClass
: return "objc-class";
3543 case CXIdxEntity_ObjCProtocol
: return "objc-protocol";
3544 case CXIdxEntity_ObjCCategory
: return "objc-category";
3545 case CXIdxEntity_ObjCInstanceMethod
: return "objc-instance-method";
3546 case CXIdxEntity_ObjCClassMethod
: return "objc-class-method";
3547 case CXIdxEntity_ObjCProperty
: return "objc-property";
3548 case CXIdxEntity_ObjCIvar
: return "objc-ivar";
3549 case CXIdxEntity_Enum
: return "enum";
3550 case CXIdxEntity_Struct
: return "struct";
3551 case CXIdxEntity_Union
: return "union";
3552 case CXIdxEntity_CXXClass
: return "c++-class";
3553 case CXIdxEntity_CXXNamespace
: return "namespace";
3554 case CXIdxEntity_CXXNamespaceAlias
: return "namespace-alias";
3555 case CXIdxEntity_CXXStaticVariable
: return "c++-static-var";
3556 case CXIdxEntity_CXXStaticMethod
: return "c++-static-method";
3557 case CXIdxEntity_CXXInstanceMethod
: return "c++-instance-method";
3558 case CXIdxEntity_CXXConstructor
: return "constructor";
3559 case CXIdxEntity_CXXDestructor
: return "destructor";
3560 case CXIdxEntity_CXXConversionFunction
: return "conversion-func";
3561 case CXIdxEntity_CXXTypeAlias
: return "type-alias";
3562 case CXIdxEntity_CXXInterface
: return "c++-__interface";
3563 case CXIdxEntity_CXXConcept
:
3566 assert(0 && "Garbage entity kind");
3570 static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind
) {
3572 case CXIdxEntity_NonTemplate
: return "";
3573 case CXIdxEntity_Template
: return "-template";
3574 case CXIdxEntity_TemplatePartialSpecialization
:
3575 return "-template-partial-spec";
3576 case CXIdxEntity_TemplateSpecialization
: return "-template-spec";
3578 assert(0 && "Garbage entity kind");
3582 static const char *getEntityLanguageString(CXIdxEntityLanguage kind
) {
3584 case CXIdxEntityLang_None
: return "<none>";
3585 case CXIdxEntityLang_C
: return "C";
3586 case CXIdxEntityLang_ObjC
: return "ObjC";
3587 case CXIdxEntityLang_CXX
: return "C++";
3588 case CXIdxEntityLang_Swift
: return "Swift";
3590 assert(0 && "Garbage language kind");
3594 static void printEntityInfo(const char *cb
,
3595 CXClientData client_data
,
3596 const CXIdxEntityInfo
*info
) {
3598 IndexData
*index_data
;
3600 index_data
= (IndexData
*)client_data
;
3601 printCheck(index_data
);
3604 printf("%s: <<NULL>>", cb
);
3610 name
= "<anon-tag>";
3612 printf("%s: kind: %s%s", cb
, getEntityKindString(info
->kind
),
3613 getEntityTemplateKindString(info
->templateKind
));
3614 printf(" | name: %s", name
);
3615 printf(" | USR: %s", info
->USR
);
3616 printf(" | lang: %s", getEntityLanguageString(info
->lang
));
3618 for (i
= 0; i
!= info
->numAttributes
; ++i
) {
3619 const CXIdxAttrInfo
*Attr
= info
->attributes
[i
];
3620 printf(" <attribute>: ");
3621 PrintCursor(Attr
->cursor
, NULL
);
3625 static void printBaseClassInfo(CXClientData client_data
,
3626 const CXIdxBaseClassInfo
*info
) {
3627 printEntityInfo(" <base>", client_data
, info
->base
);
3628 printf(" | cursor: ");
3629 PrintCursor(info
->cursor
, NULL
);
3631 printCXIndexLoc(info
->loc
, client_data
);
3634 static void printProtocolList(const CXIdxObjCProtocolRefListInfo
*ProtoInfo
,
3635 CXClientData client_data
) {
3637 for (i
= 0; i
< ProtoInfo
->numProtocols
; ++i
) {
3638 printEntityInfo(" <protocol>", client_data
,
3639 ProtoInfo
->protocols
[i
]->protocol
);
3640 printf(" | cursor: ");
3641 PrintCursor(ProtoInfo
->protocols
[i
]->cursor
, NULL
);
3643 printCXIndexLoc(ProtoInfo
->protocols
[i
]->loc
, client_data
);
3648 static void printSymbolRole(CXSymbolRole role
) {
3649 if (role
& CXSymbolRole_Declaration
)
3651 if (role
& CXSymbolRole_Definition
)
3653 if (role
& CXSymbolRole_Reference
)
3655 if (role
& CXSymbolRole_Read
)
3657 if (role
& CXSymbolRole_Write
)
3659 if (role
& CXSymbolRole_Call
)
3661 if (role
& CXSymbolRole_Dynamic
)
3663 if (role
& CXSymbolRole_AddressOf
)
3665 if (role
& CXSymbolRole_Implicit
)
3666 printf(" implicit");
3669 static void index_diagnostic(CXClientData client_data
,
3670 CXDiagnosticSet diagSet
, void *reserved
) {
3673 unsigned numDiags
, i
;
3675 IndexData
*index_data
;
3676 index_data
= (IndexData
*)client_data
;
3677 printCheck(index_data
);
3679 numDiags
= clang_getNumDiagnosticsInSet(diagSet
);
3680 for (i
= 0; i
!= numDiags
; ++i
) {
3681 diag
= clang_getDiagnosticInSet(diagSet
, i
);
3682 str
= clang_formatDiagnostic(diag
, clang_defaultDiagnosticDisplayOptions());
3683 cstr
= clang_getCString(str
);
3684 printf("[diagnostic]: %s\n", cstr
);
3685 clang_disposeString(str
);
3687 if (getenv("CINDEXTEST_FAILONERROR") &&
3688 clang_getDiagnosticSeverity(diag
) >= CXDiagnostic_Error
) {
3689 index_data
->fail_for_error
= 1;
3694 static CXIdxClientFile
index_enteredMainFile(CXClientData client_data
,
3695 CXFile file
, void *reserved
) {
3696 IndexData
*index_data
;
3698 index_data
= (IndexData
*)client_data
;
3699 printCheck(index_data
);
3701 index_data
->main_filename
= clang_getFileName(file
);
3703 printf("[enteredMainFile]: ");
3704 printCXIndexFile((CXIdxClientFile
)file
);
3707 return (CXIdxClientFile
)file
;
3710 static CXIdxClientFile
index_ppIncludedFile(CXClientData client_data
,
3711 const CXIdxIncludedFileInfo
*info
) {
3712 IndexData
*index_data
;
3714 index_data
= (IndexData
*)client_data
;
3715 printCheck(index_data
);
3717 printf("[ppIncludedFile]: ");
3718 printCXIndexFile((CXIdxClientFile
)info
->file
);
3719 printf(" | name: \"%s\"", info
->filename
);
3720 printf(" | hash loc: ");
3721 printCXIndexLoc(info
->hashLoc
, client_data
);
3722 printf(" | isImport: %d | isAngled: %d | isModule: %d",
3723 info
->isImport
, info
->isAngled
, info
->isModuleImport
);
3725 Mod
= clang_getModuleForFile(index_data
->TU
, (CXFile
)info
->file
);
3727 CXString str
= clang_Module_getFullName(Mod
);
3728 const char *cstr
= clang_getCString(str
);
3729 printf(" | module: %s", cstr
);
3730 clang_disposeString(str
);
3735 return (CXIdxClientFile
)info
->file
;
3738 static CXIdxClientFile
index_importedASTFile(CXClientData client_data
,
3739 const CXIdxImportedASTFileInfo
*info
) {
3740 IndexData
*index_data
;
3741 index_data
= (IndexData
*)client_data
;
3742 printCheck(index_data
);
3744 if (index_data
->importedASTs
) {
3745 CXString filename
= clang_getFileName(info
->file
);
3746 importedASTS_insert(index_data
->importedASTs
, clang_getCString(filename
));
3747 clang_disposeString(filename
);
3750 printf("[importedASTFile]: ");
3751 printCXIndexFile((CXIdxClientFile
)info
->file
);
3753 CXString name
= clang_Module_getFullName(info
->module
);
3755 printCXIndexLoc(info
->loc
, client_data
);
3756 printf(" | name: \"%s\"", clang_getCString(name
));
3757 printf(" | isImplicit: %d\n", info
->isImplicit
);
3758 clang_disposeString(name
);
3760 /* PCH file, the rest are not relevant. */
3764 return (CXIdxClientFile
)info
->file
;
3767 static CXIdxClientContainer
3768 index_startedTranslationUnit(CXClientData client_data
, void *reserved
) {
3769 IndexData
*index_data
;
3770 index_data
= (IndexData
*)client_data
;
3771 printCheck(index_data
);
3773 printf("[startedTranslationUnit]\n");
3775 #pragma GCC diagnostic push
3776 #pragma GCC diagnostic ignored "-Wcast-qual"
3778 return (CXIdxClientContainer
)"TU";
3780 #pragma GCC diagnostic pop
3784 static void index_indexDeclaration(CXClientData client_data
,
3785 const CXIdxDeclInfo
*info
) {
3786 IndexData
*index_data
;
3787 const CXIdxObjCCategoryDeclInfo
*CatInfo
;
3788 const CXIdxObjCInterfaceDeclInfo
*InterInfo
;
3789 const CXIdxObjCProtocolRefListInfo
*ProtoInfo
;
3790 const CXIdxObjCPropertyDeclInfo
*PropInfo
;
3791 const CXIdxCXXClassDeclInfo
*CXXClassInfo
;
3793 index_data
= (IndexData
*)client_data
;
3795 printEntityInfo("[indexDeclaration]", client_data
, info
->entityInfo
);
3796 printf(" | cursor: ");
3797 PrintCursor(info
->cursor
, NULL
);
3799 printCXIndexLoc(info
->loc
, client_data
);
3800 printf(" | semantic-container: ");
3801 printCXIndexContainer(info
->semanticContainer
);
3802 printf(" | lexical-container: ");
3803 printCXIndexContainer(info
->lexicalContainer
);
3804 printf(" | isRedecl: %d", info
->isRedeclaration
);
3805 printf(" | isDef: %d", info
->isDefinition
);
3806 if (info
->flags
& CXIdxDeclFlag_Skipped
) {
3807 assert(!info
->isContainer
);
3808 printf(" | isContainer: skipped");
3810 printf(" | isContainer: %d", info
->isContainer
);
3812 printf(" | isImplicit: %d\n", info
->isImplicit
);
3814 for (i
= 0; i
!= info
->numAttributes
; ++i
) {
3815 const CXIdxAttrInfo
*Attr
= info
->attributes
[i
];
3816 printf(" <attribute>: ");
3817 PrintCursor(Attr
->cursor
, NULL
);
3821 if (clang_index_isEntityObjCContainerKind(info
->entityInfo
->kind
)) {
3822 const char *kindName
= 0;
3823 CXIdxObjCContainerKind K
= clang_index_getObjCContainerDeclInfo(info
)->kind
;
3825 case CXIdxObjCContainer_ForwardRef
:
3826 kindName
= "forward-ref"; break;
3827 case CXIdxObjCContainer_Interface
:
3828 kindName
= "interface"; break;
3829 case CXIdxObjCContainer_Implementation
:
3830 kindName
= "implementation"; break;
3832 printCheck(index_data
);
3833 printf(" <ObjCContainerInfo>: kind: %s\n", kindName
);
3836 if ((CatInfo
= clang_index_getObjCCategoryDeclInfo(info
))) {
3837 printEntityInfo(" <ObjCCategoryInfo>: class", client_data
,
3838 CatInfo
->objcClass
);
3839 printf(" | cursor: ");
3840 PrintCursor(CatInfo
->classCursor
, NULL
);
3842 printCXIndexLoc(CatInfo
->classLoc
, client_data
);
3846 if ((InterInfo
= clang_index_getObjCInterfaceDeclInfo(info
))) {
3847 if (InterInfo
->superInfo
) {
3848 printBaseClassInfo(client_data
, InterInfo
->superInfo
);
3853 if ((ProtoInfo
= clang_index_getObjCProtocolRefListInfo(info
))) {
3854 printProtocolList(ProtoInfo
, client_data
);
3857 if ((PropInfo
= clang_index_getObjCPropertyDeclInfo(info
))) {
3858 if (PropInfo
->getter
) {
3859 printEntityInfo(" <getter>", client_data
, PropInfo
->getter
);
3862 if (PropInfo
->setter
) {
3863 printEntityInfo(" <setter>", client_data
, PropInfo
->setter
);
3868 if ((CXXClassInfo
= clang_index_getCXXClassDeclInfo(info
))) {
3869 for (i
= 0; i
!= CXXClassInfo
->numBases
; ++i
) {
3870 printBaseClassInfo(client_data
, CXXClassInfo
->bases
[i
]);
3875 if (info
->declAsContainer
)
3876 clang_index_setClientContainer(
3877 info
->declAsContainer
,
3878 makeClientContainer(client_data
, info
->entityInfo
, info
->loc
));
3881 static void index_indexEntityReference(CXClientData client_data
,
3882 const CXIdxEntityRefInfo
*info
) {
3883 printEntityInfo("[indexEntityReference]", client_data
,
3884 info
->referencedEntity
);
3885 printf(" | cursor: ");
3886 PrintCursor(info
->cursor
, NULL
);
3888 printCXIndexLoc(info
->loc
, client_data
);
3889 printEntityInfo(" | <parent>:", client_data
, info
->parentEntity
);
3890 printf(" | container: ");
3891 printCXIndexContainer(info
->container
);
3892 printf(" | refkind: ");
3893 switch (info
->kind
) {
3894 case CXIdxEntityRef_Direct
: printf("direct"); break;
3895 case CXIdxEntityRef_Implicit
: printf("implicit"); break;
3898 printSymbolRole(info
->role
);
3902 static int index_abortQuery(CXClientData client_data
, void *reserved
) {
3903 IndexData
*index_data
;
3904 index_data
= (IndexData
*)client_data
;
3905 return index_data
->abort
;
3908 static IndexerCallbacks IndexCB
= {
3911 index_enteredMainFile
,
3912 index_ppIncludedFile
,
3913 index_importedASTFile
,
3914 index_startedTranslationUnit
,
3915 index_indexDeclaration
,
3916 index_indexEntityReference
3919 static unsigned getIndexOptions(void) {
3920 unsigned index_opts
;
3922 if (getenv("CINDEXTEST_SUPPRESSREFS"))
3923 index_opts
|= CXIndexOpt_SuppressRedundantRefs
;
3924 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
3925 index_opts
|= CXIndexOpt_IndexFunctionLocalSymbols
;
3926 if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
3927 index_opts
|= CXIndexOpt_SkipParsedBodiesInSession
;
3928 if (getenv("CINDEXTEST_INDEXIMPLICITTEMPLATEINSTANTIATIONS"))
3929 index_opts
|= CXIndexOpt_IndexImplicitTemplateInstantiations
;
3934 static int index_compile_args(int num_args
, const char **args
,
3935 CXIndexAction idxAction
,
3936 ImportedASTFilesData
*importedASTs
,
3937 const char *check_prefix
) {
3938 IndexData index_data
;
3939 unsigned index_opts
;
3942 if (num_args
== 0) {
3943 fprintf(stderr
, "no compiler arguments\n");
3947 index_data
.check_prefix
= check_prefix
;
3948 index_data
.first_check_printed
= 0;
3949 index_data
.fail_for_error
= 0;
3950 index_data
.abort
= 0;
3951 index_data
.main_filename
= createCXString("");
3952 index_data
.importedASTs
= importedASTs
;
3953 index_data
.strings
= NULL
;
3954 index_data
.TU
= NULL
;
3956 index_opts
= getIndexOptions();
3957 result
= clang_indexSourceFile(idxAction
, &index_data
,
3958 &IndexCB
,sizeof(IndexCB
), index_opts
,
3959 0, args
, num_args
, 0, 0, 0,
3960 getDefaultParsingOptions());
3961 if (result
!= CXError_Success
)
3962 describeLibclangFailure(result
);
3964 if (index_data
.fail_for_error
)
3967 clang_disposeString(index_data
.main_filename
);
3968 free_client_data(&index_data
);
3972 static int index_ast_file(const char *ast_file
,
3974 CXIndexAction idxAction
,
3975 ImportedASTFilesData
*importedASTs
,
3976 const char *check_prefix
) {
3977 CXTranslationUnit TU
;
3978 IndexData index_data
;
3979 unsigned index_opts
;
3982 if (!CreateTranslationUnit(Idx
, ast_file
, &TU
))
3985 index_data
.check_prefix
= check_prefix
;
3986 index_data
.first_check_printed
= 0;
3987 index_data
.fail_for_error
= 0;
3988 index_data
.abort
= 0;
3989 index_data
.main_filename
= createCXString("");
3990 index_data
.importedASTs
= importedASTs
;
3991 index_data
.strings
= NULL
;
3994 index_opts
= getIndexOptions();
3995 result
= clang_indexTranslationUnit(idxAction
, &index_data
,
3996 &IndexCB
,sizeof(IndexCB
),
3998 if (index_data
.fail_for_error
)
4001 clang_disposeTranslationUnit(TU
);
4002 clang_disposeString(index_data
.main_filename
);
4003 free_client_data(&index_data
);
4007 static int index_file(int argc
, const char **argv
, int full
) {
4008 const char *check_prefix
;
4010 CXIndexAction idxAction
;
4011 ImportedASTFilesData
*importedASTs
;
4016 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4017 check_prefix
= argv
[0] + strlen("-check-prefix=");
4023 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4024 /* displayDiagnostics=*/1))) {
4025 fprintf(stderr
, "Could not create Index\n");
4028 idxAction
= clang_IndexAction_create(Idx
);
4031 importedASTs
= importedASTs_create();
4033 result
= index_compile_args(argc
, argv
, idxAction
, importedASTs
, check_prefix
);
4039 for (i
= 0; i
< importedASTs
->num_files
&& result
== 0; ++i
) {
4040 result
= index_ast_file(importedASTs
->filenames
[i
], Idx
, idxAction
,
4041 importedASTs
, check_prefix
);
4046 importedASTs_dispose(importedASTs
);
4047 clang_IndexAction_dispose(idxAction
);
4048 clang_disposeIndex(Idx
);
4052 static int index_tu(int argc
, const char **argv
) {
4053 const char *check_prefix
;
4055 CXIndexAction idxAction
;
4060 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4061 check_prefix
= argv
[0] + strlen("-check-prefix=");
4067 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4068 /* displayDiagnostics=*/1))) {
4069 fprintf(stderr
, "Could not create Index\n");
4072 idxAction
= clang_IndexAction_create(Idx
);
4074 result
= index_ast_file(argv
[0], Idx
, idxAction
,
4075 /*importedASTs=*/0, check_prefix
);
4077 clang_IndexAction_dispose(idxAction
);
4078 clang_disposeIndex(Idx
);
4082 static int index_compile_db(int argc
, const char **argv
) {
4083 const char *check_prefix
;
4085 CXIndexAction idxAction
;
4090 if (strstr(argv
[0], "-check-prefix=") == argv
[0]) {
4091 check_prefix
= argv
[0] + strlen("-check-prefix=");
4098 fprintf(stderr
, "no compilation database\n");
4102 if (!(Idx
= clang_createIndex(/* excludeDeclsFromPCH */ 1,
4103 /* displayDiagnostics=*/1))) {
4104 fprintf(stderr
, "Could not create Index\n");
4107 idxAction
= clang_IndexAction_create(Idx
);
4110 const char *database
= argv
[0];
4111 CXCompilationDatabase db
= 0;
4112 CXCompileCommands CCmds
= 0;
4113 CXCompileCommand CCmd
;
4114 CXCompilationDatabase_Error ec
;
4116 #define MAX_COMPILE_ARGS 512
4117 CXString cxargs
[MAX_COMPILE_ARGS
];
4118 const char *args
[MAX_COMPILE_ARGS
];
4122 int i
, a
, numCmds
, numArgs
;
4124 len
= strlen(database
);
4125 tmp
= (char *) malloc(len
+1);
4127 memcpy(tmp
, database
, len
+1);
4128 buildDir
= dirname(tmp
);
4130 db
= clang_CompilationDatabase_fromDirectory(buildDir
, &ec
);
4134 if (ec
!=CXCompilationDatabase_NoError
) {
4135 printf("unexpected error %d code while loading compilation database\n", ec
);
4140 if (chdir(buildDir
) != 0) {
4141 printf("Could not chdir to %s\n", buildDir
);
4146 CCmds
= clang_CompilationDatabase_getAllCompileCommands(db
);
4148 printf("compilation db is empty\n");
4153 numCmds
= clang_CompileCommands_getSize(CCmds
);
4156 fprintf(stderr
, "should not get an empty compileCommand set\n");
4161 for (i
=0; i
<numCmds
&& errorCode
== 0; ++i
) {
4162 CCmd
= clang_CompileCommands_getCommand(CCmds
, i
);
4164 wd
= clang_CompileCommand_getDirectory(CCmd
);
4165 if (chdir(clang_getCString(wd
)) != 0) {
4166 printf("Could not chdir to %s\n", clang_getCString(wd
));
4170 clang_disposeString(wd
);
4172 numArgs
= clang_CompileCommand_getNumArgs(CCmd
);
4173 if (numArgs
> MAX_COMPILE_ARGS
){
4174 fprintf(stderr
, "got more compile arguments than maximum\n");
4178 for (a
=0; a
<numArgs
; ++a
) {
4179 cxargs
[a
] = clang_CompileCommand_getArg(CCmd
, a
);
4180 args
[a
] = clang_getCString(cxargs
[a
]);
4183 errorCode
= index_compile_args(numArgs
, args
, idxAction
,
4184 /*importedASTs=*/0, check_prefix
);
4186 for (a
=0; a
<numArgs
; ++a
)
4187 clang_disposeString(cxargs
[a
]);
4190 printf("database loading failed with error code %d.\n", ec
);
4195 clang_CompileCommands_dispose(CCmds
);
4196 clang_CompilationDatabase_dispose(db
);
4201 clang_IndexAction_dispose(idxAction
);
4202 clang_disposeIndex(Idx
);
4206 int perform_token_annotation(int argc
, const char **argv
) {
4207 const char *input
= argv
[1];
4209 unsigned line
, second_line
;
4210 unsigned column
, second_column
;
4212 CXTranslationUnit TU
= 0;
4214 struct CXUnsavedFile
*unsaved_files
= 0;
4215 int num_unsaved_files
= 0;
4217 unsigned num_tokens
;
4218 CXSourceRange range
;
4219 CXSourceLocation startLoc
, endLoc
;
4221 CXCursor
*cursors
= 0;
4222 CXSourceRangeList
*skipped_ranges
= 0;
4223 enum CXErrorCode Err
;
4226 input
+= strlen("-test-annotate-tokens=");
4227 if ((errorCode
= parse_file_line_column(input
, &filename
, &line
, &column
,
4228 &second_line
, &second_column
)))
4231 if (parse_remapped_files(argc
, argv
, 2, &unsaved_files
, &num_unsaved_files
)) {
4236 CIdx
= clang_createIndex(0, 1);
4237 Err
= clang_parseTranslationUnit2(CIdx
, argv
[argc
- 1],
4238 argv
+ num_unsaved_files
+ 2,
4239 argc
- num_unsaved_files
- 3,
4242 getDefaultParsingOptions(), &TU
);
4243 if (Err
!= CXError_Success
) {
4244 fprintf(stderr
, "unable to parse input\n");
4245 describeLibclangFailure(Err
);
4246 clang_disposeIndex(CIdx
);
4248 free_remapped_files(unsaved_files
, num_unsaved_files
);
4253 if (checkForErrors(TU
) != 0) {
4258 if (getenv("CINDEXTEST_EDITING")) {
4259 for (i
= 0; i
< 5; ++i
) {
4260 Err
= clang_reparseTranslationUnit(TU
, num_unsaved_files
, unsaved_files
,
4261 clang_defaultReparseOptions(TU
));
4262 if (Err
!= CXError_Success
) {
4263 fprintf(stderr
, "Unable to reparse translation unit!\n");
4264 describeLibclangFailure(Err
);
4271 if (checkForErrors(TU
) != 0) {
4276 file
= clang_getFile(TU
, filename
);
4278 fprintf(stderr
, "file %s is not in this translation unit\n", filename
);
4283 startLoc
= clang_getLocation(TU
, file
, line
, column
);
4284 if (clang_equalLocations(clang_getNullLocation(), startLoc
)) {
4285 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
, line
,
4291 endLoc
= clang_getLocation(TU
, file
, second_line
, second_column
);
4292 if (clang_equalLocations(clang_getNullLocation(), endLoc
)) {
4293 fprintf(stderr
, "invalid source location %s:%d:%d\n", filename
,
4294 second_line
, second_column
);
4299 range
= clang_getRange(startLoc
, endLoc
);
4300 clang_tokenize(TU
, range
, &tokens
, &num_tokens
);
4302 if (checkForErrors(TU
) != 0) {
4307 cursors
= (CXCursor
*)malloc(num_tokens
* sizeof(CXCursor
));
4309 clang_annotateTokens(TU
, tokens
, num_tokens
, cursors
);
4311 if (checkForErrors(TU
) != 0) {
4316 skipped_ranges
= clang_getSkippedRanges(TU
, file
);
4317 for (i
= 0; i
!= skipped_ranges
->count
; ++i
) {
4318 unsigned start_line
, start_column
, end_line
, end_column
;
4319 clang_getSpellingLocation(clang_getRangeStart(skipped_ranges
->ranges
[i
]),
4320 0, &start_line
, &start_column
, 0);
4321 clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges
->ranges
[i
]),
4322 0, &end_line
, &end_column
, 0);
4323 printf("Skipping: ");
4324 PrintExtent(stdout
, start_line
, start_column
, end_line
, end_column
);
4327 clang_disposeSourceRangeList(skipped_ranges
);
4329 for (i
= 0; i
!= num_tokens
; ++i
) {
4330 const char *kind
= "<unknown>";
4331 CXString spelling
= clang_getTokenSpelling(TU
, tokens
[i
]);
4332 CXSourceRange extent
= clang_getTokenExtent(TU
, tokens
[i
]);
4333 unsigned start_line
, start_column
, end_line
, end_column
;
4335 switch (clang_getTokenKind(tokens
[i
])) {
4336 case CXToken_Punctuation
: kind
= "Punctuation"; break;
4337 case CXToken_Keyword
: kind
= "Keyword"; break;
4338 case CXToken_Identifier
: kind
= "Identifier"; break;
4339 case CXToken_Literal
: kind
= "Literal"; break;
4340 case CXToken_Comment
: kind
= "Comment"; break;
4342 clang_getSpellingLocation(clang_getRangeStart(extent
),
4343 0, &start_line
, &start_column
, 0);
4344 clang_getSpellingLocation(clang_getRangeEnd(extent
),
4345 0, &end_line
, &end_column
, 0);
4346 printf("%s: \"%s\" ", kind
, clang_getCString(spelling
));
4347 clang_disposeString(spelling
);
4348 PrintExtent(stdout
, start_line
, start_column
, end_line
, end_column
);
4349 if (!clang_isInvalid(cursors
[i
].kind
)) {
4351 PrintCursor(cursors
[i
], NULL
);
4356 clang_disposeTokens(TU
, tokens
, num_tokens
);
4359 PrintDiagnostics(TU
);
4360 clang_disposeTranslationUnit(TU
);
4361 clang_disposeIndex(CIdx
);
4363 free_remapped_files(unsaved_files
, num_unsaved_files
);
4368 perform_test_compilation_db(const char *database
, int argc
, const char **argv
) {
4369 CXCompilationDatabase db
;
4370 CXCompileCommands CCmds
;
4371 CXCompileCommand CCmd
;
4372 CXCompilationDatabase_Error ec
;
4379 int i
, j
, a
, numCmds
, numArgs
;
4381 len
= strlen(database
);
4382 tmp
= (char *) malloc(len
+1);
4384 memcpy(tmp
, database
, len
+1);
4385 buildDir
= dirname(tmp
);
4387 db
= clang_CompilationDatabase_fromDirectory(buildDir
, &ec
);
4391 if (ec
!=CXCompilationDatabase_NoError
) {
4392 printf("unexpected error %d code while loading compilation database\n", ec
);
4397 for (i
=0; i
<argc
&& errorCode
==0; ) {
4398 if (strcmp(argv
[i
],"lookup")==0){
4399 CCmds
= clang_CompilationDatabase_getCompileCommands(db
, argv
[i
+1]);
4402 printf("file %s not found in compilation db\n", argv
[i
+1]);
4407 numCmds
= clang_CompileCommands_getSize(CCmds
);
4410 fprintf(stderr
, "should not get an empty compileCommand set for file"
4411 " '%s'\n", argv
[i
+1]);
4416 for (j
=0; j
<numCmds
; ++j
) {
4417 CCmd
= clang_CompileCommands_getCommand(CCmds
, j
);
4419 wd
= clang_CompileCommand_getDirectory(CCmd
);
4420 printf("workdir:'%s'", clang_getCString(wd
));
4421 clang_disposeString(wd
);
4423 printf(" cmdline:'");
4424 numArgs
= clang_CompileCommand_getNumArgs(CCmd
);
4425 for (a
=0; a
<numArgs
; ++a
) {
4427 arg
= clang_CompileCommand_getArg(CCmd
, a
);
4428 printf("%s", clang_getCString(arg
));
4429 clang_disposeString(arg
);
4434 clang_CompileCommands_dispose(CCmds
);
4439 clang_CompilationDatabase_dispose(db
);
4441 printf("database loading failed with error code %d.\n", ec
);
4451 /******************************************************************************/
4453 /******************************************************************************/
4455 static int insufficient_usr(const char *kind
, const char *usage
) {
4456 fprintf(stderr
, "USR for '%s' requires: %s\n", kind
, usage
);
4460 static unsigned isUSR(const char *s
) {
4461 return s
[0] == 'c' && s
[1] == ':';
4464 static int not_usr(const char *s
, const char *arg
) {
4465 fprintf(stderr
, "'%s' argument ('%s') is not a USR\n", s
, arg
);
4469 static void print_usr(CXString usr
) {
4470 const char *s
= clang_getCString(usr
);
4472 clang_disposeString(usr
);
4475 static void display_usrs(void) {
4476 fprintf(stderr
, "-print-usrs options:\n"
4477 " ObjCCategory <class name> <category name>\n"
4478 " ObjCClass <class name>\n"
4479 " ObjCIvar <ivar name> <class USR>\n"
4480 " ObjCMethod <selector> [0=class method|1=instance method] "
4482 " ObjCProperty <property name> <class USR>\n"
4483 " ObjCProtocol <protocol name>\n");
4486 int print_usrs(const char **I
, const char **E
) {
4488 const char *kind
= *I
;
4489 unsigned len
= strlen(kind
);
4492 if (memcmp(kind
, "ObjCIvar", 8) == 0) {
4494 return insufficient_usr(kind
, "<ivar name> <class USR>");
4496 return not_usr("<class USR>", I
[2]);
4498 CXString x
= createCXString(I
[2]);
4499 print_usr(clang_constructUSR_ObjCIvar(I
[1], x
));
4507 if (memcmp(kind
, "ObjCClass", 9) == 0) {
4509 return insufficient_usr(kind
, "<class name>");
4510 print_usr(clang_constructUSR_ObjCClass(I
[1]));
4516 if (memcmp(kind
, "ObjCMethod", 10) == 0) {
4518 return insufficient_usr(kind
, "<method selector> "
4519 "[0=class method|1=instance method] <class USR>");
4521 return not_usr("<class USR>", I
[3]);
4523 CXString x
= createCXString(I
[3]);
4524 print_usr(clang_constructUSR_ObjCMethod(I
[1], atoi(I
[2]), x
));
4531 if (memcmp(kind
, "ObjCCategory", 12) == 0) {
4533 return insufficient_usr(kind
, "<class name> <category name>");
4534 print_usr(clang_constructUSR_ObjCCategory(I
[1], I
[2]));
4538 if (memcmp(kind
, "ObjCProtocol", 12) == 0) {
4540 return insufficient_usr(kind
, "<protocol name>");
4541 print_usr(clang_constructUSR_ObjCProtocol(I
[1]));
4545 if (memcmp(kind
, "ObjCProperty", 12) == 0) {
4547 return insufficient_usr(kind
, "<property name> <class USR>");
4549 return not_usr("<class USR>", I
[2]);
4551 CXString x
= createCXString(I
[2]);
4552 print_usr(clang_constructUSR_ObjCProperty(I
[1], x
));
4565 fprintf(stderr
, "Invalid USR kind: %s\n", *I
);
4572 int print_usrs_file(const char *file_name
) {
4574 const char *args
[128];
4575 unsigned numChars
= 0;
4577 FILE *fp
= fopen(file_name
, "r");
4579 fprintf(stderr
, "error: cannot open '%s'\n", file_name
);
4583 /* This code is not really all that safe, but it works fine for testing. */
4593 line
[numChars
] = '\0';
4596 if (line
[0] == '/' && line
[1] == '/')
4599 s
= strtok(line
, " ");
4605 if (print_usrs(&args
[0], &args
[i
]))
4609 line
[numChars
++] = c
;
4616 /******************************************************************************/
4617 /* Command line processing. */
4618 /******************************************************************************/
4619 int write_pch_file(const char *filename
, int argc
, const char *argv
[]) {
4621 CXTranslationUnit TU
;
4622 struct CXUnsavedFile
*unsaved_files
= 0;
4623 int num_unsaved_files
= 0;
4624 enum CXErrorCode Err
;
4627 Idx
= clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
4629 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
4630 clang_disposeIndex(Idx
);
4634 Err
= clang_parseTranslationUnit2(
4635 Idx
, 0, argv
+ num_unsaved_files
, argc
- num_unsaved_files
,
4636 unsaved_files
, num_unsaved_files
,
4637 CXTranslationUnit_Incomplete
|
4638 CXTranslationUnit_DetailedPreprocessingRecord
|
4639 CXTranslationUnit_ForSerialization
,
4641 if (Err
!= CXError_Success
) {
4642 fprintf(stderr
, "Unable to load translation unit!\n");
4643 describeLibclangFailure(Err
);
4644 free_remapped_files(unsaved_files
, num_unsaved_files
);
4645 clang_disposeTranslationUnit(TU
);
4646 clang_disposeIndex(Idx
);
4650 switch (clang_saveTranslationUnit(TU
, filename
,
4651 clang_defaultSaveOptions(TU
))) {
4652 case CXSaveError_None
:
4655 case CXSaveError_TranslationErrors
:
4656 fprintf(stderr
, "Unable to write PCH file %s: translation errors\n",
4661 case CXSaveError_InvalidTU
:
4662 fprintf(stderr
, "Unable to write PCH file %s: invalid translation unit\n",
4667 case CXSaveError_Unknown
:
4669 fprintf(stderr
, "Unable to write PCH file %s: unknown error \n", filename
);
4674 clang_disposeTranslationUnit(TU
);
4675 free_remapped_files(unsaved_files
, num_unsaved_files
);
4676 clang_disposeIndex(Idx
);
4680 /******************************************************************************/
4681 /* Serialized diagnostics. */
4682 /******************************************************************************/
4684 static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error
) {
4686 case CXLoadDiag_CannotLoad
: return "Cannot Load File";
4687 case CXLoadDiag_None
: break;
4688 case CXLoadDiag_Unknown
: return "Unknown";
4689 case CXLoadDiag_InvalidFile
: return "Invalid File";
4694 static const char *getSeverityString(enum CXDiagnosticSeverity severity
) {
4696 case CXDiagnostic_Note
: return "note";
4697 case CXDiagnostic_Error
: return "error";
4698 case CXDiagnostic_Fatal
: return "fatal";
4699 case CXDiagnostic_Ignored
: return "ignored";
4700 case CXDiagnostic_Warning
: return "warning";
4705 static void printIndent(unsigned indent
) {
4708 fprintf(stderr
, "+");
4710 while (indent
> 0) {
4711 fprintf(stderr
, "-");
4716 static void printLocation(CXSourceLocation L
) {
4719 unsigned line
, column
, offset
;
4721 clang_getExpansionLocation(L
, &File
, &line
, &column
, &offset
);
4722 FileName
= clang_getFileName(File
);
4724 fprintf(stderr
, "%s:%d:%d", clang_getCString(FileName
), line
, column
);
4725 clang_disposeString(FileName
);
4728 static void printRanges(CXDiagnostic D
, unsigned indent
) {
4729 unsigned i
, n
= clang_getDiagnosticNumRanges(D
);
4731 for (i
= 0; i
< n
; ++i
) {
4732 CXSourceLocation Start
, End
;
4733 CXSourceRange SR
= clang_getDiagnosticRange(D
, i
);
4734 Start
= clang_getRangeStart(SR
);
4735 End
= clang_getRangeEnd(SR
);
4737 printIndent(indent
);
4738 fprintf(stderr
, "Range: ");
4739 printLocation(Start
);
4740 fprintf(stderr
, " ");
4742 fprintf(stderr
, "\n");
4746 static void printFixIts(CXDiagnostic D
, unsigned indent
) {
4747 unsigned i
, n
= clang_getDiagnosticNumFixIts(D
);
4748 fprintf(stderr
, "Number FIXITs = %d\n", n
);
4749 for (i
= 0 ; i
< n
; ++i
) {
4750 CXSourceRange ReplacementRange
;
4752 text
= clang_getDiagnosticFixIt(D
, i
, &ReplacementRange
);
4754 printIndent(indent
);
4755 fprintf(stderr
, "FIXIT: (");
4756 printLocation(clang_getRangeStart(ReplacementRange
));
4757 fprintf(stderr
, " - ");
4758 printLocation(clang_getRangeEnd(ReplacementRange
));
4759 fprintf(stderr
, "): \"%s\"\n", clang_getCString(text
));
4760 clang_disposeString(text
);
4764 static void printDiagnosticSet(CXDiagnosticSet Diags
, unsigned indent
) {
4770 n
= clang_getNumDiagnosticsInSet(Diags
);
4771 for (i
= 0; i
< n
; ++i
) {
4772 CXSourceLocation DiagLoc
;
4775 CXString FileName
, DiagSpelling
, DiagOption
, DiagCat
;
4776 unsigned line
, column
, offset
;
4777 const char *FileNameStr
= 0, *DiagOptionStr
= 0, *DiagCatStr
= 0;
4779 D
= clang_getDiagnosticInSet(Diags
, i
);
4780 DiagLoc
= clang_getDiagnosticLocation(D
);
4781 clang_getExpansionLocation(DiagLoc
, &File
, &line
, &column
, &offset
);
4782 FileName
= clang_getFileName(File
);
4783 FileNameStr
= clang_getCString(FileName
);
4784 DiagSpelling
= clang_getDiagnosticSpelling(D
);
4786 printIndent(indent
);
4788 fprintf(stderr
, "%s:%d:%d: %s: %s",
4789 FileNameStr
? FileNameStr
: "(null)",
4792 getSeverityString(clang_getDiagnosticSeverity(D
)),
4793 clang_getCString(DiagSpelling
));
4795 DiagOption
= clang_getDiagnosticOption(D
, 0);
4796 DiagOptionStr
= clang_getCString(DiagOption
);
4797 if (DiagOptionStr
) {
4798 fprintf(stderr
, " [%s]", DiagOptionStr
);
4801 DiagCat
= clang_getDiagnosticCategoryText(D
);
4802 DiagCatStr
= clang_getCString(DiagCat
);
4804 fprintf(stderr
, " [%s]", DiagCatStr
);
4807 fprintf(stderr
, "\n");
4809 printRanges(D
, indent
);
4810 printFixIts(D
, indent
);
4812 /* Print subdiagnostics. */
4813 printDiagnosticSet(clang_getChildDiagnostics(D
), indent
+2);
4815 clang_disposeString(FileName
);
4816 clang_disposeString(DiagSpelling
);
4817 clang_disposeString(DiagOption
);
4818 clang_disposeString(DiagCat
);
4822 static int read_diagnostics(const char *filename
) {
4823 enum CXLoadDiag_Error error
;
4824 CXString errorString
;
4825 CXDiagnosticSet Diags
= 0;
4827 Diags
= clang_loadDiagnostics(filename
, &error
, &errorString
);
4829 fprintf(stderr
, "Trouble deserializing file (%s): %s\n",
4830 getDiagnosticCodeStr(error
),
4831 clang_getCString(errorString
));
4832 clang_disposeString(errorString
);
4836 printDiagnosticSet(Diags
, 0);
4837 fprintf(stderr
, "Number of diagnostics: %d\n",
4838 clang_getNumDiagnosticsInSet(Diags
));
4839 clang_disposeDiagnosticSet(Diags
);
4843 static int perform_print_build_session_timestamp(void) {
4844 printf("%lld\n", clang_getBuildSessionTimestamp());
4848 static int perform_test_single_symbol_sgf(const char *input
, int argc
,
4849 const char *argv
[]) {
4851 CXTranslationUnit TU
;
4853 struct CXUnsavedFile
*unsaved_files
= 0;
4854 int num_unsaved_files
= 0;
4855 enum CXErrorCode Err
;
4860 usr
= input
+ strlen("-single-symbol-sgf-for=");
4862 Idx
= createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */ 1,
4863 /* displayDiagnostics=*/0);
4867 if (parse_remapped_files(argc
, argv
, 0, &unsaved_files
, &num_unsaved_files
)) {
4872 Err
= clang_parseTranslationUnit2(
4873 Idx
, 0, argv
+ num_unsaved_files
, argc
- num_unsaved_files
, unsaved_files
,
4874 num_unsaved_files
, getDefaultParsingOptions(), &TU
);
4875 if (Err
!= CXError_Success
) {
4876 fprintf(stderr
, "Unable to load translation unit!\n");
4877 describeLibclangFailure(Err
);
4879 goto free_remapped_files
;
4882 Err
= clang_createAPISet(TU
, &API
);
4883 if (Err
!= CXError_Success
) {
4885 "Unable to create API Set for API information extraction!\n");
4890 SGF
= clang_getSymbolGraphForUSR(usr
, API
);
4891 printf("%s", clang_getCString(SGF
));
4893 clang_disposeString(SGF
);
4894 clang_disposeAPISet(API
);
4896 clang_disposeTranslationUnit(TU
);
4897 free_remapped_files
:
4898 free_remapped_files(unsaved_files
, num_unsaved_files
);
4900 clang_disposeIndex(Idx
);
4904 static void inspect_single_symbol_sgf_cursor(CXCursor Cursor
) {
4905 CXSourceLocation CursorLoc
;
4908 unsigned line
, column
;
4909 CursorLoc
= clang_getCursorLocation(Cursor
);
4910 clang_getSpellingLocation(CursorLoc
, 0, &line
, &column
, 0);
4912 SGFData
= clang_getSymbolGraphForCursor(Cursor
);
4913 SGF
= clang_getCString(SGFData
);
4915 printf("%d:%d: %s\n", line
, column
, SGF
);
4917 clang_disposeString(SGFData
);
4920 /******************************************************************************/
4921 /* Command line processing. */
4922 /******************************************************************************/
4924 static CXCursorVisitor
GetVisitor(const char *s
) {
4926 return FilteredPrintingVisitor
;
4927 if (strcmp(s
, "-usrs") == 0)
4929 if (strncmp(s
, "-memory-usage", 13) == 0)
4930 return GetVisitor(s
+ 13);
4934 static void print_usage(void) {
4936 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
4937 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
4938 " c-index-test -cursor-at=<site> <compiler arguments>\n"
4939 " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
4940 " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
4941 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
4942 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
4944 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4945 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4946 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
4947 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
4948 " c-index-test -test-file-scan <AST file> <source file> "
4949 "[FileCheck prefix]\n");
4951 " c-index-test -test-load-tu <AST file> <symbol filter> "
4952 "[FileCheck prefix]\n"
4953 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
4954 "[FileCheck prefix]\n"
4955 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
4957 " c-index-test -test-load-source-memory-usage "
4958 "<symbol filter> {<args>}*\n"
4959 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
4961 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
4962 " c-index-test -test-load-source-usrs-memory-usage "
4963 "<symbol filter> {<args>}*\n"
4964 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
4965 " c-index-test -test-inclusion-stack-source {<args>}*\n"
4966 " c-index-test -test-inclusion-stack-tu <AST file>\n");
4968 " c-index-test -test-print-linkage-source {<args>}*\n"
4969 " c-index-test -test-print-visibility {<args>}*\n"
4970 " c-index-test -test-print-type {<args>}*\n"
4971 " c-index-test -test-print-type-size {<args>}*\n"
4972 " c-index-test -test-print-bitwidth {<args>}*\n"
4973 " c-index-test -test-print-target-info {<args>}*\n"
4974 " c-index-test -test-print-type-declaration {<args>}*\n"
4975 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
4976 " c-index-test -print-usr-file <file>\n");
4978 " c-index-test -single-symbol-sgfs <symbol filter> {<args>*}\n"
4979 " c-index-test -single-symbol-sgf-at=<site> {<args>*}\n"
4980 " c-index-test -single-symbol-sgf-for=<usr> {<args>}*\n");
4982 " c-index-test -write-pch <file> <compiler arguments>\n"
4983 " c-index-test -compilation-db [lookup <filename>] database\n");
4985 " c-index-test -print-build-session-timestamp\n");
4987 " c-index-test -read-diagnostics <file>\n\n");
4989 " <symbol filter> values:\n%s",
4990 " all - load all symbols, including those from PCH\n"
4991 " local - load all symbols except those in PCH\n"
4992 " category - only load ObjC categories (non-PCH)\n"
4993 " interface - only load ObjC interfaces (non-PCH)\n"
4994 " protocol - only load ObjC protocols (non-PCH)\n"
4995 " function - only load functions (non-PCH)\n"
4996 " typedef - only load typdefs (non-PCH)\n"
4997 " scan-function - scan function bodies (non-PCH)\n\n");
5002 int cindextest_main(int argc
, const char **argv
) {
5003 clang_enableStackTraces();
5004 if (argc
> 2 && strcmp(argv
[1], "-read-diagnostics") == 0)
5005 return read_diagnostics(argv
[2]);
5006 if (argc
> 2 && strstr(argv
[1], "-code-completion-at=") == argv
[1])
5007 return perform_code_completion(argc
, argv
, 0);
5008 if (argc
> 2 && strstr(argv
[1], "-code-completion-timing=") == argv
[1])
5009 return perform_code_completion(argc
, argv
, 1);
5010 if (argc
> 2 && strstr(argv
[1], "-cursor-at=") == argv
[1])
5011 return inspect_cursor_at(argc
, argv
, "-cursor-at=", inspect_print_cursor
);
5012 if (argc
> 2 && strstr(argv
[1], "-evaluate-cursor-at=") == argv
[1])
5013 return inspect_cursor_at(argc
, argv
, "-evaluate-cursor-at=",
5014 inspect_evaluate_cursor
);
5015 if (argc
> 2 && strstr(argv
[1], "-get-macro-info-cursor-at=") == argv
[1])
5016 return inspect_cursor_at(argc
, argv
, "-get-macro-info-cursor-at=",
5017 inspect_macroinfo_cursor
);
5018 if (argc
> 2 && strstr(argv
[1], "-file-refs-at=") == argv
[1])
5019 return find_file_refs_at(argc
, argv
);
5020 if (argc
> 2 && strstr(argv
[1], "-file-includes-in=") == argv
[1])
5021 return find_file_includes_in(argc
, argv
);
5022 if (argc
> 2 && strcmp(argv
[1], "-index-file") == 0)
5023 return index_file(argc
- 2, argv
+ 2, /*full=*/0);
5024 if (argc
> 2 && strcmp(argv
[1], "-index-file-full") == 0)
5025 return index_file(argc
- 2, argv
+ 2, /*full=*/1);
5026 if (argc
> 2 && strcmp(argv
[1], "-index-tu") == 0)
5027 return index_tu(argc
- 2, argv
+ 2);
5028 if (argc
> 2 && strcmp(argv
[1], "-index-compile-db") == 0)
5029 return index_compile_db(argc
- 2, argv
+ 2);
5030 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-tu", 13) == 0) {
5031 CXCursorVisitor I
= GetVisitor(argv
[1] + 13);
5033 return perform_test_load_tu(argv
[2], argv
[3], argc
>= 5 ? argv
[4] : 0, I
,
5036 else if (argc
>= 5 && strncmp(argv
[1], "-test-load-source-reparse", 25) == 0){
5037 CXCursorVisitor I
= GetVisitor(argv
[1] + 25);
5039 int trials
= atoi(argv
[2]);
5040 return perform_test_reparse_source(argc
- 4, argv
+ 4, trials
, argv
[3], I
,
5044 else if (argc
>= 4 && strncmp(argv
[1], "-test-load-source", 17) == 0) {
5045 CXCursorVisitor I
= GetVisitor(argv
[1] + 17);
5047 PostVisitTU postVisit
= 0;
5048 if (strstr(argv
[1], "-memory-usage"))
5049 postVisit
= PrintMemoryUsage
;
5052 return perform_test_load_source(argc
- 3, argv
+ 3, argv
[2], I
,
5055 else if (argc
>= 3 && strcmp(argv
[1], "-single-file-parse") == 0)
5056 return perform_single_file_parse(argv
[2]);
5057 else if (argc
>= 3 && strcmp(argv
[1], "-retain-excluded-conditional-blocks") == 0)
5058 return perform_file_retain_excluded_cb(argv
[2]);
5059 else if (argc
>= 4 && strcmp(argv
[1], "-test-file-scan") == 0)
5060 return perform_file_scan(argv
[2], argv
[3],
5061 argc
>= 5 ? argv
[4] : 0);
5062 else if (argc
> 2 && strstr(argv
[1], "-test-annotate-tokens=") == argv
[1])
5063 return perform_token_annotation(argc
, argv
);
5064 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-source") == 0)
5065 return perform_test_load_source(argc
- 2, argv
+ 2, "all", NULL
,
5066 PrintInclusionStack
);
5067 else if (argc
> 2 && strcmp(argv
[1], "-test-inclusion-stack-tu") == 0)
5068 return perform_test_load_tu(argv
[2], "all", NULL
, NULL
,
5069 PrintInclusionStack
);
5070 else if (argc
> 2 && strcmp(argv
[1], "-test-print-linkage-source") == 0)
5071 return perform_test_load_source(argc
- 2, argv
+ 2, "all", PrintLinkage
,
5073 else if (argc
> 2 && strcmp(argv
[1], "-test-print-visibility") == 0)
5074 return perform_test_load_source(argc
- 2, argv
+ 2, "all", PrintVisibility
,
5076 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type") == 0)
5077 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5079 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type-size") == 0)
5080 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5082 else if (argc
> 2 && strcmp(argv
[1], "-test-print-type-declaration") == 0)
5083 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5084 PrintTypeDeclaration
, 0);
5085 else if (argc
> 2 && strcmp(argv
[1], "-test-print-decl-attributes") == 0)
5086 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5087 PrintDeclAttributes
, 0);
5088 else if (argc
> 2 && strcmp(argv
[1], "-test-print-bitwidth") == 0)
5089 return perform_test_load_source(argc
- 2, argv
+ 2, "all",
5091 else if (argc
> 2 && strcmp(argv
[1], "-test-print-mangle") == 0)
5092 return perform_test_load_tu(argv
[2], "all", NULL
, PrintMangledName
, NULL
);
5093 else if (argc
> 2 && strcmp(argv
[1], "-test-print-manglings") == 0)
5094 return perform_test_load_tu(argv
[2], "all", NULL
, PrintManglings
, NULL
);
5095 else if (argc
> 2 && strcmp(argv
[1], "-test-print-target-info") == 0)
5096 return print_target_info(argc
- 2, argv
+ 2);
5097 else if (argc
> 1 && strcmp(argv
[1], "-print-usr") == 0) {
5099 return print_usrs(argv
+ 2, argv
+ argc
);
5105 else if (argc
> 2 && strcmp(argv
[1], "-print-usr-file") == 0)
5106 return print_usrs_file(argv
[2]);
5107 else if (argc
> 2 && strcmp(argv
[1], "-write-pch") == 0)
5108 return write_pch_file(argv
[2], argc
- 3, argv
+ 3);
5109 else if (argc
> 2 && strcmp(argv
[1], "-compilation-db") == 0)
5110 return perform_test_compilation_db(argv
[argc
-1], argc
- 3, argv
+ 2);
5111 else if (argc
== 2 && strcmp(argv
[1], "-print-build-session-timestamp") == 0)
5112 return perform_print_build_session_timestamp();
5113 else if (argc
> 3 && strcmp(argv
[1], "-single-symbol-sgfs") == 0)
5114 return perform_test_load_source(argc
- 3, argv
+ 3, argv
[2],
5115 PrintSingleSymbolSGFs
, NULL
);
5116 else if (argc
> 2 && strstr(argv
[1], "-single-symbol-sgf-at=") == argv
[1])
5117 return inspect_cursor_at(
5118 argc
, argv
, "-single-symbol-sgf-at=", inspect_single_symbol_sgf_cursor
);
5119 else if (argc
> 2 && strstr(argv
[1], "-single-symbol-sgf-for=") == argv
[1])
5120 return perform_test_single_symbol_sgf(argv
[1], argc
- 2, argv
+ 2);
5128 /* We intentionally run in a separate thread to ensure we at least minimal
5129 * testing of a multithreaded environment (for example, having a reduced stack
5132 typedef struct thread_info
{
5133 int (*main_func
)(int argc
, const char **argv
);
5138 void thread_runner(void *client_data_v
) {
5139 thread_info
*client_data
= client_data_v
;
5140 client_data
->result
= client_data
->main_func(client_data
->argc
,
5144 static void flush_atexit(void) {
5145 /* stdout, and surprisingly even stderr, are not always flushed on process
5146 * and thread exit, particularly when the system is under heavy load. */
5151 int main(int argc
, const char **argv
) {
5152 thread_info client_data
;
5155 if (enableAutoConversion(fileno(stdout
)) == -1)
5156 fprintf(stderr
, "Setting conversion on stdout failed\n");
5158 if (enableAutoConversion(fileno(stderr
)) == -1)
5159 fprintf(stderr
, "Setting conversion on stderr failed\n");
5162 atexit(flush_atexit
);
5164 #ifdef CLANG_HAVE_LIBXML
5168 if (argc
> 1 && strcmp(argv
[1], "core") == 0)
5169 return indextest_core_main(argc
, argv
);
5171 client_data
.main_func
= cindextest_main
;
5172 client_data
.argc
= argc
;
5173 client_data
.argv
= argv
;
5175 if (getenv("CINDEXTEST_NOTHREADS"))
5176 return client_data
.main_func(client_data
.argc
, client_data
.argv
);
5178 clang_executeOnThread(thread_runner
, &client_data
, 0);
5179 return client_data
.result
;