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