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