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