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