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