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