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