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/* Target information testing. */
1993/******************************************************************************/
1994
1995static int print_target_info(int argc, const char **argv) {
1996 CXIndex Idx;
1997 CXTranslationUnit TU;
1998 CXTargetInfo TargetInfo;
1999 CXString Triple;
2000 const char *FileName;
2001 enum CXErrorCode Err;
2002 int PointerWidth;
2003
2004 if (argc == 0) {
2005 fprintf(stderr, format: "No filename specified\n");
2006 return 1;
2007 }
2008
2009 FileName = argv[1];
2010
2011 Idx = clang_createIndex(excludeDeclarationsFromPCH: 0, displayDiagnostics: 1);
2012 Err = clang_parseTranslationUnit2(CIdx: Idx, source_filename: FileName, command_line_args: argv, num_command_line_args: argc, NULL, num_unsaved_files: 0,
2013 options: getDefaultParsingOptions(), out_TU: &TU);
2014 if (Err != CXError_Success) {
2015 fprintf(stderr, format: "Couldn't parse translation unit!\n");
2016 describeLibclangFailure(Err);
2017 clang_disposeIndex(index: Idx);
2018 return 1;
2019 }
2020
2021 TargetInfo = clang_getTranslationUnitTargetInfo(CTUnit: TU);
2022
2023 Triple = clang_TargetInfo_getTriple(Info: TargetInfo);
2024 printf(format: "TargetTriple: %s\n", clang_getCString(string: Triple));
2025 clang_disposeString(string: Triple);
2026
2027 PointerWidth = clang_TargetInfo_getPointerWidth(Info: TargetInfo);
2028 printf(format: "PointerWidth: %d\n", PointerWidth);
2029
2030 clang_TargetInfo_dispose(Info: TargetInfo);
2031 clang_disposeTranslationUnit(TU);
2032 clang_disposeIndex(index: Idx);
2033 return 0;
2034}
2035
2036/******************************************************************************/
2037/* Loading ASTs/source. */
2038/******************************************************************************/
2039
2040static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
2041 const char *filter, const char *prefix,
2042 CXCursorVisitor Visitor,
2043 PostVisitTU PV,
2044 const char *CommentSchemaFile) {
2045
2046 if (prefix)
2047 FileCheckPrefix = prefix;
2048
2049 if (Visitor) {
2050 enum CXCursorKind K = CXCursor_NotImplemented;
2051 enum CXCursorKind *ck = &K;
2052 VisitorData Data;
2053
2054 /* Perform some simple filtering. */
2055 if (!strcmp(s1: filter, s2: "all") || !strcmp(s1: filter, s2: "local")) ck = NULL;
2056 else if (!strcmp(s1: filter, s2: "all-display") ||
2057 !strcmp(s1: filter, s2: "local-display")) {
2058 ck = NULL;
2059 wanted_display_type = DisplayType_DisplayName;
2060 }
2061 else if (!strcmp(s1: filter, s2: "all-pretty") ||
2062 !strcmp(s1: filter, s2: "local-pretty")) {
2063 ck = NULL;
2064 wanted_display_type = DisplayType_Pretty;
2065 }
2066 else if (!strcmp(s1: filter, s2: "none")) K = (enum CXCursorKind) ~0;
2067 else if (!strcmp(s1: filter, s2: "category")) K = CXCursor_ObjCCategoryDecl;
2068 else if (!strcmp(s1: filter, s2: "interface")) K = CXCursor_ObjCInterfaceDecl;
2069 else if (!strcmp(s1: filter, s2: "protocol")) K = CXCursor_ObjCProtocolDecl;
2070 else if (!strcmp(s1: filter, s2: "function")) K = CXCursor_FunctionDecl;
2071 else if (!strcmp(s1: filter, s2: "typedef")) K = CXCursor_TypedefDecl;
2072 else if (!strcmp(s1: filter, s2: "scan-function")) Visitor = FunctionScanVisitor;
2073 else {
2074 fprintf(stderr, format: "Unknown filter for -test-load-tu: %s\n", filter);
2075 return 1;
2076 }
2077
2078 Data.TU = TU;
2079 Data.Filter = ck;
2080 Data.CommentSchemaFile = CommentSchemaFile;
2081 clang_visitChildren(parent: clang_getTranslationUnitCursor(TU), visitor: Visitor, client_data: &Data);
2082 }
2083
2084 if (PV)
2085 PV(TU);
2086
2087 PrintDiagnostics(TU);
2088 if (checkForErrors(TU) != 0) {
2089 clang_disposeTranslationUnit(TU);
2090 return -1;
2091 }
2092
2093 clang_disposeTranslationUnit(TU);
2094 return 0;
2095}
2096
2097int perform_test_load_tu(const char *file, const char *filter,
2098 const char *prefix, CXCursorVisitor Visitor,
2099 PostVisitTU PV) {
2100 CXIndex Idx;
2101 CXTranslationUnit TU;
2102 int result;
2103 Idx = clang_createIndex(/* excludeDeclsFromPCH */
2104 excludeDeclarationsFromPCH: !strcmp(s1: filter, s2: "local") ? 1 : 0,
2105 /* displayDiagnostics=*/1);
2106
2107 if (!CreateTranslationUnit(Idx, file, TU: &TU)) {
2108 clang_disposeIndex(index: Idx);
2109 return 1;
2110 }
2111
2112 result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
2113 clang_disposeIndex(index: Idx);
2114 return result;
2115}
2116
2117int perform_test_load_source(int argc, const char **argv,
2118 const char *filter, CXCursorVisitor Visitor,
2119 PostVisitTU PV) {
2120 CXIndex Idx;
2121 CXTranslationUnit TU;
2122 const char *CommentSchemaFile;
2123 struct CXUnsavedFile *unsaved_files = 0;
2124 int num_unsaved_files = 0;
2125 enum CXErrorCode Err;
2126 int result;
2127 unsigned Repeats = 0;
2128 unsigned I;
2129
2130 Idx =
2131 createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */
2132 ExcludeDeclarationsFromPCH: (!strcmp(s1: filter, s2: "local") ||
2133 !strcmp(s1: filter, s2: "local-display") ||
2134 !strcmp(s1: filter, s2: "local-pretty"))
2135 ? 1
2136 : 0,
2137 /* displayDiagnostics=*/DisplayDiagnostics: 1);
2138 if (!Idx)
2139 return -1;
2140
2141 if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
2142 argc--;
2143 argv++;
2144 }
2145
2146 if (parse_remapped_files(argc, argv, start_arg: 0, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
2147 clang_disposeIndex(index: Idx);
2148 return -1;
2149 }
2150
2151 if (getenv(name: "CINDEXTEST_EDITING"))
2152 Repeats = 5;
2153
2154 Err = clang_parseTranslationUnit2(CIdx: Idx, source_filename: 0,
2155 command_line_args: argv + num_unsaved_files,
2156 num_command_line_args: argc - num_unsaved_files,
2157 unsaved_files, num_unsaved_files,
2158 options: getDefaultParsingOptions(), out_TU: &TU);
2159 if (Err != CXError_Success) {
2160 fprintf(stderr, format: "Unable to load translation unit!\n");
2161 describeLibclangFailure(Err);
2162 free_remapped_files(unsaved_files, num_unsaved_files);
2163 clang_disposeIndex(index: Idx);
2164 return 1;
2165 }
2166
2167 for (I = 0; I != Repeats; ++I) {
2168 if (checkForErrors(TU) != 0)
2169 return -1;
2170
2171 if (Repeats > 1) {
2172 clang_suspendTranslationUnit(TU);
2173
2174 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2175 options: clang_defaultReparseOptions(TU));
2176 if (Err != CXError_Success) {
2177 describeLibclangFailure(Err);
2178 free_remapped_files(unsaved_files, num_unsaved_files);
2179 clang_disposeIndex(index: Idx);
2180 return 1;
2181 }
2182 }
2183 }
2184
2185 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
2186 CommentSchemaFile);
2187 free_remapped_files(unsaved_files, num_unsaved_files);
2188 clang_disposeIndex(index: Idx);
2189 return result;
2190}
2191
2192int perform_test_reparse_source(int argc, const char **argv, int trials,
2193 const char *filter, CXCursorVisitor Visitor,
2194 PostVisitTU PV) {
2195 CXIndex Idx;
2196 CXTranslationUnit TU;
2197 struct CXUnsavedFile *unsaved_files = 0;
2198 int num_unsaved_files = 0;
2199 int compiler_arg_idx = 0;
2200 enum CXErrorCode Err;
2201 int result, i;
2202 int trial;
2203 int execute_after_trial = 0;
2204 const char *execute_command = NULL;
2205 int remap_after_trial = 0;
2206 char *endptr = 0;
2207
2208 Idx = clang_createIndex(/* excludeDeclsFromPCH */
2209 excludeDeclarationsFromPCH: !strcmp(s1: filter, s2: "local") ? 1 : 0,
2210 /* displayDiagnostics=*/1);
2211
2212 if (parse_remapped_files(argc, argv, start_arg: 0, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
2213 clang_disposeIndex(index: Idx);
2214 return -1;
2215 }
2216
2217 for (i = 0; i < argc; ++i) {
2218 if (strcmp(s1: argv[i], s2: "--") == 0)
2219 break;
2220 }
2221 if (i < argc)
2222 compiler_arg_idx = i+1;
2223 if (num_unsaved_files > compiler_arg_idx)
2224 compiler_arg_idx = num_unsaved_files;
2225
2226 /* Load the initial translation unit -- we do this without honoring remapped
2227 * files, so that we have a way to test results after changing the source. */
2228 Err = clang_parseTranslationUnit2(CIdx: Idx, source_filename: 0,
2229 command_line_args: argv + compiler_arg_idx,
2230 num_command_line_args: argc - compiler_arg_idx,
2231 unsaved_files: 0, num_unsaved_files: 0, options: getDefaultParsingOptions(), out_TU: &TU);
2232 if (Err != CXError_Success) {
2233 fprintf(stderr, format: "Unable to load translation unit!\n");
2234 describeLibclangFailure(Err);
2235 free_remapped_files(unsaved_files, num_unsaved_files);
2236 clang_disposeIndex(index: Idx);
2237 return 1;
2238 }
2239
2240 if (checkForErrors(TU) != 0)
2241 return -1;
2242
2243 if (getenv(name: "CINDEXTEST_EXECUTE_COMMAND")) {
2244 execute_command = getenv(name: "CINDEXTEST_EXECUTE_COMMAND");
2245 }
2246 if (getenv(name: "CINDEXTEST_EXECUTE_AFTER_TRIAL")) {
2247 execute_after_trial =
2248 strtol(nptr: getenv(name: "CINDEXTEST_EXECUTE_AFTER_TRIAL"), endptr: &endptr, base: 10);
2249 }
2250
2251 if (getenv(name: "CINDEXTEST_REMAP_AFTER_TRIAL")) {
2252 remap_after_trial =
2253 strtol(nptr: getenv(name: "CINDEXTEST_REMAP_AFTER_TRIAL"), endptr: &endptr, base: 10);
2254 }
2255
2256 for (trial = 0; trial < trials; ++trial) {
2257 if (execute_command && trial == execute_after_trial) {
2258 result = indextest_perform_shell_execution(command_line: execute_command);
2259 if (result != 0)
2260 return result;
2261 }
2262
2263 free_remapped_files(unsaved_files, num_unsaved_files);
2264 if (parse_remapped_files_with_try(try_idx: trial, argc, argv, start_arg: 0,
2265 unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
2266 clang_disposeTranslationUnit(TU);
2267 clang_disposeIndex(index: Idx);
2268 return -1;
2269 }
2270
2271 Err = clang_reparseTranslationUnit(
2272 TU,
2273 num_unsaved_files: trial >= remap_after_trial ? num_unsaved_files : 0,
2274 unsaved_files: trial >= remap_after_trial ? unsaved_files : 0,
2275 options: clang_defaultReparseOptions(TU));
2276 if (Err != CXError_Success) {
2277 fprintf(stderr, format: "Unable to reparse translation unit!\n");
2278 describeLibclangFailure(Err);
2279 clang_disposeTranslationUnit(TU);
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
2289 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
2290
2291 free_remapped_files(unsaved_files, num_unsaved_files);
2292 clang_disposeIndex(index: Idx);
2293 return result;
2294}
2295
2296static int perform_single_file_parse(const char *filename) {
2297 CXIndex Idx;
2298 CXTranslationUnit TU;
2299 enum CXErrorCode Err;
2300 int result;
2301
2302 Idx = clang_createIndex(/* excludeDeclsFromPCH */excludeDeclarationsFromPCH: 1,
2303 /* displayDiagnostics=*/1);
2304
2305 Err = clang_parseTranslationUnit2(CIdx: Idx, source_filename: filename,
2306 /*command_line_args=*/NULL,
2307 /*num_command_line_args=*/0,
2308 /*unsaved_files=*/NULL,
2309 /*num_unsaved_files=*/0,
2310 options: CXTranslationUnit_SingleFileParse, out_TU: &TU);
2311 if (Err != CXError_Success) {
2312 fprintf(stderr, format: "Unable to load translation unit!\n");
2313 describeLibclangFailure(Err);
2314 clang_disposeIndex(index: Idx);
2315 return 1;
2316 }
2317
2318 result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, Visitor: FilteredPrintingVisitor, /*PostVisit=*/NULL,
2319 /*CommentSchemaFile=*/NULL);
2320 clang_disposeIndex(index: Idx);
2321 return result;
2322}
2323
2324static int perform_file_retain_excluded_cb(const char *filename) {
2325 CXIndex Idx;
2326 CXTranslationUnit TU;
2327 enum CXErrorCode Err;
2328 int result;
2329
2330 Idx = clang_createIndex(/* excludeDeclsFromPCH */excludeDeclarationsFromPCH: 1,
2331 /* displayDiagnostics=*/1);
2332
2333 Err = clang_parseTranslationUnit2(CIdx: Idx, source_filename: filename,
2334 /*command_line_args=*/NULL,
2335 /*num_command_line_args=*/0,
2336 /*unsaved_files=*/NULL,
2337 /*num_unsaved_files=*/0,
2338 options: CXTranslationUnit_RetainExcludedConditionalBlocks, out_TU: &TU);
2339 if (Err != CXError_Success) {
2340 fprintf(stderr, format: "Unable to load translation unit!\n");
2341 describeLibclangFailure(Err);
2342 clang_disposeIndex(index: Idx);
2343 return 1;
2344 }
2345
2346 result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, Visitor: FilteredPrintingVisitor, /*PostVisit=*/NULL,
2347 /*CommentSchemaFile=*/NULL);
2348 clang_disposeIndex(index: Idx);
2349 return result;
2350}
2351
2352/******************************************************************************/
2353/* Logic for testing clang_getCursor(). */
2354/******************************************************************************/
2355
2356static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
2357 unsigned start_line, unsigned start_col,
2358 unsigned end_line, unsigned end_col,
2359 const char *prefix) {
2360 printf(format: "// %s: ", FileCheckPrefix);
2361 if (prefix)
2362 printf(format: "-%s", prefix);
2363 PrintExtent(stdout, begin_line: start_line, begin_column: start_col, end_line, end_column: end_col);
2364 printf(format: " ");
2365 PrintCursor(Cursor: cursor, NULL);
2366 printf(format: "\n");
2367}
2368
2369static int perform_file_scan(const char *ast_file, const char *source_file,
2370 const char *prefix) {
2371 CXIndex Idx;
2372 CXTranslationUnit TU;
2373 FILE *fp;
2374 CXCursor prevCursor = clang_getNullCursor();
2375 CXFile file;
2376 unsigned line = 1, col = 1;
2377 unsigned start_line = 1, start_col = 1;
2378
2379 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ excludeDeclarationsFromPCH: 1,
2380 /* displayDiagnostics=*/1))) {
2381 fprintf(stderr, format: "Could not create Index\n");
2382 return 1;
2383 }
2384
2385 if (!CreateTranslationUnit(Idx, file: ast_file, TU: &TU))
2386 return 1;
2387
2388 if ((fp = fopen(filename: source_file, modes: "r")) == NULL) {
2389 fprintf(stderr, format: "Could not open '%s'\n", source_file);
2390 clang_disposeTranslationUnit(TU);
2391 return 1;
2392 }
2393
2394 file = clang_getFile(tu: TU, file_name: source_file);
2395 for (;;) {
2396 CXCursor cursor;
2397 int c = fgetc(stream: fp);
2398
2399 if (c == '\n') {
2400 ++line;
2401 col = 1;
2402 } else
2403 ++col;
2404
2405 /* Check the cursor at this position, and dump the previous one if we have
2406 * found something new.
2407 */
2408 cursor = clang_getCursor(TU, clang_getLocation(tu: TU, file, line, column: col));
2409 if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
2410 prevCursor.kind != CXCursor_InvalidFile) {
2411 print_cursor_file_scan(TU, cursor: prevCursor, start_line, start_col,
2412 end_line: line, end_col: col, prefix);
2413 start_line = line;
2414 start_col = col;
2415 }
2416 if (c == EOF)
2417 break;
2418
2419 prevCursor = cursor;
2420 }
2421
2422 fclose(stream: fp);
2423 clang_disposeTranslationUnit(TU);
2424 clang_disposeIndex(index: Idx);
2425 return 0;
2426}
2427
2428/******************************************************************************/
2429/* Logic for testing clang code completion. */
2430/******************************************************************************/
2431
2432/* Parse file:line:column from the input string. Returns 0 on success, non-zero
2433 on failure. If successful, the pointer *filename will contain newly-allocated
2434 memory (that will be owned by the caller) to store the file name. */
2435int parse_file_line_column(const char *input, char **filename, unsigned *line,
2436 unsigned *column, unsigned *second_line,
2437 unsigned *second_column) {
2438 /* Find the second colon. */
2439 const char *last_colon = strrchr(s: input, c: ':');
2440 unsigned values[4], i;
2441 unsigned num_values = (second_line && second_column)? 4 : 2;
2442
2443 char *endptr = 0;
2444 if (!last_colon || last_colon == input) {
2445 if (num_values == 4)
2446 fprintf(stderr, format: "could not parse filename:line:column:line:column in "
2447 "'%s'\n", input);
2448 else
2449 fprintf(stderr, format: "could not parse filename:line:column in '%s'\n", input);
2450 return 1;
2451 }
2452
2453 for (i = 0; i != num_values; ++i) {
2454 const char *prev_colon;
2455
2456 /* Parse the next line or column. */
2457 values[num_values - i - 1] = strtol(nptr: last_colon + 1, endptr: &endptr, base: 10);
2458 if (*endptr != 0 && *endptr != ':') {
2459 fprintf(stderr, format: "could not parse %s in '%s'\n",
2460 (i % 2 ? "column" : "line"), input);
2461 return 1;
2462 }
2463
2464 if (i + 1 == num_values)
2465 break;
2466
2467 /* Find the previous colon. */
2468 prev_colon = last_colon - 1;
2469 while (prev_colon != input && *prev_colon != ':')
2470 --prev_colon;
2471 if (prev_colon == input) {
2472 fprintf(stderr, format: "could not parse %s in '%s'\n",
2473 (i % 2 == 0? "column" : "line"), input);
2474 return 1;
2475 }
2476
2477 last_colon = prev_colon;
2478 }
2479
2480 *line = values[0];
2481 *column = values[1];
2482
2483 if (second_line && second_column) {
2484 *second_line = values[2];
2485 *second_column = values[3];
2486 }
2487
2488 /* Copy the file name. */
2489 *filename = (char*)malloc(size: last_colon - input + 1);
2490 assert(*filename);
2491 memcpy(dest: *filename, src: input, n: last_colon - input);
2492 (*filename)[last_colon - input] = 0;
2493 return 0;
2494}
2495
2496const char *
2497clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
2498 switch (Kind) {
2499 case CXCompletionChunk_Optional: return "Optional";
2500 case CXCompletionChunk_TypedText: return "TypedText";
2501 case CXCompletionChunk_Text: return "Text";
2502 case CXCompletionChunk_Placeholder: return "Placeholder";
2503 case CXCompletionChunk_Informative: return "Informative";
2504 case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
2505 case CXCompletionChunk_LeftParen: return "LeftParen";
2506 case CXCompletionChunk_RightParen: return "RightParen";
2507 case CXCompletionChunk_LeftBracket: return "LeftBracket";
2508 case CXCompletionChunk_RightBracket: return "RightBracket";
2509 case CXCompletionChunk_LeftBrace: return "LeftBrace";
2510 case CXCompletionChunk_RightBrace: return "RightBrace";
2511 case CXCompletionChunk_LeftAngle: return "LeftAngle";
2512 case CXCompletionChunk_RightAngle: return "RightAngle";
2513 case CXCompletionChunk_Comma: return "Comma";
2514 case CXCompletionChunk_ResultType: return "ResultType";
2515 case CXCompletionChunk_Colon: return "Colon";
2516 case CXCompletionChunk_SemiColon: return "SemiColon";
2517 case CXCompletionChunk_Equal: return "Equal";
2518 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
2519 case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
2520 }
2521
2522 return "Unknown";
2523}
2524
2525static int checkForErrors(CXTranslationUnit TU) {
2526 unsigned Num, i;
2527 CXDiagnostic Diag;
2528 CXString DiagStr;
2529
2530 if (!getenv(name: "CINDEXTEST_FAILONERROR"))
2531 return 0;
2532
2533 Num = clang_getNumDiagnostics(Unit: TU);
2534 for (i = 0; i != Num; ++i) {
2535 Diag = clang_getDiagnostic(Unit: TU, Index: i);
2536 if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
2537 DiagStr = clang_formatDiagnostic(Diagnostic: Diag,
2538 Options: clang_defaultDiagnosticDisplayOptions());
2539 fprintf(stderr, format: "%s\n", clang_getCString(string: DiagStr));
2540 clang_disposeString(string: DiagStr);
2541 clang_disposeDiagnostic(Diagnostic: Diag);
2542 return -1;
2543 }
2544 clang_disposeDiagnostic(Diagnostic: Diag);
2545 }
2546
2547 return 0;
2548}
2549
2550static void print_completion_string(CXCompletionString completion_string,
2551 FILE *file) {
2552 int I, N;
2553
2554 N = clang_getNumCompletionChunks(completion_string);
2555 for (I = 0; I != N; ++I) {
2556 CXString text;
2557 const char *cstr;
2558 enum CXCompletionChunkKind Kind
2559 = clang_getCompletionChunkKind(completion_string, chunk_number: I);
2560
2561 if (Kind == CXCompletionChunk_Optional) {
2562 fprintf(stream: file, format: "{Optional ");
2563 print_completion_string(
2564 completion_string: clang_getCompletionChunkCompletionString(completion_string, chunk_number: I),
2565 file);
2566 fprintf(stream: file, format: "}");
2567 continue;
2568 }
2569
2570 if (Kind == CXCompletionChunk_VerticalSpace) {
2571 fprintf(stream: file, format: "{VerticalSpace }");
2572 continue;
2573 }
2574
2575 text = clang_getCompletionChunkText(completion_string, chunk_number: I);
2576 cstr = clang_getCString(string: text);
2577 fprintf(stream: file, format: "{%s %s}",
2578 clang_getCompletionChunkKindSpelling(Kind),
2579 cstr ? cstr : "");
2580 clang_disposeString(string: text);
2581 }
2582
2583}
2584
2585static void print_line_column(CXSourceLocation location, FILE *file) {
2586 unsigned line, column;
2587 clang_getExpansionLocation(location, NULL, line: &line, column: &column, NULL);
2588 fprintf(stream: file, format: "%d:%d", line, column);
2589}
2590
2591static void print_token_range(CXTranslationUnit translation_unit,
2592 CXSourceLocation start, FILE *file) {
2593 CXToken *token = clang_getToken(TU: translation_unit, Location: start);
2594
2595 fprintf(stream: file, format: "{");
2596 if (token != NULL) {
2597 CXSourceRange token_range = clang_getTokenExtent(translation_unit, *token);
2598 print_line_column(location: clang_getRangeStart(range: token_range), file);
2599 fprintf(stream: file, format: "-");
2600 print_line_column(location: clang_getRangeEnd(range: token_range), file);
2601 clang_disposeTokens(TU: translation_unit, Tokens: token, NumTokens: 1);
2602 }
2603
2604 fprintf(stream: file, format: "}");
2605}
2606
2607static void print_completion_result(CXTranslationUnit translation_unit,
2608 CXCodeCompleteResults *completion_results,
2609 unsigned index,
2610 FILE *file) {
2611 CXCompletionResult *completion_result = completion_results->Results + index;
2612 CXString ks = clang_getCursorKindSpelling(Kind: completion_result->CursorKind);
2613 unsigned annotationCount;
2614 enum CXCursorKind ParentKind;
2615 CXString ParentName;
2616 CXString BriefComment;
2617 CXString Annotation;
2618 const char *BriefCommentCString;
2619 unsigned i;
2620
2621 fprintf(stream: file, format: "%s:", clang_getCString(string: ks));
2622 clang_disposeString(string: ks);
2623
2624 print_completion_string(completion_string: completion_result->CompletionString, file);
2625 fprintf(stream: file, format: " (%u)",
2626 clang_getCompletionPriority(completion_string: completion_result->CompletionString));
2627 switch (clang_getCompletionAvailability(completion_string: completion_result->CompletionString)){
2628 case CXAvailability_Available:
2629 break;
2630
2631 case CXAvailability_Deprecated:
2632 fprintf(stream: file, format: " (deprecated)");
2633 break;
2634
2635 case CXAvailability_NotAvailable:
2636 fprintf(stream: file, format: " (unavailable)");
2637 break;
2638
2639 case CXAvailability_NotAccessible:
2640 fprintf(stream: file, format: " (inaccessible)");
2641 break;
2642 }
2643
2644 annotationCount = clang_getCompletionNumAnnotations(
2645 completion_string: completion_result->CompletionString);
2646 if (annotationCount) {
2647 unsigned i;
2648 fprintf(stream: file, format: " (");
2649 for (i = 0; i < annotationCount; ++i) {
2650 if (i != 0)
2651 fprintf(stream: file, format: ", ");
2652 Annotation =
2653 clang_getCompletionAnnotation(completion_string: completion_result->CompletionString, annotation_number: i);
2654 fprintf(stream: file, format: "\"%s\"", clang_getCString(string: Annotation));
2655 clang_disposeString(string: Annotation);
2656 }
2657 fprintf(stream: file, format: ")");
2658 }
2659
2660 if (!getenv(name: "CINDEXTEST_NO_COMPLETION_PARENTS")) {
2661 ParentName = clang_getCompletionParent(completion_string: completion_result->CompletionString,
2662 kind: &ParentKind);
2663 if (ParentKind != CXCursor_NotImplemented) {
2664 CXString KindSpelling = clang_getCursorKindSpelling(Kind: ParentKind);
2665 fprintf(stream: file, format: " (parent: %s '%s')",
2666 clang_getCString(string: KindSpelling),
2667 clang_getCString(string: ParentName));
2668 clang_disposeString(string: KindSpelling);
2669 }
2670 clang_disposeString(string: ParentName);
2671 }
2672
2673 BriefComment = clang_getCompletionBriefComment(
2674 completion_string: completion_result->CompletionString);
2675 BriefCommentCString = clang_getCString(string: BriefComment);
2676 if (BriefCommentCString && *BriefCommentCString != '\0') {
2677 fprintf(stream: file, format: "(brief comment: %s)", BriefCommentCString);
2678 }
2679 clang_disposeString(string: BriefComment);
2680
2681 for (i = 0; i < clang_getCompletionNumFixIts(results: completion_results, completion_index: index);
2682 ++i) {
2683 CXSourceRange correction_range;
2684 CXString FixIt = clang_getCompletionFixIt(results: completion_results, completion_index: index, fixit_index: i,
2685 replacement_range: &correction_range);
2686 fprintf(stream: file, format: " (requires fix-it: ");
2687 print_token_range(translation_unit, start: clang_getRangeStart(range: correction_range),
2688 file);
2689 fprintf(stream: file, format: " to \"%s\")", clang_getCString(string: FixIt));
2690 clang_disposeString(string: FixIt);
2691 }
2692
2693 fprintf(stream: file, format: "\n");
2694}
2695
2696void print_completion_contexts(unsigned long long contexts, FILE *file) {
2697 fprintf(stream: file, format: "Completion contexts:\n");
2698 if (contexts == CXCompletionContext_Unknown) {
2699 fprintf(stream: file, format: "Unknown\n");
2700 }
2701 if (contexts & CXCompletionContext_AnyType) {
2702 fprintf(stream: file, format: "Any type\n");
2703 }
2704 if (contexts & CXCompletionContext_AnyValue) {
2705 fprintf(stream: file, format: "Any value\n");
2706 }
2707 if (contexts & CXCompletionContext_ObjCObjectValue) {
2708 fprintf(stream: file, format: "Objective-C object value\n");
2709 }
2710 if (contexts & CXCompletionContext_ObjCSelectorValue) {
2711 fprintf(stream: file, format: "Objective-C selector value\n");
2712 }
2713 if (contexts & CXCompletionContext_CXXClassTypeValue) {
2714 fprintf(stream: file, format: "C++ class type value\n");
2715 }
2716 if (contexts & CXCompletionContext_DotMemberAccess) {
2717 fprintf(stream: file, format: "Dot member access\n");
2718 }
2719 if (contexts & CXCompletionContext_ArrowMemberAccess) {
2720 fprintf(stream: file, format: "Arrow member access\n");
2721 }
2722 if (contexts & CXCompletionContext_ObjCPropertyAccess) {
2723 fprintf(stream: file, format: "Objective-C property access\n");
2724 }
2725 if (contexts & CXCompletionContext_EnumTag) {
2726 fprintf(stream: file, format: "Enum tag\n");
2727 }
2728 if (contexts & CXCompletionContext_UnionTag) {
2729 fprintf(stream: file, format: "Union tag\n");
2730 }
2731 if (contexts & CXCompletionContext_StructTag) {
2732 fprintf(stream: file, format: "Struct tag\n");
2733 }
2734 if (contexts & CXCompletionContext_ClassTag) {
2735 fprintf(stream: file, format: "Class name\n");
2736 }
2737 if (contexts & CXCompletionContext_Namespace) {
2738 fprintf(stream: file, format: "Namespace or namespace alias\n");
2739 }
2740 if (contexts & CXCompletionContext_NestedNameSpecifier) {
2741 fprintf(stream: file, format: "Nested name specifier\n");
2742 }
2743 if (contexts & CXCompletionContext_ObjCInterface) {
2744 fprintf(stream: file, format: "Objective-C interface\n");
2745 }
2746 if (contexts & CXCompletionContext_ObjCProtocol) {
2747 fprintf(stream: file, format: "Objective-C protocol\n");
2748 }
2749 if (contexts & CXCompletionContext_ObjCCategory) {
2750 fprintf(stream: file, format: "Objective-C category\n");
2751 }
2752 if (contexts & CXCompletionContext_ObjCInstanceMessage) {
2753 fprintf(stream: file, format: "Objective-C instance method\n");
2754 }
2755 if (contexts & CXCompletionContext_ObjCClassMessage) {
2756 fprintf(stream: file, format: "Objective-C class method\n");
2757 }
2758 if (contexts & CXCompletionContext_ObjCSelectorName) {
2759 fprintf(stream: file, format: "Objective-C selector name\n");
2760 }
2761 if (contexts & CXCompletionContext_MacroName) {
2762 fprintf(stream: file, format: "Macro name\n");
2763 }
2764 if (contexts & CXCompletionContext_NaturalLanguage) {
2765 fprintf(stream: file, format: "Natural language\n");
2766 }
2767}
2768
2769int perform_code_completion(int argc, const char **argv, int timing_only) {
2770 const char *input = argv[1];
2771 char *filename = 0;
2772 unsigned line;
2773 unsigned column;
2774 CXIndex CIdx;
2775 int errorCode;
2776 struct CXUnsavedFile *unsaved_files = 0;
2777 int num_unsaved_files = 0;
2778 CXCodeCompleteResults *results = 0;
2779 enum CXErrorCode Err;
2780 CXTranslationUnit TU;
2781 unsigned I, Repeats = 1;
2782 unsigned completionOptions = clang_defaultCodeCompleteOptions();
2783
2784 if (getenv(name: "CINDEXTEST_CODE_COMPLETE_PATTERNS"))
2785 completionOptions |= CXCodeComplete_IncludeCodePatterns;
2786 if (getenv(name: "CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
2787 completionOptions |= CXCodeComplete_IncludeBriefComments;
2788 if (getenv(name: "CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
2789 completionOptions |= CXCodeComplete_SkipPreamble;
2790 if (getenv(name: "CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
2791 completionOptions |= CXCodeComplete_IncludeCompletionsWithFixIts;
2792
2793 if (timing_only)
2794 input += strlen(s: "-code-completion-timing=");
2795 else
2796 input += strlen(s: "-code-completion-at=");
2797
2798 if ((errorCode = parse_file_line_column(input, filename: &filename, line: &line, column: &column,
2799 second_line: 0, second_column: 0)))
2800 return errorCode;
2801
2802 if (parse_remapped_files(argc, argv, start_arg: 2, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files))
2803 return -1;
2804
2805 CIdx = createIndexWithInvocationEmissionPath(ExcludeDeclarationsFromPCH: 0, DisplayDiagnostics: 0);
2806 if (!CIdx)
2807 return -1;
2808
2809 if (getenv(name: "CINDEXTEST_EDITING"))
2810 Repeats = 5;
2811
2812 Err = clang_parseTranslationUnit2(CIdx, source_filename: 0,
2813 command_line_args: argv + num_unsaved_files + 2,
2814 num_command_line_args: argc - num_unsaved_files - 2,
2815 unsaved_files: 0, num_unsaved_files: 0, options: getDefaultParsingOptions(), out_TU: &TU);
2816 if (Err != CXError_Success) {
2817 fprintf(stderr, format: "Unable to load translation unit!\n");
2818 describeLibclangFailure(Err);
2819 return 1;
2820 }
2821
2822 Err = clang_reparseTranslationUnit(TU, num_unsaved_files: 0, unsaved_files: 0,
2823 options: clang_defaultReparseOptions(TU));
2824
2825 if (Err != CXError_Success) {
2826 fprintf(stderr, format: "Unable to reparse translation unit!\n");
2827 describeLibclangFailure(Err);
2828 clang_disposeTranslationUnit(TU);
2829 return 1;
2830 }
2831
2832 for (I = 0; I != Repeats; ++I) {
2833 results = clang_codeCompleteAt(TU, complete_filename: filename, complete_line: line, complete_column: column,
2834 unsaved_files, num_unsaved_files,
2835 options: completionOptions);
2836 if (!results) {
2837 fprintf(stderr, format: "Unable to perform code completion!\n");
2838 return 1;
2839 }
2840 if (I != Repeats-1)
2841 clang_disposeCodeCompleteResults(Results: results);
2842 }
2843
2844 if (results) {
2845 unsigned i, n = results->NumResults, containerIsIncomplete = 0;
2846 unsigned long long contexts;
2847 enum CXCursorKind containerKind;
2848 CXString objCSelector;
2849 const char *selectorString;
2850 if (!timing_only) {
2851 /* Sort the code-completion results based on the typed text. */
2852 clang_sortCodeCompletionResults(Results: results->Results, NumResults: results->NumResults);
2853
2854 for (i = 0; i != n; ++i)
2855 print_completion_result(translation_unit: TU, completion_results: results, index: i, stdout);
2856 }
2857 n = clang_codeCompleteGetNumDiagnostics(Results: results);
2858 for (i = 0; i != n; ++i) {
2859 CXDiagnostic diag = clang_codeCompleteGetDiagnostic(Results: results, Index: i);
2860 PrintDiagnostic(Diagnostic: diag);
2861 clang_disposeDiagnostic(Diagnostic: diag);
2862 }
2863
2864 contexts = clang_codeCompleteGetContexts(Results: results);
2865 print_completion_contexts(contexts, stdout);
2866
2867 containerKind = clang_codeCompleteGetContainerKind(Results: results,
2868 IsIncomplete: &containerIsIncomplete);
2869
2870 if (containerKind != CXCursor_InvalidCode) {
2871 /* We have found a container */
2872 CXString containerUSR, containerKindSpelling;
2873 containerKindSpelling = clang_getCursorKindSpelling(Kind: containerKind);
2874 printf(format: "Container Kind: %s\n", clang_getCString(string: containerKindSpelling));
2875 clang_disposeString(string: containerKindSpelling);
2876
2877 if (containerIsIncomplete) {
2878 printf(format: "Container is incomplete\n");
2879 }
2880 else {
2881 printf(format: "Container is complete\n");
2882 }
2883
2884 containerUSR = clang_codeCompleteGetContainerUSR(Results: results);
2885 printf(format: "Container USR: %s\n", clang_getCString(string: containerUSR));
2886 clang_disposeString(string: containerUSR);
2887 }
2888
2889 objCSelector = clang_codeCompleteGetObjCSelector(Results: results);
2890 selectorString = clang_getCString(string: objCSelector);
2891 if (selectorString && strlen(s: selectorString) > 0) {
2892 printf(format: "Objective-C selector: %s\n", selectorString);
2893 }
2894 clang_disposeString(string: objCSelector);
2895
2896 clang_disposeCodeCompleteResults(Results: results);
2897 }
2898 clang_disposeTranslationUnit(TU);
2899 clang_disposeIndex(index: CIdx);
2900 free(ptr: filename);
2901
2902 free_remapped_files(unsaved_files, num_unsaved_files);
2903
2904 return 0;
2905}
2906
2907typedef struct {
2908 char *filename;
2909 unsigned line;
2910 unsigned column;
2911} CursorSourceLocation;
2912
2913typedef void (*cursor_handler_t)(CXCursor cursor);
2914
2915static int inspect_cursor_at(int argc, const char **argv,
2916 const char *locations_flag,
2917 cursor_handler_t handler) {
2918 CXIndex CIdx;
2919 int errorCode;
2920 struct CXUnsavedFile *unsaved_files = 0;
2921 int num_unsaved_files = 0;
2922 enum CXErrorCode Err;
2923 CXTranslationUnit TU;
2924 CXCursor Cursor;
2925 CursorSourceLocation *Locations = 0;
2926 unsigned NumLocations = 0, Loc;
2927 unsigned Repeats = 1;
2928 unsigned I;
2929
2930 /* Count the number of locations. */
2931 while (strstr(haystack: argv[NumLocations+1], needle: locations_flag) == argv[NumLocations+1])
2932 ++NumLocations;
2933
2934 /* Parse the locations. */
2935 assert(NumLocations > 0 && "Unable to count locations?");
2936 Locations = (CursorSourceLocation *)malloc(
2937 size: NumLocations * sizeof(CursorSourceLocation));
2938 assert(Locations);
2939 for (Loc = 0; Loc < NumLocations; ++Loc) {
2940 const char *input = argv[Loc + 1] + strlen(s: locations_flag);
2941 if ((errorCode = parse_file_line_column(input, filename: &Locations[Loc].filename,
2942 line: &Locations[Loc].line,
2943 column: &Locations[Loc].column, second_line: 0, second_column: 0)))
2944 return errorCode;
2945 }
2946
2947 if (parse_remapped_files(argc, argv, start_arg: NumLocations + 1, unsaved_files: &unsaved_files,
2948 num_unsaved_files: &num_unsaved_files))
2949 return -1;
2950
2951 if (getenv(name: "CINDEXTEST_EDITING"))
2952 Repeats = 5;
2953
2954 /* Parse the translation unit. When we're testing clang_getCursor() after
2955 reparsing, don't remap unsaved files until the second parse. */
2956 CIdx = clang_createIndex(excludeDeclarationsFromPCH: 1, displayDiagnostics: 1);
2957 Err = clang_parseTranslationUnit2(CIdx, source_filename: argv[argc - 1],
2958 command_line_args: argv + num_unsaved_files + 1 + NumLocations,
2959 num_command_line_args: argc - num_unsaved_files - 2 - NumLocations,
2960 unsaved_files,
2961 num_unsaved_files: Repeats > 1? 0 : num_unsaved_files,
2962 options: getDefaultParsingOptions(), out_TU: &TU);
2963 if (Err != CXError_Success) {
2964 fprintf(stderr, format: "unable to parse input\n");
2965 describeLibclangFailure(Err);
2966 return -1;
2967 }
2968
2969 if (checkForErrors(TU) != 0)
2970 return -1;
2971
2972 for (I = 0; I != Repeats; ++I) {
2973 if (Repeats > 1) {
2974 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2975 options: clang_defaultReparseOptions(TU));
2976 if (Err != CXError_Success) {
2977 describeLibclangFailure(Err);
2978 clang_disposeTranslationUnit(TU);
2979 return 1;
2980 }
2981 }
2982
2983 if (checkForErrors(TU) != 0)
2984 return -1;
2985
2986 for (Loc = 0; Loc < NumLocations; ++Loc) {
2987 CXFile file = clang_getFile(tu: TU, file_name: Locations[Loc].filename);
2988 if (!file)
2989 continue;
2990
2991 Cursor = clang_getCursor(TU,
2992 clang_getLocation(tu: TU, file, line: Locations[Loc].line,
2993 column: Locations[Loc].column));
2994
2995 if (checkForErrors(TU) != 0)
2996 return -1;
2997
2998 if (I + 1 == Repeats) {
2999 handler(Cursor);
3000 free(ptr: Locations[Loc].filename);
3001 }
3002 }
3003 }
3004
3005 PrintDiagnostics(TU);
3006 clang_disposeTranslationUnit(TU);
3007 clang_disposeIndex(index: CIdx);
3008 free(ptr: Locations);
3009 free_remapped_files(unsaved_files, num_unsaved_files);
3010 return 0;
3011}
3012
3013static void inspect_print_cursor(CXCursor Cursor) {
3014 CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
3015 CXCompletionString completionString = clang_getCursorCompletionString(
3016 cursor: Cursor);
3017 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
3018 CXString Spelling;
3019 const char *cspell;
3020 unsigned line, column;
3021 clang_getFileLocation(location: CursorLoc, file: 0, line: &line, column: &column, offset: 0);
3022 printf(format: "%d:%d ", line, column);
3023 PrintCursor(Cursor, NULL);
3024 PrintCursorExtent(C: Cursor);
3025 Spelling = clang_getCursorSpelling(Cursor);
3026 cspell = clang_getCString(string: Spelling);
3027 if (cspell && strlen(s: cspell) != 0) {
3028 unsigned pieceIndex;
3029 printf(format: " Spelling=%s (", cspell);
3030 for (pieceIndex = 0; ; ++pieceIndex) {
3031 CXSourceRange range =
3032 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, options: 0);
3033 if (clang_Range_isNull(range))
3034 break;
3035 PrintRange(R: range, str: 0);
3036 }
3037 printf(format: ")");
3038 }
3039 clang_disposeString(string: Spelling);
3040 if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
3041 printf(format: " Selector index=%d",
3042 clang_Cursor_getObjCSelectorIndex(Cursor));
3043 if (clang_Cursor_isDynamicCall(C: Cursor))
3044 printf(format: " Dynamic-call");
3045 if (Cursor.kind == CXCursor_ObjCMessageExpr ||
3046 Cursor.kind == CXCursor_MemberRefExpr) {
3047 CXType T = clang_Cursor_getReceiverType(C: Cursor);
3048 if (T.kind != CXType_Invalid) {
3049 CXString S = clang_getTypeKindSpelling(K: T.kind);
3050 printf(format: " Receiver-type=%s", clang_getCString(string: S));
3051 clang_disposeString(string: S);
3052 }
3053 }
3054
3055 {
3056 CXModule mod = clang_Cursor_getModule(C: Cursor);
3057 CXFile astFile;
3058 CXString name, astFilename;
3059 unsigned i, numHeaders;
3060 if (mod) {
3061 astFile = clang_Module_getASTFile(Module: mod);
3062 astFilename = clang_getFileName(SFile: astFile);
3063 name = clang_Module_getFullName(Module: mod);
3064 numHeaders = clang_Module_getNumTopLevelHeaders(TU, Module: mod);
3065 printf(format: " ModuleName=%s (%s) system=%d Headers(%d):",
3066 clang_getCString(string: name), clang_getCString(string: astFilename),
3067 clang_Module_isSystem(Module: mod), numHeaders);
3068 clang_disposeString(string: name);
3069 clang_disposeString(string: astFilename);
3070 for (i = 0; i < numHeaders; ++i) {
3071 CXFile file = clang_Module_getTopLevelHeader(TU, Module: mod, Index: i);
3072 CXString filename = clang_getFileName(SFile: file);
3073 printf(format: "\n%s", clang_getCString(string: filename));
3074 clang_disposeString(string: filename);
3075 }
3076 }
3077 }
3078
3079 if (completionString != NULL) {
3080 printf(format: "\nCompletion string: ");
3081 print_completion_string(completion_string: completionString, stdout);
3082 }
3083 printf(format: "\n");
3084}
3085
3086static void display_evaluate_results(CXEvalResult result) {
3087 switch (clang_EvalResult_getKind(E: result)) {
3088 case CXEval_Int:
3089 {
3090 printf(format: "Kind: Int, ");
3091 if (clang_EvalResult_isUnsignedInt(E: result)) {
3092 unsigned long long val = clang_EvalResult_getAsUnsigned(E: result);
3093 printf(format: "unsigned, Value: %llu", val);
3094 } else {
3095 long long val = clang_EvalResult_getAsLongLong(E: result);
3096 printf(format: "Value: %lld", val);
3097 }
3098 break;
3099 }
3100 case CXEval_Float:
3101 {
3102 double val = clang_EvalResult_getAsDouble(E: result);
3103 printf(format: "Kind: Float , Value: %f", val);
3104 break;
3105 }
3106 case CXEval_ObjCStrLiteral:
3107 {
3108 const char* str = clang_EvalResult_getAsStr(E: result);
3109 printf(format: "Kind: ObjCString , Value: %s", str);
3110 break;
3111 }
3112 case CXEval_StrLiteral:
3113 {
3114 const char* str = clang_EvalResult_getAsStr(E: result);
3115 printf(format: "Kind: CString , Value: %s", str);
3116 break;
3117 }
3118 case CXEval_CFStr:
3119 {
3120 const char* str = clang_EvalResult_getAsStr(E: result);
3121 printf(format: "Kind: CFString , Value: %s", str);
3122 break;
3123 }
3124 default:
3125 printf(format: "Unexposed");
3126 break;
3127 }
3128}
3129
3130static void inspect_evaluate_cursor(CXCursor Cursor) {
3131 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
3132 CXString Spelling;
3133 const char *cspell;
3134 unsigned line, column;
3135 CXEvalResult ER;
3136
3137 clang_getFileLocation(location: CursorLoc, file: 0, line: &line, column: &column, offset: 0);
3138 printf(format: "%d:%d ", line, column);
3139 PrintCursor(Cursor, NULL);
3140 PrintCursorExtent(C: Cursor);
3141 Spelling = clang_getCursorSpelling(Cursor);
3142 cspell = clang_getCString(string: Spelling);
3143 if (cspell && strlen(s: cspell) != 0) {
3144 unsigned pieceIndex;
3145 printf(format: " Spelling=%s (", cspell);
3146 for (pieceIndex = 0; ; ++pieceIndex) {
3147 CXSourceRange range =
3148 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, options: 0);
3149 if (clang_Range_isNull(range))
3150 break;
3151 PrintRange(R: range, str: 0);
3152 }
3153 printf(format: ")");
3154 }
3155 clang_disposeString(string: Spelling);
3156
3157 ER = clang_Cursor_Evaluate(C: Cursor);
3158 if (!ER) {
3159 printf(format: "Not Evaluatable");
3160 } else {
3161 display_evaluate_results(result: ER);
3162 clang_EvalResult_dispose(E: ER);
3163 }
3164 printf(format: "\n");
3165}
3166
3167static void inspect_macroinfo_cursor(CXCursor Cursor) {
3168 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
3169 CXString Spelling;
3170 const char *cspell;
3171 unsigned line, column;
3172 clang_getFileLocation(location: CursorLoc, file: 0, line: &line, column: &column, offset: 0);
3173 printf(format: "%d:%d ", line, column);
3174 PrintCursor(Cursor, NULL);
3175 PrintCursorExtent(C: Cursor);
3176 Spelling = clang_getCursorSpelling(Cursor);
3177 cspell = clang_getCString(string: Spelling);
3178 if (cspell && strlen(s: cspell) != 0) {
3179 unsigned pieceIndex;
3180 printf(format: " Spelling=%s (", cspell);
3181 for (pieceIndex = 0; ; ++pieceIndex) {
3182 CXSourceRange range =
3183 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, options: 0);
3184 if (clang_Range_isNull(range))
3185 break;
3186 PrintRange(R: range, str: 0);
3187 }
3188 printf(format: ")");
3189 }
3190 clang_disposeString(string: Spelling);
3191
3192 if (clang_Cursor_isMacroBuiltin(C: Cursor)) {
3193 printf(format: "[builtin macro]");
3194 } else if (clang_Cursor_isMacroFunctionLike(C: Cursor)) {
3195 printf(format: "[function macro]");
3196 }
3197 printf(format: "\n");
3198}
3199
3200static enum CXVisitorResult findFileRefsVisit(void *context,
3201 CXCursor cursor, CXSourceRange range) {
3202 if (clang_Range_isNull(range))
3203 return CXVisit_Continue;
3204
3205 PrintCursor(Cursor: cursor, NULL);
3206 PrintRange(R: range, str: "");
3207 printf(format: "\n");
3208 return CXVisit_Continue;
3209}
3210
3211static int find_file_refs_at(int argc, const char **argv) {
3212 CXIndex CIdx;
3213 int errorCode;
3214 struct CXUnsavedFile *unsaved_files = 0;
3215 int num_unsaved_files = 0;
3216 enum CXErrorCode Err;
3217 CXTranslationUnit TU;
3218 CXCursor Cursor;
3219 CursorSourceLocation *Locations = 0;
3220 unsigned NumLocations = 0, Loc;
3221 unsigned Repeats = 1;
3222 unsigned I;
3223
3224 /* Count the number of locations. */
3225 while (strstr(haystack: argv[NumLocations+1], needle: "-file-refs-at=") == argv[NumLocations+1])
3226 ++NumLocations;
3227
3228 /* Parse the locations. */
3229 assert(NumLocations > 0 && "Unable to count locations?");
3230 Locations = (CursorSourceLocation *)malloc(
3231 size: NumLocations * sizeof(CursorSourceLocation));
3232 assert(Locations);
3233 for (Loc = 0; Loc < NumLocations; ++Loc) {
3234 const char *input = argv[Loc + 1] + strlen(s: "-file-refs-at=");
3235 if ((errorCode = parse_file_line_column(input, filename: &Locations[Loc].filename,
3236 line: &Locations[Loc].line,
3237 column: &Locations[Loc].column, second_line: 0, second_column: 0)))
3238 return errorCode;
3239 }
3240
3241 if (parse_remapped_files(argc, argv, start_arg: NumLocations + 1, unsaved_files: &unsaved_files,
3242 num_unsaved_files: &num_unsaved_files))
3243 return -1;
3244
3245 if (getenv(name: "CINDEXTEST_EDITING"))
3246 Repeats = 5;
3247
3248 /* Parse the translation unit. When we're testing clang_getCursor() after
3249 reparsing, don't remap unsaved files until the second parse. */
3250 CIdx = clang_createIndex(excludeDeclarationsFromPCH: 1, displayDiagnostics: 1);
3251 Err = clang_parseTranslationUnit2(CIdx, source_filename: argv[argc - 1],
3252 command_line_args: argv + num_unsaved_files + 1 + NumLocations,
3253 num_command_line_args: argc - num_unsaved_files - 2 - NumLocations,
3254 unsaved_files,
3255 num_unsaved_files: Repeats > 1? 0 : num_unsaved_files,
3256 options: getDefaultParsingOptions(), out_TU: &TU);
3257 if (Err != CXError_Success) {
3258 fprintf(stderr, format: "unable to parse input\n");
3259 describeLibclangFailure(Err);
3260 clang_disposeTranslationUnit(TU);
3261 return -1;
3262 }
3263
3264 if (checkForErrors(TU) != 0)
3265 return -1;
3266
3267 for (I = 0; I != Repeats; ++I) {
3268 if (Repeats > 1) {
3269 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
3270 options: clang_defaultReparseOptions(TU));
3271 if (Err != CXError_Success) {
3272 describeLibclangFailure(Err);
3273 clang_disposeTranslationUnit(TU);
3274 return 1;
3275 }
3276 }
3277
3278 if (checkForErrors(TU) != 0)
3279 return -1;
3280
3281 for (Loc = 0; Loc < NumLocations; ++Loc) {
3282 CXFile file = clang_getFile(tu: TU, file_name: Locations[Loc].filename);
3283 if (!file)
3284 continue;
3285
3286 Cursor = clang_getCursor(TU,
3287 clang_getLocation(tu: TU, file, line: Locations[Loc].line,
3288 column: Locations[Loc].column));
3289
3290 if (checkForErrors(TU) != 0)
3291 return -1;
3292
3293 if (I + 1 == Repeats) {
3294 CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
3295 PrintCursor(Cursor, NULL);
3296 printf(format: "\n");
3297 clang_findReferencesInFile(cursor: Cursor, file, visitor);
3298 free(ptr: Locations[Loc].filename);
3299
3300 if (checkForErrors(TU) != 0)
3301 return -1;
3302 }
3303 }
3304 }
3305
3306 PrintDiagnostics(TU);
3307 clang_disposeTranslationUnit(TU);
3308 clang_disposeIndex(index: CIdx);
3309 free(ptr: Locations);
3310 free_remapped_files(unsaved_files, num_unsaved_files);
3311 return 0;
3312}
3313
3314static enum CXVisitorResult findFileIncludesVisit(void *context,
3315 CXCursor cursor, CXSourceRange range) {
3316 PrintCursor(Cursor: cursor, NULL);
3317 PrintRange(R: range, str: "");
3318 printf(format: "\n");
3319 return CXVisit_Continue;
3320}
3321
3322static int find_file_includes_in(int argc, const char **argv) {
3323 CXIndex CIdx;
3324 struct CXUnsavedFile *unsaved_files = 0;
3325 int num_unsaved_files = 0;
3326 enum CXErrorCode Err;
3327 CXTranslationUnit TU;
3328 const char **Filenames = 0;
3329 unsigned NumFilenames = 0;
3330 unsigned Repeats = 1;
3331 unsigned I, FI;
3332
3333 /* Count the number of locations. */
3334 while (strstr(haystack: argv[NumFilenames+1], needle: "-file-includes-in=") == argv[NumFilenames+1])
3335 ++NumFilenames;
3336
3337 /* Parse the locations. */
3338 assert(NumFilenames > 0 && "Unable to count filenames?");
3339 Filenames = (const char **)malloc(size: NumFilenames * sizeof(const char *));
3340 assert(Filenames);
3341 for (I = 0; I < NumFilenames; ++I) {
3342 const char *input = argv[I + 1] + strlen(s: "-file-includes-in=");
3343 /* Copy the file name. */
3344 Filenames[I] = input;
3345 }
3346
3347 if (parse_remapped_files(argc, argv, start_arg: NumFilenames + 1, unsaved_files: &unsaved_files,
3348 num_unsaved_files: &num_unsaved_files))
3349 return -1;
3350
3351 if (getenv(name: "CINDEXTEST_EDITING"))
3352 Repeats = 2;
3353
3354 /* Parse the translation unit. When we're testing clang_getCursor() after
3355 reparsing, don't remap unsaved files until the second parse. */
3356 CIdx = clang_createIndex(excludeDeclarationsFromPCH: 1, displayDiagnostics: 1);
3357 Err = clang_parseTranslationUnit2(
3358 CIdx, source_filename: argv[argc - 1],
3359 command_line_args: argv + num_unsaved_files + 1 + NumFilenames,
3360 num_command_line_args: argc - num_unsaved_files - 2 - NumFilenames,
3361 unsaved_files,
3362 num_unsaved_files: Repeats > 1 ? 0 : num_unsaved_files, options: getDefaultParsingOptions(), out_TU: &TU);
3363
3364 if (Err != CXError_Success) {
3365 fprintf(stderr, format: "unable to parse input\n");
3366 describeLibclangFailure(Err);
3367 clang_disposeTranslationUnit(TU);
3368 return -1;
3369 }
3370
3371 if (checkForErrors(TU) != 0)
3372 return -1;
3373
3374 for (I = 0; I != Repeats; ++I) {
3375 if (Repeats > 1) {
3376 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
3377 options: clang_defaultReparseOptions(TU));
3378 if (Err != CXError_Success) {
3379 describeLibclangFailure(Err);
3380 clang_disposeTranslationUnit(TU);
3381 return 1;
3382 }
3383 }
3384
3385 if (checkForErrors(TU) != 0)
3386 return -1;
3387
3388 for (FI = 0; FI < NumFilenames; ++FI) {
3389 CXFile file = clang_getFile(tu: TU, file_name: Filenames[FI]);
3390 if (!file)
3391 continue;
3392
3393 if (checkForErrors(TU) != 0)
3394 return -1;
3395
3396 if (I + 1 == Repeats) {
3397 CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
3398 clang_findIncludesInFile(TU, file, visitor);
3399
3400 if (checkForErrors(TU) != 0)
3401 return -1;
3402 }
3403 }
3404 }
3405
3406 PrintDiagnostics(TU);
3407 clang_disposeTranslationUnit(TU);
3408 clang_disposeIndex(index: CIdx);
3409 free(ptr: (void *)Filenames);
3410 free_remapped_files(unsaved_files, num_unsaved_files);
3411 return 0;
3412}
3413
3414#define MAX_IMPORTED_ASTFILES 200
3415
3416typedef struct {
3417 char **filenames;
3418 unsigned num_files;
3419} ImportedASTFilesData;
3420
3421static ImportedASTFilesData *importedASTs_create(void) {
3422 ImportedASTFilesData *p;
3423 p = malloc(size: sizeof(ImportedASTFilesData));
3424 assert(p);
3425 p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
3426 assert(p->filenames);
3427 p->num_files = 0;
3428 return p;
3429}
3430
3431static void importedASTs_dispose(ImportedASTFilesData *p) {
3432 unsigned i;
3433 if (!p)
3434 return;
3435
3436 for (i = 0; i < p->num_files; ++i)
3437 free(ptr: p->filenames[i]);
3438 free(ptr: p->filenames);
3439 free(ptr: p);
3440}
3441
3442static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
3443 unsigned i;
3444 assert(p && file);
3445 for (i = 0; i < p->num_files; ++i)
3446 if (strcmp(s1: file, s2: p->filenames[i]) == 0)
3447 return;
3448 assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
3449 p->filenames[p->num_files++] = strdup(s: file);
3450}
3451
3452typedef struct IndexDataStringList_ {
3453 struct IndexDataStringList_ *next;
3454 char data[1]; /* Dynamically sized. */
3455} IndexDataStringList;
3456
3457typedef struct {
3458 const char *check_prefix;
3459 int first_check_printed;
3460 int fail_for_error;
3461 int abort;
3462 CXString main_filename;
3463 ImportedASTFilesData *importedASTs;
3464 IndexDataStringList *strings;
3465 CXTranslationUnit TU;
3466} IndexData;
3467
3468static void free_client_data(IndexData *index_data) {
3469 IndexDataStringList *node = index_data->strings;
3470 while (node) {
3471 IndexDataStringList *next = node->next;
3472 free(ptr: node);
3473 node = next;
3474 }
3475 index_data->strings = NULL;
3476}
3477
3478static void printCheck(IndexData *data) {
3479 if (data->check_prefix) {
3480 if (data->first_check_printed) {
3481 printf(format: "// %s-NEXT: ", data->check_prefix);
3482 } else {
3483 printf(format: "// %s : ", data->check_prefix);
3484 data->first_check_printed = 1;
3485 }
3486 }
3487}
3488
3489static void printCXIndexFile(CXIdxClientFile file) {
3490 CXString filename = clang_getFileName(SFile: (CXFile)file);
3491 printf(format: "%s", clang_getCString(string: filename));
3492 clang_disposeString(string: filename);
3493}
3494
3495static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
3496 IndexData *index_data;
3497 CXString filename;
3498 const char *cname;
3499 CXIdxClientFile file;
3500 unsigned line, column;
3501 const char *main_filename;
3502 int isMainFile;
3503
3504 index_data = (IndexData *)client_data;
3505 clang_indexLoc_getFileLocation(loc, indexFile: &file, file: 0, line: &line, column: &column, offset: 0);
3506 if (line == 0) {
3507 printf(format: "<invalid>");
3508 return;
3509 }
3510 if (!file) {
3511 printf(format: "<no idxfile>");
3512 return;
3513 }
3514 filename = clang_getFileName(SFile: (CXFile)file);
3515 cname = clang_getCString(string: filename);
3516 main_filename = clang_getCString(string: index_data->main_filename);
3517 if (strcmp(s1: cname, s2: main_filename) == 0)
3518 isMainFile = 1;
3519 else
3520 isMainFile = 0;
3521 clang_disposeString(string: filename);
3522
3523 if (!isMainFile) {
3524 printCXIndexFile(file);
3525 printf(format: ":");
3526 }
3527 printf(format: "%d:%d", line, column);
3528}
3529
3530static unsigned digitCount(unsigned val) {
3531 unsigned c = 1;
3532 while (1) {
3533 if (val < 10)
3534 return c;
3535 ++c;
3536 val /= 10;
3537 }
3538}
3539
3540static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
3541 const CXIdxEntityInfo *info,
3542 CXIdxLoc loc) {
3543 IndexData *index_data;
3544 IndexDataStringList *node;
3545 const char *name;
3546 char *newStr;
3547 CXIdxClientFile file;
3548 unsigned line, column;
3549 size_t datalen;
3550
3551 name = info->name;
3552 if (!name)
3553 name = "<anon-tag>";
3554
3555 clang_indexLoc_getFileLocation(loc, indexFile: &file, file: 0, line: &line, column: &column, offset: 0);
3556
3557 datalen = strlen(s: name) + digitCount(val: line) + digitCount(val: column) + 3;
3558 node = (IndexDataStringList *)malloc(size: datalen + sizeof(IndexDataStringList));
3559 assert(node);
3560 newStr = node->data;
3561 snprintf(s: newStr, maxlen: datalen, format: "%s:%d:%d", name, line, column);
3562
3563 /* Remember string so it can be freed later. */
3564 index_data = (IndexData *)client_data;
3565 node->next = index_data->strings;
3566 index_data->strings = node;
3567
3568 return (CXIdxClientContainer)newStr;
3569}
3570
3571static void printCXIndexContainer(const CXIdxContainerInfo *info) {
3572 CXIdxClientContainer container;
3573 container = clang_index_getClientContainer(info);
3574 if (!container)
3575 printf(format: "[<<NULL>>]");
3576 else
3577 printf(format: "[%s]", (const char *)container);
3578}
3579
3580static const char *getEntityKindString(CXIdxEntityKind kind) {
3581 switch (kind) {
3582 case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
3583 case CXIdxEntity_Typedef: return "typedef";
3584 case CXIdxEntity_Function: return "function";
3585 case CXIdxEntity_Variable: return "variable";
3586 case CXIdxEntity_Field: return "field";
3587 case CXIdxEntity_EnumConstant: return "enumerator";
3588 case CXIdxEntity_ObjCClass: return "objc-class";
3589 case CXIdxEntity_ObjCProtocol: return "objc-protocol";
3590 case CXIdxEntity_ObjCCategory: return "objc-category";
3591 case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
3592 case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
3593 case CXIdxEntity_ObjCProperty: return "objc-property";
3594 case CXIdxEntity_ObjCIvar: return "objc-ivar";
3595 case CXIdxEntity_Enum: return "enum";
3596 case CXIdxEntity_Struct: return "struct";
3597 case CXIdxEntity_Union: return "union";
3598 case CXIdxEntity_CXXClass: return "c++-class";
3599 case CXIdxEntity_CXXNamespace: return "namespace";
3600 case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
3601 case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
3602 case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
3603 case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
3604 case CXIdxEntity_CXXConstructor: return "constructor";
3605 case CXIdxEntity_CXXDestructor: return "destructor";
3606 case CXIdxEntity_CXXConversionFunction: return "conversion-func";
3607 case CXIdxEntity_CXXTypeAlias: return "type-alias";
3608 case CXIdxEntity_CXXInterface: return "c++-__interface";
3609 case CXIdxEntity_CXXConcept:
3610 return "concept";
3611 }
3612 assert(0 && "Garbage entity kind");
3613 return 0;
3614}
3615
3616static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
3617 switch (kind) {
3618 case CXIdxEntity_NonTemplate: return "";
3619 case CXIdxEntity_Template: return "-template";
3620 case CXIdxEntity_TemplatePartialSpecialization:
3621 return "-template-partial-spec";
3622 case CXIdxEntity_TemplateSpecialization: return "-template-spec";
3623 }
3624 assert(0 && "Garbage entity kind");
3625 return 0;
3626}
3627
3628static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
3629 switch (kind) {
3630 case CXIdxEntityLang_None: return "<none>";
3631 case CXIdxEntityLang_C: return "C";
3632 case CXIdxEntityLang_ObjC: return "ObjC";
3633 case CXIdxEntityLang_CXX: return "C++";
3634 case CXIdxEntityLang_Swift: return "Swift";
3635 }
3636 assert(0 && "Garbage language kind");
3637 return 0;
3638}
3639
3640static void printEntityInfo(const char *cb,
3641 CXClientData client_data,
3642 const CXIdxEntityInfo *info) {
3643 const char *name;
3644 IndexData *index_data;
3645 unsigned i;
3646 index_data = (IndexData *)client_data;
3647 printCheck(data: index_data);
3648
3649 if (!info) {
3650 printf(format: "%s: <<NULL>>", cb);
3651 return;
3652 }
3653
3654 name = info->name;
3655 if (!name)
3656 name = "<anon-tag>";
3657
3658 printf(format: "%s: kind: %s%s", cb, getEntityKindString(kind: info->kind),
3659 getEntityTemplateKindString(kind: info->templateKind));
3660 printf(format: " | name: %s", name);
3661 printf(format: " | USR: %s", info->USR);
3662 printf(format: " | lang: %s", getEntityLanguageString(kind: info->lang));
3663
3664 for (i = 0; i != info->numAttributes; ++i) {
3665 const CXIdxAttrInfo *Attr = info->attributes[i];
3666 printf(format: " <attribute>: ");
3667 PrintCursor(Cursor: Attr->cursor, NULL);
3668 }
3669}
3670
3671static void printBaseClassInfo(CXClientData client_data,
3672 const CXIdxBaseClassInfo *info) {
3673 printEntityInfo(cb: " <base>", client_data, info: info->base);
3674 printf(format: " | cursor: ");
3675 PrintCursor(Cursor: info->cursor, NULL);
3676 printf(format: " | loc: ");
3677 printCXIndexLoc(loc: info->loc, client_data);
3678}
3679
3680static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
3681 CXClientData client_data) {
3682 unsigned i;
3683 for (i = 0; i < ProtoInfo->numProtocols; ++i) {
3684 printEntityInfo(cb: " <protocol>", client_data,
3685 info: ProtoInfo->protocols[i]->protocol);
3686 printf(format: " | cursor: ");
3687 PrintCursor(Cursor: ProtoInfo->protocols[i]->cursor, NULL);
3688 printf(format: " | loc: ");
3689 printCXIndexLoc(loc: ProtoInfo->protocols[i]->loc, client_data);
3690 printf(format: "\n");
3691 }
3692}
3693
3694static void printSymbolRole(CXSymbolRole role) {
3695 if (role & CXSymbolRole_Declaration)
3696 printf(format: " decl");
3697 if (role & CXSymbolRole_Definition)
3698 printf(format: " def");
3699 if (role & CXSymbolRole_Reference)
3700 printf(format: " ref");
3701 if (role & CXSymbolRole_Read)
3702 printf(format: " read");
3703 if (role & CXSymbolRole_Write)
3704 printf(format: " write");
3705 if (role & CXSymbolRole_Call)
3706 printf(format: " call");
3707 if (role & CXSymbolRole_Dynamic)
3708 printf(format: " dyn");
3709 if (role & CXSymbolRole_AddressOf)
3710 printf(format: " addr");
3711 if (role & CXSymbolRole_Implicit)
3712 printf(format: " implicit");
3713}
3714
3715static void index_diagnostic(CXClientData client_data,
3716 CXDiagnosticSet diagSet, void *reserved) {
3717 CXString str;
3718 const char *cstr;
3719 unsigned numDiags, i;
3720 CXDiagnostic diag;
3721 IndexData *index_data;
3722 index_data = (IndexData *)client_data;
3723 printCheck(data: index_data);
3724
3725 numDiags = clang_getNumDiagnosticsInSet(Diags: diagSet);
3726 for (i = 0; i != numDiags; ++i) {
3727 diag = clang_getDiagnosticInSet(Diags: diagSet, Index: i);
3728 str = clang_formatDiagnostic(Diagnostic: diag, Options: clang_defaultDiagnosticDisplayOptions());
3729 cstr = clang_getCString(string: str);
3730 printf(format: "[diagnostic]: %s\n", cstr);
3731 clang_disposeString(string: str);
3732
3733 if (getenv(name: "CINDEXTEST_FAILONERROR") &&
3734 clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
3735 index_data->fail_for_error = 1;
3736 }
3737 }
3738}
3739
3740static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
3741 CXFile file, void *reserved) {
3742 IndexData *index_data;
3743
3744 index_data = (IndexData *)client_data;
3745 printCheck(data: index_data);
3746
3747 index_data->main_filename = clang_getFileName(SFile: file);
3748
3749 printf(format: "[enteredMainFile]: ");
3750 printCXIndexFile(file: (CXIdxClientFile)file);
3751 printf(format: "\n");
3752
3753 return (CXIdxClientFile)file;
3754}
3755
3756static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
3757 const CXIdxIncludedFileInfo *info) {
3758 IndexData *index_data;
3759 CXModule Mod;
3760 index_data = (IndexData *)client_data;
3761 printCheck(data: index_data);
3762
3763 printf(format: "[ppIncludedFile]: ");
3764 printCXIndexFile(file: (CXIdxClientFile)info->file);
3765 printf(format: " | name: \"%s\"", info->filename);
3766 printf(format: " | hash loc: ");
3767 printCXIndexLoc(loc: info->hashLoc, client_data);
3768 printf(format: " | isImport: %d | isAngled: %d | isModule: %d",
3769 info->isImport, info->isAngled, info->isModuleImport);
3770
3771 Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
3772 if (Mod) {
3773 CXString str = clang_Module_getFullName(Module: Mod);
3774 const char *cstr = clang_getCString(string: str);
3775 printf(format: " | module: %s", cstr);
3776 clang_disposeString(string: str);
3777 }
3778
3779 printf(format: "\n");
3780
3781 return (CXIdxClientFile)info->file;
3782}
3783
3784static CXIdxClientFile index_importedASTFile(CXClientData client_data,
3785 const CXIdxImportedASTFileInfo *info) {
3786 IndexData *index_data;
3787 index_data = (IndexData *)client_data;
3788 printCheck(data: index_data);
3789
3790 if (index_data->importedASTs) {
3791 CXString filename = clang_getFileName(SFile: info->file);
3792 importedASTS_insert(p: index_data->importedASTs, file: clang_getCString(string: filename));
3793 clang_disposeString(string: filename);
3794 }
3795
3796 printf(format: "[importedASTFile]: ");
3797 printCXIndexFile(file: (CXIdxClientFile)info->file);
3798 if (info->module) {
3799 CXString name = clang_Module_getFullName(Module: info->module);
3800 printf(format: " | loc: ");
3801 printCXIndexLoc(loc: info->loc, client_data);
3802 printf(format: " | name: \"%s\"", clang_getCString(string: name));
3803 printf(format: " | isImplicit: %d\n", info->isImplicit);
3804 clang_disposeString(string: name);
3805 } else {
3806 /* PCH file, the rest are not relevant. */
3807 printf(format: "\n");
3808 }
3809
3810 return (CXIdxClientFile)info->file;
3811}
3812
3813static CXIdxClientContainer
3814index_startedTranslationUnit(CXClientData client_data, void *reserved) {
3815 IndexData *index_data;
3816 index_data = (IndexData *)client_data;
3817 printCheck(data: index_data);
3818
3819 printf(format: "[startedTranslationUnit]\n");
3820#ifdef __GNUC__
3821#pragma GCC diagnostic push
3822#pragma GCC diagnostic ignored "-Wcast-qual"
3823#endif
3824 return (CXIdxClientContainer)"TU";
3825#ifdef __GNUC__
3826#pragma GCC diagnostic pop
3827#endif
3828}
3829
3830static void index_indexDeclaration(CXClientData client_data,
3831 const CXIdxDeclInfo *info) {
3832 IndexData *index_data;
3833 const CXIdxObjCCategoryDeclInfo *CatInfo;
3834 const CXIdxObjCInterfaceDeclInfo *InterInfo;
3835 const CXIdxObjCProtocolRefListInfo *ProtoInfo;
3836 const CXIdxObjCPropertyDeclInfo *PropInfo;
3837 const CXIdxCXXClassDeclInfo *CXXClassInfo;
3838 unsigned i;
3839 index_data = (IndexData *)client_data;
3840
3841 printEntityInfo(cb: "[indexDeclaration]", client_data, info: info->entityInfo);
3842 printf(format: " | cursor: ");
3843 PrintCursor(Cursor: info->cursor, NULL);
3844 printf(format: " | loc: ");
3845 printCXIndexLoc(loc: info->loc, client_data);
3846 printf(format: " | semantic-container: ");
3847 printCXIndexContainer(info: info->semanticContainer);
3848 printf(format: " | lexical-container: ");
3849 printCXIndexContainer(info: info->lexicalContainer);
3850 printf(format: " | isRedecl: %d", info->isRedeclaration);
3851 printf(format: " | isDef: %d", info->isDefinition);
3852 if (info->flags & CXIdxDeclFlag_Skipped) {
3853 assert(!info->isContainer);
3854 printf(format: " | isContainer: skipped");
3855 } else {
3856 printf(format: " | isContainer: %d", info->isContainer);
3857 }
3858 printf(format: " | isImplicit: %d\n", info->isImplicit);
3859
3860 for (i = 0; i != info->numAttributes; ++i) {
3861 const CXIdxAttrInfo *Attr = info->attributes[i];
3862 printf(format: " <attribute>: ");
3863 PrintCursor(Cursor: Attr->cursor, NULL);
3864 printf(format: "\n");
3865 }
3866
3867 if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
3868 const char *kindName = 0;
3869 CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
3870 switch (K) {
3871 case CXIdxObjCContainer_ForwardRef:
3872 kindName = "forward-ref"; break;
3873 case CXIdxObjCContainer_Interface:
3874 kindName = "interface"; break;
3875 case CXIdxObjCContainer_Implementation:
3876 kindName = "implementation"; break;
3877 }
3878 printCheck(data: index_data);
3879 printf(format: " <ObjCContainerInfo>: kind: %s\n", kindName);
3880 }
3881
3882 if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
3883 printEntityInfo(cb: " <ObjCCategoryInfo>: class", client_data,
3884 info: CatInfo->objcClass);
3885 printf(format: " | cursor: ");
3886 PrintCursor(Cursor: CatInfo->classCursor, NULL);
3887 printf(format: " | loc: ");
3888 printCXIndexLoc(loc: CatInfo->classLoc, client_data);
3889 printf(format: "\n");
3890 }
3891
3892 if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
3893 if (InterInfo->superInfo) {
3894 printBaseClassInfo(client_data, info: InterInfo->superInfo);
3895 printf(format: "\n");
3896 }
3897 }
3898
3899 if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
3900 printProtocolList(ProtoInfo, client_data);
3901 }
3902
3903 if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
3904 if (PropInfo->getter) {
3905 printEntityInfo(cb: " <getter>", client_data, info: PropInfo->getter);
3906 printf(format: "\n");
3907 }
3908 if (PropInfo->setter) {
3909 printEntityInfo(cb: " <setter>", client_data, info: PropInfo->setter);
3910 printf(format: "\n");
3911 }
3912 }
3913
3914 if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
3915 for (i = 0; i != CXXClassInfo->numBases; ++i) {
3916 printBaseClassInfo(client_data, info: CXXClassInfo->bases[i]);
3917 printf(format: "\n");
3918 }
3919 }
3920
3921 if (info->declAsContainer)
3922 clang_index_setClientContainer(
3923 info->declAsContainer,
3924 makeClientContainer(client_data, info: info->entityInfo, loc: info->loc));
3925}
3926
3927static void index_indexEntityReference(CXClientData client_data,
3928 const CXIdxEntityRefInfo *info) {
3929 printEntityInfo(cb: "[indexEntityReference]", client_data,
3930 info: info->referencedEntity);
3931 printf(format: " | cursor: ");
3932 PrintCursor(Cursor: info->cursor, NULL);
3933 printf(format: " | loc: ");
3934 printCXIndexLoc(loc: info->loc, client_data);
3935 printEntityInfo(cb: " | <parent>:", client_data, info: info->parentEntity);
3936 printf(format: " | container: ");
3937 printCXIndexContainer(info: info->container);
3938 printf(format: " | refkind: ");
3939 switch (info->kind) {
3940 case CXIdxEntityRef_Direct: printf(format: "direct"); break;
3941 case CXIdxEntityRef_Implicit: printf(format: "implicit"); break;
3942 }
3943 printf(format: " | role:");
3944 printSymbolRole(role: info->role);
3945 printf(format: "\n");
3946}
3947
3948static int index_abortQuery(CXClientData client_data, void *reserved) {
3949 IndexData *index_data;
3950 index_data = (IndexData *)client_data;
3951 return index_data->abort;
3952}
3953
3954static IndexerCallbacks IndexCB = {
3955 index_abortQuery,
3956 index_diagnostic,
3957 index_enteredMainFile,
3958 index_ppIncludedFile,
3959 index_importedASTFile,
3960 index_startedTranslationUnit,
3961 index_indexDeclaration,
3962 index_indexEntityReference
3963};
3964
3965static unsigned getIndexOptions(void) {
3966 unsigned index_opts;
3967 index_opts = 0;
3968 if (getenv(name: "CINDEXTEST_SUPPRESSREFS"))
3969 index_opts |= CXIndexOpt_SuppressRedundantRefs;
3970 if (getenv(name: "CINDEXTEST_INDEXLOCALSYMBOLS"))
3971 index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
3972 if (!getenv(name: "CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
3973 index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
3974 if (getenv(name: "CINDEXTEST_INDEXIMPLICITTEMPLATEINSTANTIATIONS"))
3975 index_opts |= CXIndexOpt_IndexImplicitTemplateInstantiations;
3976
3977 return index_opts;
3978}
3979
3980static int index_compile_args(int num_args, const char **args,
3981 CXIndexAction idxAction,
3982 ImportedASTFilesData *importedASTs,
3983 const char *check_prefix) {
3984 IndexData index_data;
3985 unsigned index_opts;
3986 int result;
3987
3988 if (num_args == 0) {
3989 fprintf(stderr, format: "no compiler arguments\n");
3990 return -1;
3991 }
3992
3993 index_data.check_prefix = check_prefix;
3994 index_data.first_check_printed = 0;
3995 index_data.fail_for_error = 0;
3996 index_data.abort = 0;
3997 index_data.main_filename = createCXString(CS: "");
3998 index_data.importedASTs = importedASTs;
3999 index_data.strings = NULL;
4000 index_data.TU = NULL;
4001
4002 index_opts = getIndexOptions();
4003 result = clang_indexSourceFile(idxAction, client_data: &index_data,
4004 index_callbacks: &IndexCB,index_callbacks_size: sizeof(IndexCB), index_options: index_opts,
4005 source_filename: 0, command_line_args: args, num_command_line_args: num_args, unsaved_files: 0, num_unsaved_files: 0, out_TU: 0,
4006 TU_options: getDefaultParsingOptions());
4007 if (result != CXError_Success)
4008 describeLibclangFailure(Err: result);
4009
4010 if (index_data.fail_for_error)
4011 result = -1;
4012
4013 clang_disposeString(string: index_data.main_filename);
4014 free_client_data(index_data: &index_data);
4015 return result;
4016}
4017
4018static int index_ast_file(const char *ast_file,
4019 CXIndex Idx,
4020 CXIndexAction idxAction,
4021 ImportedASTFilesData *importedASTs,
4022 const char *check_prefix) {
4023 CXTranslationUnit TU;
4024 IndexData index_data;
4025 unsigned index_opts;
4026 int result;
4027
4028 if (!CreateTranslationUnit(Idx, file: ast_file, TU: &TU))
4029 return -1;
4030
4031 index_data.check_prefix = check_prefix;
4032 index_data.first_check_printed = 0;
4033 index_data.fail_for_error = 0;
4034 index_data.abort = 0;
4035 index_data.main_filename = createCXString(CS: "");
4036 index_data.importedASTs = importedASTs;
4037 index_data.strings = NULL;
4038 index_data.TU = TU;
4039
4040 index_opts = getIndexOptions();
4041 result = clang_indexTranslationUnit(idxAction, client_data: &index_data,
4042 index_callbacks: &IndexCB,index_callbacks_size: sizeof(IndexCB),
4043 index_options: index_opts, TU);
4044 if (index_data.fail_for_error)
4045 result = -1;
4046
4047 clang_disposeTranslationUnit(TU);
4048 clang_disposeString(string: index_data.main_filename);
4049 free_client_data(index_data: &index_data);
4050 return result;
4051}
4052
4053static int index_file(int argc, const char **argv, int full) {
4054 const char *check_prefix;
4055 CXIndex Idx;
4056 CXIndexAction idxAction;
4057 ImportedASTFilesData *importedASTs;
4058 int result;
4059
4060 check_prefix = 0;
4061 if (argc > 0) {
4062 if (strstr(haystack: argv[0], needle: "-check-prefix=") == argv[0]) {
4063 check_prefix = argv[0] + strlen(s: "-check-prefix=");
4064 ++argv;
4065 --argc;
4066 }
4067 }
4068
4069 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ excludeDeclarationsFromPCH: 1,
4070 /* displayDiagnostics=*/1))) {
4071 fprintf(stderr, format: "Could not create Index\n");
4072 return 1;
4073 }
4074 idxAction = clang_IndexAction_create(CIdx: Idx);
4075 importedASTs = 0;
4076 if (full)
4077 importedASTs = importedASTs_create();
4078
4079 result = index_compile_args(num_args: argc, args: argv, idxAction, importedASTs, check_prefix);
4080 if (result != 0)
4081 goto finished;
4082
4083 if (full) {
4084 unsigned i;
4085 for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
4086 result = index_ast_file(ast_file: importedASTs->filenames[i], Idx, idxAction,
4087 importedASTs, check_prefix);
4088 }
4089 }
4090
4091finished:
4092 importedASTs_dispose(p: importedASTs);
4093 clang_IndexAction_dispose(idxAction);
4094 clang_disposeIndex(index: Idx);
4095 return result;
4096}
4097
4098static int index_tu(int argc, const char **argv) {
4099 const char *check_prefix;
4100 CXIndex Idx;
4101 CXIndexAction idxAction;
4102 int result;
4103
4104 check_prefix = 0;
4105 if (argc > 0) {
4106 if (strstr(haystack: argv[0], needle: "-check-prefix=") == argv[0]) {
4107 check_prefix = argv[0] + strlen(s: "-check-prefix=");
4108 ++argv;
4109 --argc;
4110 }
4111 }
4112
4113 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ excludeDeclarationsFromPCH: 1,
4114 /* displayDiagnostics=*/1))) {
4115 fprintf(stderr, format: "Could not create Index\n");
4116 return 1;
4117 }
4118 idxAction = clang_IndexAction_create(CIdx: Idx);
4119
4120 result = index_ast_file(ast_file: argv[0], Idx, idxAction,
4121 /*importedASTs=*/0, check_prefix);
4122
4123 clang_IndexAction_dispose(idxAction);
4124 clang_disposeIndex(index: Idx);
4125 return result;
4126}
4127
4128static int index_compile_db(int argc, const char **argv) {
4129 const char *check_prefix;
4130 CXIndex Idx;
4131 CXIndexAction idxAction;
4132 int errorCode = 0;
4133
4134 check_prefix = 0;
4135 if (argc > 0) {
4136 if (strstr(haystack: argv[0], needle: "-check-prefix=") == argv[0]) {
4137 check_prefix = argv[0] + strlen(s: "-check-prefix=");
4138 ++argv;
4139 --argc;
4140 }
4141 }
4142
4143 if (argc == 0) {
4144 fprintf(stderr, format: "no compilation database\n");
4145 return -1;
4146 }
4147
4148 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ excludeDeclarationsFromPCH: 1,
4149 /* displayDiagnostics=*/1))) {
4150 fprintf(stderr, format: "Could not create Index\n");
4151 return 1;
4152 }
4153 idxAction = clang_IndexAction_create(CIdx: Idx);
4154
4155 {
4156 const char *database = argv[0];
4157 CXCompilationDatabase db = 0;
4158 CXCompileCommands CCmds = 0;
4159 CXCompileCommand CCmd;
4160 CXCompilationDatabase_Error ec;
4161 CXString wd;
4162#define MAX_COMPILE_ARGS 512
4163 CXString cxargs[MAX_COMPILE_ARGS];
4164 const char *args[MAX_COMPILE_ARGS];
4165 char *tmp;
4166 unsigned len;
4167 char *buildDir;
4168 int i, a, numCmds, numArgs;
4169
4170 len = strlen(s: database);
4171 tmp = (char *) malloc(size: len+1);
4172 assert(tmp);
4173 memcpy(dest: tmp, src: database, n: len+1);
4174 buildDir = dirname(tmp);
4175
4176 db = clang_CompilationDatabase_fromDirectory(BuildDir: buildDir, ErrorCode: &ec);
4177
4178 if (db) {
4179
4180 if (ec!=CXCompilationDatabase_NoError) {
4181 printf(format: "unexpected error %d code while loading compilation database\n", ec);
4182 errorCode = -1;
4183 goto cdb_end;
4184 }
4185
4186 if (chdir(path: buildDir) != 0) {
4187 printf(format: "Could not chdir to %s\n", buildDir);
4188 errorCode = -1;
4189 goto cdb_end;
4190 }
4191
4192 CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
4193 if (!CCmds) {
4194 printf(format: "compilation db is empty\n");
4195 errorCode = -1;
4196 goto cdb_end;
4197 }
4198
4199 numCmds = clang_CompileCommands_getSize(CCmds);
4200
4201 if (numCmds==0) {
4202 fprintf(stderr, format: "should not get an empty compileCommand set\n");
4203 errorCode = -1;
4204 goto cdb_end;
4205 }
4206
4207 for (i=0; i<numCmds && errorCode == 0; ++i) {
4208 CCmd = clang_CompileCommands_getCommand(CCmds, I: i);
4209
4210 wd = clang_CompileCommand_getDirectory(CCmd);
4211 if (chdir(path: clang_getCString(string: wd)) != 0) {
4212 printf(format: "Could not chdir to %s\n", clang_getCString(string: wd));
4213 errorCode = -1;
4214 goto cdb_end;
4215 }
4216 clang_disposeString(string: wd);
4217
4218 numArgs = clang_CompileCommand_getNumArgs(CCmd);
4219 if (numArgs > MAX_COMPILE_ARGS){
4220 fprintf(stderr, format: "got more compile arguments than maximum\n");
4221 errorCode = -1;
4222 goto cdb_end;
4223 }
4224 for (a=0; a<numArgs; ++a) {
4225 cxargs[a] = clang_CompileCommand_getArg(CCmd, I: a);
4226 args[a] = clang_getCString(string: cxargs[a]);
4227 }
4228
4229 errorCode = index_compile_args(num_args: numArgs, args, idxAction,
4230 /*importedASTs=*/0, check_prefix);
4231
4232 for (a=0; a<numArgs; ++a)
4233 clang_disposeString(string: cxargs[a]);
4234 }
4235 } else {
4236 printf(format: "database loading failed with error code %d.\n", ec);
4237 errorCode = -1;
4238 }
4239
4240 cdb_end:
4241 clang_CompileCommands_dispose(CCmds);
4242 clang_CompilationDatabase_dispose(db);
4243 free(ptr: tmp);
4244
4245 }
4246
4247 clang_IndexAction_dispose(idxAction);
4248 clang_disposeIndex(index: Idx);
4249 return errorCode;
4250}
4251
4252int perform_token_annotation(int argc, const char **argv) {
4253 const char *input = argv[1];
4254 char *filename = 0;
4255 unsigned line, second_line;
4256 unsigned column, second_column;
4257 CXIndex CIdx;
4258 CXTranslationUnit TU = 0;
4259 int errorCode;
4260 struct CXUnsavedFile *unsaved_files = 0;
4261 int num_unsaved_files = 0;
4262 CXToken *tokens;
4263 unsigned num_tokens;
4264 CXSourceRange range;
4265 CXSourceLocation startLoc, endLoc;
4266 CXFile file = 0;
4267 CXCursor *cursors = 0;
4268 CXSourceRangeList *skipped_ranges = 0;
4269 enum CXErrorCode Err;
4270 unsigned i;
4271
4272 input += strlen(s: "-test-annotate-tokens=");
4273 if ((errorCode = parse_file_line_column(input, filename: &filename, line: &line, column: &column,
4274 second_line: &second_line, second_column: &second_column)))
4275 return errorCode;
4276
4277 if (parse_remapped_files(argc, argv, start_arg: 2, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
4278 free(ptr: filename);
4279 return -1;
4280 }
4281
4282 CIdx = clang_createIndex(excludeDeclarationsFromPCH: 0, displayDiagnostics: 1);
4283 Err = clang_parseTranslationUnit2(CIdx, source_filename: argv[argc - 1],
4284 command_line_args: argv + num_unsaved_files + 2,
4285 num_command_line_args: argc - num_unsaved_files - 3,
4286 unsaved_files,
4287 num_unsaved_files,
4288 options: getDefaultParsingOptions(), out_TU: &TU);
4289 if (Err != CXError_Success) {
4290 fprintf(stderr, format: "unable to parse input\n");
4291 describeLibclangFailure(Err);
4292 clang_disposeIndex(index: CIdx);
4293 free(ptr: filename);
4294 free_remapped_files(unsaved_files, num_unsaved_files);
4295 return -1;
4296 }
4297 errorCode = 0;
4298
4299 if (checkForErrors(TU) != 0) {
4300 errorCode = -1;
4301 goto teardown;
4302 }
4303
4304 if (getenv(name: "CINDEXTEST_EDITING")) {
4305 for (i = 0; i < 5; ++i) {
4306 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
4307 options: clang_defaultReparseOptions(TU));
4308 if (Err != CXError_Success) {
4309 fprintf(stderr, format: "Unable to reparse translation unit!\n");
4310 describeLibclangFailure(Err);
4311 errorCode = -1;
4312 goto teardown;
4313 }
4314 }
4315 }
4316
4317 if (checkForErrors(TU) != 0) {
4318 errorCode = -1;
4319 goto teardown;
4320 }
4321
4322 file = clang_getFile(tu: TU, file_name: filename);
4323 if (!file) {
4324 fprintf(stderr, format: "file %s is not in this translation unit\n", filename);
4325 errorCode = -1;
4326 goto teardown;
4327 }
4328
4329 startLoc = clang_getLocation(tu: TU, file, line, column);
4330 if (clang_equalLocations(loc1: clang_getNullLocation(), loc2: startLoc)) {
4331 fprintf(stderr, format: "invalid source location %s:%d:%d\n", filename, line,
4332 column);
4333 errorCode = -1;
4334 goto teardown;
4335 }
4336
4337 endLoc = clang_getLocation(tu: TU, file, line: second_line, column: second_column);
4338 if (clang_equalLocations(loc1: clang_getNullLocation(), loc2: endLoc)) {
4339 fprintf(stderr, format: "invalid source location %s:%d:%d\n", filename,
4340 second_line, second_column);
4341 errorCode = -1;
4342 goto teardown;
4343 }
4344
4345 range = clang_getRange(begin: startLoc, end: endLoc);
4346 clang_tokenize(TU, Range: range, Tokens: &tokens, NumTokens: &num_tokens);
4347
4348 if (checkForErrors(TU) != 0) {
4349 errorCode = -1;
4350 goto teardown;
4351 }
4352
4353 cursors = (CXCursor *)malloc(size: num_tokens * sizeof(CXCursor));
4354 assert(cursors);
4355 clang_annotateTokens(TU, Tokens: tokens, NumTokens: num_tokens, Cursors: cursors);
4356
4357 if (checkForErrors(TU) != 0) {
4358 errorCode = -1;
4359 goto teardown;
4360 }
4361
4362 skipped_ranges = clang_getSkippedRanges(tu: TU, file);
4363 for (i = 0; i != skipped_ranges->count; ++i) {
4364 unsigned start_line, start_column, end_line, end_column;
4365 clang_getFileLocation(location: clang_getRangeStart(range: skipped_ranges->ranges[i]), file: 0,
4366 line: &start_line, column: &start_column, offset: 0);
4367 clang_getFileLocation(location: clang_getRangeEnd(range: skipped_ranges->ranges[i]), file: 0,
4368 line: &end_line, column: &end_column, offset: 0);
4369 printf(format: "Skipping: ");
4370 PrintExtent(stdout, begin_line: start_line, begin_column: start_column, end_line, end_column);
4371 printf(format: "\n");
4372 }
4373 clang_disposeSourceRangeList(ranges: skipped_ranges);
4374
4375 for (i = 0; i != num_tokens; ++i) {
4376 const char *kind = "<unknown>";
4377 CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
4378 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
4379 unsigned start_line, start_column, end_line, end_column;
4380
4381 switch (clang_getTokenKind(tokens[i])) {
4382 case CXToken_Punctuation: kind = "Punctuation"; break;
4383 case CXToken_Keyword: kind = "Keyword"; break;
4384 case CXToken_Identifier: kind = "Identifier"; break;
4385 case CXToken_Literal: kind = "Literal"; break;
4386 case CXToken_Comment: kind = "Comment"; break;
4387 }
4388 clang_getFileLocation(location: clang_getRangeStart(range: extent), file: 0, line: &start_line,
4389 column: &start_column, offset: 0);
4390 clang_getFileLocation(location: clang_getRangeEnd(range: extent), file: 0, line: &end_line, column: &end_column,
4391 offset: 0);
4392 printf(format: "%s: \"%s\" ", kind, clang_getCString(string: spelling));
4393 clang_disposeString(string: spelling);
4394 PrintExtent(stdout, begin_line: start_line, begin_column: start_column, end_line, end_column);
4395 if (!clang_isInvalid(cursors[i].kind)) {
4396 printf(format: " ");
4397 PrintCursor(Cursor: cursors[i], NULL);
4398 }
4399 printf(format: "\n");
4400 }
4401 free(ptr: cursors);
4402 clang_disposeTokens(TU, Tokens: tokens, NumTokens: num_tokens);
4403
4404 teardown:
4405 PrintDiagnostics(TU);
4406 clang_disposeTranslationUnit(TU);
4407 clang_disposeIndex(index: CIdx);
4408 free(ptr: filename);
4409 free_remapped_files(unsaved_files, num_unsaved_files);
4410 return errorCode;
4411}
4412
4413static int
4414perform_test_compilation_db(const char *database, int argc, const char **argv) {
4415 CXCompilationDatabase db;
4416 CXCompileCommands CCmds;
4417 CXCompileCommand CCmd;
4418 CXCompilationDatabase_Error ec;
4419 CXString wd;
4420 CXString arg;
4421 int errorCode = 0;
4422 char *tmp;
4423 unsigned len;
4424 char *buildDir;
4425 int i, j, a, numCmds, numArgs;
4426
4427 len = strlen(s: database);
4428 tmp = (char *) malloc(size: len+1);
4429 assert(tmp);
4430 memcpy(dest: tmp, src: database, n: len+1);
4431 buildDir = dirname(tmp);
4432
4433 db = clang_CompilationDatabase_fromDirectory(BuildDir: buildDir, ErrorCode: &ec);
4434
4435 if (db) {
4436
4437 if (ec!=CXCompilationDatabase_NoError) {
4438 printf(format: "unexpected error %d code while loading compilation database\n", ec);
4439 errorCode = -1;
4440 goto cdb_end;
4441 }
4442
4443 for (i=0; i<argc && errorCode==0; ) {
4444 if (strcmp(s1: argv[i],s2: "lookup")==0){
4445 CCmds = clang_CompilationDatabase_getCompileCommands(db, CompleteFileName: argv[i+1]);
4446
4447 if (!CCmds) {
4448 printf(format: "file %s not found in compilation db\n", argv[i+1]);
4449 errorCode = -1;
4450 break;
4451 }
4452
4453 numCmds = clang_CompileCommands_getSize(CCmds);
4454
4455 if (numCmds==0) {
4456 fprintf(stderr, format: "should not get an empty compileCommand set for file"
4457 " '%s'\n", argv[i+1]);
4458 errorCode = -1;
4459 break;
4460 }
4461
4462 for (j=0; j<numCmds; ++j) {
4463 CCmd = clang_CompileCommands_getCommand(CCmds, I: j);
4464
4465 wd = clang_CompileCommand_getDirectory(CCmd);
4466 printf(format: "workdir:'%s'", clang_getCString(string: wd));
4467 clang_disposeString(string: wd);
4468
4469 printf(format: " cmdline:'");
4470 numArgs = clang_CompileCommand_getNumArgs(CCmd);
4471 for (a=0; a<numArgs; ++a) {
4472 if (a) printf(format: " ");
4473 arg = clang_CompileCommand_getArg(CCmd, I: a);
4474 printf(format: "%s", clang_getCString(string: arg));
4475 clang_disposeString(string: arg);
4476 }
4477 printf(format: "'\n");
4478 }
4479
4480 clang_CompileCommands_dispose(CCmds);
4481
4482 i += 2;
4483 }
4484 }
4485 clang_CompilationDatabase_dispose(db);
4486 } else {
4487 printf(format: "database loading failed with error code %d.\n", ec);
4488 errorCode = -1;
4489 }
4490
4491cdb_end:
4492 free(ptr: tmp);
4493
4494 return errorCode;
4495}
4496
4497/******************************************************************************/
4498/* USR printing. */
4499/******************************************************************************/
4500
4501static int insufficient_usr(const char *kind, const char *usage) {
4502 fprintf(stderr, format: "USR for '%s' requires: %s\n", kind, usage);
4503 return 1;
4504}
4505
4506static unsigned isUSR(const char *s) {
4507 return s[0] == 'c' && s[1] == ':';
4508}
4509
4510static int not_usr(const char *s, const char *arg) {
4511 fprintf(stderr, format: "'%s' argument ('%s') is not a USR\n", s, arg);
4512 return 1;
4513}
4514
4515static void print_usr(CXString usr) {
4516 const char *s = clang_getCString(string: usr);
4517 printf(format: "%s\n", s);
4518 clang_disposeString(string: usr);
4519}
4520
4521static void display_usrs(void) {
4522 fprintf(stderr, format: "-print-usrs options:\n"
4523 " ObjCCategory <class name> <category name>\n"
4524 " ObjCClass <class name>\n"
4525 " ObjCIvar <ivar name> <class USR>\n"
4526 " ObjCMethod <selector> [0=class method|1=instance method] "
4527 "<class USR>\n"
4528 " ObjCProperty <property name> <class USR>\n"
4529 " ObjCProtocol <protocol name>\n");
4530}
4531
4532int print_usrs(const char **I, const char **E) {
4533 while (I != E) {
4534 const char *kind = *I;
4535 unsigned len = strlen(s: kind);
4536 switch (len) {
4537 case 8:
4538 if (memcmp(s1: kind, s2: "ObjCIvar", n: 8) == 0) {
4539 if (I + 2 >= E)
4540 return insufficient_usr(kind, usage: "<ivar name> <class USR>");
4541 if (!isUSR(s: I[2]))
4542 return not_usr(s: "<class USR>", arg: I[2]);
4543 else {
4544 CXString x = createCXString(CS: I[2]);
4545 print_usr(usr: clang_constructUSR_ObjCIvar(name: I[1], classUSR: x));
4546 }
4547
4548 I += 3;
4549 continue;
4550 }
4551 break;
4552 case 9:
4553 if (memcmp(s1: kind, s2: "ObjCClass", n: 9) == 0) {
4554 if (I + 1 >= E)
4555 return insufficient_usr(kind, usage: "<class name>");
4556 print_usr(usr: clang_constructUSR_ObjCClass(class_name: I[1]));
4557 I += 2;
4558 continue;
4559 }
4560 break;
4561 case 10:
4562 if (memcmp(s1: kind, s2: "ObjCMethod", n: 10) == 0) {
4563 if (I + 3 >= E)
4564 return insufficient_usr(kind, usage: "<method selector> "
4565 "[0=class method|1=instance method] <class USR>");
4566 if (!isUSR(s: I[3]))
4567 return not_usr(s: "<class USR>", arg: I[3]);
4568 else {
4569 CXString x = createCXString(CS: I[3]);
4570 print_usr(usr: clang_constructUSR_ObjCMethod(name: I[1], isInstanceMethod: atoi(nptr: I[2]), classUSR: x));
4571 }
4572 I += 4;
4573 continue;
4574 }
4575 break;
4576 case 12:
4577 if (memcmp(s1: kind, s2: "ObjCCategory", n: 12) == 0) {
4578 if (I + 2 >= E)
4579 return insufficient_usr(kind, usage: "<class name> <category name>");
4580 print_usr(usr: clang_constructUSR_ObjCCategory(class_name: I[1], category_name: I[2]));
4581 I += 3;
4582 continue;
4583 }
4584 if (memcmp(s1: kind, s2: "ObjCProtocol", n: 12) == 0) {
4585 if (I + 1 >= E)
4586 return insufficient_usr(kind, usage: "<protocol name>");
4587 print_usr(usr: clang_constructUSR_ObjCProtocol(protocol_name: I[1]));
4588 I += 2;
4589 continue;
4590 }
4591 if (memcmp(s1: kind, s2: "ObjCProperty", n: 12) == 0) {
4592 if (I + 2 >= E)
4593 return insufficient_usr(kind, usage: "<property name> <class USR>");
4594 if (!isUSR(s: I[2]))
4595 return not_usr(s: "<class USR>", arg: I[2]);
4596 else {
4597 CXString x = createCXString(CS: I[2]);
4598 print_usr(usr: clang_constructUSR_ObjCProperty(property: I[1], classUSR: x));
4599 }
4600 I += 3;
4601 continue;
4602 }
4603 break;
4604 default:
4605 break;
4606 }
4607 break;
4608 }
4609
4610 if (I != E) {
4611 fprintf(stderr, format: "Invalid USR kind: %s\n", *I);
4612 display_usrs();
4613 return 1;
4614 }
4615 return 0;
4616}
4617
4618int print_usrs_file(const char *file_name) {
4619 char line[2048];
4620 const char *args[128];
4621 unsigned numChars = 0;
4622
4623 FILE *fp = fopen(filename: file_name, modes: "r");
4624 if (!fp) {
4625 fprintf(stderr, format: "error: cannot open '%s'\n", file_name);
4626 return 1;
4627 }
4628
4629 /* This code is not really all that safe, but it works fine for testing. */
4630 while (!feof(stream: fp)) {
4631 char c = fgetc(stream: fp);
4632 if (c == '\n') {
4633 unsigned i = 0;
4634 const char *s = 0;
4635
4636 if (numChars == 0)
4637 continue;
4638
4639 line[numChars] = '\0';
4640 numChars = 0;
4641
4642 if (line[0] == '/' && line[1] == '/')
4643 continue;
4644
4645 s = strtok(s: line, delim: " ");
4646 while (s) {
4647 args[i] = s;
4648 ++i;
4649 s = strtok(s: 0, delim: " ");
4650 }
4651 if (print_usrs(I: &args[0], E: &args[i]))
4652 return 1;
4653 }
4654 else
4655 line[numChars++] = c;
4656 }
4657
4658 fclose(stream: fp);
4659 return 0;
4660}
4661
4662/******************************************************************************/
4663/* Command line processing. */
4664/******************************************************************************/
4665int write_pch_file(const char *filename, int argc, const char *argv[]) {
4666 CXIndex Idx;
4667 CXTranslationUnit TU;
4668 struct CXUnsavedFile *unsaved_files = 0;
4669 int num_unsaved_files = 0;
4670 enum CXErrorCode Err;
4671 int result = 0;
4672
4673 Idx = clang_createIndex(/* excludeDeclsFromPCH */excludeDeclarationsFromPCH: 1, /* displayDiagnostics=*/1);
4674
4675 if (parse_remapped_files(argc, argv, start_arg: 0, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
4676 clang_disposeIndex(index: Idx);
4677 return -1;
4678 }
4679
4680 Err = clang_parseTranslationUnit2(
4681 CIdx: Idx, source_filename: 0, command_line_args: argv + num_unsaved_files, num_command_line_args: argc - num_unsaved_files,
4682 unsaved_files, num_unsaved_files,
4683 options: CXTranslationUnit_Incomplete |
4684 CXTranslationUnit_DetailedPreprocessingRecord |
4685 CXTranslationUnit_ForSerialization,
4686 out_TU: &TU);
4687 if (Err != CXError_Success) {
4688 fprintf(stderr, format: "Unable to load translation unit!\n");
4689 describeLibclangFailure(Err);
4690 free_remapped_files(unsaved_files, num_unsaved_files);
4691 clang_disposeTranslationUnit(TU);
4692 clang_disposeIndex(index: Idx);
4693 return 1;
4694 }
4695
4696 switch (clang_saveTranslationUnit(TU, FileName: filename,
4697 options: clang_defaultSaveOptions(TU))) {
4698 case CXSaveError_None:
4699 break;
4700
4701 case CXSaveError_TranslationErrors:
4702 fprintf(stderr, format: "Unable to write PCH file %s: translation errors\n",
4703 filename);
4704 result = 2;
4705 break;
4706
4707 case CXSaveError_InvalidTU:
4708 fprintf(stderr, format: "Unable to write PCH file %s: invalid translation unit\n",
4709 filename);
4710 result = 3;
4711 break;
4712
4713 case CXSaveError_Unknown:
4714 default:
4715 fprintf(stderr, format: "Unable to write PCH file %s: unknown error \n", filename);
4716 result = 1;
4717 break;
4718 }
4719
4720 clang_disposeTranslationUnit(TU);
4721 free_remapped_files(unsaved_files, num_unsaved_files);
4722 clang_disposeIndex(index: Idx);
4723 return result;
4724}
4725
4726/******************************************************************************/
4727/* Serialized diagnostics. */
4728/******************************************************************************/
4729
4730static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
4731 switch (error) {
4732 case CXLoadDiag_CannotLoad: return "Cannot Load File";
4733 case CXLoadDiag_None: break;
4734 case CXLoadDiag_Unknown: return "Unknown";
4735 case CXLoadDiag_InvalidFile: return "Invalid File";
4736 }
4737 return "None";
4738}
4739
4740static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
4741 switch (severity) {
4742 case CXDiagnostic_Note: return "note";
4743 case CXDiagnostic_Error: return "error";
4744 case CXDiagnostic_Fatal: return "fatal";
4745 case CXDiagnostic_Ignored: return "ignored";
4746 case CXDiagnostic_Warning: return "warning";
4747 }
4748 return "unknown";
4749}
4750
4751static void printIndent(unsigned indent) {
4752 if (indent == 0)
4753 return;
4754 fprintf(stderr, format: "+");
4755 --indent;
4756 while (indent > 0) {
4757 fprintf(stderr, format: "-");
4758 --indent;
4759 }
4760}
4761
4762static void printLocation(CXSourceLocation L) {
4763 CXFile File;
4764 CXString FileName;
4765 unsigned line, column, offset;
4766
4767 clang_getExpansionLocation(location: L, file: &File, line: &line, column: &column, offset: &offset);
4768 FileName = clang_getFileName(SFile: File);
4769
4770 fprintf(stderr, format: "%s:%d:%d", clang_getCString(string: FileName), line, column);
4771 clang_disposeString(string: FileName);
4772}
4773
4774static void printRanges(CXDiagnostic D, unsigned indent) {
4775 unsigned i, n = clang_getDiagnosticNumRanges(D);
4776
4777 for (i = 0; i < n; ++i) {
4778 CXSourceLocation Start, End;
4779 CXSourceRange SR = clang_getDiagnosticRange(Diagnostic: D, Range: i);
4780 Start = clang_getRangeStart(range: SR);
4781 End = clang_getRangeEnd(range: SR);
4782
4783 printIndent(indent);
4784 fprintf(stderr, format: "Range: ");
4785 printLocation(L: Start);
4786 fprintf(stderr, format: " ");
4787 printLocation(L: End);
4788 fprintf(stderr, format: "\n");
4789 }
4790}
4791
4792static void printFixIts(CXDiagnostic D, unsigned indent) {
4793 unsigned i, n = clang_getDiagnosticNumFixIts(Diagnostic: D);
4794 fprintf(stderr, format: "Number FIXITs = %d\n", n);
4795 for (i = 0 ; i < n; ++i) {
4796 CXSourceRange ReplacementRange;
4797 CXString text;
4798 text = clang_getDiagnosticFixIt(Diagnostic: D, FixIt: i, ReplacementRange: &ReplacementRange);
4799
4800 printIndent(indent);
4801 fprintf(stderr, format: "FIXIT: (");
4802 printLocation(L: clang_getRangeStart(range: ReplacementRange));
4803 fprintf(stderr, format: " - ");
4804 printLocation(L: clang_getRangeEnd(range: ReplacementRange));
4805 fprintf(stderr, format: "): \"%s\"\n", clang_getCString(string: text));
4806 clang_disposeString(string: text);
4807 }
4808}
4809
4810static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
4811 unsigned i, n;
4812
4813 if (!Diags)
4814 return;
4815
4816 n = clang_getNumDiagnosticsInSet(Diags);
4817 for (i = 0; i < n; ++i) {
4818 CXSourceLocation DiagLoc;
4819 CXDiagnostic D;
4820 CXFile File;
4821 CXString FileName, DiagSpelling, DiagOption, DiagCat;
4822 unsigned line, column, offset;
4823 const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0;
4824
4825 D = clang_getDiagnosticInSet(Diags, Index: i);
4826 DiagLoc = clang_getDiagnosticLocation(D);
4827 clang_getExpansionLocation(location: DiagLoc, file: &File, line: &line, column: &column, offset: &offset);
4828 FileName = clang_getFileName(SFile: File);
4829 FileNameStr = clang_getCString(string: FileName);
4830 DiagSpelling = clang_getDiagnosticSpelling(D);
4831
4832 printIndent(indent);
4833
4834 fprintf(stderr, format: "%s:%d:%d: %s: %s",
4835 FileNameStr ? FileNameStr : "(null)",
4836 line,
4837 column,
4838 getSeverityString(severity: clang_getDiagnosticSeverity(D)),
4839 clang_getCString(string: DiagSpelling));
4840
4841 DiagOption = clang_getDiagnosticOption(Diag: D, Disable: 0);
4842 DiagOptionStr = clang_getCString(string: DiagOption);
4843 if (DiagOptionStr) {
4844 fprintf(stderr, format: " [%s]", DiagOptionStr);
4845 }
4846
4847 DiagCat = clang_getDiagnosticCategoryText(D);
4848 DiagCatStr = clang_getCString(string: DiagCat);
4849 if (DiagCatStr) {
4850 fprintf(stderr, format: " [%s]", DiagCatStr);
4851 }
4852
4853 fprintf(stderr, format: "\n");
4854
4855 printRanges(D, indent);
4856 printFixIts(D, indent);
4857
4858 /* Print subdiagnostics. */
4859 printDiagnosticSet(Diags: clang_getChildDiagnostics(D), indent: indent+2);
4860
4861 clang_disposeString(string: FileName);
4862 clang_disposeString(string: DiagSpelling);
4863 clang_disposeString(string: DiagOption);
4864 clang_disposeString(string: DiagCat);
4865 }
4866}
4867
4868static int read_diagnostics(const char *filename) {
4869 enum CXLoadDiag_Error error;
4870 CXString errorString;
4871 CXDiagnosticSet Diags = 0;
4872
4873 Diags = clang_loadDiagnostics(file: filename, error: &error, errorString: &errorString);
4874 if (!Diags) {
4875 fprintf(stderr, format: "Trouble deserializing file (%s): %s\n",
4876 getDiagnosticCodeStr(error),
4877 clang_getCString(string: errorString));
4878 clang_disposeString(string: errorString);
4879 return 1;
4880 }
4881
4882 printDiagnosticSet(Diags, indent: 0);
4883 fprintf(stderr, format: "Number of diagnostics: %d\n",
4884 clang_getNumDiagnosticsInSet(Diags));
4885 clang_disposeDiagnosticSet(Diags);
4886 return 0;
4887}
4888
4889static int perform_print_build_session_timestamp(void) {
4890 printf(format: "%lld\n", clang_getBuildSessionTimestamp());
4891 return 0;
4892}
4893
4894static int perform_test_single_symbol_sgf(const char *input, int argc,
4895 const char *argv[]) {
4896 CXIndex Idx;
4897 CXTranslationUnit TU;
4898 CXAPISet API;
4899 struct CXUnsavedFile *unsaved_files = 0;
4900 int num_unsaved_files = 0;
4901 enum CXErrorCode Err;
4902 int result = 0;
4903 CXString SGF;
4904 const char *usr;
4905
4906 usr = input + strlen(s: "-single-symbol-sgf-for=");
4907
4908 Idx = createIndexWithInvocationEmissionPath(/* excludeDeclsFromPCH */ ExcludeDeclarationsFromPCH: 1,
4909 /* displayDiagnostics=*/DisplayDiagnostics: 0);
4910 if (!Idx)
4911 return -1;
4912
4913 if (parse_remapped_files(argc, argv, start_arg: 0, unsaved_files: &unsaved_files, num_unsaved_files: &num_unsaved_files)) {
4914 result = -1;
4915 goto dispose_index;
4916 }
4917
4918 Err = clang_parseTranslationUnit2(
4919 CIdx: Idx, source_filename: 0, command_line_args: argv + num_unsaved_files, num_command_line_args: argc - num_unsaved_files, unsaved_files,
4920 num_unsaved_files, options: getDefaultParsingOptions(), out_TU: &TU);
4921 if (Err != CXError_Success) {
4922 fprintf(stderr, format: "Unable to load translation unit!\n");
4923 describeLibclangFailure(Err);
4924 result = 1;
4925 goto free_remapped_files;
4926 }
4927
4928 Err = clang_createAPISet(tu: TU, out_api: &API);
4929 if (Err != CXError_Success) {
4930 fprintf(stderr,
4931 format: "Unable to create API Set for API information extraction!\n");
4932 result = 2;
4933 goto dispose_tu;
4934 }
4935
4936 SGF = clang_getSymbolGraphForUSR(usr, api: API);
4937 printf(format: "%s", clang_getCString(string: SGF));
4938
4939 clang_disposeString(string: SGF);
4940 clang_disposeAPISet(api: API);
4941dispose_tu:
4942 clang_disposeTranslationUnit(TU);
4943free_remapped_files:
4944 free_remapped_files(unsaved_files, num_unsaved_files);
4945dispose_index:
4946 clang_disposeIndex(index: Idx);
4947 return result;
4948}
4949
4950static void inspect_single_symbol_sgf_cursor(CXCursor Cursor) {
4951 CXSourceLocation CursorLoc;
4952 CXString SGFData;
4953 const char *SGF;
4954 unsigned line, column;
4955 CursorLoc = clang_getCursorLocation(Cursor);
4956 clang_getSpellingLocation(location: CursorLoc, file: 0, line: &line, column: &column, offset: 0);
4957
4958 SGFData = clang_getSymbolGraphForCursor(cursor: Cursor);
4959 SGF = clang_getCString(string: SGFData);
4960 if (SGF)
4961 printf(format: "%d:%d: %s\n", line, column, SGF);
4962
4963 clang_disposeString(string: SGFData);
4964}
4965
4966/******************************************************************************/
4967/* Command line processing. */
4968/******************************************************************************/
4969
4970static CXCursorVisitor GetVisitor(const char *s) {
4971 if (s[0] == '\0')
4972 return FilteredPrintingVisitor;
4973 if (strcmp(s1: s, s2: "-usrs") == 0)
4974 return USRVisitor;
4975 if (strncmp(s1: s, s2: "-memory-usage", n: 13) == 0)
4976 return GetVisitor(s: s + 13);
4977 return NULL;
4978}
4979
4980static void print_usage(void) {
4981 fprintf(stderr,
4982 format: "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
4983 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
4984 " c-index-test -cursor-at=<site> <compiler arguments>\n"
4985 " c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
4986 " c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
4987 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
4988 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
4989 fprintf(stderr,
4990 format: " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4991 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
4992 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
4993 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
4994 " c-index-test -test-file-scan <AST file> <source file> "
4995 "[FileCheck prefix]\n");
4996 fprintf(stderr,
4997 format: " c-index-test -test-load-tu <AST file> <symbol filter> "
4998 "[FileCheck prefix]\n"
4999 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
5000 "[FileCheck prefix]\n"
5001 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
5002 fprintf(stderr,
5003 format: " c-index-test -test-load-source-memory-usage "
5004 "<symbol filter> {<args>}*\n"
5005 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
5006 " {<args>}*\n"
5007 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
5008 " c-index-test -test-load-source-usrs-memory-usage "
5009 "<symbol filter> {<args>}*\n"
5010 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
5011 " c-index-test -test-inclusion-stack-source {<args>}*\n"
5012 " c-index-test -test-inclusion-stack-tu <AST file>\n");
5013 fprintf(stderr,
5014 format: " c-index-test -test-print-linkage-source {<args>}*\n"
5015 " c-index-test -test-print-visibility {<args>}*\n"
5016 " c-index-test -test-print-type {<args>}*\n"
5017 " c-index-test -test-print-type-size {<args>}*\n"
5018 " c-index-test -test-print-bitwidth {<args>}*\n"
5019 " c-index-test -test-print-target-info {<args>}*\n"
5020 " c-index-test -test-print-type-declaration {<args>}*\n"
5021 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
5022 " c-index-test -print-usr-file <file>\n");
5023 fprintf(stderr,
5024 format: " c-index-test -single-symbol-sgfs <symbol filter> {<args>*}\n"
5025 " c-index-test -single-symbol-sgf-at=<site> {<args>*}\n"
5026 " c-index-test -single-symbol-sgf-for=<usr> {<args>}*\n");
5027 fprintf(stderr,
5028 format: " c-index-test -write-pch <file> <compiler arguments>\n"
5029 " c-index-test -compilation-db [lookup <filename>] database\n");
5030 fprintf(stderr,
5031 format: " c-index-test -print-build-session-timestamp\n");
5032 fprintf(stderr,
5033 format: " c-index-test -read-diagnostics <file>\n\n");
5034 fprintf(stderr,
5035 format: " <symbol filter> values:\n%s",
5036 " all - load all symbols, including those from PCH\n"
5037 " local - load all symbols except those in PCH\n"
5038 " category - only load ObjC categories (non-PCH)\n"
5039 " interface - only load ObjC interfaces (non-PCH)\n"
5040 " protocol - only load ObjC protocols (non-PCH)\n"
5041 " function - only load functions (non-PCH)\n"
5042 " typedef - only load typdefs (non-PCH)\n"
5043 " scan-function - scan function bodies (non-PCH)\n\n");
5044}
5045
5046/***/
5047
5048int cindextest_main(int argc, const char **argv) {
5049 clang_enableStackTraces();
5050 if (argc > 2 && strcmp(s1: argv[1], s2: "-read-diagnostics") == 0)
5051 return read_diagnostics(filename: argv[2]);
5052 if (argc > 2 && strstr(haystack: argv[1], needle: "-code-completion-at=") == argv[1])
5053 return perform_code_completion(argc, argv, timing_only: 0);
5054 if (argc > 2 && strstr(haystack: argv[1], needle: "-code-completion-timing=") == argv[1])
5055 return perform_code_completion(argc, argv, timing_only: 1);
5056 if (argc > 2 && strstr(haystack: argv[1], needle: "-cursor-at=") == argv[1])
5057 return inspect_cursor_at(argc, argv, locations_flag: "-cursor-at=", handler: inspect_print_cursor);
5058 if (argc > 2 && strstr(haystack: argv[1], needle: "-evaluate-cursor-at=") == argv[1])
5059 return inspect_cursor_at(argc, argv, locations_flag: "-evaluate-cursor-at=",
5060 handler: inspect_evaluate_cursor);
5061 if (argc > 2 && strstr(haystack: argv[1], needle: "-get-macro-info-cursor-at=") == argv[1])
5062 return inspect_cursor_at(argc, argv, locations_flag: "-get-macro-info-cursor-at=",
5063 handler: inspect_macroinfo_cursor);
5064 if (argc > 2 && strstr(haystack: argv[1], needle: "-file-refs-at=") == argv[1])
5065 return find_file_refs_at(argc, argv);
5066 if (argc > 2 && strstr(haystack: argv[1], needle: "-file-includes-in=") == argv[1])
5067 return find_file_includes_in(argc, argv);
5068 if (argc > 2 && strcmp(s1: argv[1], s2: "-index-file") == 0)
5069 return index_file(argc: argc - 2, argv: argv + 2, /*full=*/0);
5070 if (argc > 2 && strcmp(s1: argv[1], s2: "-index-file-full") == 0)
5071 return index_file(argc: argc - 2, argv: argv + 2, /*full=*/1);
5072 if (argc > 2 && strcmp(s1: argv[1], s2: "-index-tu") == 0)
5073 return index_tu(argc: argc - 2, argv: argv + 2);
5074 if (argc > 2 && strcmp(s1: argv[1], s2: "-index-compile-db") == 0)
5075 return index_compile_db(argc: argc - 2, argv: argv + 2);
5076 else if (argc >= 4 && strncmp(s1: argv[1], s2: "-test-load-tu", n: 13) == 0) {
5077 CXCursorVisitor I = GetVisitor(s: argv[1] + 13);
5078 if (I)
5079 return perform_test_load_tu(file: argv[2], filter: argv[3], prefix: argc >= 5 ? argv[4] : 0, Visitor: I,
5080 NULL);
5081 }
5082 else if (argc >= 5 && strncmp(s1: argv[1], s2: "-test-load-source-reparse", n: 25) == 0){
5083 CXCursorVisitor I = GetVisitor(s: argv[1] + 25);
5084 if (I) {
5085 int trials = atoi(nptr: argv[2]);
5086 return perform_test_reparse_source(argc: argc - 4, argv: argv + 4, trials, filter: argv[3], Visitor: I,
5087 NULL);
5088 }
5089 }
5090 else if (argc >= 4 && strncmp(s1: argv[1], s2: "-test-load-source", n: 17) == 0) {
5091 CXCursorVisitor I = GetVisitor(s: argv[1] + 17);
5092
5093 PostVisitTU postVisit = 0;
5094 if (strstr(haystack: argv[1], needle: "-memory-usage"))
5095 postVisit = PrintMemoryUsage;
5096
5097 if (I)
5098 return perform_test_load_source(argc: argc - 3, argv: argv + 3, filter: argv[2], Visitor: I,
5099 PV: postVisit);
5100 }
5101 else if (argc >= 3 && strcmp(s1: argv[1], s2: "-single-file-parse") == 0)
5102 return perform_single_file_parse(filename: argv[2]);
5103 else if (argc >= 3 && strcmp(s1: argv[1], s2: "-retain-excluded-conditional-blocks") == 0)
5104 return perform_file_retain_excluded_cb(filename: argv[2]);
5105 else if (argc >= 4 && strcmp(s1: argv[1], s2: "-test-file-scan") == 0)
5106 return perform_file_scan(ast_file: argv[2], source_file: argv[3],
5107 prefix: argc >= 5 ? argv[4] : 0);
5108 else if (argc > 2 && strstr(haystack: argv[1], needle: "-test-annotate-tokens=") == argv[1])
5109 return perform_token_annotation(argc, argv);
5110 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-inclusion-stack-source") == 0)
5111 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all", NULL,
5112 PV: PrintInclusionStack);
5113 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-inclusion-stack-tu") == 0)
5114 return perform_test_load_tu(file: argv[2], filter: "all", NULL, NULL,
5115 PV: PrintInclusionStack);
5116 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-linkage-source") == 0)
5117 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all", Visitor: PrintLinkage,
5118 NULL);
5119 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-visibility") == 0)
5120 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all", Visitor: PrintVisibility,
5121 NULL);
5122 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-type") == 0)
5123 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all",
5124 Visitor: PrintType, PV: 0);
5125 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-type-size") == 0)
5126 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all",
5127 Visitor: PrintTypeSize, PV: 0);
5128 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-type-declaration") == 0)
5129 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all",
5130 Visitor: PrintTypeDeclaration, PV: 0);
5131 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-decl-attributes") == 0)
5132 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all",
5133 Visitor: PrintDeclAttributes, PV: 0);
5134 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-bitwidth") == 0)
5135 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all",
5136 Visitor: PrintBitWidth, PV: 0);
5137 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-binops") == 0)
5138 return perform_test_load_source(argc: argc - 2, argv: argv + 2, filter: "all", Visitor: PrintBinOps, PV: 0);
5139 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-mangle") == 0)
5140 return perform_test_load_tu(file: argv[2], filter: "all", NULL, Visitor: PrintMangledName, NULL);
5141 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-manglings") == 0)
5142 return perform_test_load_tu(file: argv[2], filter: "all", NULL, Visitor: PrintManglings, NULL);
5143 else if (argc > 2 && strcmp(s1: argv[1], s2: "-test-print-target-info") == 0)
5144 return print_target_info(argc: argc - 2, argv: argv + 2);
5145 else if (argc > 1 && strcmp(s1: argv[1], s2: "-print-usr") == 0) {
5146 if (argc > 2)
5147 return print_usrs(I: argv + 2, E: argv + argc);
5148 else {
5149 display_usrs();
5150 return 1;
5151 }
5152 }
5153 else if (argc > 2 && strcmp(s1: argv[1], s2: "-print-usr-file") == 0)
5154 return print_usrs_file(file_name: argv[2]);
5155 else if (argc > 2 && strcmp(s1: argv[1], s2: "-write-pch") == 0)
5156 return write_pch_file(filename: argv[2], argc: argc - 3, argv: argv + 3);
5157 else if (argc > 2 && strcmp(s1: argv[1], s2: "-compilation-db") == 0)
5158 return perform_test_compilation_db(database: argv[argc-1], argc: argc - 3, argv: argv + 2);
5159 else if (argc == 2 && strcmp(s1: argv[1], s2: "-print-build-session-timestamp") == 0)
5160 return perform_print_build_session_timestamp();
5161 else if (argc > 3 && strcmp(s1: argv[1], s2: "-single-symbol-sgfs") == 0)
5162 return perform_test_load_source(argc: argc - 3, argv: argv + 3, filter: argv[2],
5163 Visitor: PrintSingleSymbolSGFs, NULL);
5164 else if (argc > 2 && strstr(haystack: argv[1], needle: "-single-symbol-sgf-at=") == argv[1])
5165 return inspect_cursor_at(
5166 argc, argv, locations_flag: "-single-symbol-sgf-at=", handler: inspect_single_symbol_sgf_cursor);
5167 else if (argc > 2 && strstr(haystack: argv[1], needle: "-single-symbol-sgf-for=") == argv[1])
5168 return perform_test_single_symbol_sgf(input: argv[1], argc: argc - 2, argv: argv + 2);
5169
5170 print_usage();
5171 return 1;
5172}
5173
5174/***/
5175
5176/* We intentionally run in a separate thread to ensure we at least minimal
5177 * testing of a multithreaded environment (for example, having a reduced stack
5178 * size). */
5179
5180typedef struct thread_info {
5181 int (*main_func)(int argc, const char **argv);
5182 int argc;
5183 const char **argv;
5184 int result;
5185} thread_info;
5186void thread_runner(void *client_data_v) {
5187 thread_info *client_data = client_data_v;
5188 client_data->result = client_data->main_func(client_data->argc,
5189 client_data->argv);
5190}
5191
5192static void flush_atexit(void) {
5193 /* stdout, and surprisingly even stderr, are not always flushed on process
5194 * and thread exit, particularly when the system is under heavy load. */
5195 fflush(stdout);
5196 fflush(stderr);
5197}
5198
5199int main(int argc, const char **argv) {
5200 thread_info client_data;
5201
5202#ifdef __MVS__
5203 if (enablezOSAutoConversion(fileno(stdout)) == -1)
5204 fprintf(stderr, "Setting conversion on stdout failed\n");
5205
5206 if (enablezOSAutoConversion(fileno(stderr)) == -1)
5207 fprintf(stderr, "Setting conversion on stderr failed\n");
5208#endif
5209
5210 atexit(func: flush_atexit);
5211
5212#ifdef CLANG_HAVE_LIBXML
5213 LIBXML_TEST_VERSION
5214#endif
5215
5216 if (argc > 1 && strcmp(s1: argv[1], s2: "core") == 0)
5217 return indextest_core_main(argc, argv);
5218
5219 client_data.main_func = cindextest_main;
5220 client_data.argc = argc;
5221 client_data.argv = argv;
5222
5223 if (getenv(name: "CINDEXTEST_NOTHREADS"))
5224 return client_data.main_func(client_data.argc, client_data.argv);
5225
5226 clang_executeOnThread(fn: thread_runner, user_data: &client_data, stack_size: 0);
5227 return client_data.result;
5228}
5229

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/tools/c-index-test/c-index-test.c