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