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