xref: /netbsd-src/external/apache2/llvm/dist/clang/tools/c-index-test/c-index-test.c (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg /* c-index-test.c */
27330f729Sjoerg 
37330f729Sjoerg #include "clang/Config/config.h"
47330f729Sjoerg #include "clang-c/Index.h"
57330f729Sjoerg #include "clang-c/CXCompilationDatabase.h"
67330f729Sjoerg #include "clang-c/BuildSystem.h"
77330f729Sjoerg #include "clang-c/Documentation.h"
87330f729Sjoerg #include <ctype.h>
97330f729Sjoerg #include <stdlib.h>
107330f729Sjoerg #include <stdio.h>
117330f729Sjoerg #include <string.h>
127330f729Sjoerg #include <assert.h>
137330f729Sjoerg 
147330f729Sjoerg #ifdef CLANG_HAVE_LIBXML
157330f729Sjoerg #include <libxml/parser.h>
167330f729Sjoerg #include <libxml/relaxng.h>
177330f729Sjoerg #include <libxml/xmlerror.h>
187330f729Sjoerg #endif
197330f729Sjoerg 
207330f729Sjoerg #ifdef _WIN32
217330f729Sjoerg #  include <direct.h>
227330f729Sjoerg #else
237330f729Sjoerg #  include <unistd.h>
247330f729Sjoerg #endif
257330f729Sjoerg 
267330f729Sjoerg extern int indextest_core_main(int argc, const char **argv);
27*e038c9c4Sjoerg extern int indextest_perform_shell_execution(const char *command_line);
287330f729Sjoerg 
297330f729Sjoerg /******************************************************************************/
307330f729Sjoerg /* Utility functions.                                                         */
317330f729Sjoerg /******************************************************************************/
327330f729Sjoerg 
337330f729Sjoerg #ifdef _MSC_VER
basename(const char * path)347330f729Sjoerg char *basename(const char* path)
357330f729Sjoerg {
367330f729Sjoerg     char* base1 = (char*)strrchr(path, '/');
377330f729Sjoerg     char* base2 = (char*)strrchr(path, '\\');
387330f729Sjoerg     if (base1 && base2)
397330f729Sjoerg         return((base1 > base2) ? base1 + 1 : base2 + 1);
407330f729Sjoerg     else if (base1)
417330f729Sjoerg         return(base1 + 1);
427330f729Sjoerg     else if (base2)
437330f729Sjoerg         return(base2 + 1);
447330f729Sjoerg 
457330f729Sjoerg     return((char*)path);
467330f729Sjoerg }
dirname(char * path)477330f729Sjoerg char *dirname(char* path)
487330f729Sjoerg {
497330f729Sjoerg     char* base1 = (char*)strrchr(path, '/');
507330f729Sjoerg     char* base2 = (char*)strrchr(path, '\\');
517330f729Sjoerg     if (base1 && base2)
527330f729Sjoerg         if (base1 > base2)
537330f729Sjoerg           *base1 = 0;
547330f729Sjoerg         else
557330f729Sjoerg           *base2 = 0;
567330f729Sjoerg     else if (base1)
577330f729Sjoerg         *base1 = 0;
587330f729Sjoerg     else if (base2)
597330f729Sjoerg         *base2 = 0;
607330f729Sjoerg 
617330f729Sjoerg     return path;
627330f729Sjoerg }
637330f729Sjoerg #else
647330f729Sjoerg extern char *basename(const char *);
657330f729Sjoerg extern char *dirname(char *);
667330f729Sjoerg #endif
677330f729Sjoerg 
687330f729Sjoerg /** Return the default parsing options. */
getDefaultParsingOptions()697330f729Sjoerg static unsigned getDefaultParsingOptions() {
707330f729Sjoerg   unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
717330f729Sjoerg 
727330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
737330f729Sjoerg     options |= clang_defaultEditingTranslationUnitOptions();
747330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_CACHING"))
757330f729Sjoerg     options |= CXTranslationUnit_CacheCompletionResults;
767330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
777330f729Sjoerg     options &= ~CXTranslationUnit_CacheCompletionResults;
787330f729Sjoerg   if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
797330f729Sjoerg     options |= CXTranslationUnit_SkipFunctionBodies;
807330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
817330f729Sjoerg     options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
827330f729Sjoerg   if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE"))
837330f729Sjoerg     options |= CXTranslationUnit_CreatePreambleOnFirstParse;
847330f729Sjoerg   if (getenv("CINDEXTEST_KEEP_GOING"))
857330f729Sjoerg     options |= CXTranslationUnit_KeepGoing;
867330f729Sjoerg   if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE"))
877330f729Sjoerg     options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble;
887330f729Sjoerg   if (getenv("CINDEXTEST_INCLUDE_ATTRIBUTED_TYPES"))
897330f729Sjoerg     options |= CXTranslationUnit_IncludeAttributedTypes;
907330f729Sjoerg   if (getenv("CINDEXTEST_VISIT_IMPLICIT_ATTRIBUTES"))
917330f729Sjoerg     options |= CXTranslationUnit_VisitImplicitAttributes;
927330f729Sjoerg   if (getenv("CINDEXTEST_IGNORE_NONERRORS_FROM_INCLUDED_FILES"))
937330f729Sjoerg     options |= CXTranslationUnit_IgnoreNonErrorsFromIncludedFiles;
947330f729Sjoerg 
957330f729Sjoerg   return options;
967330f729Sjoerg }
977330f729Sjoerg 
ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy)987330f729Sjoerg static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy) {
997330f729Sjoerg   struct Mapping {
1007330f729Sjoerg     const char *name;
1017330f729Sjoerg     enum CXPrintingPolicyProperty property;
1027330f729Sjoerg   };
1037330f729Sjoerg   struct Mapping mappings[] = {
1047330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_INDENTATION", CXPrintingPolicy_Indentation},
1057330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSPECIFIERS",
1067330f729Sjoerg        CXPrintingPolicy_SuppressSpecifiers},
1077330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTAGKEYWORD",
1087330f729Sjoerg        CXPrintingPolicy_SuppressTagKeyword},
1097330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_INCLUDETAGDEFINITION",
1107330f729Sjoerg        CXPrintingPolicy_IncludeTagDefinition},
1117330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSCOPE",
1127330f729Sjoerg        CXPrintingPolicy_SuppressScope},
1137330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSUNWRITTENSCOPE",
1147330f729Sjoerg        CXPrintingPolicy_SuppressUnwrittenScope},
1157330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSINITIALIZERS",
1167330f729Sjoerg        CXPrintingPolicy_SuppressInitializers},
1177330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_CONSTANTARRAYSIZEASWRITTEN",
1187330f729Sjoerg        CXPrintingPolicy_ConstantArraySizeAsWritten},
1197330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_ANONYMOUSTAGLOCATIONS",
1207330f729Sjoerg        CXPrintingPolicy_AnonymousTagLocations},
1217330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSSTRONGLIFETIME",
1227330f729Sjoerg        CXPrintingPolicy_SuppressStrongLifetime},
1237330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSLIFETIMEQUALIFIERS",
1247330f729Sjoerg        CXPrintingPolicy_SuppressLifetimeQualifiers},
1257330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSTEMPLATEARGSINCXXCONSTRUCTORS",
1267330f729Sjoerg        CXPrintingPolicy_SuppressTemplateArgsInCXXConstructors},
1277330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_BOOL", CXPrintingPolicy_Bool},
1287330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_RESTRICT", CXPrintingPolicy_Restrict},
1297330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_ALIGNOF", CXPrintingPolicy_Alignof},
1307330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_UNDERSCOREALIGNOF",
1317330f729Sjoerg        CXPrintingPolicy_UnderscoreAlignof},
1327330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_USEVOIDFORZEROPARAMS",
1337330f729Sjoerg        CXPrintingPolicy_UseVoidForZeroParams},
1347330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_TERSEOUTPUT", CXPrintingPolicy_TerseOutput},
1357330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_POLISHFORDECLARATION",
1367330f729Sjoerg        CXPrintingPolicy_PolishForDeclaration},
1377330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_HALF", CXPrintingPolicy_Half},
1387330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_MSWCHAR", CXPrintingPolicy_MSWChar},
1397330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_INCLUDENEWLINES",
1407330f729Sjoerg        CXPrintingPolicy_IncludeNewlines},
1417330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_MSVCFORMATTING",
1427330f729Sjoerg        CXPrintingPolicy_MSVCFormatting},
1437330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_CONSTANTSASWRITTEN",
1447330f729Sjoerg        CXPrintingPolicy_ConstantsAsWritten},
1457330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_SUPPRESSIMPLICITBASE",
1467330f729Sjoerg        CXPrintingPolicy_SuppressImplicitBase},
1477330f729Sjoerg       {"CINDEXTEST_PRINTINGPOLICY_FULLYQUALIFIEDNAME",
1487330f729Sjoerg        CXPrintingPolicy_FullyQualifiedName},
1497330f729Sjoerg   };
1507330f729Sjoerg 
1517330f729Sjoerg   unsigned i;
1527330f729Sjoerg   for (i = 0; i < sizeof(mappings) / sizeof(struct Mapping); i++) {
1537330f729Sjoerg     char *value = getenv(mappings[i].name);
1547330f729Sjoerg     if (value) {
1557330f729Sjoerg       clang_PrintingPolicy_setProperty(Policy, mappings[i].property,
1567330f729Sjoerg                                        (unsigned)strtoul(value, 0L, 10));
1577330f729Sjoerg     }
1587330f729Sjoerg   }
1597330f729Sjoerg }
1607330f729Sjoerg 
1617330f729Sjoerg /** Returns 0 in case of success, non-zero in case of a failure. */
1627330f729Sjoerg static int checkForErrors(CXTranslationUnit TU);
1637330f729Sjoerg 
describeLibclangFailure(enum CXErrorCode Err)1647330f729Sjoerg static void describeLibclangFailure(enum CXErrorCode Err) {
1657330f729Sjoerg   switch (Err) {
1667330f729Sjoerg   case CXError_Success:
1677330f729Sjoerg     fprintf(stderr, "Success\n");
1687330f729Sjoerg     return;
1697330f729Sjoerg 
1707330f729Sjoerg   case CXError_Failure:
1717330f729Sjoerg     fprintf(stderr, "Failure (no details available)\n");
1727330f729Sjoerg     return;
1737330f729Sjoerg 
1747330f729Sjoerg   case CXError_Crashed:
1757330f729Sjoerg     fprintf(stderr, "Failure: libclang crashed\n");
1767330f729Sjoerg     return;
1777330f729Sjoerg 
1787330f729Sjoerg   case CXError_InvalidArguments:
1797330f729Sjoerg     fprintf(stderr, "Failure: invalid arguments passed to a libclang routine\n");
1807330f729Sjoerg     return;
1817330f729Sjoerg 
1827330f729Sjoerg   case CXError_ASTReadError:
1837330f729Sjoerg     fprintf(stderr, "Failure: AST deserialization error occurred\n");
1847330f729Sjoerg     return;
1857330f729Sjoerg   }
1867330f729Sjoerg }
1877330f729Sjoerg 
PrintExtent(FILE * out,unsigned begin_line,unsigned begin_column,unsigned end_line,unsigned end_column)1887330f729Sjoerg static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
1897330f729Sjoerg                         unsigned end_line, unsigned end_column) {
1907330f729Sjoerg   fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
1917330f729Sjoerg           end_line, end_column);
1927330f729Sjoerg }
1937330f729Sjoerg 
CreateTranslationUnit(CXIndex Idx,const char * file,CXTranslationUnit * TU)1947330f729Sjoerg static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
1957330f729Sjoerg                                       CXTranslationUnit *TU) {
1967330f729Sjoerg   enum CXErrorCode Err = clang_createTranslationUnit2(Idx, file, TU);
1977330f729Sjoerg   if (Err != CXError_Success) {
1987330f729Sjoerg     fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
1997330f729Sjoerg     describeLibclangFailure(Err);
2007330f729Sjoerg     *TU = 0;
2017330f729Sjoerg     return 0;
2027330f729Sjoerg   }
2037330f729Sjoerg   return 1;
2047330f729Sjoerg }
2057330f729Sjoerg 
free_remapped_files(struct CXUnsavedFile * unsaved_files,int num_unsaved_files)2067330f729Sjoerg void free_remapped_files(struct CXUnsavedFile *unsaved_files,
2077330f729Sjoerg                          int num_unsaved_files) {
2087330f729Sjoerg   int i;
2097330f729Sjoerg   for (i = 0; i != num_unsaved_files; ++i) {
2107330f729Sjoerg     free((char *)unsaved_files[i].Filename);
2117330f729Sjoerg     free((char *)unsaved_files[i].Contents);
2127330f729Sjoerg   }
2137330f729Sjoerg   free(unsaved_files);
2147330f729Sjoerg }
2157330f729Sjoerg 
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)2167330f729Sjoerg static int parse_remapped_files_with_opt(const char *opt_name,
2177330f729Sjoerg                                          int argc, const char **argv,
2187330f729Sjoerg                                          int start_arg,
2197330f729Sjoerg                                          struct CXUnsavedFile **unsaved_files,
2207330f729Sjoerg                                          int *num_unsaved_files) {
2217330f729Sjoerg   int i;
2227330f729Sjoerg   int arg;
2237330f729Sjoerg   int prefix_len = strlen(opt_name);
2247330f729Sjoerg   int arg_indices[20];
2257330f729Sjoerg   *unsaved_files = 0;
2267330f729Sjoerg   *num_unsaved_files = 0;
2277330f729Sjoerg 
2287330f729Sjoerg   /* Count the number of remapped files. */
2297330f729Sjoerg   for (arg = start_arg; arg < argc; ++arg) {
2307330f729Sjoerg     if (strncmp(argv[arg], opt_name, prefix_len))
2317330f729Sjoerg       continue;
2327330f729Sjoerg 
2337330f729Sjoerg     assert(*num_unsaved_files < (int)(sizeof(arg_indices)/sizeof(int)));
2347330f729Sjoerg     arg_indices[*num_unsaved_files] = arg;
2357330f729Sjoerg     ++*num_unsaved_files;
2367330f729Sjoerg   }
2377330f729Sjoerg 
2387330f729Sjoerg   if (*num_unsaved_files == 0)
2397330f729Sjoerg     return 0;
2407330f729Sjoerg 
2417330f729Sjoerg   *unsaved_files
2427330f729Sjoerg     = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
2437330f729Sjoerg                                      *num_unsaved_files);
2447330f729Sjoerg   assert(*unsaved_files);
2457330f729Sjoerg   for (i = 0; i != *num_unsaved_files; ++i) {
2467330f729Sjoerg     struct CXUnsavedFile *unsaved = *unsaved_files + i;
2477330f729Sjoerg     const char *arg_string = argv[arg_indices[i]] + prefix_len;
2487330f729Sjoerg     int filename_len;
2497330f729Sjoerg     char *filename;
2507330f729Sjoerg     char *contents;
2517330f729Sjoerg     FILE *to_file;
2527330f729Sjoerg     const char *sep = strchr(arg_string, ',');
2537330f729Sjoerg     if (!sep) {
2547330f729Sjoerg       fprintf(stderr,
2557330f729Sjoerg               "error: %sfrom:to argument is missing comma\n", opt_name);
2567330f729Sjoerg       free_remapped_files(*unsaved_files, i);
2577330f729Sjoerg       *unsaved_files = 0;
2587330f729Sjoerg       *num_unsaved_files = 0;
2597330f729Sjoerg       return -1;
2607330f729Sjoerg     }
2617330f729Sjoerg 
2627330f729Sjoerg     /* Open the file that we're remapping to. */
2637330f729Sjoerg     to_file = fopen(sep + 1, "rb");
2647330f729Sjoerg     if (!to_file) {
2657330f729Sjoerg       fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
2667330f729Sjoerg               sep + 1);
2677330f729Sjoerg       free_remapped_files(*unsaved_files, i);
2687330f729Sjoerg       *unsaved_files = 0;
2697330f729Sjoerg       *num_unsaved_files = 0;
2707330f729Sjoerg       return -1;
2717330f729Sjoerg     }
2727330f729Sjoerg 
2737330f729Sjoerg     /* Determine the length of the file we're remapping to. */
2747330f729Sjoerg     fseek(to_file, 0, SEEK_END);
2757330f729Sjoerg     unsaved->Length = ftell(to_file);
2767330f729Sjoerg     fseek(to_file, 0, SEEK_SET);
2777330f729Sjoerg 
2787330f729Sjoerg     /* Read the contents of the file we're remapping to. */
2797330f729Sjoerg     contents = (char *)malloc(unsaved->Length + 1);
2807330f729Sjoerg     assert(contents);
2817330f729Sjoerg     if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
2827330f729Sjoerg       fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
2837330f729Sjoerg               (feof(to_file) ? "EOF" : "error"), sep + 1);
2847330f729Sjoerg       fclose(to_file);
2857330f729Sjoerg       free_remapped_files(*unsaved_files, i);
2867330f729Sjoerg       free(contents);
2877330f729Sjoerg       *unsaved_files = 0;
2887330f729Sjoerg       *num_unsaved_files = 0;
2897330f729Sjoerg       return -1;
2907330f729Sjoerg     }
2917330f729Sjoerg     contents[unsaved->Length] = 0;
2927330f729Sjoerg     unsaved->Contents = contents;
2937330f729Sjoerg 
2947330f729Sjoerg     /* Close the file. */
2957330f729Sjoerg     fclose(to_file);
2967330f729Sjoerg 
2977330f729Sjoerg     /* Copy the file name that we're remapping from. */
2987330f729Sjoerg     filename_len = sep - arg_string;
2997330f729Sjoerg     filename = (char *)malloc(filename_len + 1);
3007330f729Sjoerg     assert(filename);
3017330f729Sjoerg     memcpy(filename, arg_string, filename_len);
3027330f729Sjoerg     filename[filename_len] = 0;
3037330f729Sjoerg     unsaved->Filename = filename;
3047330f729Sjoerg   }
3057330f729Sjoerg 
3067330f729Sjoerg   return 0;
3077330f729Sjoerg }
3087330f729Sjoerg 
parse_remapped_files(int argc,const char ** argv,int start_arg,struct CXUnsavedFile ** unsaved_files,int * num_unsaved_files)3097330f729Sjoerg static int parse_remapped_files(int argc, const char **argv, int start_arg,
3107330f729Sjoerg                                 struct CXUnsavedFile **unsaved_files,
3117330f729Sjoerg                                 int *num_unsaved_files) {
3127330f729Sjoerg   return parse_remapped_files_with_opt("-remap-file=", argc, argv, start_arg,
3137330f729Sjoerg       unsaved_files, num_unsaved_files);
3147330f729Sjoerg }
3157330f729Sjoerg 
parse_remapped_files_with_try(int try_idx,int argc,const char ** argv,int start_arg,struct CXUnsavedFile ** unsaved_files,int * num_unsaved_files)3167330f729Sjoerg static int parse_remapped_files_with_try(int try_idx,
3177330f729Sjoerg                                          int argc, const char **argv,
3187330f729Sjoerg                                          int start_arg,
3197330f729Sjoerg                                          struct CXUnsavedFile **unsaved_files,
3207330f729Sjoerg                                          int *num_unsaved_files) {
3217330f729Sjoerg   struct CXUnsavedFile *unsaved_files_no_try_idx;
3227330f729Sjoerg   int num_unsaved_files_no_try_idx;
3237330f729Sjoerg   struct CXUnsavedFile *unsaved_files_try_idx;
3247330f729Sjoerg   int num_unsaved_files_try_idx;
3257330f729Sjoerg   int ret;
3267330f729Sjoerg   char opt_name[32];
3277330f729Sjoerg 
3287330f729Sjoerg   ret = parse_remapped_files(argc, argv, start_arg,
3297330f729Sjoerg       &unsaved_files_no_try_idx, &num_unsaved_files_no_try_idx);
3307330f729Sjoerg   if (ret)
3317330f729Sjoerg     return ret;
3327330f729Sjoerg 
3337330f729Sjoerg   sprintf(opt_name, "-remap-file-%d=", try_idx);
3347330f729Sjoerg   ret = parse_remapped_files_with_opt(opt_name, argc, argv, start_arg,
3357330f729Sjoerg       &unsaved_files_try_idx, &num_unsaved_files_try_idx);
3367330f729Sjoerg   if (ret)
3377330f729Sjoerg     return ret;
3387330f729Sjoerg 
3397330f729Sjoerg   if (num_unsaved_files_no_try_idx == 0) {
3407330f729Sjoerg     *unsaved_files = unsaved_files_try_idx;
3417330f729Sjoerg     *num_unsaved_files = num_unsaved_files_try_idx;
3427330f729Sjoerg     return 0;
3437330f729Sjoerg   }
3447330f729Sjoerg   if (num_unsaved_files_try_idx == 0) {
3457330f729Sjoerg     *unsaved_files = unsaved_files_no_try_idx;
3467330f729Sjoerg     *num_unsaved_files = num_unsaved_files_no_try_idx;
3477330f729Sjoerg     return 0;
3487330f729Sjoerg   }
3497330f729Sjoerg 
3507330f729Sjoerg   *num_unsaved_files = num_unsaved_files_no_try_idx + num_unsaved_files_try_idx;
3517330f729Sjoerg   *unsaved_files
3527330f729Sjoerg     = (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
3537330f729Sjoerg                                       sizeof(struct CXUnsavedFile) *
3547330f729Sjoerg                                         *num_unsaved_files);
3557330f729Sjoerg   assert(*unsaved_files);
3567330f729Sjoerg   memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
3577330f729Sjoerg          unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
3587330f729Sjoerg             num_unsaved_files_try_idx);
3597330f729Sjoerg   free(unsaved_files_try_idx);
3607330f729Sjoerg   return 0;
3617330f729Sjoerg }
3627330f729Sjoerg 
parse_comments_schema(int argc,const char ** argv)3637330f729Sjoerg static const char *parse_comments_schema(int argc, const char **argv) {
3647330f729Sjoerg   const char *CommentsSchemaArg = "-comments-xml-schema=";
3657330f729Sjoerg   const char *CommentSchemaFile = NULL;
3667330f729Sjoerg 
3677330f729Sjoerg   if (argc == 0)
3687330f729Sjoerg     return CommentSchemaFile;
3697330f729Sjoerg 
3707330f729Sjoerg   if (!strncmp(argv[0], CommentsSchemaArg, strlen(CommentsSchemaArg)))
3717330f729Sjoerg     CommentSchemaFile = argv[0] + strlen(CommentsSchemaArg);
3727330f729Sjoerg 
3737330f729Sjoerg   return CommentSchemaFile;
3747330f729Sjoerg }
3757330f729Sjoerg 
3767330f729Sjoerg /******************************************************************************/
3777330f729Sjoerg /* Pretty-printing.                                                           */
3787330f729Sjoerg /******************************************************************************/
3797330f729Sjoerg 
3807330f729Sjoerg static const char *FileCheckPrefix = "CHECK";
3817330f729Sjoerg 
PrintCString(const char * CStr)3827330f729Sjoerg static void PrintCString(const char *CStr) {
3837330f729Sjoerg   if (CStr != NULL && CStr[0] != '\0') {
3847330f729Sjoerg     for ( ; *CStr; ++CStr) {
3857330f729Sjoerg       const char C = *CStr;
3867330f729Sjoerg       switch (C) {
3877330f729Sjoerg         case '\n': printf("\\n"); break;
3887330f729Sjoerg         case '\r': printf("\\r"); break;
3897330f729Sjoerg         case '\t': printf("\\t"); break;
3907330f729Sjoerg         case '\v': printf("\\v"); break;
3917330f729Sjoerg         case '\f': printf("\\f"); break;
3927330f729Sjoerg         default:   putchar(C);    break;
3937330f729Sjoerg       }
3947330f729Sjoerg     }
3957330f729Sjoerg   }
3967330f729Sjoerg }
3977330f729Sjoerg 
PrintCStringWithPrefix(const char * Prefix,const char * CStr)3987330f729Sjoerg static void PrintCStringWithPrefix(const char *Prefix, const char *CStr) {
3997330f729Sjoerg   printf(" %s=[", Prefix);
4007330f729Sjoerg   PrintCString(CStr);
4017330f729Sjoerg   printf("]");
4027330f729Sjoerg }
4037330f729Sjoerg 
PrintCXStringAndDispose(CXString Str)4047330f729Sjoerg static void PrintCXStringAndDispose(CXString Str) {
4057330f729Sjoerg   PrintCString(clang_getCString(Str));
4067330f729Sjoerg   clang_disposeString(Str);
4077330f729Sjoerg }
4087330f729Sjoerg 
PrintCXStringWithPrefix(const char * Prefix,CXString Str)4097330f729Sjoerg static void PrintCXStringWithPrefix(const char *Prefix, CXString Str) {
4107330f729Sjoerg   PrintCStringWithPrefix(Prefix, clang_getCString(Str));
4117330f729Sjoerg }
4127330f729Sjoerg 
PrintCXStringWithPrefixAndDispose(const char * Prefix,CXString Str)4137330f729Sjoerg static void PrintCXStringWithPrefixAndDispose(const char *Prefix,
4147330f729Sjoerg                                               CXString Str) {
4157330f729Sjoerg   PrintCStringWithPrefix(Prefix, clang_getCString(Str));
4167330f729Sjoerg   clang_disposeString(Str);
4177330f729Sjoerg }
4187330f729Sjoerg 
PrintRange(CXSourceRange R,const char * str)4197330f729Sjoerg static void PrintRange(CXSourceRange R, const char *str) {
4207330f729Sjoerg   CXFile begin_file, end_file;
4217330f729Sjoerg   unsigned begin_line, begin_column, end_line, end_column;
4227330f729Sjoerg 
4237330f729Sjoerg   clang_getSpellingLocation(clang_getRangeStart(R),
4247330f729Sjoerg                             &begin_file, &begin_line, &begin_column, 0);
4257330f729Sjoerg   clang_getSpellingLocation(clang_getRangeEnd(R),
4267330f729Sjoerg                             &end_file, &end_line, &end_column, 0);
4277330f729Sjoerg   if (!begin_file || !end_file)
4287330f729Sjoerg     return;
4297330f729Sjoerg 
4307330f729Sjoerg   if (str)
4317330f729Sjoerg     printf(" %s=", str);
4327330f729Sjoerg   PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
4337330f729Sjoerg }
4347330f729Sjoerg 
4357330f729Sjoerg static enum DisplayType {
4367330f729Sjoerg     DisplayType_Spelling,
4377330f729Sjoerg     DisplayType_DisplayName,
4387330f729Sjoerg     DisplayType_Pretty
4397330f729Sjoerg } wanted_display_type = DisplayType_Spelling;
4407330f729Sjoerg 
printVersion(const char * Prefix,CXVersion Version)4417330f729Sjoerg static void printVersion(const char *Prefix, CXVersion Version) {
4427330f729Sjoerg   if (Version.Major < 0)
4437330f729Sjoerg     return;
4447330f729Sjoerg   printf("%s%d", Prefix, Version.Major);
4457330f729Sjoerg 
4467330f729Sjoerg   if (Version.Minor < 0)
4477330f729Sjoerg     return;
4487330f729Sjoerg   printf(".%d", Version.Minor);
4497330f729Sjoerg 
4507330f729Sjoerg   if (Version.Subminor < 0)
4517330f729Sjoerg     return;
4527330f729Sjoerg   printf(".%d", Version.Subminor);
4537330f729Sjoerg }
4547330f729Sjoerg 
4557330f729Sjoerg struct CommentASTDumpingContext {
4567330f729Sjoerg   int IndentLevel;
4577330f729Sjoerg };
4587330f729Sjoerg 
DumpCXCommentInternal(struct CommentASTDumpingContext * Ctx,CXComment Comment)4597330f729Sjoerg static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
4607330f729Sjoerg                                   CXComment Comment) {
4617330f729Sjoerg   unsigned i;
4627330f729Sjoerg   unsigned e;
4637330f729Sjoerg   enum CXCommentKind Kind = clang_Comment_getKind(Comment);
4647330f729Sjoerg 
4657330f729Sjoerg   Ctx->IndentLevel++;
4667330f729Sjoerg   for (i = 0, e = Ctx->IndentLevel; i != e; ++i)
4677330f729Sjoerg     printf("  ");
4687330f729Sjoerg 
4697330f729Sjoerg   printf("(");
4707330f729Sjoerg   switch (Kind) {
4717330f729Sjoerg   case CXComment_Null:
4727330f729Sjoerg     printf("CXComment_Null");
4737330f729Sjoerg     break;
4747330f729Sjoerg   case CXComment_Text:
4757330f729Sjoerg     printf("CXComment_Text");
4767330f729Sjoerg     PrintCXStringWithPrefixAndDispose("Text",
4777330f729Sjoerg                                       clang_TextComment_getText(Comment));
4787330f729Sjoerg     if (clang_Comment_isWhitespace(Comment))
4797330f729Sjoerg       printf(" IsWhitespace");
4807330f729Sjoerg     if (clang_InlineContentComment_hasTrailingNewline(Comment))
4817330f729Sjoerg       printf(" HasTrailingNewline");
4827330f729Sjoerg     break;
4837330f729Sjoerg   case CXComment_InlineCommand:
4847330f729Sjoerg     printf("CXComment_InlineCommand");
4857330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
4867330f729Sjoerg         "CommandName",
4877330f729Sjoerg         clang_InlineCommandComment_getCommandName(Comment));
4887330f729Sjoerg     switch (clang_InlineCommandComment_getRenderKind(Comment)) {
4897330f729Sjoerg     case CXCommentInlineCommandRenderKind_Normal:
4907330f729Sjoerg       printf(" RenderNormal");
4917330f729Sjoerg       break;
4927330f729Sjoerg     case CXCommentInlineCommandRenderKind_Bold:
4937330f729Sjoerg       printf(" RenderBold");
4947330f729Sjoerg       break;
4957330f729Sjoerg     case CXCommentInlineCommandRenderKind_Monospaced:
4967330f729Sjoerg       printf(" RenderMonospaced");
4977330f729Sjoerg       break;
4987330f729Sjoerg     case CXCommentInlineCommandRenderKind_Emphasized:
4997330f729Sjoerg       printf(" RenderEmphasized");
5007330f729Sjoerg       break;
501*e038c9c4Sjoerg     case CXCommentInlineCommandRenderKind_Anchor:
502*e038c9c4Sjoerg       printf(" RenderAnchor");
503*e038c9c4Sjoerg       break;
5047330f729Sjoerg     }
5057330f729Sjoerg     for (i = 0, e = clang_InlineCommandComment_getNumArgs(Comment);
5067330f729Sjoerg          i != e; ++i) {
5077330f729Sjoerg       printf(" Arg[%u]=", i);
5087330f729Sjoerg       PrintCXStringAndDispose(
5097330f729Sjoerg           clang_InlineCommandComment_getArgText(Comment, i));
5107330f729Sjoerg     }
5117330f729Sjoerg     if (clang_InlineContentComment_hasTrailingNewline(Comment))
5127330f729Sjoerg       printf(" HasTrailingNewline");
5137330f729Sjoerg     break;
5147330f729Sjoerg   case CXComment_HTMLStartTag: {
5157330f729Sjoerg     unsigned NumAttrs;
5167330f729Sjoerg     printf("CXComment_HTMLStartTag");
5177330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
5187330f729Sjoerg         "Name",
5197330f729Sjoerg         clang_HTMLTagComment_getTagName(Comment));
5207330f729Sjoerg     NumAttrs = clang_HTMLStartTag_getNumAttrs(Comment);
5217330f729Sjoerg     if (NumAttrs != 0) {
5227330f729Sjoerg       printf(" Attrs:");
5237330f729Sjoerg       for (i = 0; i != NumAttrs; ++i) {
5247330f729Sjoerg         printf(" ");
5257330f729Sjoerg         PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment, i));
5267330f729Sjoerg         printf("=");
5277330f729Sjoerg         PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment, i));
5287330f729Sjoerg       }
5297330f729Sjoerg     }
5307330f729Sjoerg     if (clang_HTMLStartTagComment_isSelfClosing(Comment))
5317330f729Sjoerg       printf(" SelfClosing");
5327330f729Sjoerg     if (clang_InlineContentComment_hasTrailingNewline(Comment))
5337330f729Sjoerg       printf(" HasTrailingNewline");
5347330f729Sjoerg     break;
5357330f729Sjoerg   }
5367330f729Sjoerg   case CXComment_HTMLEndTag:
5377330f729Sjoerg     printf("CXComment_HTMLEndTag");
5387330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
5397330f729Sjoerg         "Name",
5407330f729Sjoerg         clang_HTMLTagComment_getTagName(Comment));
5417330f729Sjoerg     if (clang_InlineContentComment_hasTrailingNewline(Comment))
5427330f729Sjoerg       printf(" HasTrailingNewline");
5437330f729Sjoerg     break;
5447330f729Sjoerg   case CXComment_Paragraph:
5457330f729Sjoerg     printf("CXComment_Paragraph");
5467330f729Sjoerg     if (clang_Comment_isWhitespace(Comment))
5477330f729Sjoerg       printf(" IsWhitespace");
5487330f729Sjoerg     break;
5497330f729Sjoerg   case CXComment_BlockCommand:
5507330f729Sjoerg     printf("CXComment_BlockCommand");
5517330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
5527330f729Sjoerg         "CommandName",
5537330f729Sjoerg         clang_BlockCommandComment_getCommandName(Comment));
5547330f729Sjoerg     for (i = 0, e = clang_BlockCommandComment_getNumArgs(Comment);
5557330f729Sjoerg          i != e; ++i) {
5567330f729Sjoerg       printf(" Arg[%u]=", i);
5577330f729Sjoerg       PrintCXStringAndDispose(
5587330f729Sjoerg           clang_BlockCommandComment_getArgText(Comment, i));
5597330f729Sjoerg     }
5607330f729Sjoerg     break;
5617330f729Sjoerg   case CXComment_ParamCommand:
5627330f729Sjoerg     printf("CXComment_ParamCommand");
5637330f729Sjoerg     switch (clang_ParamCommandComment_getDirection(Comment)) {
5647330f729Sjoerg     case CXCommentParamPassDirection_In:
5657330f729Sjoerg       printf(" in");
5667330f729Sjoerg       break;
5677330f729Sjoerg     case CXCommentParamPassDirection_Out:
5687330f729Sjoerg       printf(" out");
5697330f729Sjoerg       break;
5707330f729Sjoerg     case CXCommentParamPassDirection_InOut:
5717330f729Sjoerg       printf(" in,out");
5727330f729Sjoerg       break;
5737330f729Sjoerg     }
5747330f729Sjoerg     if (clang_ParamCommandComment_isDirectionExplicit(Comment))
5757330f729Sjoerg       printf(" explicitly");
5767330f729Sjoerg     else
5777330f729Sjoerg       printf(" implicitly");
5787330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
5797330f729Sjoerg         "ParamName",
5807330f729Sjoerg         clang_ParamCommandComment_getParamName(Comment));
5817330f729Sjoerg     if (clang_ParamCommandComment_isParamIndexValid(Comment))
5827330f729Sjoerg       printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment));
5837330f729Sjoerg     else
5847330f729Sjoerg       printf(" ParamIndex=Invalid");
5857330f729Sjoerg     break;
5867330f729Sjoerg   case CXComment_TParamCommand:
5877330f729Sjoerg     printf("CXComment_TParamCommand");
5887330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
5897330f729Sjoerg         "ParamName",
5907330f729Sjoerg         clang_TParamCommandComment_getParamName(Comment));
5917330f729Sjoerg     if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
5927330f729Sjoerg       printf(" ParamPosition={");
5937330f729Sjoerg       for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
5947330f729Sjoerg            i != e; ++i) {
5957330f729Sjoerg         printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
5967330f729Sjoerg         if (i != e - 1)
5977330f729Sjoerg           printf(", ");
5987330f729Sjoerg       }
5997330f729Sjoerg       printf("}");
6007330f729Sjoerg     } else
6017330f729Sjoerg       printf(" ParamPosition=Invalid");
6027330f729Sjoerg     break;
6037330f729Sjoerg   case CXComment_VerbatimBlockCommand:
6047330f729Sjoerg     printf("CXComment_VerbatimBlockCommand");
6057330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
6067330f729Sjoerg         "CommandName",
6077330f729Sjoerg         clang_BlockCommandComment_getCommandName(Comment));
6087330f729Sjoerg     break;
6097330f729Sjoerg   case CXComment_VerbatimBlockLine:
6107330f729Sjoerg     printf("CXComment_VerbatimBlockLine");
6117330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
6127330f729Sjoerg         "Text",
6137330f729Sjoerg         clang_VerbatimBlockLineComment_getText(Comment));
6147330f729Sjoerg     break;
6157330f729Sjoerg   case CXComment_VerbatimLine:
6167330f729Sjoerg     printf("CXComment_VerbatimLine");
6177330f729Sjoerg     PrintCXStringWithPrefixAndDispose(
6187330f729Sjoerg         "Text",
6197330f729Sjoerg         clang_VerbatimLineComment_getText(Comment));
6207330f729Sjoerg     break;
6217330f729Sjoerg   case CXComment_FullComment:
6227330f729Sjoerg     printf("CXComment_FullComment");
6237330f729Sjoerg     break;
6247330f729Sjoerg   }
6257330f729Sjoerg   if (Kind != CXComment_Null) {
6267330f729Sjoerg     const unsigned NumChildren = clang_Comment_getNumChildren(Comment);
6277330f729Sjoerg     unsigned i;
6287330f729Sjoerg     for (i = 0; i != NumChildren; ++i) {
6297330f729Sjoerg       printf("\n// %s: ", FileCheckPrefix);
6307330f729Sjoerg       DumpCXCommentInternal(Ctx, clang_Comment_getChild(Comment, i));
6317330f729Sjoerg     }
6327330f729Sjoerg   }
6337330f729Sjoerg   printf(")");
6347330f729Sjoerg   Ctx->IndentLevel--;
6357330f729Sjoerg }
6367330f729Sjoerg 
DumpCXComment(CXComment Comment)6377330f729Sjoerg static void DumpCXComment(CXComment Comment) {
6387330f729Sjoerg   struct CommentASTDumpingContext Ctx;
6397330f729Sjoerg   Ctx.IndentLevel = 1;
6407330f729Sjoerg   printf("\n// %s:  CommentAST=[\n// %s:", FileCheckPrefix, FileCheckPrefix);
6417330f729Sjoerg   DumpCXCommentInternal(&Ctx, Comment);
6427330f729Sjoerg   printf("]");
6437330f729Sjoerg }
6447330f729Sjoerg 
ValidateCommentXML(const char * Str,const char * CommentSchemaFile)6457330f729Sjoerg static void ValidateCommentXML(const char *Str, const char *CommentSchemaFile) {
6467330f729Sjoerg #ifdef CLANG_HAVE_LIBXML
6477330f729Sjoerg   xmlRelaxNGParserCtxtPtr RNGParser;
6487330f729Sjoerg   xmlRelaxNGPtr Schema;
6497330f729Sjoerg   xmlDocPtr Doc;
6507330f729Sjoerg   xmlRelaxNGValidCtxtPtr ValidationCtxt;
6517330f729Sjoerg   int status;
6527330f729Sjoerg 
6537330f729Sjoerg   if (!CommentSchemaFile)
6547330f729Sjoerg     return;
6557330f729Sjoerg 
6567330f729Sjoerg   RNGParser = xmlRelaxNGNewParserCtxt(CommentSchemaFile);
6577330f729Sjoerg   if (!RNGParser) {
6587330f729Sjoerg     printf(" libXMLError");
6597330f729Sjoerg     return;
6607330f729Sjoerg   }
6617330f729Sjoerg   Schema = xmlRelaxNGParse(RNGParser);
6627330f729Sjoerg 
6637330f729Sjoerg   Doc = xmlParseDoc((const xmlChar *) Str);
6647330f729Sjoerg 
6657330f729Sjoerg   if (!Doc) {
6667330f729Sjoerg     xmlErrorPtr Error = xmlGetLastError();
6677330f729Sjoerg     printf(" CommentXMLInvalid [not well-formed XML: %s]", Error->message);
6687330f729Sjoerg     return;
6697330f729Sjoerg   }
6707330f729Sjoerg 
6717330f729Sjoerg   ValidationCtxt = xmlRelaxNGNewValidCtxt(Schema);
6727330f729Sjoerg   status = xmlRelaxNGValidateDoc(ValidationCtxt, Doc);
6737330f729Sjoerg   if (!status)
6747330f729Sjoerg     printf(" CommentXMLValid");
6757330f729Sjoerg   else if (status > 0) {
6767330f729Sjoerg     xmlErrorPtr Error = xmlGetLastError();
6777330f729Sjoerg     printf(" CommentXMLInvalid [not valid XML: %s]", Error->message);
6787330f729Sjoerg   } else
6797330f729Sjoerg     printf(" libXMLError");
6807330f729Sjoerg 
6817330f729Sjoerg   xmlRelaxNGFreeValidCtxt(ValidationCtxt);
6827330f729Sjoerg   xmlFreeDoc(Doc);
6837330f729Sjoerg   xmlRelaxNGFree(Schema);
6847330f729Sjoerg   xmlRelaxNGFreeParserCtxt(RNGParser);
6857330f729Sjoerg #endif
6867330f729Sjoerg }
6877330f729Sjoerg 
PrintCursorComments(CXCursor Cursor,const char * CommentSchemaFile)6887330f729Sjoerg static void PrintCursorComments(CXCursor Cursor,
6897330f729Sjoerg                                 const char *CommentSchemaFile) {
6907330f729Sjoerg   {
6917330f729Sjoerg     CXString RawComment;
6927330f729Sjoerg     const char *RawCommentCString;
6937330f729Sjoerg     CXString BriefComment;
6947330f729Sjoerg     const char *BriefCommentCString;
6957330f729Sjoerg 
6967330f729Sjoerg     RawComment = clang_Cursor_getRawCommentText(Cursor);
6977330f729Sjoerg     RawCommentCString = clang_getCString(RawComment);
6987330f729Sjoerg     if (RawCommentCString != NULL && RawCommentCString[0] != '\0') {
6997330f729Sjoerg       PrintCStringWithPrefix("RawComment", RawCommentCString);
7007330f729Sjoerg       PrintRange(clang_Cursor_getCommentRange(Cursor), "RawCommentRange");
7017330f729Sjoerg 
7027330f729Sjoerg       BriefComment = clang_Cursor_getBriefCommentText(Cursor);
7037330f729Sjoerg       BriefCommentCString = clang_getCString(BriefComment);
7047330f729Sjoerg       if (BriefCommentCString != NULL && BriefCommentCString[0] != '\0')
7057330f729Sjoerg         PrintCStringWithPrefix("BriefComment", BriefCommentCString);
7067330f729Sjoerg       clang_disposeString(BriefComment);
7077330f729Sjoerg     }
7087330f729Sjoerg     clang_disposeString(RawComment);
7097330f729Sjoerg   }
7107330f729Sjoerg 
7117330f729Sjoerg   {
7127330f729Sjoerg     CXComment Comment = clang_Cursor_getParsedComment(Cursor);
7137330f729Sjoerg     if (clang_Comment_getKind(Comment) != CXComment_Null) {
7147330f729Sjoerg       PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
7157330f729Sjoerg                                         clang_FullComment_getAsHTML(Comment));
7167330f729Sjoerg       {
7177330f729Sjoerg         CXString XML;
7187330f729Sjoerg         XML = clang_FullComment_getAsXML(Comment);
7197330f729Sjoerg         PrintCXStringWithPrefix("FullCommentAsXML", XML);
7207330f729Sjoerg         ValidateCommentXML(clang_getCString(XML), CommentSchemaFile);
7217330f729Sjoerg         clang_disposeString(XML);
7227330f729Sjoerg       }
7237330f729Sjoerg 
7247330f729Sjoerg       DumpCXComment(Comment);
7257330f729Sjoerg     }
7267330f729Sjoerg   }
7277330f729Sjoerg }
7287330f729Sjoerg 
7297330f729Sjoerg typedef struct {
7307330f729Sjoerg   unsigned line;
7317330f729Sjoerg   unsigned col;
7327330f729Sjoerg } LineCol;
7337330f729Sjoerg 
lineCol_cmp(const void * p1,const void * p2)7347330f729Sjoerg static int lineCol_cmp(const void *p1, const void *p2) {
7357330f729Sjoerg   const LineCol *lhs = p1;
7367330f729Sjoerg   const LineCol *rhs = p2;
7377330f729Sjoerg   if (lhs->line != rhs->line)
7387330f729Sjoerg     return (int)lhs->line - (int)rhs->line;
7397330f729Sjoerg   return (int)lhs->col - (int)rhs->col;
7407330f729Sjoerg }
7417330f729Sjoerg 
CursorToText(CXCursor Cursor)7427330f729Sjoerg static CXString CursorToText(CXCursor Cursor) {
7437330f729Sjoerg   CXString text;
7447330f729Sjoerg   switch (wanted_display_type) {
7457330f729Sjoerg   case DisplayType_Spelling:
7467330f729Sjoerg     return clang_getCursorSpelling(Cursor);
7477330f729Sjoerg   case DisplayType_DisplayName:
7487330f729Sjoerg     return clang_getCursorDisplayName(Cursor);
7497330f729Sjoerg   case DisplayType_Pretty: {
7507330f729Sjoerg     CXPrintingPolicy Policy = clang_getCursorPrintingPolicy(Cursor);
7517330f729Sjoerg     ModifyPrintingPolicyAccordingToEnv(Policy);
7527330f729Sjoerg     text = clang_getCursorPrettyPrinted(Cursor, Policy);
7537330f729Sjoerg     clang_PrintingPolicy_dispose(Policy);
7547330f729Sjoerg     return text;
7557330f729Sjoerg   }
7567330f729Sjoerg   }
7577330f729Sjoerg   assert(0 && "unknown display type"); /* no llvm_unreachable in C. */
7587330f729Sjoerg   /* Set to NULL to prevent uninitialized variable warnings. */
7597330f729Sjoerg   text.data = NULL;
7607330f729Sjoerg   text.private_flags = 0;
7617330f729Sjoerg   return text;
7627330f729Sjoerg }
7637330f729Sjoerg 
PrintCursor(CXCursor Cursor,const char * CommentSchemaFile)7647330f729Sjoerg static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) {
7657330f729Sjoerg   CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
7667330f729Sjoerg   if (clang_isInvalid(Cursor.kind)) {
7677330f729Sjoerg     CXString ks = clang_getCursorKindSpelling(Cursor.kind);
7687330f729Sjoerg     printf("Invalid Cursor => %s", clang_getCString(ks));
7697330f729Sjoerg     clang_disposeString(ks);
7707330f729Sjoerg   }
7717330f729Sjoerg   else {
7727330f729Sjoerg     CXString string, ks;
7737330f729Sjoerg     CXCursor Referenced;
7747330f729Sjoerg     unsigned line, column;
7757330f729Sjoerg     CXCursor SpecializationOf;
7767330f729Sjoerg     CXCursor *overridden;
7777330f729Sjoerg     unsigned num_overridden;
7787330f729Sjoerg     unsigned RefNameRangeNr;
7797330f729Sjoerg     CXSourceRange CursorExtent;
7807330f729Sjoerg     CXSourceRange RefNameRange;
7817330f729Sjoerg     int AlwaysUnavailable;
7827330f729Sjoerg     int AlwaysDeprecated;
7837330f729Sjoerg     CXString UnavailableMessage;
7847330f729Sjoerg     CXString DeprecatedMessage;
7857330f729Sjoerg     CXPlatformAvailability PlatformAvailability[2];
7867330f729Sjoerg     int NumPlatformAvailability;
7877330f729Sjoerg     int I;
7887330f729Sjoerg 
7897330f729Sjoerg     ks = clang_getCursorKindSpelling(Cursor.kind);
7907330f729Sjoerg     string = CursorToText(Cursor);
7917330f729Sjoerg     printf("%s=%s", clang_getCString(ks),
7927330f729Sjoerg                     clang_getCString(string));
7937330f729Sjoerg     clang_disposeString(ks);
7947330f729Sjoerg     clang_disposeString(string);
7957330f729Sjoerg 
7967330f729Sjoerg     Referenced = clang_getCursorReferenced(Cursor);
7977330f729Sjoerg     if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
7987330f729Sjoerg       if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) {
7997330f729Sjoerg         unsigned I, N = clang_getNumOverloadedDecls(Referenced);
8007330f729Sjoerg         printf("[");
8017330f729Sjoerg         for (I = 0; I != N; ++I) {
8027330f729Sjoerg           CXCursor Ovl = clang_getOverloadedDecl(Referenced, I);
8037330f729Sjoerg           CXSourceLocation Loc;
8047330f729Sjoerg           if (I)
8057330f729Sjoerg             printf(", ");
8067330f729Sjoerg 
8077330f729Sjoerg           Loc = clang_getCursorLocation(Ovl);
8087330f729Sjoerg           clang_getSpellingLocation(Loc, 0, &line, &column, 0);
8097330f729Sjoerg           printf("%d:%d", line, column);
8107330f729Sjoerg         }
8117330f729Sjoerg         printf("]");
8127330f729Sjoerg       } else {
8137330f729Sjoerg         CXSourceLocation Loc = clang_getCursorLocation(Referenced);
8147330f729Sjoerg         clang_getSpellingLocation(Loc, 0, &line, &column, 0);
8157330f729Sjoerg         printf(":%d:%d", line, column);
8167330f729Sjoerg       }
8177330f729Sjoerg 
8187330f729Sjoerg       if (clang_getCursorKind(Referenced) == CXCursor_TypedefDecl) {
8197330f729Sjoerg         CXType T = clang_getCursorType(Referenced);
8207330f729Sjoerg         if (clang_Type_isTransparentTagTypedef(T)) {
8217330f729Sjoerg           CXType Underlying = clang_getTypedefDeclUnderlyingType(Referenced);
8227330f729Sjoerg           CXString S = clang_getTypeSpelling(Underlying);
8237330f729Sjoerg           printf(" (Transparent: %s)", clang_getCString(S));
8247330f729Sjoerg           clang_disposeString(S);
8257330f729Sjoerg         }
8267330f729Sjoerg       }
8277330f729Sjoerg     }
8287330f729Sjoerg 
8297330f729Sjoerg     if (clang_isCursorDefinition(Cursor))
8307330f729Sjoerg       printf(" (Definition)");
8317330f729Sjoerg 
8327330f729Sjoerg     switch (clang_getCursorAvailability(Cursor)) {
8337330f729Sjoerg       case CXAvailability_Available:
8347330f729Sjoerg         break;
8357330f729Sjoerg 
8367330f729Sjoerg       case CXAvailability_Deprecated:
8377330f729Sjoerg         printf(" (deprecated)");
8387330f729Sjoerg         break;
8397330f729Sjoerg 
8407330f729Sjoerg       case CXAvailability_NotAvailable:
8417330f729Sjoerg         printf(" (unavailable)");
8427330f729Sjoerg         break;
8437330f729Sjoerg 
8447330f729Sjoerg       case CXAvailability_NotAccessible:
8457330f729Sjoerg         printf(" (inaccessible)");
8467330f729Sjoerg         break;
8477330f729Sjoerg     }
8487330f729Sjoerg 
8497330f729Sjoerg     NumPlatformAvailability
8507330f729Sjoerg       = clang_getCursorPlatformAvailability(Cursor,
8517330f729Sjoerg                                             &AlwaysDeprecated,
8527330f729Sjoerg                                             &DeprecatedMessage,
8537330f729Sjoerg                                             &AlwaysUnavailable,
8547330f729Sjoerg                                             &UnavailableMessage,
8557330f729Sjoerg                                             PlatformAvailability, 2);
8567330f729Sjoerg     if (AlwaysUnavailable) {
8577330f729Sjoerg       printf("  (always unavailable: \"%s\")",
8587330f729Sjoerg              clang_getCString(UnavailableMessage));
8597330f729Sjoerg     } else if (AlwaysDeprecated) {
8607330f729Sjoerg       printf("  (always deprecated: \"%s\")",
8617330f729Sjoerg              clang_getCString(DeprecatedMessage));
8627330f729Sjoerg     } else {
8637330f729Sjoerg       for (I = 0; I != NumPlatformAvailability; ++I) {
8647330f729Sjoerg         if (I >= 2)
8657330f729Sjoerg           break;
8667330f729Sjoerg 
8677330f729Sjoerg         printf("  (%s", clang_getCString(PlatformAvailability[I].Platform));
8687330f729Sjoerg         if (PlatformAvailability[I].Unavailable)
8697330f729Sjoerg           printf(", unavailable");
8707330f729Sjoerg         else {
8717330f729Sjoerg           printVersion(", introduced=", PlatformAvailability[I].Introduced);
8727330f729Sjoerg           printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
8737330f729Sjoerg           printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
8747330f729Sjoerg         }
8757330f729Sjoerg         if (clang_getCString(PlatformAvailability[I].Message)[0])
8767330f729Sjoerg           printf(", message=\"%s\"",
8777330f729Sjoerg                  clang_getCString(PlatformAvailability[I].Message));
8787330f729Sjoerg         printf(")");
8797330f729Sjoerg       }
8807330f729Sjoerg     }
8817330f729Sjoerg     for (I = 0; I != NumPlatformAvailability; ++I) {
8827330f729Sjoerg       if (I >= 2)
8837330f729Sjoerg         break;
8847330f729Sjoerg       clang_disposeCXPlatformAvailability(PlatformAvailability + I);
8857330f729Sjoerg     }
8867330f729Sjoerg 
8877330f729Sjoerg     clang_disposeString(DeprecatedMessage);
8887330f729Sjoerg     clang_disposeString(UnavailableMessage);
8897330f729Sjoerg 
8907330f729Sjoerg     if (clang_CXXConstructor_isDefaultConstructor(Cursor))
8917330f729Sjoerg       printf(" (default constructor)");
8927330f729Sjoerg 
8937330f729Sjoerg     if (clang_CXXConstructor_isMoveConstructor(Cursor))
8947330f729Sjoerg       printf(" (move constructor)");
8957330f729Sjoerg     if (clang_CXXConstructor_isCopyConstructor(Cursor))
8967330f729Sjoerg       printf(" (copy constructor)");
8977330f729Sjoerg     if (clang_CXXConstructor_isConvertingConstructor(Cursor))
8987330f729Sjoerg       printf(" (converting constructor)");
8997330f729Sjoerg     if (clang_CXXField_isMutable(Cursor))
9007330f729Sjoerg       printf(" (mutable)");
9017330f729Sjoerg     if (clang_CXXMethod_isDefaulted(Cursor))
9027330f729Sjoerg       printf(" (defaulted)");
9037330f729Sjoerg     if (clang_CXXMethod_isStatic(Cursor))
9047330f729Sjoerg       printf(" (static)");
9057330f729Sjoerg     if (clang_CXXMethod_isVirtual(Cursor))
9067330f729Sjoerg       printf(" (virtual)");
9077330f729Sjoerg     if (clang_CXXMethod_isConst(Cursor))
9087330f729Sjoerg       printf(" (const)");
9097330f729Sjoerg     if (clang_CXXMethod_isPureVirtual(Cursor))
9107330f729Sjoerg       printf(" (pure)");
9117330f729Sjoerg     if (clang_CXXRecord_isAbstract(Cursor))
9127330f729Sjoerg       printf(" (abstract)");
9137330f729Sjoerg     if (clang_EnumDecl_isScoped(Cursor))
9147330f729Sjoerg       printf(" (scoped)");
9157330f729Sjoerg     if (clang_Cursor_isVariadic(Cursor))
9167330f729Sjoerg       printf(" (variadic)");
9177330f729Sjoerg     if (clang_Cursor_isObjCOptional(Cursor))
9187330f729Sjoerg       printf(" (@optional)");
9197330f729Sjoerg     if (clang_isInvalidDeclaration(Cursor))
9207330f729Sjoerg       printf(" (invalid)");
9217330f729Sjoerg 
9227330f729Sjoerg     switch (clang_getCursorExceptionSpecificationType(Cursor))
9237330f729Sjoerg     {
9247330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_None:
9257330f729Sjoerg         break;
9267330f729Sjoerg 
9277330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_DynamicNone:
9287330f729Sjoerg         printf(" (noexcept dynamic none)");
9297330f729Sjoerg         break;
9307330f729Sjoerg 
9317330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_Dynamic:
9327330f729Sjoerg         printf(" (noexcept dynamic)");
9337330f729Sjoerg         break;
9347330f729Sjoerg 
9357330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_MSAny:
9367330f729Sjoerg         printf(" (noexcept dynamic any)");
9377330f729Sjoerg         break;
9387330f729Sjoerg 
9397330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_BasicNoexcept:
9407330f729Sjoerg         printf(" (noexcept)");
9417330f729Sjoerg         break;
9427330f729Sjoerg 
9437330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_ComputedNoexcept:
9447330f729Sjoerg         printf(" (computed-noexcept)");
9457330f729Sjoerg         break;
9467330f729Sjoerg 
9477330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_Unevaluated:
9487330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_Uninstantiated:
9497330f729Sjoerg       case CXCursor_ExceptionSpecificationKind_Unparsed:
9507330f729Sjoerg         break;
9517330f729Sjoerg     }
9527330f729Sjoerg 
9537330f729Sjoerg     {
9547330f729Sjoerg       CXString language;
9557330f729Sjoerg       CXString definedIn;
9567330f729Sjoerg       unsigned generated;
9577330f729Sjoerg       if (clang_Cursor_isExternalSymbol(Cursor, &language, &definedIn,
9587330f729Sjoerg                                         &generated)) {
9597330f729Sjoerg         printf(" (external lang: %s, defined: %s, gen: %d)",
9607330f729Sjoerg             clang_getCString(language), clang_getCString(definedIn), generated);
9617330f729Sjoerg         clang_disposeString(language);
9627330f729Sjoerg         clang_disposeString(definedIn);
9637330f729Sjoerg       }
9647330f729Sjoerg     }
9657330f729Sjoerg 
9667330f729Sjoerg     if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
9677330f729Sjoerg       CXType T =
9687330f729Sjoerg         clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
9697330f729Sjoerg       CXString S = clang_getTypeKindSpelling(T.kind);
9707330f729Sjoerg       printf(" [IBOutletCollection=%s]", clang_getCString(S));
9717330f729Sjoerg       clang_disposeString(S);
9727330f729Sjoerg     }
9737330f729Sjoerg 
9747330f729Sjoerg     if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
9757330f729Sjoerg       enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
9767330f729Sjoerg       unsigned isVirtual = clang_isVirtualBase(Cursor);
9777330f729Sjoerg       const char *accessStr = 0;
9787330f729Sjoerg 
9797330f729Sjoerg       switch (access) {
9807330f729Sjoerg         case CX_CXXInvalidAccessSpecifier:
9817330f729Sjoerg           accessStr = "invalid"; break;
9827330f729Sjoerg         case CX_CXXPublic:
9837330f729Sjoerg           accessStr = "public"; break;
9847330f729Sjoerg         case CX_CXXProtected:
9857330f729Sjoerg           accessStr = "protected"; break;
9867330f729Sjoerg         case CX_CXXPrivate:
9877330f729Sjoerg           accessStr = "private"; break;
9887330f729Sjoerg       }
9897330f729Sjoerg 
9907330f729Sjoerg       printf(" [access=%s isVirtual=%s]", accessStr,
9917330f729Sjoerg              isVirtual ? "true" : "false");
9927330f729Sjoerg     }
9937330f729Sjoerg 
9947330f729Sjoerg     SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
9957330f729Sjoerg     if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
9967330f729Sjoerg       CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
9977330f729Sjoerg       CXString Name = clang_getCursorSpelling(SpecializationOf);
9987330f729Sjoerg       clang_getSpellingLocation(Loc, 0, &line, &column, 0);
9997330f729Sjoerg       printf(" [Specialization of %s:%d:%d]",
10007330f729Sjoerg              clang_getCString(Name), line, column);
10017330f729Sjoerg       clang_disposeString(Name);
10027330f729Sjoerg 
10037330f729Sjoerg       if (Cursor.kind == CXCursor_FunctionDecl) {
10047330f729Sjoerg         /* Collect the template parameter kinds from the base template. */
10057330f729Sjoerg         int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
10067330f729Sjoerg         int I;
10077330f729Sjoerg         if (NumTemplateArgs < 0) {
10087330f729Sjoerg           printf(" [no template arg info]");
10097330f729Sjoerg         }
10107330f729Sjoerg         for (I = 0; I < NumTemplateArgs; I++) {
10117330f729Sjoerg           enum CXTemplateArgumentKind TAK =
10127330f729Sjoerg               clang_Cursor_getTemplateArgumentKind(Cursor, I);
10137330f729Sjoerg           switch(TAK) {
10147330f729Sjoerg             case CXTemplateArgumentKind_Type:
10157330f729Sjoerg               {
10167330f729Sjoerg                 CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I);
10177330f729Sjoerg                 CXString S = clang_getTypeSpelling(T);
10187330f729Sjoerg                 printf(" [Template arg %d: kind: %d, type: %s]",
10197330f729Sjoerg                        I, TAK, clang_getCString(S));
10207330f729Sjoerg                 clang_disposeString(S);
10217330f729Sjoerg               }
10227330f729Sjoerg               break;
10237330f729Sjoerg             case CXTemplateArgumentKind_Integral:
10247330f729Sjoerg               printf(" [Template arg %d: kind: %d, intval: %lld]",
10257330f729Sjoerg                      I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I));
10267330f729Sjoerg               break;
10277330f729Sjoerg             default:
10287330f729Sjoerg               printf(" [Template arg %d: kind: %d]\n", I, TAK);
10297330f729Sjoerg           }
10307330f729Sjoerg         }
10317330f729Sjoerg       }
10327330f729Sjoerg     }
10337330f729Sjoerg 
10347330f729Sjoerg     clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
10357330f729Sjoerg     if (num_overridden) {
10367330f729Sjoerg       unsigned I;
10377330f729Sjoerg       LineCol lineCols[50];
10387330f729Sjoerg       assert(num_overridden <= 50);
10397330f729Sjoerg       printf(" [Overrides ");
10407330f729Sjoerg       for (I = 0; I != num_overridden; ++I) {
10417330f729Sjoerg         CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
10427330f729Sjoerg         clang_getSpellingLocation(Loc, 0, &line, &column, 0);
10437330f729Sjoerg         lineCols[I].line = line;
10447330f729Sjoerg         lineCols[I].col = column;
10457330f729Sjoerg       }
10467330f729Sjoerg       /* Make the order of the override list deterministic. */
10477330f729Sjoerg       qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
10487330f729Sjoerg       for (I = 0; I != num_overridden; ++I) {
10497330f729Sjoerg         if (I)
10507330f729Sjoerg           printf(", ");
10517330f729Sjoerg         printf("@%d:%d", lineCols[I].line, lineCols[I].col);
10527330f729Sjoerg       }
10537330f729Sjoerg       printf("]");
10547330f729Sjoerg       clang_disposeOverriddenCursors(overridden);
10557330f729Sjoerg     }
10567330f729Sjoerg 
10577330f729Sjoerg     if (Cursor.kind == CXCursor_InclusionDirective) {
10587330f729Sjoerg       CXFile File = clang_getIncludedFile(Cursor);
10597330f729Sjoerg       CXString Included = clang_getFileName(File);
10607330f729Sjoerg       const char *IncludedString = clang_getCString(Included);
10617330f729Sjoerg       printf(" (%s)", IncludedString ? IncludedString : "(null)");
10627330f729Sjoerg       clang_disposeString(Included);
10637330f729Sjoerg 
10647330f729Sjoerg       if (clang_isFileMultipleIncludeGuarded(TU, File))
10657330f729Sjoerg         printf("  [multi-include guarded]");
10667330f729Sjoerg     }
10677330f729Sjoerg 
10687330f729Sjoerg     CursorExtent = clang_getCursorExtent(Cursor);
10697330f729Sjoerg     RefNameRange = clang_getCursorReferenceNameRange(Cursor,
10707330f729Sjoerg                                                    CXNameRange_WantQualifier
10717330f729Sjoerg                                                  | CXNameRange_WantSinglePiece
10727330f729Sjoerg                                                  | CXNameRange_WantTemplateArgs,
10737330f729Sjoerg                                                      0);
10747330f729Sjoerg     if (!clang_equalRanges(CursorExtent, RefNameRange))
10757330f729Sjoerg       PrintRange(RefNameRange, "SingleRefName");
10767330f729Sjoerg 
10777330f729Sjoerg     for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
10787330f729Sjoerg       RefNameRange = clang_getCursorReferenceNameRange(Cursor,
10797330f729Sjoerg                                                    CXNameRange_WantQualifier
10807330f729Sjoerg                                                  | CXNameRange_WantTemplateArgs,
10817330f729Sjoerg                                                        RefNameRangeNr);
10827330f729Sjoerg       if (clang_equalRanges(clang_getNullRange(), RefNameRange))
10837330f729Sjoerg         break;
10847330f729Sjoerg       if (!clang_equalRanges(CursorExtent, RefNameRange))
10857330f729Sjoerg         PrintRange(RefNameRange, "RefName");
10867330f729Sjoerg     }
10877330f729Sjoerg 
10887330f729Sjoerg     PrintCursorComments(Cursor, CommentSchemaFile);
10897330f729Sjoerg 
10907330f729Sjoerg     {
10917330f729Sjoerg       unsigned PropAttrs = clang_Cursor_getObjCPropertyAttributes(Cursor, 0);
10927330f729Sjoerg       if (PropAttrs != CXObjCPropertyAttr_noattr) {
10937330f729Sjoerg         printf(" [");
10947330f729Sjoerg         #define PRINT_PROP_ATTR(A) \
10957330f729Sjoerg           if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
10967330f729Sjoerg         PRINT_PROP_ATTR(readonly);
10977330f729Sjoerg         PRINT_PROP_ATTR(getter);
10987330f729Sjoerg         PRINT_PROP_ATTR(assign);
10997330f729Sjoerg         PRINT_PROP_ATTR(readwrite);
11007330f729Sjoerg         PRINT_PROP_ATTR(retain);
11017330f729Sjoerg         PRINT_PROP_ATTR(copy);
11027330f729Sjoerg         PRINT_PROP_ATTR(nonatomic);
11037330f729Sjoerg         PRINT_PROP_ATTR(setter);
11047330f729Sjoerg         PRINT_PROP_ATTR(atomic);
11057330f729Sjoerg         PRINT_PROP_ATTR(weak);
11067330f729Sjoerg         PRINT_PROP_ATTR(strong);
11077330f729Sjoerg         PRINT_PROP_ATTR(unsafe_unretained);
11087330f729Sjoerg         PRINT_PROP_ATTR(class);
11097330f729Sjoerg         printf("]");
11107330f729Sjoerg       }
11117330f729Sjoerg     }
11127330f729Sjoerg 
11137330f729Sjoerg     if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
11147330f729Sjoerg       CXString Name = clang_Cursor_getObjCPropertyGetterName(Cursor);
11157330f729Sjoerg       CXString Spelling = clang_getCursorSpelling(Cursor);
11167330f729Sjoerg       const char *CName = clang_getCString(Name);
11177330f729Sjoerg       const char *CSpelling = clang_getCString(Spelling);
11187330f729Sjoerg       if (CName && strcmp(CName, CSpelling)) {
11197330f729Sjoerg         printf(" (getter=%s)", CName);
11207330f729Sjoerg       }
11217330f729Sjoerg       clang_disposeString(Spelling);
11227330f729Sjoerg       clang_disposeString(Name);
11237330f729Sjoerg     }
11247330f729Sjoerg 
11257330f729Sjoerg     if (Cursor.kind == CXCursor_ObjCPropertyDecl) {
11267330f729Sjoerg       CXString Name = clang_Cursor_getObjCPropertySetterName(Cursor);
11277330f729Sjoerg       CXString Spelling = clang_getCursorSpelling(Cursor);
11287330f729Sjoerg       const char *CName = clang_getCString(Name);
11297330f729Sjoerg       const char *CSpelling = clang_getCString(Spelling);
11307330f729Sjoerg       char *DefaultSetter = malloc(strlen(CSpelling) + 5);
11317330f729Sjoerg       sprintf(DefaultSetter, "set%s:", CSpelling);
11327330f729Sjoerg       DefaultSetter[3] &= ~(1 << 5); /* Make uppercase */
11337330f729Sjoerg       if (CName && strcmp(CName, DefaultSetter)) {
11347330f729Sjoerg         printf(" (setter=%s)", CName);
11357330f729Sjoerg       }
11367330f729Sjoerg       free(DefaultSetter);
11377330f729Sjoerg       clang_disposeString(Spelling);
11387330f729Sjoerg       clang_disposeString(Name);
11397330f729Sjoerg     }
11407330f729Sjoerg 
11417330f729Sjoerg     {
11427330f729Sjoerg       unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
11437330f729Sjoerg       if (QT != CXObjCDeclQualifier_None) {
11447330f729Sjoerg         printf(" [");
11457330f729Sjoerg         #define PRINT_OBJC_QUAL(A) \
11467330f729Sjoerg           if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
11477330f729Sjoerg         PRINT_OBJC_QUAL(In);
11487330f729Sjoerg         PRINT_OBJC_QUAL(Inout);
11497330f729Sjoerg         PRINT_OBJC_QUAL(Out);
11507330f729Sjoerg         PRINT_OBJC_QUAL(Bycopy);
11517330f729Sjoerg         PRINT_OBJC_QUAL(Byref);
11527330f729Sjoerg         PRINT_OBJC_QUAL(Oneway);
11537330f729Sjoerg         printf("]");
11547330f729Sjoerg       }
11557330f729Sjoerg     }
11567330f729Sjoerg   }
11577330f729Sjoerg }
11587330f729Sjoerg 
GetCursorSource(CXCursor Cursor)11597330f729Sjoerg static const char* GetCursorSource(CXCursor Cursor) {
11607330f729Sjoerg   CXSourceLocation Loc = clang_getCursorLocation(Cursor);
11617330f729Sjoerg   CXString source;
11627330f729Sjoerg   CXFile file;
11637330f729Sjoerg   clang_getExpansionLocation(Loc, &file, 0, 0, 0);
11647330f729Sjoerg   source = clang_getFileName(file);
11657330f729Sjoerg   if (!clang_getCString(source)) {
11667330f729Sjoerg     clang_disposeString(source);
11677330f729Sjoerg     return "<invalid loc>";
11687330f729Sjoerg   }
11697330f729Sjoerg   else {
11707330f729Sjoerg     const char *b = basename(clang_getCString(source));
11717330f729Sjoerg     clang_disposeString(source);
11727330f729Sjoerg     return b;
11737330f729Sjoerg   }
11747330f729Sjoerg }
11757330f729Sjoerg 
createCXString(const char * CS)11767330f729Sjoerg static CXString createCXString(const char *CS) {
11777330f729Sjoerg   CXString Str;
11787330f729Sjoerg   Str.data = (const void *) CS;
11797330f729Sjoerg   Str.private_flags = 0;
11807330f729Sjoerg   return Str;
11817330f729Sjoerg }
11827330f729Sjoerg 
11837330f729Sjoerg /******************************************************************************/
11847330f729Sjoerg /* Callbacks.                                                                 */
11857330f729Sjoerg /******************************************************************************/
11867330f729Sjoerg 
11877330f729Sjoerg typedef void (*PostVisitTU)(CXTranslationUnit);
11887330f729Sjoerg 
PrintDiagnostic(CXDiagnostic Diagnostic)11897330f729Sjoerg void PrintDiagnostic(CXDiagnostic Diagnostic) {
11907330f729Sjoerg   FILE *out = stderr;
11917330f729Sjoerg   CXFile file;
11927330f729Sjoerg   CXString Msg;
11937330f729Sjoerg   unsigned display_opts = CXDiagnostic_DisplaySourceLocation
11947330f729Sjoerg     | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
11957330f729Sjoerg     | CXDiagnostic_DisplayOption;
11967330f729Sjoerg   unsigned i, num_fixits;
11977330f729Sjoerg 
11987330f729Sjoerg   if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
11997330f729Sjoerg     return;
12007330f729Sjoerg 
12017330f729Sjoerg   Msg = clang_formatDiagnostic(Diagnostic, display_opts);
12027330f729Sjoerg   fprintf(stderr, "%s\n", clang_getCString(Msg));
12037330f729Sjoerg   clang_disposeString(Msg);
12047330f729Sjoerg 
12057330f729Sjoerg   clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
12067330f729Sjoerg                             &file, 0, 0, 0);
12077330f729Sjoerg   if (!file)
12087330f729Sjoerg     return;
12097330f729Sjoerg 
12107330f729Sjoerg   num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
12117330f729Sjoerg   fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
12127330f729Sjoerg   for (i = 0; i != num_fixits; ++i) {
12137330f729Sjoerg     CXSourceRange range;
12147330f729Sjoerg     CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
12157330f729Sjoerg     CXSourceLocation start = clang_getRangeStart(range);
12167330f729Sjoerg     CXSourceLocation end = clang_getRangeEnd(range);
12177330f729Sjoerg     unsigned start_line, start_column, end_line, end_column;
12187330f729Sjoerg     CXFile start_file, end_file;
12197330f729Sjoerg     clang_getSpellingLocation(start, &start_file, &start_line,
12207330f729Sjoerg                               &start_column, 0);
12217330f729Sjoerg     clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
12227330f729Sjoerg     if (clang_equalLocations(start, end)) {
12237330f729Sjoerg       /* Insertion. */
12247330f729Sjoerg       if (start_file == file)
12257330f729Sjoerg         fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
12267330f729Sjoerg                 clang_getCString(insertion_text), start_line, start_column);
12277330f729Sjoerg     } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
12287330f729Sjoerg       /* Removal. */
12297330f729Sjoerg       if (start_file == file && end_file == file) {
12307330f729Sjoerg         fprintf(out, "FIX-IT: Remove ");
12317330f729Sjoerg         PrintExtent(out, start_line, start_column, end_line, end_column);
12327330f729Sjoerg         fprintf(out, "\n");
12337330f729Sjoerg       }
12347330f729Sjoerg     } else {
12357330f729Sjoerg       /* Replacement. */
12367330f729Sjoerg       if (start_file == end_file) {
12377330f729Sjoerg         fprintf(out, "FIX-IT: Replace ");
12387330f729Sjoerg         PrintExtent(out, start_line, start_column, end_line, end_column);
12397330f729Sjoerg         fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
12407330f729Sjoerg       }
12417330f729Sjoerg     }
12427330f729Sjoerg     clang_disposeString(insertion_text);
12437330f729Sjoerg   }
12447330f729Sjoerg }
12457330f729Sjoerg 
PrintDiagnosticSet(CXDiagnosticSet Set)12467330f729Sjoerg void PrintDiagnosticSet(CXDiagnosticSet Set) {
12477330f729Sjoerg   int i = 0, n = clang_getNumDiagnosticsInSet(Set);
12487330f729Sjoerg   for ( ; i != n ; ++i) {
12497330f729Sjoerg     CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
12507330f729Sjoerg     CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
12517330f729Sjoerg     PrintDiagnostic(Diag);
12527330f729Sjoerg     if (ChildDiags)
12537330f729Sjoerg       PrintDiagnosticSet(ChildDiags);
12547330f729Sjoerg   }
12557330f729Sjoerg }
12567330f729Sjoerg 
PrintDiagnostics(CXTranslationUnit TU)12577330f729Sjoerg void PrintDiagnostics(CXTranslationUnit TU) {
12587330f729Sjoerg   CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
12597330f729Sjoerg   PrintDiagnosticSet(TUSet);
12607330f729Sjoerg   clang_disposeDiagnosticSet(TUSet);
12617330f729Sjoerg }
12627330f729Sjoerg 
PrintMemoryUsage(CXTranslationUnit TU)12637330f729Sjoerg void PrintMemoryUsage(CXTranslationUnit TU) {
12647330f729Sjoerg   unsigned long total = 0;
12657330f729Sjoerg   unsigned i = 0;
12667330f729Sjoerg   CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
12677330f729Sjoerg   fprintf(stderr, "Memory usage:\n");
12687330f729Sjoerg   for (i = 0 ; i != usage.numEntries; ++i) {
12697330f729Sjoerg     const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
12707330f729Sjoerg     unsigned long amount = usage.entries[i].amount;
12717330f729Sjoerg     total += amount;
12727330f729Sjoerg     fprintf(stderr, "  %s : %ld bytes (%f MBytes)\n", name, amount,
12737330f729Sjoerg             ((double) amount)/(1024*1024));
12747330f729Sjoerg   }
12757330f729Sjoerg   fprintf(stderr, "  TOTAL = %ld bytes (%f MBytes)\n", total,
12767330f729Sjoerg           ((double) total)/(1024*1024));
12777330f729Sjoerg   clang_disposeCXTUResourceUsage(usage);
12787330f729Sjoerg }
12797330f729Sjoerg 
12807330f729Sjoerg /******************************************************************************/
12817330f729Sjoerg /* Logic for testing traversal.                                               */
12827330f729Sjoerg /******************************************************************************/
12837330f729Sjoerg 
PrintCursorExtent(CXCursor C)12847330f729Sjoerg static void PrintCursorExtent(CXCursor C) {
12857330f729Sjoerg   CXSourceRange extent = clang_getCursorExtent(C);
12867330f729Sjoerg   PrintRange(extent, "Extent");
12877330f729Sjoerg }
12887330f729Sjoerg 
12897330f729Sjoerg /* Data used by the visitors. */
12907330f729Sjoerg typedef struct {
12917330f729Sjoerg   CXTranslationUnit TU;
12927330f729Sjoerg   enum CXCursorKind *Filter;
12937330f729Sjoerg   const char *CommentSchemaFile;
12947330f729Sjoerg } VisitorData;
12957330f729Sjoerg 
12967330f729Sjoerg 
FilteredPrintingVisitor(CXCursor Cursor,CXCursor Parent,CXClientData ClientData)12977330f729Sjoerg enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
12987330f729Sjoerg                                                 CXCursor Parent,
12997330f729Sjoerg                                                 CXClientData ClientData) {
13007330f729Sjoerg   VisitorData *Data = (VisitorData *)ClientData;
13017330f729Sjoerg   if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
13027330f729Sjoerg     CXSourceLocation Loc = clang_getCursorLocation(Cursor);
13037330f729Sjoerg     unsigned line, column;
13047330f729Sjoerg     clang_getSpellingLocation(Loc, 0, &line, &column, 0);
13057330f729Sjoerg     printf("// %s: %s:%d:%d: ", FileCheckPrefix,
13067330f729Sjoerg            GetCursorSource(Cursor), line, column);
13077330f729Sjoerg     PrintCursor(Cursor, Data->CommentSchemaFile);
13087330f729Sjoerg     PrintCursorExtent(Cursor);
13097330f729Sjoerg     if (clang_isDeclaration(Cursor.kind)) {
13107330f729Sjoerg       enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
13117330f729Sjoerg       const char *accessStr = 0;
13127330f729Sjoerg 
13137330f729Sjoerg       switch (access) {
13147330f729Sjoerg         case CX_CXXInvalidAccessSpecifier: break;
13157330f729Sjoerg         case CX_CXXPublic:
13167330f729Sjoerg           accessStr = "public"; break;
13177330f729Sjoerg         case CX_CXXProtected:
13187330f729Sjoerg           accessStr = "protected"; break;
13197330f729Sjoerg         case CX_CXXPrivate:
13207330f729Sjoerg           accessStr = "private"; break;
13217330f729Sjoerg       }
13227330f729Sjoerg 
13237330f729Sjoerg       if (accessStr)
13247330f729Sjoerg         printf(" [access=%s]", accessStr);
13257330f729Sjoerg     }
13267330f729Sjoerg     printf("\n");
13277330f729Sjoerg     return CXChildVisit_Recurse;
13287330f729Sjoerg   }
13297330f729Sjoerg 
13307330f729Sjoerg   return CXChildVisit_Continue;
13317330f729Sjoerg }
13327330f729Sjoerg 
FunctionScanVisitor(CXCursor Cursor,CXCursor Parent,CXClientData ClientData)13337330f729Sjoerg static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
13347330f729Sjoerg                                                    CXCursor Parent,
13357330f729Sjoerg                                                    CXClientData ClientData) {
13367330f729Sjoerg   const char *startBuf, *endBuf;
13377330f729Sjoerg   unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
13387330f729Sjoerg   CXCursor Ref;
13397330f729Sjoerg   VisitorData *Data = (VisitorData *)ClientData;
13407330f729Sjoerg 
13417330f729Sjoerg   if (Cursor.kind != CXCursor_FunctionDecl ||
13427330f729Sjoerg       !clang_isCursorDefinition(Cursor))
13437330f729Sjoerg     return CXChildVisit_Continue;
13447330f729Sjoerg 
13457330f729Sjoerg   clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
13467330f729Sjoerg                                        &startLine, &startColumn,
13477330f729Sjoerg                                        &endLine, &endColumn);
13487330f729Sjoerg   /* Probe the entire body, looking for both decls and refs. */
13497330f729Sjoerg   curLine = startLine;
13507330f729Sjoerg   curColumn = startColumn;
13517330f729Sjoerg 
13527330f729Sjoerg   while (startBuf < endBuf) {
13537330f729Sjoerg     CXSourceLocation Loc;
13547330f729Sjoerg     CXFile file;
13557330f729Sjoerg     CXString source;
13567330f729Sjoerg 
13577330f729Sjoerg     if (*startBuf == '\n') {
13587330f729Sjoerg       startBuf++;
13597330f729Sjoerg       curLine++;
13607330f729Sjoerg       curColumn = 1;
13617330f729Sjoerg     } else if (*startBuf != '\t')
13627330f729Sjoerg       curColumn++;
13637330f729Sjoerg 
13647330f729Sjoerg     Loc = clang_getCursorLocation(Cursor);
13657330f729Sjoerg     clang_getSpellingLocation(Loc, &file, 0, 0, 0);
13667330f729Sjoerg 
13677330f729Sjoerg     source = clang_getFileName(file);
13687330f729Sjoerg     if (clang_getCString(source)) {
13697330f729Sjoerg       CXSourceLocation RefLoc
13707330f729Sjoerg         = clang_getLocation(Data->TU, file, curLine, curColumn);
13717330f729Sjoerg       Ref = clang_getCursor(Data->TU, RefLoc);
13727330f729Sjoerg       if (Ref.kind == CXCursor_NoDeclFound) {
13737330f729Sjoerg         /* Nothing found here; that's fine. */
13747330f729Sjoerg       } else if (Ref.kind != CXCursor_FunctionDecl) {
13757330f729Sjoerg         printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
13767330f729Sjoerg                curLine, curColumn);
13777330f729Sjoerg         PrintCursor(Ref, Data->CommentSchemaFile);
13787330f729Sjoerg         printf("\n");
13797330f729Sjoerg       }
13807330f729Sjoerg     }
13817330f729Sjoerg     clang_disposeString(source);
13827330f729Sjoerg     startBuf++;
13837330f729Sjoerg   }
13847330f729Sjoerg 
13857330f729Sjoerg   return CXChildVisit_Continue;
13867330f729Sjoerg }
13877330f729Sjoerg 
13887330f729Sjoerg /******************************************************************************/
13897330f729Sjoerg /* USR testing.                                                               */
13907330f729Sjoerg /******************************************************************************/
13917330f729Sjoerg 
USRVisitor(CXCursor C,CXCursor parent,CXClientData ClientData)13927330f729Sjoerg enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
13937330f729Sjoerg                                    CXClientData ClientData) {
13947330f729Sjoerg   VisitorData *Data = (VisitorData *)ClientData;
13957330f729Sjoerg   if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
13967330f729Sjoerg     CXString USR = clang_getCursorUSR(C);
13977330f729Sjoerg     const char *cstr = clang_getCString(USR);
13987330f729Sjoerg     if (!cstr || cstr[0] == '\0') {
13997330f729Sjoerg       clang_disposeString(USR);
14007330f729Sjoerg       return CXChildVisit_Recurse;
14017330f729Sjoerg     }
14027330f729Sjoerg     printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
14037330f729Sjoerg 
14047330f729Sjoerg     PrintCursorExtent(C);
14057330f729Sjoerg     printf("\n");
14067330f729Sjoerg     clang_disposeString(USR);
14077330f729Sjoerg 
14087330f729Sjoerg     return CXChildVisit_Recurse;
14097330f729Sjoerg   }
14107330f729Sjoerg 
14117330f729Sjoerg   return CXChildVisit_Continue;
14127330f729Sjoerg }
14137330f729Sjoerg 
14147330f729Sjoerg /******************************************************************************/
14157330f729Sjoerg /* Inclusion stack testing.                                                   */
14167330f729Sjoerg /******************************************************************************/
14177330f729Sjoerg 
InclusionVisitor(CXFile includedFile,CXSourceLocation * includeStack,unsigned includeStackLen,CXClientData data)14187330f729Sjoerg void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
14197330f729Sjoerg                       unsigned includeStackLen, CXClientData data) {
14207330f729Sjoerg 
14217330f729Sjoerg   unsigned i;
14227330f729Sjoerg   CXString fname;
14237330f729Sjoerg 
14247330f729Sjoerg   fname = clang_getFileName(includedFile);
14257330f729Sjoerg   printf("file: %s\nincluded by:\n", clang_getCString(fname));
14267330f729Sjoerg   clang_disposeString(fname);
14277330f729Sjoerg 
14287330f729Sjoerg   for (i = 0; i < includeStackLen; ++i) {
14297330f729Sjoerg     CXFile includingFile;
14307330f729Sjoerg     unsigned line, column;
14317330f729Sjoerg     clang_getSpellingLocation(includeStack[i], &includingFile, &line,
14327330f729Sjoerg                               &column, 0);
14337330f729Sjoerg     fname = clang_getFileName(includingFile);
14347330f729Sjoerg     printf("  %s:%d:%d\n", clang_getCString(fname), line, column);
14357330f729Sjoerg     clang_disposeString(fname);
14367330f729Sjoerg   }
14377330f729Sjoerg   printf("\n");
14387330f729Sjoerg }
14397330f729Sjoerg 
PrintInclusionStack(CXTranslationUnit TU)14407330f729Sjoerg void PrintInclusionStack(CXTranslationUnit TU) {
14417330f729Sjoerg   clang_getInclusions(TU, InclusionVisitor, NULL);
14427330f729Sjoerg }
14437330f729Sjoerg 
14447330f729Sjoerg /******************************************************************************/
14457330f729Sjoerg /* Linkage testing.                                                           */
14467330f729Sjoerg /******************************************************************************/
14477330f729Sjoerg 
PrintLinkage(CXCursor cursor,CXCursor p,CXClientData d)14487330f729Sjoerg static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
14497330f729Sjoerg                                             CXClientData d) {
14507330f729Sjoerg   const char *linkage = 0;
14517330f729Sjoerg 
14527330f729Sjoerg   if (clang_isInvalid(clang_getCursorKind(cursor)))
14537330f729Sjoerg     return CXChildVisit_Recurse;
14547330f729Sjoerg 
14557330f729Sjoerg   switch (clang_getCursorLinkage(cursor)) {
14567330f729Sjoerg     case CXLinkage_Invalid: break;
14577330f729Sjoerg     case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
14587330f729Sjoerg     case CXLinkage_Internal: linkage = "Internal"; break;
14597330f729Sjoerg     case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
14607330f729Sjoerg     case CXLinkage_External: linkage = "External"; break;
14617330f729Sjoerg   }
14627330f729Sjoerg 
14637330f729Sjoerg   if (linkage) {
14647330f729Sjoerg     PrintCursor(cursor, NULL);
14657330f729Sjoerg     printf("linkage=%s\n", linkage);
14667330f729Sjoerg   }
14677330f729Sjoerg 
14687330f729Sjoerg   return CXChildVisit_Recurse;
14697330f729Sjoerg }
14707330f729Sjoerg 
14717330f729Sjoerg /******************************************************************************/
14727330f729Sjoerg /* Visibility testing.                                                        */
14737330f729Sjoerg /******************************************************************************/
14747330f729Sjoerg 
PrintVisibility(CXCursor cursor,CXCursor p,CXClientData d)14757330f729Sjoerg static enum CXChildVisitResult PrintVisibility(CXCursor cursor, CXCursor p,
14767330f729Sjoerg                                                CXClientData d) {
14777330f729Sjoerg   const char *visibility = 0;
14787330f729Sjoerg 
14797330f729Sjoerg   if (clang_isInvalid(clang_getCursorKind(cursor)))
14807330f729Sjoerg     return CXChildVisit_Recurse;
14817330f729Sjoerg 
14827330f729Sjoerg   switch (clang_getCursorVisibility(cursor)) {
14837330f729Sjoerg     case CXVisibility_Invalid: break;
14847330f729Sjoerg     case CXVisibility_Hidden: visibility = "Hidden"; break;
14857330f729Sjoerg     case CXVisibility_Protected: visibility = "Protected"; break;
14867330f729Sjoerg     case CXVisibility_Default: visibility = "Default"; break;
14877330f729Sjoerg   }
14887330f729Sjoerg 
14897330f729Sjoerg   if (visibility) {
14907330f729Sjoerg     PrintCursor(cursor, NULL);
14917330f729Sjoerg     printf("visibility=%s\n", visibility);
14927330f729Sjoerg   }
14937330f729Sjoerg 
14947330f729Sjoerg   return CXChildVisit_Recurse;
14957330f729Sjoerg }
14967330f729Sjoerg 
14977330f729Sjoerg /******************************************************************************/
14987330f729Sjoerg /* Typekind testing.                                                          */
14997330f729Sjoerg /******************************************************************************/
15007330f729Sjoerg 
PrintTypeAndTypeKind(CXType T,const char * Format)15017330f729Sjoerg static void PrintTypeAndTypeKind(CXType T, const char *Format) {
15027330f729Sjoerg   CXString TypeSpelling, TypeKindSpelling;
15037330f729Sjoerg 
15047330f729Sjoerg   TypeSpelling = clang_getTypeSpelling(T);
15057330f729Sjoerg   TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
15067330f729Sjoerg   printf(Format,
15077330f729Sjoerg          clang_getCString(TypeSpelling),
15087330f729Sjoerg          clang_getCString(TypeKindSpelling));
15097330f729Sjoerg   clang_disposeString(TypeSpelling);
15107330f729Sjoerg   clang_disposeString(TypeKindSpelling);
15117330f729Sjoerg }
15127330f729Sjoerg 
FieldVisitor(CXCursor C,CXClientData client_data)15137330f729Sjoerg static enum CXVisitorResult FieldVisitor(CXCursor C,
15147330f729Sjoerg                                          CXClientData client_data) {
15157330f729Sjoerg     (*(int *) client_data)+=1;
15167330f729Sjoerg     return CXVisit_Continue;
15177330f729Sjoerg }
15187330f729Sjoerg 
PrintTypeTemplateArgs(CXType T,const char * Format)15197330f729Sjoerg static void PrintTypeTemplateArgs(CXType T, const char *Format) {
15207330f729Sjoerg   int NumTArgs = clang_Type_getNumTemplateArguments(T);
15217330f729Sjoerg   if (NumTArgs != -1 && NumTArgs != 0) {
15227330f729Sjoerg     int i;
15237330f729Sjoerg     CXType TArg;
15247330f729Sjoerg     printf(Format, NumTArgs);
15257330f729Sjoerg     for (i = 0; i < NumTArgs; ++i) {
15267330f729Sjoerg       TArg = clang_Type_getTemplateArgumentAsType(T, i);
15277330f729Sjoerg       if (TArg.kind != CXType_Invalid) {
15287330f729Sjoerg         PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]");
15297330f729Sjoerg       }
15307330f729Sjoerg     }
15317330f729Sjoerg     /* Ensure that the returned type is invalid when indexing off-by-one. */
15327330f729Sjoerg     TArg = clang_Type_getTemplateArgumentAsType(T, i);
15337330f729Sjoerg     assert(TArg.kind == CXType_Invalid);
15347330f729Sjoerg     printf("]");
15357330f729Sjoerg   }
15367330f729Sjoerg }
15377330f729Sjoerg 
PrintNullabilityKind(CXType T,const char * Format)15387330f729Sjoerg static void PrintNullabilityKind(CXType T, const char *Format) {
15397330f729Sjoerg   enum CXTypeNullabilityKind N = clang_Type_getNullability(T);
15407330f729Sjoerg 
15417330f729Sjoerg   const char *nullability = 0;
15427330f729Sjoerg   switch (N) {
1543*e038c9c4Sjoerg   case CXTypeNullability_NonNull:
1544*e038c9c4Sjoerg     nullability = "nonnull";
1545*e038c9c4Sjoerg     break;
1546*e038c9c4Sjoerg   case CXTypeNullability_Nullable:
1547*e038c9c4Sjoerg     nullability = "nullable";
1548*e038c9c4Sjoerg     break;
1549*e038c9c4Sjoerg   case CXTypeNullability_NullableResult:
1550*e038c9c4Sjoerg     nullability = "nullable_result";
1551*e038c9c4Sjoerg     break;
1552*e038c9c4Sjoerg   case CXTypeNullability_Unspecified:
1553*e038c9c4Sjoerg     nullability = "unspecified";
1554*e038c9c4Sjoerg     break;
1555*e038c9c4Sjoerg   case CXTypeNullability_Invalid:
1556*e038c9c4Sjoerg     break;
15577330f729Sjoerg   }
15587330f729Sjoerg 
15597330f729Sjoerg   if (nullability) {
15607330f729Sjoerg     printf(Format, nullability);
15617330f729Sjoerg   }
15627330f729Sjoerg }
15637330f729Sjoerg 
PrintType(CXCursor cursor,CXCursor p,CXClientData d)15647330f729Sjoerg static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
15657330f729Sjoerg                                          CXClientData d) {
15667330f729Sjoerg   if (!clang_isInvalid(clang_getCursorKind(cursor))) {
15677330f729Sjoerg     CXType T = clang_getCursorType(cursor);
15687330f729Sjoerg     CXType PT = clang_getPointeeType(T);
15697330f729Sjoerg     enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
15707330f729Sjoerg     PrintCursor(cursor, NULL);
15717330f729Sjoerg     PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
15727330f729Sjoerg     PrintNullabilityKind(T, " [nullability=%s]");
15737330f729Sjoerg     if (clang_isConstQualifiedType(T))
15747330f729Sjoerg       printf(" const");
15757330f729Sjoerg     if (clang_isVolatileQualifiedType(T))
15767330f729Sjoerg       printf(" volatile");
15777330f729Sjoerg     if (clang_isRestrictQualifiedType(T))
15787330f729Sjoerg       printf(" restrict");
15797330f729Sjoerg     if (RQ == CXRefQualifier_LValue)
15807330f729Sjoerg       printf(" lvalue-ref-qualifier");
15817330f729Sjoerg     if (RQ == CXRefQualifier_RValue)
15827330f729Sjoerg       printf(" rvalue-ref-qualifier");
15837330f729Sjoerg     /* Print the template argument types if they exist. */
15847330f729Sjoerg     PrintTypeTemplateArgs(T, " [templateargs/%d=");
15857330f729Sjoerg     /* Print the canonical type if it is different. */
15867330f729Sjoerg     {
15877330f729Sjoerg       CXType CT = clang_getCanonicalType(T);
15887330f729Sjoerg       if (!clang_equalTypes(T, CT)) {
15897330f729Sjoerg         PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
15907330f729Sjoerg         PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d=");
15917330f729Sjoerg       }
15927330f729Sjoerg     }
1593*e038c9c4Sjoerg     /* Print the value type if it exists. */
1594*e038c9c4Sjoerg     {
1595*e038c9c4Sjoerg       CXType VT = clang_Type_getValueType(T);
1596*e038c9c4Sjoerg       if (VT.kind != CXType_Invalid)
1597*e038c9c4Sjoerg         PrintTypeAndTypeKind(VT, " [valuetype=%s] [valuetypekind=%s]");
1598*e038c9c4Sjoerg     }
15997330f729Sjoerg     /* Print the modified type if it exists. */
16007330f729Sjoerg     {
16017330f729Sjoerg       CXType MT = clang_Type_getModifiedType(T);
16027330f729Sjoerg       if (MT.kind != CXType_Invalid) {
16037330f729Sjoerg         PrintTypeAndTypeKind(MT, " [modifiedtype=%s] [modifiedtypekind=%s]");
16047330f729Sjoerg       }
16057330f729Sjoerg     }
16067330f729Sjoerg     /* Print the return type if it exists. */
16077330f729Sjoerg     {
16087330f729Sjoerg       CXType RT = clang_getCursorResultType(cursor);
16097330f729Sjoerg       if (RT.kind != CXType_Invalid) {
16107330f729Sjoerg         PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
16117330f729Sjoerg       }
16127330f729Sjoerg       PrintNullabilityKind(RT, " [resultnullability=%s]");
16137330f729Sjoerg     }
16147330f729Sjoerg     /* Print the argument types if they exist. */
16157330f729Sjoerg     {
16167330f729Sjoerg       int NumArgs = clang_Cursor_getNumArguments(cursor);
16177330f729Sjoerg       if (NumArgs != -1 && NumArgs != 0) {
16187330f729Sjoerg         int i;
16197330f729Sjoerg         printf(" [args=");
16207330f729Sjoerg         for (i = 0; i < NumArgs; ++i) {
16217330f729Sjoerg           CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
16227330f729Sjoerg           if (T.kind != CXType_Invalid) {
16237330f729Sjoerg             PrintTypeAndTypeKind(T, " [%s] [%s]");
16247330f729Sjoerg             PrintNullabilityKind(T, " [%s]");
16257330f729Sjoerg           }
16267330f729Sjoerg         }
16277330f729Sjoerg         printf("]");
16287330f729Sjoerg       }
16297330f729Sjoerg     }
16307330f729Sjoerg     /* Print ObjC base types, type arguments, and protocol list if available. */
16317330f729Sjoerg     {
16327330f729Sjoerg       CXType BT = clang_Type_getObjCObjectBaseType(PT);
16337330f729Sjoerg       if (BT.kind != CXType_Invalid) {
16347330f729Sjoerg         PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]");
16357330f729Sjoerg       }
16367330f729Sjoerg     }
16377330f729Sjoerg     {
16387330f729Sjoerg       unsigned NumTypeArgs = clang_Type_getNumObjCTypeArgs(PT);
16397330f729Sjoerg       if (NumTypeArgs > 0) {
16407330f729Sjoerg         unsigned i;
16417330f729Sjoerg         printf(" [typeargs=");
16427330f729Sjoerg         for (i = 0; i < NumTypeArgs; ++i) {
16437330f729Sjoerg           CXType TA = clang_Type_getObjCTypeArg(PT, i);
16447330f729Sjoerg           if (TA.kind != CXType_Invalid) {
16457330f729Sjoerg             PrintTypeAndTypeKind(TA, " [%s] [%s]");
16467330f729Sjoerg           }
16477330f729Sjoerg         }
16487330f729Sjoerg         printf("]");
16497330f729Sjoerg       }
16507330f729Sjoerg     }
16517330f729Sjoerg     {
16527330f729Sjoerg       unsigned NumProtocols = clang_Type_getNumObjCProtocolRefs(PT);
16537330f729Sjoerg       if (NumProtocols > 0) {
16547330f729Sjoerg         unsigned i;
16557330f729Sjoerg         printf(" [protocols=");
16567330f729Sjoerg         for (i = 0; i < NumProtocols; ++i) {
16577330f729Sjoerg           CXCursor P = clang_Type_getObjCProtocolDecl(PT, i);
16587330f729Sjoerg           if (!clang_isInvalid(clang_getCursorKind(P))) {
16597330f729Sjoerg             PrintCursor(P, NULL);
16607330f729Sjoerg           }
16617330f729Sjoerg         }
16627330f729Sjoerg         printf("]");
16637330f729Sjoerg       }
16647330f729Sjoerg     }
16657330f729Sjoerg     /* Print if this is a non-POD type. */
16667330f729Sjoerg     printf(" [isPOD=%d]", clang_isPODType(T));
16677330f729Sjoerg     /* Print the pointee type. */
16687330f729Sjoerg     {
16697330f729Sjoerg       if (PT.kind != CXType_Invalid) {
16707330f729Sjoerg         PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]");
16717330f729Sjoerg       }
16727330f729Sjoerg     }
16737330f729Sjoerg     /* Print the number of fields if they exist. */
16747330f729Sjoerg     {
16757330f729Sjoerg       int numFields = 0;
16767330f729Sjoerg       if (clang_Type_visitFields(T, FieldVisitor, &numFields)){
16777330f729Sjoerg         if (numFields != 0) {
16787330f729Sjoerg           printf(" [nbFields=%d]", numFields);
16797330f729Sjoerg         }
16807330f729Sjoerg       }
16817330f729Sjoerg     }
16827330f729Sjoerg 
16837330f729Sjoerg     /* Print if it is an anonymous record or namespace. */
16847330f729Sjoerg     {
16857330f729Sjoerg       unsigned isAnon = clang_Cursor_isAnonymous(cursor);
16867330f729Sjoerg       if (isAnon != 0) {
16877330f729Sjoerg         printf(" [isAnon=%d]", isAnon);
16887330f729Sjoerg       }
16897330f729Sjoerg     }
16907330f729Sjoerg 
16917330f729Sjoerg     /* Print if it is an anonymous record decl */
16927330f729Sjoerg     {
16937330f729Sjoerg       unsigned isAnonRecDecl = clang_Cursor_isAnonymousRecordDecl(cursor);
16947330f729Sjoerg       printf(" [isAnonRecDecl=%d]", isAnonRecDecl);
16957330f729Sjoerg     }
16967330f729Sjoerg 
16977330f729Sjoerg     /* Print if it is an inline namespace decl */
16987330f729Sjoerg     {
16997330f729Sjoerg       unsigned isInlineNamespace = clang_Cursor_isInlineNamespace(cursor);
17007330f729Sjoerg       if (isInlineNamespace != 0)
17017330f729Sjoerg         printf(" [isInlineNamespace=%d]", isInlineNamespace);
17027330f729Sjoerg     }
17037330f729Sjoerg 
17047330f729Sjoerg     printf("\n");
17057330f729Sjoerg   }
17067330f729Sjoerg   return CXChildVisit_Recurse;
17077330f729Sjoerg }
17087330f729Sjoerg 
PrintSingleTypeSize(CXType T,const char * TypeKindFormat,const char * SizeFormat,const char * AlignFormat)17097330f729Sjoerg static void PrintSingleTypeSize(CXType T, const char *TypeKindFormat,
17107330f729Sjoerg                                 const char *SizeFormat,
17117330f729Sjoerg                                 const char *AlignFormat) {
17127330f729Sjoerg   PrintTypeAndTypeKind(T, TypeKindFormat);
17137330f729Sjoerg   /* Print the type sizeof if applicable. */
17147330f729Sjoerg   {
17157330f729Sjoerg     long long Size = clang_Type_getSizeOf(T);
17167330f729Sjoerg     if (Size >= 0 || Size < -1 ) {
17177330f729Sjoerg       printf(SizeFormat, Size);
17187330f729Sjoerg     }
17197330f729Sjoerg   }
17207330f729Sjoerg   /* Print the type alignof if applicable. */
17217330f729Sjoerg   {
17227330f729Sjoerg     long long Align = clang_Type_getAlignOf(T);
17237330f729Sjoerg     if (Align >= 0 || Align < -1) {
17247330f729Sjoerg       printf(AlignFormat, Align);
17257330f729Sjoerg     }
17267330f729Sjoerg   }
17277330f729Sjoerg 
17287330f729Sjoerg   /* Print the return type if it exists. */
17297330f729Sjoerg   {
17307330f729Sjoerg     CXType RT = clang_getResultType(T);
17317330f729Sjoerg     if (RT.kind != CXType_Invalid)
17327330f729Sjoerg       PrintSingleTypeSize(RT, " [resulttype=%s] [resulttypekind=%s]",
17337330f729Sjoerg                               " [resultsizeof=%lld]", " [resultalignof=%lld]");
17347330f729Sjoerg   }
17357330f729Sjoerg }
17367330f729Sjoerg 
PrintTypeSize(CXCursor cursor,CXCursor p,CXClientData d)17377330f729Sjoerg static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
17387330f729Sjoerg                                              CXClientData d) {
17397330f729Sjoerg   CXType T;
17407330f729Sjoerg   enum CXCursorKind K = clang_getCursorKind(cursor);
17417330f729Sjoerg   if (clang_isInvalid(K))
17427330f729Sjoerg     return CXChildVisit_Recurse;
17437330f729Sjoerg   T = clang_getCursorType(cursor);
17447330f729Sjoerg   PrintCursor(cursor, NULL);
17457330f729Sjoerg   PrintSingleTypeSize(T, " [type=%s] [typekind=%s]", " [sizeof=%lld]",
17467330f729Sjoerg                       " [alignof=%lld]");
17477330f729Sjoerg   /* Print the record field offset if applicable. */
17487330f729Sjoerg   {
17497330f729Sjoerg     CXString FieldSpelling = clang_getCursorSpelling(cursor);
17507330f729Sjoerg     const char *FieldName = clang_getCString(FieldSpelling);
17517330f729Sjoerg     /* recurse to get the first parent record that is not anonymous. */
17527330f729Sjoerg     unsigned RecordIsAnonymous = 0;
17537330f729Sjoerg     if (clang_getCursorKind(cursor) == CXCursor_FieldDecl) {
17547330f729Sjoerg       CXCursor Record;
17557330f729Sjoerg       CXCursor Parent = p;
17567330f729Sjoerg       do {
17577330f729Sjoerg         Record = Parent;
17587330f729Sjoerg         Parent = clang_getCursorSemanticParent(Record);
17597330f729Sjoerg         RecordIsAnonymous = clang_Cursor_isAnonymous(Record);
17607330f729Sjoerg         /* Recurse as long as the parent is a CXType_Record and the Record
17617330f729Sjoerg            is anonymous */
17627330f729Sjoerg       } while ( clang_getCursorType(Parent).kind == CXType_Record &&
17637330f729Sjoerg                 RecordIsAnonymous > 0);
17647330f729Sjoerg       {
17657330f729Sjoerg         long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record),
17667330f729Sjoerg                                                   FieldName);
17677330f729Sjoerg         long long Offset2 = clang_Cursor_getOffsetOfField(cursor);
17687330f729Sjoerg         if (Offset == Offset2){
17697330f729Sjoerg             printf(" [offsetof=%lld]", Offset);
17707330f729Sjoerg         } else {
17717330f729Sjoerg             /* Offsets will be different in anonymous records. */
17727330f729Sjoerg             printf(" [offsetof=%lld/%lld]", Offset, Offset2);
17737330f729Sjoerg         }
17747330f729Sjoerg       }
17757330f729Sjoerg     }
17767330f729Sjoerg     clang_disposeString(FieldSpelling);
17777330f729Sjoerg   }
17787330f729Sjoerg   /* Print if its a bitfield */
17797330f729Sjoerg   {
17807330f729Sjoerg     int IsBitfield = clang_Cursor_isBitField(cursor);
17817330f729Sjoerg     if (IsBitfield)
17827330f729Sjoerg       printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
17837330f729Sjoerg   }
17847330f729Sjoerg 
17857330f729Sjoerg   printf("\n");
17867330f729Sjoerg 
17877330f729Sjoerg   return CXChildVisit_Recurse;
17887330f729Sjoerg }
17897330f729Sjoerg 
17907330f729Sjoerg /******************************************************************************/
17917330f729Sjoerg /* Mangling testing.                                                          */
17927330f729Sjoerg /******************************************************************************/
17937330f729Sjoerg 
PrintMangledName(CXCursor cursor,CXCursor p,CXClientData d)17947330f729Sjoerg static enum CXChildVisitResult PrintMangledName(CXCursor cursor, CXCursor p,
17957330f729Sjoerg                                                 CXClientData d) {
17967330f729Sjoerg   CXString MangledName;
17977330f729Sjoerg   if (clang_isUnexposed(clang_getCursorKind(cursor)))
17987330f729Sjoerg     return CXChildVisit_Recurse;
17997330f729Sjoerg   PrintCursor(cursor, NULL);
18007330f729Sjoerg   MangledName = clang_Cursor_getMangling(cursor);
18017330f729Sjoerg   printf(" [mangled=%s]\n", clang_getCString(MangledName));
18027330f729Sjoerg   clang_disposeString(MangledName);
18037330f729Sjoerg   return CXChildVisit_Continue;
18047330f729Sjoerg }
18057330f729Sjoerg 
PrintManglings(CXCursor cursor,CXCursor p,CXClientData d)18067330f729Sjoerg static enum CXChildVisitResult PrintManglings(CXCursor cursor, CXCursor p,
18077330f729Sjoerg                                               CXClientData d) {
18087330f729Sjoerg   unsigned I, E;
18097330f729Sjoerg   CXStringSet *Manglings = NULL;
18107330f729Sjoerg   if (clang_isUnexposed(clang_getCursorKind(cursor)))
18117330f729Sjoerg     return CXChildVisit_Recurse;
18127330f729Sjoerg   if (!clang_isDeclaration(clang_getCursorKind(cursor)))
18137330f729Sjoerg     return CXChildVisit_Recurse;
18147330f729Sjoerg   if (clang_getCursorKind(cursor) == CXCursor_ParmDecl)
18157330f729Sjoerg     return CXChildVisit_Continue;
18167330f729Sjoerg   PrintCursor(cursor, NULL);
18177330f729Sjoerg   Manglings = clang_Cursor_getCXXManglings(cursor);
18187330f729Sjoerg   if (Manglings) {
18197330f729Sjoerg     for (I = 0, E = Manglings->Count; I < E; ++I)
18207330f729Sjoerg       printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
18217330f729Sjoerg     clang_disposeStringSet(Manglings);
18227330f729Sjoerg     printf("\n");
18237330f729Sjoerg   }
18247330f729Sjoerg   Manglings = clang_Cursor_getObjCManglings(cursor);
18257330f729Sjoerg   if (Manglings) {
18267330f729Sjoerg     for (I = 0, E = Manglings->Count; I < E; ++I)
18277330f729Sjoerg       printf(" [mangled=%s]", clang_getCString(Manglings->Strings[I]));
18287330f729Sjoerg     clang_disposeStringSet(Manglings);
18297330f729Sjoerg     printf("\n");
18307330f729Sjoerg   }
18317330f729Sjoerg   return CXChildVisit_Recurse;
18327330f729Sjoerg }
18337330f729Sjoerg 
18347330f729Sjoerg /******************************************************************************/
18357330f729Sjoerg /* Bitwidth testing.                                                          */
18367330f729Sjoerg /******************************************************************************/
18377330f729Sjoerg 
PrintBitWidth(CXCursor cursor,CXCursor p,CXClientData d)18387330f729Sjoerg static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
18397330f729Sjoerg                                              CXClientData d) {
18407330f729Sjoerg   int Bitwidth;
18417330f729Sjoerg   if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
18427330f729Sjoerg     return CXChildVisit_Recurse;
18437330f729Sjoerg 
18447330f729Sjoerg   Bitwidth = clang_getFieldDeclBitWidth(cursor);
18457330f729Sjoerg   if (Bitwidth >= 0) {
18467330f729Sjoerg     PrintCursor(cursor, NULL);
18477330f729Sjoerg     printf(" bitwidth=%d\n", Bitwidth);
18487330f729Sjoerg   }
18497330f729Sjoerg 
18507330f729Sjoerg   return CXChildVisit_Recurse;
18517330f729Sjoerg }
18527330f729Sjoerg 
18537330f729Sjoerg /******************************************************************************/
18547330f729Sjoerg /* Type declaration testing                                                   */
18557330f729Sjoerg /******************************************************************************/
18567330f729Sjoerg 
PrintTypeDeclaration(CXCursor cursor,CXCursor p,CXClientData d)18577330f729Sjoerg static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p,
18587330f729Sjoerg                                              CXClientData d) {
18597330f729Sjoerg   CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor));
18607330f729Sjoerg 
18617330f729Sjoerg   if (clang_isDeclaration(typeDeclaration.kind)) {
18627330f729Sjoerg     PrintCursor(cursor, NULL);
18637330f729Sjoerg     PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n");
18647330f729Sjoerg   }
18657330f729Sjoerg 
18667330f729Sjoerg   return CXChildVisit_Recurse;
18677330f729Sjoerg }
18687330f729Sjoerg 
18697330f729Sjoerg /******************************************************************************/
18707330f729Sjoerg /* Declaration attributes testing                                             */
18717330f729Sjoerg /******************************************************************************/
18727330f729Sjoerg 
PrintDeclAttributes(CXCursor cursor,CXCursor p,CXClientData d)18737330f729Sjoerg static enum CXChildVisitResult PrintDeclAttributes(CXCursor cursor, CXCursor p,
18747330f729Sjoerg                                                    CXClientData d) {
18757330f729Sjoerg   if (clang_isDeclaration(cursor.kind)) {
18767330f729Sjoerg     printf("\n");
18777330f729Sjoerg     PrintCursor(cursor, NULL);
18787330f729Sjoerg     return CXChildVisit_Recurse;
18797330f729Sjoerg   } else if (clang_isAttribute(cursor.kind)) {
18807330f729Sjoerg     printf(" ");
18817330f729Sjoerg     PrintCursor(cursor, NULL);
18827330f729Sjoerg   }
18837330f729Sjoerg   return CXChildVisit_Continue;
18847330f729Sjoerg }
18857330f729Sjoerg 
18867330f729Sjoerg /******************************************************************************/
18877330f729Sjoerg /* Target information testing.                                                */
18887330f729Sjoerg /******************************************************************************/
18897330f729Sjoerg 
print_target_info(int argc,const char ** argv)18907330f729Sjoerg static int print_target_info(int argc, const char **argv) {
18917330f729Sjoerg   CXIndex Idx;
18927330f729Sjoerg   CXTranslationUnit TU;
18937330f729Sjoerg   CXTargetInfo TargetInfo;
18947330f729Sjoerg   CXString Triple;
18957330f729Sjoerg   const char *FileName;
18967330f729Sjoerg   enum CXErrorCode Err;
18977330f729Sjoerg   int PointerWidth;
18987330f729Sjoerg 
18997330f729Sjoerg   if (argc == 0) {
19007330f729Sjoerg     fprintf(stderr, "No filename specified\n");
19017330f729Sjoerg     return 1;
19027330f729Sjoerg   }
19037330f729Sjoerg 
19047330f729Sjoerg   FileName = argv[1];
19057330f729Sjoerg 
19067330f729Sjoerg   Idx = clang_createIndex(0, 1);
19077330f729Sjoerg   Err = clang_parseTranslationUnit2(Idx, FileName, argv, argc, NULL, 0,
19087330f729Sjoerg                                     getDefaultParsingOptions(), &TU);
19097330f729Sjoerg   if (Err != CXError_Success) {
19107330f729Sjoerg     fprintf(stderr, "Couldn't parse translation unit!\n");
19117330f729Sjoerg     describeLibclangFailure(Err);
19127330f729Sjoerg     clang_disposeIndex(Idx);
19137330f729Sjoerg     return 1;
19147330f729Sjoerg   }
19157330f729Sjoerg 
19167330f729Sjoerg   TargetInfo = clang_getTranslationUnitTargetInfo(TU);
19177330f729Sjoerg 
19187330f729Sjoerg   Triple = clang_TargetInfo_getTriple(TargetInfo);
19197330f729Sjoerg   printf("TargetTriple: %s\n", clang_getCString(Triple));
19207330f729Sjoerg   clang_disposeString(Triple);
19217330f729Sjoerg 
19227330f729Sjoerg   PointerWidth = clang_TargetInfo_getPointerWidth(TargetInfo);
19237330f729Sjoerg   printf("PointerWidth: %d\n", PointerWidth);
19247330f729Sjoerg 
19257330f729Sjoerg   clang_TargetInfo_dispose(TargetInfo);
19267330f729Sjoerg   clang_disposeTranslationUnit(TU);
19277330f729Sjoerg   clang_disposeIndex(Idx);
19287330f729Sjoerg   return 0;
19297330f729Sjoerg }
19307330f729Sjoerg 
19317330f729Sjoerg /******************************************************************************/
19327330f729Sjoerg /* Loading ASTs/source.                                                       */
19337330f729Sjoerg /******************************************************************************/
19347330f729Sjoerg 
perform_test_load(CXIndex Idx,CXTranslationUnit TU,const char * filter,const char * prefix,CXCursorVisitor Visitor,PostVisitTU PV,const char * CommentSchemaFile)19357330f729Sjoerg static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
19367330f729Sjoerg                              const char *filter, const char *prefix,
19377330f729Sjoerg                              CXCursorVisitor Visitor,
19387330f729Sjoerg                              PostVisitTU PV,
19397330f729Sjoerg                              const char *CommentSchemaFile) {
19407330f729Sjoerg 
19417330f729Sjoerg   if (prefix)
19427330f729Sjoerg     FileCheckPrefix = prefix;
19437330f729Sjoerg 
19447330f729Sjoerg   if (Visitor) {
19457330f729Sjoerg     enum CXCursorKind K = CXCursor_NotImplemented;
19467330f729Sjoerg     enum CXCursorKind *ck = &K;
19477330f729Sjoerg     VisitorData Data;
19487330f729Sjoerg 
19497330f729Sjoerg     /* Perform some simple filtering. */
19507330f729Sjoerg     if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
19517330f729Sjoerg     else if (!strcmp(filter, "all-display") ||
19527330f729Sjoerg              !strcmp(filter, "local-display")) {
19537330f729Sjoerg       ck = NULL;
19547330f729Sjoerg       wanted_display_type = DisplayType_DisplayName;
19557330f729Sjoerg     }
19567330f729Sjoerg     else if (!strcmp(filter, "all-pretty") ||
19577330f729Sjoerg              !strcmp(filter, "local-pretty")) {
19587330f729Sjoerg       ck = NULL;
19597330f729Sjoerg       wanted_display_type = DisplayType_Pretty;
19607330f729Sjoerg     }
19617330f729Sjoerg     else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
19627330f729Sjoerg     else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
19637330f729Sjoerg     else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
19647330f729Sjoerg     else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
19657330f729Sjoerg     else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
19667330f729Sjoerg     else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
19677330f729Sjoerg     else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
19687330f729Sjoerg     else {
19697330f729Sjoerg       fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
19707330f729Sjoerg       return 1;
19717330f729Sjoerg     }
19727330f729Sjoerg 
19737330f729Sjoerg     Data.TU = TU;
19747330f729Sjoerg     Data.Filter = ck;
19757330f729Sjoerg     Data.CommentSchemaFile = CommentSchemaFile;
19767330f729Sjoerg     clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
19777330f729Sjoerg   }
19787330f729Sjoerg 
19797330f729Sjoerg   if (PV)
19807330f729Sjoerg     PV(TU);
19817330f729Sjoerg 
19827330f729Sjoerg   PrintDiagnostics(TU);
19837330f729Sjoerg   if (checkForErrors(TU) != 0) {
19847330f729Sjoerg     clang_disposeTranslationUnit(TU);
19857330f729Sjoerg     return -1;
19867330f729Sjoerg   }
19877330f729Sjoerg 
19887330f729Sjoerg   clang_disposeTranslationUnit(TU);
19897330f729Sjoerg   return 0;
19907330f729Sjoerg }
19917330f729Sjoerg 
perform_test_load_tu(const char * file,const char * filter,const char * prefix,CXCursorVisitor Visitor,PostVisitTU PV)19927330f729Sjoerg int perform_test_load_tu(const char *file, const char *filter,
19937330f729Sjoerg                          const char *prefix, CXCursorVisitor Visitor,
19947330f729Sjoerg                          PostVisitTU PV) {
19957330f729Sjoerg   CXIndex Idx;
19967330f729Sjoerg   CXTranslationUnit TU;
19977330f729Sjoerg   int result;
19987330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */
19997330f729Sjoerg                           !strcmp(filter, "local") ? 1 : 0,
20007330f729Sjoerg                           /* displayDiagnostics=*/1);
20017330f729Sjoerg 
20027330f729Sjoerg   if (!CreateTranslationUnit(Idx, file, &TU)) {
20037330f729Sjoerg     clang_disposeIndex(Idx);
20047330f729Sjoerg     return 1;
20057330f729Sjoerg   }
20067330f729Sjoerg 
20077330f729Sjoerg   result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
20087330f729Sjoerg   clang_disposeIndex(Idx);
20097330f729Sjoerg   return result;
20107330f729Sjoerg }
20117330f729Sjoerg 
perform_test_load_source(int argc,const char ** argv,const char * filter,CXCursorVisitor Visitor,PostVisitTU PV)20127330f729Sjoerg int perform_test_load_source(int argc, const char **argv,
20137330f729Sjoerg                              const char *filter, CXCursorVisitor Visitor,
20147330f729Sjoerg                              PostVisitTU PV) {
20157330f729Sjoerg   CXIndex Idx;
20167330f729Sjoerg   CXTranslationUnit TU;
20177330f729Sjoerg   const char *CommentSchemaFile;
20187330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
20197330f729Sjoerg   int num_unsaved_files = 0;
20207330f729Sjoerg   enum CXErrorCode Err;
20217330f729Sjoerg   int result;
20227330f729Sjoerg   unsigned Repeats = 0;
20237330f729Sjoerg   unsigned I;
20247330f729Sjoerg   const char *InvocationPath;
20257330f729Sjoerg 
20267330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */
20277330f729Sjoerg                           (!strcmp(filter, "local") ||
20287330f729Sjoerg                            !strcmp(filter, "local-display") ||
20297330f729Sjoerg                            !strcmp(filter, "local-pretty"))
20307330f729Sjoerg                               ? 1
20317330f729Sjoerg                               : 0,
20327330f729Sjoerg                           /* displayDiagnostics=*/1);
20337330f729Sjoerg   InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
20347330f729Sjoerg   if (InvocationPath)
20357330f729Sjoerg     clang_CXIndex_setInvocationEmissionPathOption(Idx, InvocationPath);
20367330f729Sjoerg 
20377330f729Sjoerg   if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
20387330f729Sjoerg     argc--;
20397330f729Sjoerg     argv++;
20407330f729Sjoerg   }
20417330f729Sjoerg 
20427330f729Sjoerg   if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
20437330f729Sjoerg     clang_disposeIndex(Idx);
20447330f729Sjoerg     return -1;
20457330f729Sjoerg   }
20467330f729Sjoerg 
20477330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
20487330f729Sjoerg     Repeats = 5;
20497330f729Sjoerg 
20507330f729Sjoerg   Err = clang_parseTranslationUnit2(Idx, 0,
20517330f729Sjoerg                                     argv + num_unsaved_files,
20527330f729Sjoerg                                     argc - num_unsaved_files,
20537330f729Sjoerg                                     unsaved_files, num_unsaved_files,
20547330f729Sjoerg                                     getDefaultParsingOptions(), &TU);
20557330f729Sjoerg   if (Err != CXError_Success) {
20567330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
20577330f729Sjoerg     describeLibclangFailure(Err);
20587330f729Sjoerg     free_remapped_files(unsaved_files, num_unsaved_files);
20597330f729Sjoerg     clang_disposeIndex(Idx);
20607330f729Sjoerg     return 1;
20617330f729Sjoerg   }
20627330f729Sjoerg 
20637330f729Sjoerg   for (I = 0; I != Repeats; ++I) {
20647330f729Sjoerg     if (checkForErrors(TU) != 0)
20657330f729Sjoerg       return -1;
20667330f729Sjoerg 
20677330f729Sjoerg     if (Repeats > 1) {
20687330f729Sjoerg       clang_suspendTranslationUnit(TU);
20697330f729Sjoerg 
20707330f729Sjoerg       Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
20717330f729Sjoerg                                          clang_defaultReparseOptions(TU));
20727330f729Sjoerg       if (Err != CXError_Success) {
20737330f729Sjoerg         describeLibclangFailure(Err);
20747330f729Sjoerg         free_remapped_files(unsaved_files, num_unsaved_files);
20757330f729Sjoerg         clang_disposeIndex(Idx);
20767330f729Sjoerg         return 1;
20777330f729Sjoerg       }
20787330f729Sjoerg     }
20797330f729Sjoerg   }
20807330f729Sjoerg 
20817330f729Sjoerg   result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
20827330f729Sjoerg                              CommentSchemaFile);
20837330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
20847330f729Sjoerg   clang_disposeIndex(Idx);
20857330f729Sjoerg   return result;
20867330f729Sjoerg }
20877330f729Sjoerg 
perform_test_reparse_source(int argc,const char ** argv,int trials,const char * filter,CXCursorVisitor Visitor,PostVisitTU PV)20887330f729Sjoerg int perform_test_reparse_source(int argc, const char **argv, int trials,
20897330f729Sjoerg                                 const char *filter, CXCursorVisitor Visitor,
20907330f729Sjoerg                                 PostVisitTU PV) {
20917330f729Sjoerg   CXIndex Idx;
20927330f729Sjoerg   CXTranslationUnit TU;
20937330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
20947330f729Sjoerg   int num_unsaved_files = 0;
20957330f729Sjoerg   int compiler_arg_idx = 0;
20967330f729Sjoerg   enum CXErrorCode Err;
20977330f729Sjoerg   int result, i;
20987330f729Sjoerg   int trial;
2099*e038c9c4Sjoerg   int execute_after_trial = 0;
2100*e038c9c4Sjoerg   const char *execute_command = NULL;
21017330f729Sjoerg   int remap_after_trial = 0;
21027330f729Sjoerg   char *endptr = 0;
21037330f729Sjoerg 
21047330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */
21057330f729Sjoerg                           !strcmp(filter, "local") ? 1 : 0,
21067330f729Sjoerg                           /* displayDiagnostics=*/1);
21077330f729Sjoerg 
21087330f729Sjoerg   if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
21097330f729Sjoerg     clang_disposeIndex(Idx);
21107330f729Sjoerg     return -1;
21117330f729Sjoerg   }
21127330f729Sjoerg 
21137330f729Sjoerg   for (i = 0; i < argc; ++i) {
21147330f729Sjoerg     if (strcmp(argv[i], "--") == 0)
21157330f729Sjoerg       break;
21167330f729Sjoerg   }
21177330f729Sjoerg   if (i < argc)
21187330f729Sjoerg     compiler_arg_idx = i+1;
21197330f729Sjoerg   if (num_unsaved_files > compiler_arg_idx)
21207330f729Sjoerg     compiler_arg_idx = num_unsaved_files;
21217330f729Sjoerg 
21227330f729Sjoerg   /* Load the initial translation unit -- we do this without honoring remapped
21237330f729Sjoerg    * files, so that we have a way to test results after changing the source. */
21247330f729Sjoerg   Err = clang_parseTranslationUnit2(Idx, 0,
21257330f729Sjoerg                                     argv + compiler_arg_idx,
21267330f729Sjoerg                                     argc - compiler_arg_idx,
21277330f729Sjoerg                                     0, 0, getDefaultParsingOptions(), &TU);
21287330f729Sjoerg   if (Err != CXError_Success) {
21297330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
21307330f729Sjoerg     describeLibclangFailure(Err);
21317330f729Sjoerg     free_remapped_files(unsaved_files, num_unsaved_files);
21327330f729Sjoerg     clang_disposeIndex(Idx);
21337330f729Sjoerg     return 1;
21347330f729Sjoerg   }
21357330f729Sjoerg 
21367330f729Sjoerg   if (checkForErrors(TU) != 0)
21377330f729Sjoerg     return -1;
21387330f729Sjoerg 
2139*e038c9c4Sjoerg   if (getenv("CINDEXTEST_EXECUTE_COMMAND")) {
2140*e038c9c4Sjoerg     execute_command = getenv("CINDEXTEST_EXECUTE_COMMAND");
2141*e038c9c4Sjoerg   }
2142*e038c9c4Sjoerg   if (getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL")) {
2143*e038c9c4Sjoerg     execute_after_trial =
2144*e038c9c4Sjoerg         strtol(getenv("CINDEXTEST_EXECUTE_AFTER_TRIAL"), &endptr, 10);
2145*e038c9c4Sjoerg   }
2146*e038c9c4Sjoerg 
21477330f729Sjoerg   if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
21487330f729Sjoerg     remap_after_trial =
21497330f729Sjoerg         strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
21507330f729Sjoerg   }
21517330f729Sjoerg 
21527330f729Sjoerg   for (trial = 0; trial < trials; ++trial) {
2153*e038c9c4Sjoerg     if (execute_command && trial == execute_after_trial) {
2154*e038c9c4Sjoerg       result = indextest_perform_shell_execution(execute_command);
2155*e038c9c4Sjoerg       if (result != 0)
2156*e038c9c4Sjoerg         return result;
2157*e038c9c4Sjoerg     }
2158*e038c9c4Sjoerg 
21597330f729Sjoerg     free_remapped_files(unsaved_files, num_unsaved_files);
21607330f729Sjoerg     if (parse_remapped_files_with_try(trial, argc, argv, 0,
21617330f729Sjoerg                                       &unsaved_files, &num_unsaved_files)) {
21627330f729Sjoerg       clang_disposeTranslationUnit(TU);
21637330f729Sjoerg       clang_disposeIndex(Idx);
21647330f729Sjoerg       return -1;
21657330f729Sjoerg     }
21667330f729Sjoerg 
21677330f729Sjoerg     Err = clang_reparseTranslationUnit(
21687330f729Sjoerg         TU,
21697330f729Sjoerg         trial >= remap_after_trial ? num_unsaved_files : 0,
21707330f729Sjoerg         trial >= remap_after_trial ? unsaved_files : 0,
21717330f729Sjoerg         clang_defaultReparseOptions(TU));
21727330f729Sjoerg     if (Err != CXError_Success) {
21737330f729Sjoerg       fprintf(stderr, "Unable to reparse translation unit!\n");
21747330f729Sjoerg       describeLibclangFailure(Err);
21757330f729Sjoerg       clang_disposeTranslationUnit(TU);
21767330f729Sjoerg       free_remapped_files(unsaved_files, num_unsaved_files);
21777330f729Sjoerg       clang_disposeIndex(Idx);
21787330f729Sjoerg       return -1;
21797330f729Sjoerg     }
21807330f729Sjoerg 
21817330f729Sjoerg     if (checkForErrors(TU) != 0)
21827330f729Sjoerg       return -1;
21837330f729Sjoerg   }
21847330f729Sjoerg 
21857330f729Sjoerg   result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
21867330f729Sjoerg 
21877330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
21887330f729Sjoerg   clang_disposeIndex(Idx);
21897330f729Sjoerg   return result;
21907330f729Sjoerg }
21917330f729Sjoerg 
perform_single_file_parse(const char * filename)21927330f729Sjoerg static int perform_single_file_parse(const char *filename) {
21937330f729Sjoerg   CXIndex Idx;
21947330f729Sjoerg   CXTranslationUnit TU;
21957330f729Sjoerg   enum CXErrorCode Err;
21967330f729Sjoerg   int result;
21977330f729Sjoerg 
21987330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */1,
21997330f729Sjoerg                           /* displayDiagnostics=*/1);
22007330f729Sjoerg 
22017330f729Sjoerg   Err = clang_parseTranslationUnit2(Idx, filename,
22027330f729Sjoerg                                     /*command_line_args=*/NULL,
22037330f729Sjoerg                                     /*num_command_line_args=*/0,
22047330f729Sjoerg                                     /*unsaved_files=*/NULL,
22057330f729Sjoerg                                     /*num_unsaved_files=*/0,
22067330f729Sjoerg                                     CXTranslationUnit_SingleFileParse, &TU);
22077330f729Sjoerg   if (Err != CXError_Success) {
22087330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
22097330f729Sjoerg     describeLibclangFailure(Err);
22107330f729Sjoerg     clang_disposeIndex(Idx);
22117330f729Sjoerg     return 1;
22127330f729Sjoerg   }
22137330f729Sjoerg 
22147330f729Sjoerg   result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL,
22157330f729Sjoerg                              /*CommentSchemaFile=*/NULL);
22167330f729Sjoerg   clang_disposeIndex(Idx);
22177330f729Sjoerg   return result;
22187330f729Sjoerg }
22197330f729Sjoerg 
perform_file_retain_excluded_cb(const char * filename)22207330f729Sjoerg static int perform_file_retain_excluded_cb(const char *filename) {
22217330f729Sjoerg   CXIndex Idx;
22227330f729Sjoerg   CXTranslationUnit TU;
22237330f729Sjoerg   enum CXErrorCode Err;
22247330f729Sjoerg   int result;
22257330f729Sjoerg 
22267330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */1,
22277330f729Sjoerg                           /* displayDiagnostics=*/1);
22287330f729Sjoerg 
22297330f729Sjoerg   Err = clang_parseTranslationUnit2(Idx, filename,
22307330f729Sjoerg                                     /*command_line_args=*/NULL,
22317330f729Sjoerg                                     /*num_command_line_args=*/0,
22327330f729Sjoerg                                     /*unsaved_files=*/NULL,
22337330f729Sjoerg                                     /*num_unsaved_files=*/0,
22347330f729Sjoerg                                     CXTranslationUnit_RetainExcludedConditionalBlocks, &TU);
22357330f729Sjoerg   if (Err != CXError_Success) {
22367330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
22377330f729Sjoerg     describeLibclangFailure(Err);
22387330f729Sjoerg     clang_disposeIndex(Idx);
22397330f729Sjoerg     return 1;
22407330f729Sjoerg   }
22417330f729Sjoerg 
22427330f729Sjoerg   result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL,
22437330f729Sjoerg                              /*CommentSchemaFile=*/NULL);
22447330f729Sjoerg   clang_disposeIndex(Idx);
22457330f729Sjoerg   return result;
22467330f729Sjoerg }
22477330f729Sjoerg 
22487330f729Sjoerg /******************************************************************************/
22497330f729Sjoerg /* Logic for testing clang_getCursor().                                       */
22507330f729Sjoerg /******************************************************************************/
22517330f729Sjoerg 
print_cursor_file_scan(CXTranslationUnit TU,CXCursor cursor,unsigned start_line,unsigned start_col,unsigned end_line,unsigned end_col,const char * prefix)22527330f729Sjoerg static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
22537330f729Sjoerg                                    unsigned start_line, unsigned start_col,
22547330f729Sjoerg                                    unsigned end_line, unsigned end_col,
22557330f729Sjoerg                                    const char *prefix) {
22567330f729Sjoerg   printf("// %s: ", FileCheckPrefix);
22577330f729Sjoerg   if (prefix)
22587330f729Sjoerg     printf("-%s", prefix);
22597330f729Sjoerg   PrintExtent(stdout, start_line, start_col, end_line, end_col);
22607330f729Sjoerg   printf(" ");
22617330f729Sjoerg   PrintCursor(cursor, NULL);
22627330f729Sjoerg   printf("\n");
22637330f729Sjoerg }
22647330f729Sjoerg 
perform_file_scan(const char * ast_file,const char * source_file,const char * prefix)22657330f729Sjoerg static int perform_file_scan(const char *ast_file, const char *source_file,
22667330f729Sjoerg                              const char *prefix) {
22677330f729Sjoerg   CXIndex Idx;
22687330f729Sjoerg   CXTranslationUnit TU;
22697330f729Sjoerg   FILE *fp;
22707330f729Sjoerg   CXCursor prevCursor = clang_getNullCursor();
22717330f729Sjoerg   CXFile file;
22727330f729Sjoerg   unsigned line = 1, col = 1;
22737330f729Sjoerg   unsigned start_line = 1, start_col = 1;
22747330f729Sjoerg 
22757330f729Sjoerg   if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
22767330f729Sjoerg                                 /* displayDiagnostics=*/1))) {
22777330f729Sjoerg     fprintf(stderr, "Could not create Index\n");
22787330f729Sjoerg     return 1;
22797330f729Sjoerg   }
22807330f729Sjoerg 
22817330f729Sjoerg   if (!CreateTranslationUnit(Idx, ast_file, &TU))
22827330f729Sjoerg     return 1;
22837330f729Sjoerg 
22847330f729Sjoerg   if ((fp = fopen(source_file, "r")) == NULL) {
22857330f729Sjoerg     fprintf(stderr, "Could not open '%s'\n", source_file);
22867330f729Sjoerg     clang_disposeTranslationUnit(TU);
22877330f729Sjoerg     return 1;
22887330f729Sjoerg   }
22897330f729Sjoerg 
22907330f729Sjoerg   file = clang_getFile(TU, source_file);
22917330f729Sjoerg   for (;;) {
22927330f729Sjoerg     CXCursor cursor;
22937330f729Sjoerg     int c = fgetc(fp);
22947330f729Sjoerg 
22957330f729Sjoerg     if (c == '\n') {
22967330f729Sjoerg       ++line;
22977330f729Sjoerg       col = 1;
22987330f729Sjoerg     } else
22997330f729Sjoerg       ++col;
23007330f729Sjoerg 
23017330f729Sjoerg     /* Check the cursor at this position, and dump the previous one if we have
23027330f729Sjoerg      * found something new.
23037330f729Sjoerg      */
23047330f729Sjoerg     cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
23057330f729Sjoerg     if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
23067330f729Sjoerg         prevCursor.kind != CXCursor_InvalidFile) {
23077330f729Sjoerg       print_cursor_file_scan(TU, prevCursor, start_line, start_col,
23087330f729Sjoerg                              line, col, prefix);
23097330f729Sjoerg       start_line = line;
23107330f729Sjoerg       start_col = col;
23117330f729Sjoerg     }
23127330f729Sjoerg     if (c == EOF)
23137330f729Sjoerg       break;
23147330f729Sjoerg 
23157330f729Sjoerg     prevCursor = cursor;
23167330f729Sjoerg   }
23177330f729Sjoerg 
23187330f729Sjoerg   fclose(fp);
23197330f729Sjoerg   clang_disposeTranslationUnit(TU);
23207330f729Sjoerg   clang_disposeIndex(Idx);
23217330f729Sjoerg   return 0;
23227330f729Sjoerg }
23237330f729Sjoerg 
23247330f729Sjoerg /******************************************************************************/
23257330f729Sjoerg /* Logic for testing clang code completion.                                   */
23267330f729Sjoerg /******************************************************************************/
23277330f729Sjoerg 
23287330f729Sjoerg /* Parse file:line:column from the input string. Returns 0 on success, non-zero
23297330f729Sjoerg    on failure. If successful, the pointer *filename will contain newly-allocated
23307330f729Sjoerg    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)23317330f729Sjoerg int parse_file_line_column(const char *input, char **filename, unsigned *line,
23327330f729Sjoerg                            unsigned *column, unsigned *second_line,
23337330f729Sjoerg                            unsigned *second_column) {
23347330f729Sjoerg   /* Find the second colon. */
23357330f729Sjoerg   const char *last_colon = strrchr(input, ':');
23367330f729Sjoerg   unsigned values[4], i;
23377330f729Sjoerg   unsigned num_values = (second_line && second_column)? 4 : 2;
23387330f729Sjoerg 
23397330f729Sjoerg   char *endptr = 0;
23407330f729Sjoerg   if (!last_colon || last_colon == input) {
23417330f729Sjoerg     if (num_values == 4)
23427330f729Sjoerg       fprintf(stderr, "could not parse filename:line:column:line:column in "
23437330f729Sjoerg               "'%s'\n", input);
23447330f729Sjoerg     else
23457330f729Sjoerg       fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
23467330f729Sjoerg     return 1;
23477330f729Sjoerg   }
23487330f729Sjoerg 
23497330f729Sjoerg   for (i = 0; i != num_values; ++i) {
23507330f729Sjoerg     const char *prev_colon;
23517330f729Sjoerg 
23527330f729Sjoerg     /* Parse the next line or column. */
23537330f729Sjoerg     values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
23547330f729Sjoerg     if (*endptr != 0 && *endptr != ':') {
23557330f729Sjoerg       fprintf(stderr, "could not parse %s in '%s'\n",
23567330f729Sjoerg               (i % 2 ? "column" : "line"), input);
23577330f729Sjoerg       return 1;
23587330f729Sjoerg     }
23597330f729Sjoerg 
23607330f729Sjoerg     if (i + 1 == num_values)
23617330f729Sjoerg       break;
23627330f729Sjoerg 
23637330f729Sjoerg     /* Find the previous colon. */
23647330f729Sjoerg     prev_colon = last_colon - 1;
23657330f729Sjoerg     while (prev_colon != input && *prev_colon != ':')
23667330f729Sjoerg       --prev_colon;
23677330f729Sjoerg     if (prev_colon == input) {
23687330f729Sjoerg       fprintf(stderr, "could not parse %s in '%s'\n",
23697330f729Sjoerg               (i % 2 == 0? "column" : "line"), input);
23707330f729Sjoerg       return 1;
23717330f729Sjoerg     }
23727330f729Sjoerg 
23737330f729Sjoerg     last_colon = prev_colon;
23747330f729Sjoerg   }
23757330f729Sjoerg 
23767330f729Sjoerg   *line = values[0];
23777330f729Sjoerg   *column = values[1];
23787330f729Sjoerg 
23797330f729Sjoerg   if (second_line && second_column) {
23807330f729Sjoerg     *second_line = values[2];
23817330f729Sjoerg     *second_column = values[3];
23827330f729Sjoerg   }
23837330f729Sjoerg 
23847330f729Sjoerg   /* Copy the file name. */
23857330f729Sjoerg   *filename = (char*)malloc(last_colon - input + 1);
23867330f729Sjoerg   assert(*filename);
23877330f729Sjoerg   memcpy(*filename, input, last_colon - input);
23887330f729Sjoerg   (*filename)[last_colon - input] = 0;
23897330f729Sjoerg   return 0;
23907330f729Sjoerg }
23917330f729Sjoerg 
23927330f729Sjoerg const char *
clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind)23937330f729Sjoerg clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
23947330f729Sjoerg   switch (Kind) {
23957330f729Sjoerg   case CXCompletionChunk_Optional: return "Optional";
23967330f729Sjoerg   case CXCompletionChunk_TypedText: return "TypedText";
23977330f729Sjoerg   case CXCompletionChunk_Text: return "Text";
23987330f729Sjoerg   case CXCompletionChunk_Placeholder: return "Placeholder";
23997330f729Sjoerg   case CXCompletionChunk_Informative: return "Informative";
24007330f729Sjoerg   case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
24017330f729Sjoerg   case CXCompletionChunk_LeftParen: return "LeftParen";
24027330f729Sjoerg   case CXCompletionChunk_RightParen: return "RightParen";
24037330f729Sjoerg   case CXCompletionChunk_LeftBracket: return "LeftBracket";
24047330f729Sjoerg   case CXCompletionChunk_RightBracket: return "RightBracket";
24057330f729Sjoerg   case CXCompletionChunk_LeftBrace: return "LeftBrace";
24067330f729Sjoerg   case CXCompletionChunk_RightBrace: return "RightBrace";
24077330f729Sjoerg   case CXCompletionChunk_LeftAngle: return "LeftAngle";
24087330f729Sjoerg   case CXCompletionChunk_RightAngle: return "RightAngle";
24097330f729Sjoerg   case CXCompletionChunk_Comma: return "Comma";
24107330f729Sjoerg   case CXCompletionChunk_ResultType: return "ResultType";
24117330f729Sjoerg   case CXCompletionChunk_Colon: return "Colon";
24127330f729Sjoerg   case CXCompletionChunk_SemiColon: return "SemiColon";
24137330f729Sjoerg   case CXCompletionChunk_Equal: return "Equal";
24147330f729Sjoerg   case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
24157330f729Sjoerg   case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
24167330f729Sjoerg   }
24177330f729Sjoerg 
24187330f729Sjoerg   return "Unknown";
24197330f729Sjoerg }
24207330f729Sjoerg 
checkForErrors(CXTranslationUnit TU)24217330f729Sjoerg static int checkForErrors(CXTranslationUnit TU) {
24227330f729Sjoerg   unsigned Num, i;
24237330f729Sjoerg   CXDiagnostic Diag;
24247330f729Sjoerg   CXString DiagStr;
24257330f729Sjoerg 
24267330f729Sjoerg   if (!getenv("CINDEXTEST_FAILONERROR"))
24277330f729Sjoerg     return 0;
24287330f729Sjoerg 
24297330f729Sjoerg   Num = clang_getNumDiagnostics(TU);
24307330f729Sjoerg   for (i = 0; i != Num; ++i) {
24317330f729Sjoerg     Diag = clang_getDiagnostic(TU, i);
24327330f729Sjoerg     if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
24337330f729Sjoerg       DiagStr = clang_formatDiagnostic(Diag,
24347330f729Sjoerg                                        clang_defaultDiagnosticDisplayOptions());
24357330f729Sjoerg       fprintf(stderr, "%s\n", clang_getCString(DiagStr));
24367330f729Sjoerg       clang_disposeString(DiagStr);
24377330f729Sjoerg       clang_disposeDiagnostic(Diag);
24387330f729Sjoerg       return -1;
24397330f729Sjoerg     }
24407330f729Sjoerg     clang_disposeDiagnostic(Diag);
24417330f729Sjoerg   }
24427330f729Sjoerg 
24437330f729Sjoerg   return 0;
24447330f729Sjoerg }
24457330f729Sjoerg 
print_completion_string(CXCompletionString completion_string,FILE * file)24467330f729Sjoerg static void print_completion_string(CXCompletionString completion_string,
24477330f729Sjoerg                                     FILE *file) {
24487330f729Sjoerg   int I, N;
24497330f729Sjoerg 
24507330f729Sjoerg   N = clang_getNumCompletionChunks(completion_string);
24517330f729Sjoerg   for (I = 0; I != N; ++I) {
24527330f729Sjoerg     CXString text;
24537330f729Sjoerg     const char *cstr;
24547330f729Sjoerg     enum CXCompletionChunkKind Kind
24557330f729Sjoerg       = clang_getCompletionChunkKind(completion_string, I);
24567330f729Sjoerg 
24577330f729Sjoerg     if (Kind == CXCompletionChunk_Optional) {
24587330f729Sjoerg       fprintf(file, "{Optional ");
24597330f729Sjoerg       print_completion_string(
24607330f729Sjoerg                 clang_getCompletionChunkCompletionString(completion_string, I),
24617330f729Sjoerg                               file);
24627330f729Sjoerg       fprintf(file, "}");
24637330f729Sjoerg       continue;
24647330f729Sjoerg     }
24657330f729Sjoerg 
24667330f729Sjoerg     if (Kind == CXCompletionChunk_VerticalSpace) {
24677330f729Sjoerg       fprintf(file, "{VerticalSpace  }");
24687330f729Sjoerg       continue;
24697330f729Sjoerg     }
24707330f729Sjoerg 
24717330f729Sjoerg     text = clang_getCompletionChunkText(completion_string, I);
24727330f729Sjoerg     cstr = clang_getCString(text);
24737330f729Sjoerg     fprintf(file, "{%s %s}",
24747330f729Sjoerg             clang_getCompletionChunkKindSpelling(Kind),
24757330f729Sjoerg             cstr ? cstr : "");
24767330f729Sjoerg     clang_disposeString(text);
24777330f729Sjoerg   }
24787330f729Sjoerg 
24797330f729Sjoerg }
24807330f729Sjoerg 
print_line_column(CXSourceLocation location,FILE * file)24817330f729Sjoerg static void print_line_column(CXSourceLocation location, FILE *file) {
24827330f729Sjoerg     unsigned line, column;
24837330f729Sjoerg     clang_getExpansionLocation(location, NULL, &line, &column, NULL);
24847330f729Sjoerg     fprintf(file, "%d:%d", line, column);
24857330f729Sjoerg }
24867330f729Sjoerg 
print_token_range(CXTranslationUnit translation_unit,CXSourceLocation start,FILE * file)24877330f729Sjoerg static void print_token_range(CXTranslationUnit translation_unit,
24887330f729Sjoerg                               CXSourceLocation start, FILE *file) {
24897330f729Sjoerg   CXToken *token = clang_getToken(translation_unit, start);
24907330f729Sjoerg 
24917330f729Sjoerg   fprintf(file, "{");
24927330f729Sjoerg   if (token != NULL) {
24937330f729Sjoerg     CXSourceRange token_range = clang_getTokenExtent(translation_unit, *token);
24947330f729Sjoerg     print_line_column(clang_getRangeStart(token_range), file);
24957330f729Sjoerg     fprintf(file, "-");
24967330f729Sjoerg     print_line_column(clang_getRangeEnd(token_range), file);
24977330f729Sjoerg     clang_disposeTokens(translation_unit, token, 1);
24987330f729Sjoerg   }
24997330f729Sjoerg 
25007330f729Sjoerg   fprintf(file, "}");
25017330f729Sjoerg }
25027330f729Sjoerg 
print_completion_result(CXTranslationUnit translation_unit,CXCodeCompleteResults * completion_results,unsigned index,FILE * file)25037330f729Sjoerg static void print_completion_result(CXTranslationUnit translation_unit,
25047330f729Sjoerg                                     CXCodeCompleteResults *completion_results,
25057330f729Sjoerg                                     unsigned index,
25067330f729Sjoerg                                     FILE *file) {
25077330f729Sjoerg   CXCompletionResult *completion_result = completion_results->Results + index;
25087330f729Sjoerg   CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
25097330f729Sjoerg   unsigned annotationCount;
25107330f729Sjoerg   enum CXCursorKind ParentKind;
25117330f729Sjoerg   CXString ParentName;
25127330f729Sjoerg   CXString BriefComment;
25137330f729Sjoerg   CXString Annotation;
25147330f729Sjoerg   const char *BriefCommentCString;
25157330f729Sjoerg   unsigned i;
25167330f729Sjoerg 
25177330f729Sjoerg   fprintf(file, "%s:", clang_getCString(ks));
25187330f729Sjoerg   clang_disposeString(ks);
25197330f729Sjoerg 
25207330f729Sjoerg   print_completion_string(completion_result->CompletionString, file);
25217330f729Sjoerg   fprintf(file, " (%u)",
25227330f729Sjoerg           clang_getCompletionPriority(completion_result->CompletionString));
25237330f729Sjoerg   switch (clang_getCompletionAvailability(completion_result->CompletionString)){
25247330f729Sjoerg   case CXAvailability_Available:
25257330f729Sjoerg     break;
25267330f729Sjoerg 
25277330f729Sjoerg   case CXAvailability_Deprecated:
25287330f729Sjoerg     fprintf(file, " (deprecated)");
25297330f729Sjoerg     break;
25307330f729Sjoerg 
25317330f729Sjoerg   case CXAvailability_NotAvailable:
25327330f729Sjoerg     fprintf(file, " (unavailable)");
25337330f729Sjoerg     break;
25347330f729Sjoerg 
25357330f729Sjoerg   case CXAvailability_NotAccessible:
25367330f729Sjoerg     fprintf(file, " (inaccessible)");
25377330f729Sjoerg     break;
25387330f729Sjoerg   }
25397330f729Sjoerg 
25407330f729Sjoerg   annotationCount = clang_getCompletionNumAnnotations(
25417330f729Sjoerg         completion_result->CompletionString);
25427330f729Sjoerg   if (annotationCount) {
25437330f729Sjoerg     unsigned i;
25447330f729Sjoerg     fprintf(file, " (");
25457330f729Sjoerg     for (i = 0; i < annotationCount; ++i) {
25467330f729Sjoerg       if (i != 0)
25477330f729Sjoerg         fprintf(file, ", ");
25487330f729Sjoerg       Annotation =
25497330f729Sjoerg           clang_getCompletionAnnotation(completion_result->CompletionString, i);
25507330f729Sjoerg       fprintf(file, "\"%s\"", clang_getCString(Annotation));
25517330f729Sjoerg       clang_disposeString(Annotation);
25527330f729Sjoerg     }
25537330f729Sjoerg     fprintf(file, ")");
25547330f729Sjoerg   }
25557330f729Sjoerg 
25567330f729Sjoerg   if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
25577330f729Sjoerg     ParentName = clang_getCompletionParent(completion_result->CompletionString,
25587330f729Sjoerg                                            &ParentKind);
25597330f729Sjoerg     if (ParentKind != CXCursor_NotImplemented) {
25607330f729Sjoerg       CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
25617330f729Sjoerg       fprintf(file, " (parent: %s '%s')",
25627330f729Sjoerg               clang_getCString(KindSpelling),
25637330f729Sjoerg               clang_getCString(ParentName));
25647330f729Sjoerg       clang_disposeString(KindSpelling);
25657330f729Sjoerg     }
25667330f729Sjoerg     clang_disposeString(ParentName);
25677330f729Sjoerg   }
25687330f729Sjoerg 
25697330f729Sjoerg   BriefComment = clang_getCompletionBriefComment(
25707330f729Sjoerg                                         completion_result->CompletionString);
25717330f729Sjoerg   BriefCommentCString = clang_getCString(BriefComment);
25727330f729Sjoerg   if (BriefCommentCString && *BriefCommentCString != '\0') {
25737330f729Sjoerg     fprintf(file, "(brief comment: %s)", BriefCommentCString);
25747330f729Sjoerg   }
25757330f729Sjoerg   clang_disposeString(BriefComment);
25767330f729Sjoerg 
25777330f729Sjoerg   for (i = 0; i < clang_getCompletionNumFixIts(completion_results, index);
25787330f729Sjoerg        ++i) {
25797330f729Sjoerg     CXSourceRange correction_range;
25807330f729Sjoerg     CXString FixIt = clang_getCompletionFixIt(completion_results, index, i,
25817330f729Sjoerg                                               &correction_range);
25827330f729Sjoerg     fprintf(file, " (requires fix-it: ");
25837330f729Sjoerg     print_token_range(translation_unit, clang_getRangeStart(correction_range),
25847330f729Sjoerg                       file);
25857330f729Sjoerg     fprintf(file, " to \"%s\")", clang_getCString(FixIt));
25867330f729Sjoerg     clang_disposeString(FixIt);
25877330f729Sjoerg   }
25887330f729Sjoerg 
25897330f729Sjoerg   fprintf(file, "\n");
25907330f729Sjoerg }
25917330f729Sjoerg 
print_completion_contexts(unsigned long long contexts,FILE * file)25927330f729Sjoerg void print_completion_contexts(unsigned long long contexts, FILE *file) {
25937330f729Sjoerg   fprintf(file, "Completion contexts:\n");
25947330f729Sjoerg   if (contexts == CXCompletionContext_Unknown) {
25957330f729Sjoerg     fprintf(file, "Unknown\n");
25967330f729Sjoerg   }
25977330f729Sjoerg   if (contexts & CXCompletionContext_AnyType) {
25987330f729Sjoerg     fprintf(file, "Any type\n");
25997330f729Sjoerg   }
26007330f729Sjoerg   if (contexts & CXCompletionContext_AnyValue) {
26017330f729Sjoerg     fprintf(file, "Any value\n");
26027330f729Sjoerg   }
26037330f729Sjoerg   if (contexts & CXCompletionContext_ObjCObjectValue) {
26047330f729Sjoerg     fprintf(file, "Objective-C object value\n");
26057330f729Sjoerg   }
26067330f729Sjoerg   if (contexts & CXCompletionContext_ObjCSelectorValue) {
26077330f729Sjoerg     fprintf(file, "Objective-C selector value\n");
26087330f729Sjoerg   }
26097330f729Sjoerg   if (contexts & CXCompletionContext_CXXClassTypeValue) {
26107330f729Sjoerg     fprintf(file, "C++ class type value\n");
26117330f729Sjoerg   }
26127330f729Sjoerg   if (contexts & CXCompletionContext_DotMemberAccess) {
26137330f729Sjoerg     fprintf(file, "Dot member access\n");
26147330f729Sjoerg   }
26157330f729Sjoerg   if (contexts & CXCompletionContext_ArrowMemberAccess) {
26167330f729Sjoerg     fprintf(file, "Arrow member access\n");
26177330f729Sjoerg   }
26187330f729Sjoerg   if (contexts & CXCompletionContext_ObjCPropertyAccess) {
26197330f729Sjoerg     fprintf(file, "Objective-C property access\n");
26207330f729Sjoerg   }
26217330f729Sjoerg   if (contexts & CXCompletionContext_EnumTag) {
26227330f729Sjoerg     fprintf(file, "Enum tag\n");
26237330f729Sjoerg   }
26247330f729Sjoerg   if (contexts & CXCompletionContext_UnionTag) {
26257330f729Sjoerg     fprintf(file, "Union tag\n");
26267330f729Sjoerg   }
26277330f729Sjoerg   if (contexts & CXCompletionContext_StructTag) {
26287330f729Sjoerg     fprintf(file, "Struct tag\n");
26297330f729Sjoerg   }
26307330f729Sjoerg   if (contexts & CXCompletionContext_ClassTag) {
26317330f729Sjoerg     fprintf(file, "Class name\n");
26327330f729Sjoerg   }
26337330f729Sjoerg   if (contexts & CXCompletionContext_Namespace) {
26347330f729Sjoerg     fprintf(file, "Namespace or namespace alias\n");
26357330f729Sjoerg   }
26367330f729Sjoerg   if (contexts & CXCompletionContext_NestedNameSpecifier) {
26377330f729Sjoerg     fprintf(file, "Nested name specifier\n");
26387330f729Sjoerg   }
26397330f729Sjoerg   if (contexts & CXCompletionContext_ObjCInterface) {
26407330f729Sjoerg     fprintf(file, "Objective-C interface\n");
26417330f729Sjoerg   }
26427330f729Sjoerg   if (contexts & CXCompletionContext_ObjCProtocol) {
26437330f729Sjoerg     fprintf(file, "Objective-C protocol\n");
26447330f729Sjoerg   }
26457330f729Sjoerg   if (contexts & CXCompletionContext_ObjCCategory) {
26467330f729Sjoerg     fprintf(file, "Objective-C category\n");
26477330f729Sjoerg   }
26487330f729Sjoerg   if (contexts & CXCompletionContext_ObjCInstanceMessage) {
26497330f729Sjoerg     fprintf(file, "Objective-C instance method\n");
26507330f729Sjoerg   }
26517330f729Sjoerg   if (contexts & CXCompletionContext_ObjCClassMessage) {
26527330f729Sjoerg     fprintf(file, "Objective-C class method\n");
26537330f729Sjoerg   }
26547330f729Sjoerg   if (contexts & CXCompletionContext_ObjCSelectorName) {
26557330f729Sjoerg     fprintf(file, "Objective-C selector name\n");
26567330f729Sjoerg   }
26577330f729Sjoerg   if (contexts & CXCompletionContext_MacroName) {
26587330f729Sjoerg     fprintf(file, "Macro name\n");
26597330f729Sjoerg   }
26607330f729Sjoerg   if (contexts & CXCompletionContext_NaturalLanguage) {
26617330f729Sjoerg     fprintf(file, "Natural language\n");
26627330f729Sjoerg   }
26637330f729Sjoerg }
26647330f729Sjoerg 
perform_code_completion(int argc,const char ** argv,int timing_only)26657330f729Sjoerg int perform_code_completion(int argc, const char **argv, int timing_only) {
26667330f729Sjoerg   const char *input = argv[1];
26677330f729Sjoerg   char *filename = 0;
26687330f729Sjoerg   unsigned line;
26697330f729Sjoerg   unsigned column;
26707330f729Sjoerg   CXIndex CIdx;
26717330f729Sjoerg   int errorCode;
26727330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
26737330f729Sjoerg   int num_unsaved_files = 0;
26747330f729Sjoerg   CXCodeCompleteResults *results = 0;
26757330f729Sjoerg   enum CXErrorCode Err;
26767330f729Sjoerg   CXTranslationUnit TU;
26777330f729Sjoerg   unsigned I, Repeats = 1;
26787330f729Sjoerg   unsigned completionOptions = clang_defaultCodeCompleteOptions();
26797330f729Sjoerg   const char *InvocationPath;
26807330f729Sjoerg 
26817330f729Sjoerg   if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
26827330f729Sjoerg     completionOptions |= CXCodeComplete_IncludeCodePatterns;
26837330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
26847330f729Sjoerg     completionOptions |= CXCodeComplete_IncludeBriefComments;
26857330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_SKIP_PREAMBLE"))
26867330f729Sjoerg     completionOptions |= CXCodeComplete_SkipPreamble;
26877330f729Sjoerg   if (getenv("CINDEXTEST_COMPLETION_INCLUDE_FIXITS"))
26887330f729Sjoerg     completionOptions |= CXCodeComplete_IncludeCompletionsWithFixIts;
26897330f729Sjoerg 
26907330f729Sjoerg   if (timing_only)
26917330f729Sjoerg     input += strlen("-code-completion-timing=");
26927330f729Sjoerg   else
26937330f729Sjoerg     input += strlen("-code-completion-at=");
26947330f729Sjoerg 
26957330f729Sjoerg   if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
26967330f729Sjoerg                                           0, 0)))
26977330f729Sjoerg     return errorCode;
26987330f729Sjoerg 
26997330f729Sjoerg   if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
27007330f729Sjoerg     return -1;
27017330f729Sjoerg 
27027330f729Sjoerg   CIdx = clang_createIndex(0, 0);
27037330f729Sjoerg   InvocationPath = getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
27047330f729Sjoerg   if (InvocationPath)
27057330f729Sjoerg     clang_CXIndex_setInvocationEmissionPathOption(CIdx, InvocationPath);
27067330f729Sjoerg 
27077330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
27087330f729Sjoerg     Repeats = 5;
27097330f729Sjoerg 
27107330f729Sjoerg   Err = clang_parseTranslationUnit2(CIdx, 0,
27117330f729Sjoerg                                     argv + num_unsaved_files + 2,
27127330f729Sjoerg                                     argc - num_unsaved_files - 2,
27137330f729Sjoerg                                     0, 0, getDefaultParsingOptions(), &TU);
27147330f729Sjoerg   if (Err != CXError_Success) {
27157330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
27167330f729Sjoerg     describeLibclangFailure(Err);
27177330f729Sjoerg     return 1;
27187330f729Sjoerg   }
27197330f729Sjoerg 
27207330f729Sjoerg   Err = clang_reparseTranslationUnit(TU, 0, 0,
27217330f729Sjoerg                                      clang_defaultReparseOptions(TU));
27227330f729Sjoerg 
27237330f729Sjoerg   if (Err != CXError_Success) {
27247330f729Sjoerg     fprintf(stderr, "Unable to reparse translation unit!\n");
27257330f729Sjoerg     describeLibclangFailure(Err);
27267330f729Sjoerg     clang_disposeTranslationUnit(TU);
27277330f729Sjoerg     return 1;
27287330f729Sjoerg   }
27297330f729Sjoerg 
27307330f729Sjoerg   for (I = 0; I != Repeats; ++I) {
27317330f729Sjoerg     results = clang_codeCompleteAt(TU, filename, line, column,
27327330f729Sjoerg                                    unsaved_files, num_unsaved_files,
27337330f729Sjoerg                                    completionOptions);
27347330f729Sjoerg     if (!results) {
27357330f729Sjoerg       fprintf(stderr, "Unable to perform code completion!\n");
27367330f729Sjoerg       return 1;
27377330f729Sjoerg     }
27387330f729Sjoerg     if (I != Repeats-1)
27397330f729Sjoerg       clang_disposeCodeCompleteResults(results);
27407330f729Sjoerg   }
27417330f729Sjoerg 
27427330f729Sjoerg   if (results) {
27437330f729Sjoerg     unsigned i, n = results->NumResults, containerIsIncomplete = 0;
27447330f729Sjoerg     unsigned long long contexts;
27457330f729Sjoerg     enum CXCursorKind containerKind;
27467330f729Sjoerg     CXString objCSelector;
27477330f729Sjoerg     const char *selectorString;
27487330f729Sjoerg     if (!timing_only) {
27497330f729Sjoerg       /* Sort the code-completion results based on the typed text. */
27507330f729Sjoerg       clang_sortCodeCompletionResults(results->Results, results->NumResults);
27517330f729Sjoerg 
27527330f729Sjoerg       for (i = 0; i != n; ++i)
27537330f729Sjoerg         print_completion_result(TU, results, i, stdout);
27547330f729Sjoerg     }
27557330f729Sjoerg     n = clang_codeCompleteGetNumDiagnostics(results);
27567330f729Sjoerg     for (i = 0; i != n; ++i) {
27577330f729Sjoerg       CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
27587330f729Sjoerg       PrintDiagnostic(diag);
27597330f729Sjoerg       clang_disposeDiagnostic(diag);
27607330f729Sjoerg     }
27617330f729Sjoerg 
27627330f729Sjoerg     contexts = clang_codeCompleteGetContexts(results);
27637330f729Sjoerg     print_completion_contexts(contexts, stdout);
27647330f729Sjoerg 
27657330f729Sjoerg     containerKind = clang_codeCompleteGetContainerKind(results,
27667330f729Sjoerg                                                        &containerIsIncomplete);
27677330f729Sjoerg 
27687330f729Sjoerg     if (containerKind != CXCursor_InvalidCode) {
27697330f729Sjoerg       /* We have found a container */
27707330f729Sjoerg       CXString containerUSR, containerKindSpelling;
27717330f729Sjoerg       containerKindSpelling = clang_getCursorKindSpelling(containerKind);
27727330f729Sjoerg       printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
27737330f729Sjoerg       clang_disposeString(containerKindSpelling);
27747330f729Sjoerg 
27757330f729Sjoerg       if (containerIsIncomplete) {
27767330f729Sjoerg         printf("Container is incomplete\n");
27777330f729Sjoerg       }
27787330f729Sjoerg       else {
27797330f729Sjoerg         printf("Container is complete\n");
27807330f729Sjoerg       }
27817330f729Sjoerg 
27827330f729Sjoerg       containerUSR = clang_codeCompleteGetContainerUSR(results);
27837330f729Sjoerg       printf("Container USR: %s\n", clang_getCString(containerUSR));
27847330f729Sjoerg       clang_disposeString(containerUSR);
27857330f729Sjoerg     }
27867330f729Sjoerg 
27877330f729Sjoerg     objCSelector = clang_codeCompleteGetObjCSelector(results);
27887330f729Sjoerg     selectorString = clang_getCString(objCSelector);
27897330f729Sjoerg     if (selectorString && strlen(selectorString) > 0) {
27907330f729Sjoerg       printf("Objective-C selector: %s\n", selectorString);
27917330f729Sjoerg     }
27927330f729Sjoerg     clang_disposeString(objCSelector);
27937330f729Sjoerg 
27947330f729Sjoerg     clang_disposeCodeCompleteResults(results);
27957330f729Sjoerg   }
27967330f729Sjoerg   clang_disposeTranslationUnit(TU);
27977330f729Sjoerg   clang_disposeIndex(CIdx);
27987330f729Sjoerg   free(filename);
27997330f729Sjoerg 
28007330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
28017330f729Sjoerg 
28027330f729Sjoerg   return 0;
28037330f729Sjoerg }
28047330f729Sjoerg 
28057330f729Sjoerg typedef struct {
28067330f729Sjoerg   char *filename;
28077330f729Sjoerg   unsigned line;
28087330f729Sjoerg   unsigned column;
28097330f729Sjoerg } CursorSourceLocation;
28107330f729Sjoerg 
28117330f729Sjoerg typedef void (*cursor_handler_t)(CXCursor cursor);
28127330f729Sjoerg 
inspect_cursor_at(int argc,const char ** argv,const char * locations_flag,cursor_handler_t handler)28137330f729Sjoerg static int inspect_cursor_at(int argc, const char **argv,
28147330f729Sjoerg                              const char *locations_flag,
28157330f729Sjoerg                              cursor_handler_t handler) {
28167330f729Sjoerg   CXIndex CIdx;
28177330f729Sjoerg   int errorCode;
28187330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
28197330f729Sjoerg   int num_unsaved_files = 0;
28207330f729Sjoerg   enum CXErrorCode Err;
28217330f729Sjoerg   CXTranslationUnit TU;
28227330f729Sjoerg   CXCursor Cursor;
28237330f729Sjoerg   CursorSourceLocation *Locations = 0;
28247330f729Sjoerg   unsigned NumLocations = 0, Loc;
28257330f729Sjoerg   unsigned Repeats = 1;
28267330f729Sjoerg   unsigned I;
28277330f729Sjoerg 
28287330f729Sjoerg   /* Count the number of locations. */
28297330f729Sjoerg   while (strstr(argv[NumLocations+1], locations_flag) == argv[NumLocations+1])
28307330f729Sjoerg     ++NumLocations;
28317330f729Sjoerg 
28327330f729Sjoerg   /* Parse the locations. */
28337330f729Sjoerg   assert(NumLocations > 0 && "Unable to count locations?");
28347330f729Sjoerg   Locations = (CursorSourceLocation *)malloc(
28357330f729Sjoerg                                   NumLocations * sizeof(CursorSourceLocation));
28367330f729Sjoerg   assert(Locations);
28377330f729Sjoerg   for (Loc = 0; Loc < NumLocations; ++Loc) {
28387330f729Sjoerg     const char *input = argv[Loc + 1] + strlen(locations_flag);
28397330f729Sjoerg     if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
28407330f729Sjoerg                                             &Locations[Loc].line,
28417330f729Sjoerg                                             &Locations[Loc].column, 0, 0)))
28427330f729Sjoerg       return errorCode;
28437330f729Sjoerg   }
28447330f729Sjoerg 
28457330f729Sjoerg   if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
28467330f729Sjoerg                            &num_unsaved_files))
28477330f729Sjoerg     return -1;
28487330f729Sjoerg 
28497330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
28507330f729Sjoerg     Repeats = 5;
28517330f729Sjoerg 
28527330f729Sjoerg   /* Parse the translation unit. When we're testing clang_getCursor() after
28537330f729Sjoerg      reparsing, don't remap unsaved files until the second parse. */
28547330f729Sjoerg   CIdx = clang_createIndex(1, 1);
28557330f729Sjoerg   Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
28567330f729Sjoerg                                    argv + num_unsaved_files + 1 + NumLocations,
28577330f729Sjoerg                                    argc - num_unsaved_files - 2 - NumLocations,
28587330f729Sjoerg                                    unsaved_files,
28597330f729Sjoerg                                    Repeats > 1? 0 : num_unsaved_files,
28607330f729Sjoerg                                    getDefaultParsingOptions(), &TU);
28617330f729Sjoerg   if (Err != CXError_Success) {
28627330f729Sjoerg     fprintf(stderr, "unable to parse input\n");
28637330f729Sjoerg     describeLibclangFailure(Err);
28647330f729Sjoerg     return -1;
28657330f729Sjoerg   }
28667330f729Sjoerg 
28677330f729Sjoerg   if (checkForErrors(TU) != 0)
28687330f729Sjoerg     return -1;
28697330f729Sjoerg 
28707330f729Sjoerg   for (I = 0; I != Repeats; ++I) {
28717330f729Sjoerg     if (Repeats > 1) {
28727330f729Sjoerg       Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
28737330f729Sjoerg                                          clang_defaultReparseOptions(TU));
28747330f729Sjoerg       if (Err != CXError_Success) {
28757330f729Sjoerg         describeLibclangFailure(Err);
28767330f729Sjoerg         clang_disposeTranslationUnit(TU);
28777330f729Sjoerg         return 1;
28787330f729Sjoerg       }
28797330f729Sjoerg     }
28807330f729Sjoerg 
28817330f729Sjoerg     if (checkForErrors(TU) != 0)
28827330f729Sjoerg       return -1;
28837330f729Sjoerg 
28847330f729Sjoerg     for (Loc = 0; Loc < NumLocations; ++Loc) {
28857330f729Sjoerg       CXFile file = clang_getFile(TU, Locations[Loc].filename);
28867330f729Sjoerg       if (!file)
28877330f729Sjoerg         continue;
28887330f729Sjoerg 
28897330f729Sjoerg       Cursor = clang_getCursor(TU,
28907330f729Sjoerg                                clang_getLocation(TU, file, Locations[Loc].line,
28917330f729Sjoerg                                                  Locations[Loc].column));
28927330f729Sjoerg 
28937330f729Sjoerg       if (checkForErrors(TU) != 0)
28947330f729Sjoerg         return -1;
28957330f729Sjoerg 
28967330f729Sjoerg       if (I + 1 == Repeats) {
28977330f729Sjoerg         handler(Cursor);
28987330f729Sjoerg         free(Locations[Loc].filename);
28997330f729Sjoerg       }
29007330f729Sjoerg     }
29017330f729Sjoerg   }
29027330f729Sjoerg 
29037330f729Sjoerg   PrintDiagnostics(TU);
29047330f729Sjoerg   clang_disposeTranslationUnit(TU);
29057330f729Sjoerg   clang_disposeIndex(CIdx);
29067330f729Sjoerg   free(Locations);
29077330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
29087330f729Sjoerg   return 0;
29097330f729Sjoerg }
29107330f729Sjoerg 
inspect_print_cursor(CXCursor Cursor)29117330f729Sjoerg static void inspect_print_cursor(CXCursor Cursor) {
29127330f729Sjoerg   CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
29137330f729Sjoerg   CXCompletionString completionString = clang_getCursorCompletionString(
29147330f729Sjoerg                                                                   Cursor);
29157330f729Sjoerg   CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
29167330f729Sjoerg   CXString Spelling;
29177330f729Sjoerg   const char *cspell;
29187330f729Sjoerg   unsigned line, column;
29197330f729Sjoerg   clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
29207330f729Sjoerg   printf("%d:%d ", line, column);
29217330f729Sjoerg   PrintCursor(Cursor, NULL);
29227330f729Sjoerg   PrintCursorExtent(Cursor);
29237330f729Sjoerg   Spelling = clang_getCursorSpelling(Cursor);
29247330f729Sjoerg   cspell = clang_getCString(Spelling);
29257330f729Sjoerg   if (cspell && strlen(cspell) != 0) {
29267330f729Sjoerg     unsigned pieceIndex;
29277330f729Sjoerg     printf(" Spelling=%s (", cspell);
29287330f729Sjoerg     for (pieceIndex = 0; ; ++pieceIndex) {
29297330f729Sjoerg       CXSourceRange range =
29307330f729Sjoerg         clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
29317330f729Sjoerg       if (clang_Range_isNull(range))
29327330f729Sjoerg         break;
29337330f729Sjoerg       PrintRange(range, 0);
29347330f729Sjoerg     }
29357330f729Sjoerg     printf(")");
29367330f729Sjoerg   }
29377330f729Sjoerg   clang_disposeString(Spelling);
29387330f729Sjoerg   if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
29397330f729Sjoerg     printf(" Selector index=%d",
29407330f729Sjoerg            clang_Cursor_getObjCSelectorIndex(Cursor));
29417330f729Sjoerg   if (clang_Cursor_isDynamicCall(Cursor))
29427330f729Sjoerg     printf(" Dynamic-call");
29437330f729Sjoerg   if (Cursor.kind == CXCursor_ObjCMessageExpr ||
29447330f729Sjoerg       Cursor.kind == CXCursor_MemberRefExpr) {
29457330f729Sjoerg     CXType T = clang_Cursor_getReceiverType(Cursor);
29467330f729Sjoerg     if (T.kind != CXType_Invalid) {
29477330f729Sjoerg       CXString S = clang_getTypeKindSpelling(T.kind);
29487330f729Sjoerg       printf(" Receiver-type=%s", clang_getCString(S));
29497330f729Sjoerg       clang_disposeString(S);
29507330f729Sjoerg     }
29517330f729Sjoerg   }
29527330f729Sjoerg 
29537330f729Sjoerg   {
29547330f729Sjoerg     CXModule mod = clang_Cursor_getModule(Cursor);
29557330f729Sjoerg     CXFile astFile;
29567330f729Sjoerg     CXString name, astFilename;
29577330f729Sjoerg     unsigned i, numHeaders;
29587330f729Sjoerg     if (mod) {
29597330f729Sjoerg       astFile = clang_Module_getASTFile(mod);
29607330f729Sjoerg       astFilename = clang_getFileName(astFile);
29617330f729Sjoerg       name = clang_Module_getFullName(mod);
29627330f729Sjoerg       numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
29637330f729Sjoerg       printf(" ModuleName=%s (%s) system=%d Headers(%d):",
29647330f729Sjoerg              clang_getCString(name), clang_getCString(astFilename),
29657330f729Sjoerg              clang_Module_isSystem(mod), numHeaders);
29667330f729Sjoerg       clang_disposeString(name);
29677330f729Sjoerg       clang_disposeString(astFilename);
29687330f729Sjoerg       for (i = 0; i < numHeaders; ++i) {
29697330f729Sjoerg         CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
29707330f729Sjoerg         CXString filename = clang_getFileName(file);
29717330f729Sjoerg         printf("\n%s", clang_getCString(filename));
29727330f729Sjoerg         clang_disposeString(filename);
29737330f729Sjoerg       }
29747330f729Sjoerg     }
29757330f729Sjoerg   }
29767330f729Sjoerg 
29777330f729Sjoerg   if (completionString != NULL) {
29787330f729Sjoerg     printf("\nCompletion string: ");
29797330f729Sjoerg     print_completion_string(completionString, stdout);
29807330f729Sjoerg   }
29817330f729Sjoerg   printf("\n");
29827330f729Sjoerg }
29837330f729Sjoerg 
display_evaluate_results(CXEvalResult result)29847330f729Sjoerg static void display_evaluate_results(CXEvalResult result) {
29857330f729Sjoerg   switch (clang_EvalResult_getKind(result)) {
29867330f729Sjoerg     case CXEval_Int:
29877330f729Sjoerg     {
29887330f729Sjoerg       printf("Kind: Int, ");
29897330f729Sjoerg       if (clang_EvalResult_isUnsignedInt(result)) {
29907330f729Sjoerg         unsigned long long val = clang_EvalResult_getAsUnsigned(result);
29917330f729Sjoerg         printf("unsigned, Value: %llu", val);
29927330f729Sjoerg       } else {
29937330f729Sjoerg         long long val = clang_EvalResult_getAsLongLong(result);
29947330f729Sjoerg         printf("Value: %lld", val);
29957330f729Sjoerg       }
29967330f729Sjoerg       break;
29977330f729Sjoerg     }
29987330f729Sjoerg     case CXEval_Float:
29997330f729Sjoerg     {
30007330f729Sjoerg       double val = clang_EvalResult_getAsDouble(result);
30017330f729Sjoerg       printf("Kind: Float , Value: %f", val);
30027330f729Sjoerg       break;
30037330f729Sjoerg     }
30047330f729Sjoerg     case CXEval_ObjCStrLiteral:
30057330f729Sjoerg     {
30067330f729Sjoerg       const char* str = clang_EvalResult_getAsStr(result);
30077330f729Sjoerg       printf("Kind: ObjCString , Value: %s", str);
30087330f729Sjoerg       break;
30097330f729Sjoerg     }
30107330f729Sjoerg     case CXEval_StrLiteral:
30117330f729Sjoerg     {
30127330f729Sjoerg       const char* str = clang_EvalResult_getAsStr(result);
30137330f729Sjoerg       printf("Kind: CString , Value: %s", str);
30147330f729Sjoerg       break;
30157330f729Sjoerg     }
30167330f729Sjoerg     case CXEval_CFStr:
30177330f729Sjoerg     {
30187330f729Sjoerg       const char* str = clang_EvalResult_getAsStr(result);
30197330f729Sjoerg       printf("Kind: CFString , Value: %s", str);
30207330f729Sjoerg       break;
30217330f729Sjoerg     }
30227330f729Sjoerg     default:
30237330f729Sjoerg       printf("Unexposed");
30247330f729Sjoerg       break;
30257330f729Sjoerg     }
30267330f729Sjoerg }
30277330f729Sjoerg 
inspect_evaluate_cursor(CXCursor Cursor)30287330f729Sjoerg static void inspect_evaluate_cursor(CXCursor Cursor) {
30297330f729Sjoerg   CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
30307330f729Sjoerg   CXString Spelling;
30317330f729Sjoerg   const char *cspell;
30327330f729Sjoerg   unsigned line, column;
30337330f729Sjoerg   CXEvalResult ER;
30347330f729Sjoerg 
30357330f729Sjoerg   clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
30367330f729Sjoerg   printf("%d:%d ", line, column);
30377330f729Sjoerg   PrintCursor(Cursor, NULL);
30387330f729Sjoerg   PrintCursorExtent(Cursor);
30397330f729Sjoerg   Spelling = clang_getCursorSpelling(Cursor);
30407330f729Sjoerg   cspell = clang_getCString(Spelling);
30417330f729Sjoerg   if (cspell && strlen(cspell) != 0) {
30427330f729Sjoerg     unsigned pieceIndex;
30437330f729Sjoerg     printf(" Spelling=%s (", cspell);
30447330f729Sjoerg     for (pieceIndex = 0; ; ++pieceIndex) {
30457330f729Sjoerg       CXSourceRange range =
30467330f729Sjoerg          clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
30477330f729Sjoerg       if (clang_Range_isNull(range))
30487330f729Sjoerg         break;
30497330f729Sjoerg       PrintRange(range, 0);
30507330f729Sjoerg     }
30517330f729Sjoerg     printf(")");
30527330f729Sjoerg   }
30537330f729Sjoerg   clang_disposeString(Spelling);
30547330f729Sjoerg 
30557330f729Sjoerg   ER = clang_Cursor_Evaluate(Cursor);
30567330f729Sjoerg   if (!ER) {
30577330f729Sjoerg     printf("Not Evaluatable");
30587330f729Sjoerg   } else {
30597330f729Sjoerg     display_evaluate_results(ER);
30607330f729Sjoerg     clang_EvalResult_dispose(ER);
30617330f729Sjoerg   }
30627330f729Sjoerg   printf("\n");
30637330f729Sjoerg }
30647330f729Sjoerg 
inspect_macroinfo_cursor(CXCursor Cursor)30657330f729Sjoerg static void inspect_macroinfo_cursor(CXCursor Cursor) {
30667330f729Sjoerg   CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
30677330f729Sjoerg   CXString Spelling;
30687330f729Sjoerg   const char *cspell;
30697330f729Sjoerg   unsigned line, column;
30707330f729Sjoerg   clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
30717330f729Sjoerg   printf("%d:%d ", line, column);
30727330f729Sjoerg   PrintCursor(Cursor, NULL);
30737330f729Sjoerg   PrintCursorExtent(Cursor);
30747330f729Sjoerg   Spelling = clang_getCursorSpelling(Cursor);
30757330f729Sjoerg   cspell = clang_getCString(Spelling);
30767330f729Sjoerg   if (cspell && strlen(cspell) != 0) {
30777330f729Sjoerg     unsigned pieceIndex;
30787330f729Sjoerg     printf(" Spelling=%s (", cspell);
30797330f729Sjoerg     for (pieceIndex = 0; ; ++pieceIndex) {
30807330f729Sjoerg       CXSourceRange range =
30817330f729Sjoerg          clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
30827330f729Sjoerg       if (clang_Range_isNull(range))
30837330f729Sjoerg         break;
30847330f729Sjoerg       PrintRange(range, 0);
30857330f729Sjoerg     }
30867330f729Sjoerg     printf(")");
30877330f729Sjoerg   }
30887330f729Sjoerg   clang_disposeString(Spelling);
30897330f729Sjoerg 
30907330f729Sjoerg   if (clang_Cursor_isMacroBuiltin(Cursor)) {
30917330f729Sjoerg     printf("[builtin macro]");
30927330f729Sjoerg   } else if (clang_Cursor_isMacroFunctionLike(Cursor)) {
30937330f729Sjoerg     printf("[function macro]");
30947330f729Sjoerg   }
30957330f729Sjoerg   printf("\n");
30967330f729Sjoerg }
30977330f729Sjoerg 
findFileRefsVisit(void * context,CXCursor cursor,CXSourceRange range)30987330f729Sjoerg static enum CXVisitorResult findFileRefsVisit(void *context,
30997330f729Sjoerg                                          CXCursor cursor, CXSourceRange range) {
31007330f729Sjoerg   if (clang_Range_isNull(range))
31017330f729Sjoerg     return CXVisit_Continue;
31027330f729Sjoerg 
31037330f729Sjoerg   PrintCursor(cursor, NULL);
31047330f729Sjoerg   PrintRange(range, "");
31057330f729Sjoerg   printf("\n");
31067330f729Sjoerg   return CXVisit_Continue;
31077330f729Sjoerg }
31087330f729Sjoerg 
find_file_refs_at(int argc,const char ** argv)31097330f729Sjoerg static int find_file_refs_at(int argc, const char **argv) {
31107330f729Sjoerg   CXIndex CIdx;
31117330f729Sjoerg   int errorCode;
31127330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
31137330f729Sjoerg   int num_unsaved_files = 0;
31147330f729Sjoerg   enum CXErrorCode Err;
31157330f729Sjoerg   CXTranslationUnit TU;
31167330f729Sjoerg   CXCursor Cursor;
31177330f729Sjoerg   CursorSourceLocation *Locations = 0;
31187330f729Sjoerg   unsigned NumLocations = 0, Loc;
31197330f729Sjoerg   unsigned Repeats = 1;
31207330f729Sjoerg   unsigned I;
31217330f729Sjoerg 
31227330f729Sjoerg   /* Count the number of locations. */
31237330f729Sjoerg   while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
31247330f729Sjoerg     ++NumLocations;
31257330f729Sjoerg 
31267330f729Sjoerg   /* Parse the locations. */
31277330f729Sjoerg   assert(NumLocations > 0 && "Unable to count locations?");
31287330f729Sjoerg   Locations = (CursorSourceLocation *)malloc(
31297330f729Sjoerg                                   NumLocations * sizeof(CursorSourceLocation));
31307330f729Sjoerg   assert(Locations);
31317330f729Sjoerg   for (Loc = 0; Loc < NumLocations; ++Loc) {
31327330f729Sjoerg     const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
31337330f729Sjoerg     if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
31347330f729Sjoerg                                             &Locations[Loc].line,
31357330f729Sjoerg                                             &Locations[Loc].column, 0, 0)))
31367330f729Sjoerg       return errorCode;
31377330f729Sjoerg   }
31387330f729Sjoerg 
31397330f729Sjoerg   if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
31407330f729Sjoerg                            &num_unsaved_files))
31417330f729Sjoerg     return -1;
31427330f729Sjoerg 
31437330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
31447330f729Sjoerg     Repeats = 5;
31457330f729Sjoerg 
31467330f729Sjoerg   /* Parse the translation unit. When we're testing clang_getCursor() after
31477330f729Sjoerg      reparsing, don't remap unsaved files until the second parse. */
31487330f729Sjoerg   CIdx = clang_createIndex(1, 1);
31497330f729Sjoerg   Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
31507330f729Sjoerg                                     argv + num_unsaved_files + 1 + NumLocations,
31517330f729Sjoerg                                     argc - num_unsaved_files - 2 - NumLocations,
31527330f729Sjoerg                                     unsaved_files,
31537330f729Sjoerg                                     Repeats > 1? 0 : num_unsaved_files,
31547330f729Sjoerg                                     getDefaultParsingOptions(), &TU);
31557330f729Sjoerg   if (Err != CXError_Success) {
31567330f729Sjoerg     fprintf(stderr, "unable to parse input\n");
31577330f729Sjoerg     describeLibclangFailure(Err);
31587330f729Sjoerg     clang_disposeTranslationUnit(TU);
31597330f729Sjoerg     return -1;
31607330f729Sjoerg   }
31617330f729Sjoerg 
31627330f729Sjoerg   if (checkForErrors(TU) != 0)
31637330f729Sjoerg     return -1;
31647330f729Sjoerg 
31657330f729Sjoerg   for (I = 0; I != Repeats; ++I) {
31667330f729Sjoerg     if (Repeats > 1) {
31677330f729Sjoerg       Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
31687330f729Sjoerg                                          clang_defaultReparseOptions(TU));
31697330f729Sjoerg       if (Err != CXError_Success) {
31707330f729Sjoerg         describeLibclangFailure(Err);
31717330f729Sjoerg         clang_disposeTranslationUnit(TU);
31727330f729Sjoerg         return 1;
31737330f729Sjoerg       }
31747330f729Sjoerg     }
31757330f729Sjoerg 
31767330f729Sjoerg     if (checkForErrors(TU) != 0)
31777330f729Sjoerg       return -1;
31787330f729Sjoerg 
31797330f729Sjoerg     for (Loc = 0; Loc < NumLocations; ++Loc) {
31807330f729Sjoerg       CXFile file = clang_getFile(TU, Locations[Loc].filename);
31817330f729Sjoerg       if (!file)
31827330f729Sjoerg         continue;
31837330f729Sjoerg 
31847330f729Sjoerg       Cursor = clang_getCursor(TU,
31857330f729Sjoerg                                clang_getLocation(TU, file, Locations[Loc].line,
31867330f729Sjoerg                                                  Locations[Loc].column));
31877330f729Sjoerg 
31887330f729Sjoerg       if (checkForErrors(TU) != 0)
31897330f729Sjoerg         return -1;
31907330f729Sjoerg 
31917330f729Sjoerg       if (I + 1 == Repeats) {
31927330f729Sjoerg         CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
31937330f729Sjoerg         PrintCursor(Cursor, NULL);
31947330f729Sjoerg         printf("\n");
31957330f729Sjoerg         clang_findReferencesInFile(Cursor, file, visitor);
31967330f729Sjoerg         free(Locations[Loc].filename);
31977330f729Sjoerg 
31987330f729Sjoerg         if (checkForErrors(TU) != 0)
31997330f729Sjoerg           return -1;
32007330f729Sjoerg       }
32017330f729Sjoerg     }
32027330f729Sjoerg   }
32037330f729Sjoerg 
32047330f729Sjoerg   PrintDiagnostics(TU);
32057330f729Sjoerg   clang_disposeTranslationUnit(TU);
32067330f729Sjoerg   clang_disposeIndex(CIdx);
32077330f729Sjoerg   free(Locations);
32087330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
32097330f729Sjoerg   return 0;
32107330f729Sjoerg }
32117330f729Sjoerg 
findFileIncludesVisit(void * context,CXCursor cursor,CXSourceRange range)32127330f729Sjoerg static enum CXVisitorResult findFileIncludesVisit(void *context,
32137330f729Sjoerg                                          CXCursor cursor, CXSourceRange range) {
32147330f729Sjoerg   PrintCursor(cursor, NULL);
32157330f729Sjoerg   PrintRange(range, "");
32167330f729Sjoerg   printf("\n");
32177330f729Sjoerg   return CXVisit_Continue;
32187330f729Sjoerg }
32197330f729Sjoerg 
find_file_includes_in(int argc,const char ** argv)32207330f729Sjoerg static int find_file_includes_in(int argc, const char **argv) {
32217330f729Sjoerg   CXIndex CIdx;
32227330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
32237330f729Sjoerg   int num_unsaved_files = 0;
32247330f729Sjoerg   enum CXErrorCode Err;
32257330f729Sjoerg   CXTranslationUnit TU;
32267330f729Sjoerg   const char **Filenames = 0;
32277330f729Sjoerg   unsigned NumFilenames = 0;
32287330f729Sjoerg   unsigned Repeats = 1;
32297330f729Sjoerg   unsigned I, FI;
32307330f729Sjoerg 
32317330f729Sjoerg   /* Count the number of locations. */
32327330f729Sjoerg   while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
32337330f729Sjoerg     ++NumFilenames;
32347330f729Sjoerg 
32357330f729Sjoerg   /* Parse the locations. */
32367330f729Sjoerg   assert(NumFilenames > 0 && "Unable to count filenames?");
32377330f729Sjoerg   Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
32387330f729Sjoerg   assert(Filenames);
32397330f729Sjoerg   for (I = 0; I < NumFilenames; ++I) {
32407330f729Sjoerg     const char *input = argv[I + 1] + strlen("-file-includes-in=");
32417330f729Sjoerg     /* Copy the file name. */
32427330f729Sjoerg     Filenames[I] = input;
32437330f729Sjoerg   }
32447330f729Sjoerg 
32457330f729Sjoerg   if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
32467330f729Sjoerg                            &num_unsaved_files))
32477330f729Sjoerg     return -1;
32487330f729Sjoerg 
32497330f729Sjoerg   if (getenv("CINDEXTEST_EDITING"))
32507330f729Sjoerg     Repeats = 2;
32517330f729Sjoerg 
32527330f729Sjoerg   /* Parse the translation unit. When we're testing clang_getCursor() after
32537330f729Sjoerg      reparsing, don't remap unsaved files until the second parse. */
32547330f729Sjoerg   CIdx = clang_createIndex(1, 1);
32557330f729Sjoerg   Err = clang_parseTranslationUnit2(
32567330f729Sjoerg       CIdx, argv[argc - 1],
32577330f729Sjoerg       argv + num_unsaved_files + 1 + NumFilenames,
32587330f729Sjoerg       argc - num_unsaved_files - 2 - NumFilenames,
32597330f729Sjoerg       unsaved_files,
32607330f729Sjoerg       Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU);
32617330f729Sjoerg 
32627330f729Sjoerg   if (Err != CXError_Success) {
32637330f729Sjoerg     fprintf(stderr, "unable to parse input\n");
32647330f729Sjoerg     describeLibclangFailure(Err);
32657330f729Sjoerg     clang_disposeTranslationUnit(TU);
32667330f729Sjoerg     return -1;
32677330f729Sjoerg   }
32687330f729Sjoerg 
32697330f729Sjoerg   if (checkForErrors(TU) != 0)
32707330f729Sjoerg     return -1;
32717330f729Sjoerg 
32727330f729Sjoerg   for (I = 0; I != Repeats; ++I) {
32737330f729Sjoerg     if (Repeats > 1) {
32747330f729Sjoerg       Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
32757330f729Sjoerg                                          clang_defaultReparseOptions(TU));
32767330f729Sjoerg       if (Err != CXError_Success) {
32777330f729Sjoerg         describeLibclangFailure(Err);
32787330f729Sjoerg         clang_disposeTranslationUnit(TU);
32797330f729Sjoerg         return 1;
32807330f729Sjoerg       }
32817330f729Sjoerg     }
32827330f729Sjoerg 
32837330f729Sjoerg     if (checkForErrors(TU) != 0)
32847330f729Sjoerg       return -1;
32857330f729Sjoerg 
32867330f729Sjoerg     for (FI = 0; FI < NumFilenames; ++FI) {
32877330f729Sjoerg       CXFile file = clang_getFile(TU, Filenames[FI]);
32887330f729Sjoerg       if (!file)
32897330f729Sjoerg         continue;
32907330f729Sjoerg 
32917330f729Sjoerg       if (checkForErrors(TU) != 0)
32927330f729Sjoerg         return -1;
32937330f729Sjoerg 
32947330f729Sjoerg       if (I + 1 == Repeats) {
32957330f729Sjoerg         CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
32967330f729Sjoerg         clang_findIncludesInFile(TU, file, visitor);
32977330f729Sjoerg 
32987330f729Sjoerg         if (checkForErrors(TU) != 0)
32997330f729Sjoerg           return -1;
33007330f729Sjoerg       }
33017330f729Sjoerg     }
33027330f729Sjoerg   }
33037330f729Sjoerg 
33047330f729Sjoerg   PrintDiagnostics(TU);
33057330f729Sjoerg   clang_disposeTranslationUnit(TU);
33067330f729Sjoerg   clang_disposeIndex(CIdx);
33077330f729Sjoerg   free((void *)Filenames);
33087330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
33097330f729Sjoerg   return 0;
33107330f729Sjoerg }
33117330f729Sjoerg 
33127330f729Sjoerg #define MAX_IMPORTED_ASTFILES 200
33137330f729Sjoerg 
33147330f729Sjoerg typedef struct {
33157330f729Sjoerg   char **filenames;
33167330f729Sjoerg   unsigned num_files;
33177330f729Sjoerg } ImportedASTFilesData;
33187330f729Sjoerg 
importedASTs_create()33197330f729Sjoerg static ImportedASTFilesData *importedASTs_create() {
33207330f729Sjoerg   ImportedASTFilesData *p;
33217330f729Sjoerg   p = malloc(sizeof(ImportedASTFilesData));
33227330f729Sjoerg   assert(p);
33237330f729Sjoerg   p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
33247330f729Sjoerg   assert(p->filenames);
33257330f729Sjoerg   p->num_files = 0;
33267330f729Sjoerg   return p;
33277330f729Sjoerg }
33287330f729Sjoerg 
importedASTs_dispose(ImportedASTFilesData * p)33297330f729Sjoerg static void importedASTs_dispose(ImportedASTFilesData *p) {
33307330f729Sjoerg   unsigned i;
33317330f729Sjoerg   if (!p)
33327330f729Sjoerg     return;
33337330f729Sjoerg 
33347330f729Sjoerg   for (i = 0; i < p->num_files; ++i)
33357330f729Sjoerg     free(p->filenames[i]);
33367330f729Sjoerg   free(p->filenames);
33377330f729Sjoerg   free(p);
33387330f729Sjoerg }
33397330f729Sjoerg 
importedASTS_insert(ImportedASTFilesData * p,const char * file)33407330f729Sjoerg static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
33417330f729Sjoerg   unsigned i;
33427330f729Sjoerg   assert(p && file);
33437330f729Sjoerg   for (i = 0; i < p->num_files; ++i)
33447330f729Sjoerg     if (strcmp(file, p->filenames[i]) == 0)
33457330f729Sjoerg       return;
33467330f729Sjoerg   assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
33477330f729Sjoerg   p->filenames[p->num_files++] = strdup(file);
33487330f729Sjoerg }
33497330f729Sjoerg 
33507330f729Sjoerg typedef struct IndexDataStringList_ {
33517330f729Sjoerg   struct IndexDataStringList_ *next;
33527330f729Sjoerg   char data[1]; /* Dynamically sized. */
33537330f729Sjoerg } IndexDataStringList;
33547330f729Sjoerg 
33557330f729Sjoerg typedef struct {
33567330f729Sjoerg   const char *check_prefix;
33577330f729Sjoerg   int first_check_printed;
33587330f729Sjoerg   int fail_for_error;
33597330f729Sjoerg   int abort;
33607330f729Sjoerg   CXString main_filename;
33617330f729Sjoerg   ImportedASTFilesData *importedASTs;
33627330f729Sjoerg   IndexDataStringList *strings;
33637330f729Sjoerg   CXTranslationUnit TU;
33647330f729Sjoerg } IndexData;
33657330f729Sjoerg 
free_client_data(IndexData * index_data)33667330f729Sjoerg static void free_client_data(IndexData *index_data) {
33677330f729Sjoerg   IndexDataStringList *node = index_data->strings;
33687330f729Sjoerg   while (node) {
33697330f729Sjoerg     IndexDataStringList *next = node->next;
33707330f729Sjoerg     free(node);
33717330f729Sjoerg     node = next;
33727330f729Sjoerg   }
33737330f729Sjoerg   index_data->strings = NULL;
33747330f729Sjoerg }
33757330f729Sjoerg 
printCheck(IndexData * data)33767330f729Sjoerg static void printCheck(IndexData *data) {
33777330f729Sjoerg   if (data->check_prefix) {
33787330f729Sjoerg     if (data->first_check_printed) {
33797330f729Sjoerg       printf("// %s-NEXT: ", data->check_prefix);
33807330f729Sjoerg     } else {
33817330f729Sjoerg       printf("// %s     : ", data->check_prefix);
33827330f729Sjoerg       data->first_check_printed = 1;
33837330f729Sjoerg     }
33847330f729Sjoerg   }
33857330f729Sjoerg }
33867330f729Sjoerg 
printCXIndexFile(CXIdxClientFile file)33877330f729Sjoerg static void printCXIndexFile(CXIdxClientFile file) {
33887330f729Sjoerg   CXString filename = clang_getFileName((CXFile)file);
33897330f729Sjoerg   printf("%s", clang_getCString(filename));
33907330f729Sjoerg   clang_disposeString(filename);
33917330f729Sjoerg }
33927330f729Sjoerg 
printCXIndexLoc(CXIdxLoc loc,CXClientData client_data)33937330f729Sjoerg static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
33947330f729Sjoerg   IndexData *index_data;
33957330f729Sjoerg   CXString filename;
33967330f729Sjoerg   const char *cname;
33977330f729Sjoerg   CXIdxClientFile file;
33987330f729Sjoerg   unsigned line, column;
33997330f729Sjoerg   const char *main_filename;
34007330f729Sjoerg   int isMainFile;
34017330f729Sjoerg 
34027330f729Sjoerg   index_data = (IndexData *)client_data;
34037330f729Sjoerg   clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
34047330f729Sjoerg   if (line == 0) {
34057330f729Sjoerg     printf("<invalid>");
34067330f729Sjoerg     return;
34077330f729Sjoerg   }
34087330f729Sjoerg   if (!file) {
34097330f729Sjoerg     printf("<no idxfile>");
34107330f729Sjoerg     return;
34117330f729Sjoerg   }
34127330f729Sjoerg   filename = clang_getFileName((CXFile)file);
34137330f729Sjoerg   cname = clang_getCString(filename);
34147330f729Sjoerg   main_filename = clang_getCString(index_data->main_filename);
34157330f729Sjoerg   if (strcmp(cname, main_filename) == 0)
34167330f729Sjoerg     isMainFile = 1;
34177330f729Sjoerg   else
34187330f729Sjoerg     isMainFile = 0;
34197330f729Sjoerg   clang_disposeString(filename);
34207330f729Sjoerg 
34217330f729Sjoerg   if (!isMainFile) {
34227330f729Sjoerg     printCXIndexFile(file);
34237330f729Sjoerg     printf(":");
34247330f729Sjoerg   }
34257330f729Sjoerg   printf("%d:%d", line, column);
34267330f729Sjoerg }
34277330f729Sjoerg 
digitCount(unsigned val)34287330f729Sjoerg static unsigned digitCount(unsigned val) {
34297330f729Sjoerg   unsigned c = 1;
34307330f729Sjoerg   while (1) {
34317330f729Sjoerg     if (val < 10)
34327330f729Sjoerg       return c;
34337330f729Sjoerg     ++c;
34347330f729Sjoerg     val /= 10;
34357330f729Sjoerg   }
34367330f729Sjoerg }
34377330f729Sjoerg 
makeClientContainer(CXClientData * client_data,const CXIdxEntityInfo * info,CXIdxLoc loc)34387330f729Sjoerg static CXIdxClientContainer makeClientContainer(CXClientData *client_data,
34397330f729Sjoerg                                                 const CXIdxEntityInfo *info,
34407330f729Sjoerg                                                 CXIdxLoc loc) {
34417330f729Sjoerg   IndexData *index_data;
34427330f729Sjoerg   IndexDataStringList *node;
34437330f729Sjoerg   const char *name;
34447330f729Sjoerg   char *newStr;
34457330f729Sjoerg   CXIdxClientFile file;
34467330f729Sjoerg   unsigned line, column;
34477330f729Sjoerg 
34487330f729Sjoerg   name = info->name;
34497330f729Sjoerg   if (!name)
34507330f729Sjoerg     name = "<anon-tag>";
34517330f729Sjoerg 
34527330f729Sjoerg   clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
34537330f729Sjoerg 
34547330f729Sjoerg   node =
34557330f729Sjoerg       (IndexDataStringList *)malloc(sizeof(IndexDataStringList) + strlen(name) +
34567330f729Sjoerg                                     digitCount(line) + digitCount(column) + 2);
34577330f729Sjoerg   assert(node);
34587330f729Sjoerg   newStr = node->data;
34597330f729Sjoerg   sprintf(newStr, "%s:%d:%d", name, line, column);
34607330f729Sjoerg 
34617330f729Sjoerg   /* Remember string so it can be freed later. */
34627330f729Sjoerg   index_data = (IndexData *)client_data;
34637330f729Sjoerg   node->next = index_data->strings;
34647330f729Sjoerg   index_data->strings = node;
34657330f729Sjoerg 
34667330f729Sjoerg   return (CXIdxClientContainer)newStr;
34677330f729Sjoerg }
34687330f729Sjoerg 
printCXIndexContainer(const CXIdxContainerInfo * info)34697330f729Sjoerg static void printCXIndexContainer(const CXIdxContainerInfo *info) {
34707330f729Sjoerg   CXIdxClientContainer container;
34717330f729Sjoerg   container = clang_index_getClientContainer(info);
34727330f729Sjoerg   if (!container)
34737330f729Sjoerg     printf("[<<NULL>>]");
34747330f729Sjoerg   else
34757330f729Sjoerg     printf("[%s]", (const char *)container);
34767330f729Sjoerg }
34777330f729Sjoerg 
getEntityKindString(CXIdxEntityKind kind)34787330f729Sjoerg static const char *getEntityKindString(CXIdxEntityKind kind) {
34797330f729Sjoerg   switch (kind) {
34807330f729Sjoerg   case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
34817330f729Sjoerg   case CXIdxEntity_Typedef: return "typedef";
34827330f729Sjoerg   case CXIdxEntity_Function: return "function";
34837330f729Sjoerg   case CXIdxEntity_Variable: return "variable";
34847330f729Sjoerg   case CXIdxEntity_Field: return "field";
34857330f729Sjoerg   case CXIdxEntity_EnumConstant: return "enumerator";
34867330f729Sjoerg   case CXIdxEntity_ObjCClass: return "objc-class";
34877330f729Sjoerg   case CXIdxEntity_ObjCProtocol: return "objc-protocol";
34887330f729Sjoerg   case CXIdxEntity_ObjCCategory: return "objc-category";
34897330f729Sjoerg   case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
34907330f729Sjoerg   case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
34917330f729Sjoerg   case CXIdxEntity_ObjCProperty: return "objc-property";
34927330f729Sjoerg   case CXIdxEntity_ObjCIvar: return "objc-ivar";
34937330f729Sjoerg   case CXIdxEntity_Enum: return "enum";
34947330f729Sjoerg   case CXIdxEntity_Struct: return "struct";
34957330f729Sjoerg   case CXIdxEntity_Union: return "union";
34967330f729Sjoerg   case CXIdxEntity_CXXClass: return "c++-class";
34977330f729Sjoerg   case CXIdxEntity_CXXNamespace: return "namespace";
34987330f729Sjoerg   case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
34997330f729Sjoerg   case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
35007330f729Sjoerg   case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
35017330f729Sjoerg   case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
35027330f729Sjoerg   case CXIdxEntity_CXXConstructor: return "constructor";
35037330f729Sjoerg   case CXIdxEntity_CXXDestructor: return "destructor";
35047330f729Sjoerg   case CXIdxEntity_CXXConversionFunction: return "conversion-func";
35057330f729Sjoerg   case CXIdxEntity_CXXTypeAlias: return "type-alias";
35067330f729Sjoerg   case CXIdxEntity_CXXInterface: return "c++-__interface";
35077330f729Sjoerg   }
35087330f729Sjoerg   assert(0 && "Garbage entity kind");
35097330f729Sjoerg   return 0;
35107330f729Sjoerg }
35117330f729Sjoerg 
getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind)35127330f729Sjoerg static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
35137330f729Sjoerg   switch (kind) {
35147330f729Sjoerg   case CXIdxEntity_NonTemplate: return "";
35157330f729Sjoerg   case CXIdxEntity_Template: return "-template";
35167330f729Sjoerg   case CXIdxEntity_TemplatePartialSpecialization:
35177330f729Sjoerg     return "-template-partial-spec";
35187330f729Sjoerg   case CXIdxEntity_TemplateSpecialization: return "-template-spec";
35197330f729Sjoerg   }
35207330f729Sjoerg   assert(0 && "Garbage entity kind");
35217330f729Sjoerg   return 0;
35227330f729Sjoerg }
35237330f729Sjoerg 
getEntityLanguageString(CXIdxEntityLanguage kind)35247330f729Sjoerg static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
35257330f729Sjoerg   switch (kind) {
35267330f729Sjoerg   case CXIdxEntityLang_None: return "<none>";
35277330f729Sjoerg   case CXIdxEntityLang_C: return "C";
35287330f729Sjoerg   case CXIdxEntityLang_ObjC: return "ObjC";
35297330f729Sjoerg   case CXIdxEntityLang_CXX: return "C++";
35307330f729Sjoerg   case CXIdxEntityLang_Swift: return "Swift";
35317330f729Sjoerg   }
35327330f729Sjoerg   assert(0 && "Garbage language kind");
35337330f729Sjoerg   return 0;
35347330f729Sjoerg }
35357330f729Sjoerg 
printEntityInfo(const char * cb,CXClientData client_data,const CXIdxEntityInfo * info)35367330f729Sjoerg static void printEntityInfo(const char *cb,
35377330f729Sjoerg                             CXClientData client_data,
35387330f729Sjoerg                             const CXIdxEntityInfo *info) {
35397330f729Sjoerg   const char *name;
35407330f729Sjoerg   IndexData *index_data;
35417330f729Sjoerg   unsigned i;
35427330f729Sjoerg   index_data = (IndexData *)client_data;
35437330f729Sjoerg   printCheck(index_data);
35447330f729Sjoerg 
35457330f729Sjoerg   if (!info) {
35467330f729Sjoerg     printf("%s: <<NULL>>", cb);
35477330f729Sjoerg     return;
35487330f729Sjoerg   }
35497330f729Sjoerg 
35507330f729Sjoerg   name = info->name;
35517330f729Sjoerg   if (!name)
35527330f729Sjoerg     name = "<anon-tag>";
35537330f729Sjoerg 
35547330f729Sjoerg   printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
35557330f729Sjoerg          getEntityTemplateKindString(info->templateKind));
35567330f729Sjoerg   printf(" | name: %s", name);
35577330f729Sjoerg   printf(" | USR: %s", info->USR);
35587330f729Sjoerg   printf(" | lang: %s", getEntityLanguageString(info->lang));
35597330f729Sjoerg 
35607330f729Sjoerg   for (i = 0; i != info->numAttributes; ++i) {
35617330f729Sjoerg     const CXIdxAttrInfo *Attr = info->attributes[i];
35627330f729Sjoerg     printf("     <attribute>: ");
35637330f729Sjoerg     PrintCursor(Attr->cursor, NULL);
35647330f729Sjoerg   }
35657330f729Sjoerg }
35667330f729Sjoerg 
printBaseClassInfo(CXClientData client_data,const CXIdxBaseClassInfo * info)35677330f729Sjoerg static void printBaseClassInfo(CXClientData client_data,
35687330f729Sjoerg                                const CXIdxBaseClassInfo *info) {
35697330f729Sjoerg   printEntityInfo("     <base>", client_data, info->base);
35707330f729Sjoerg   printf(" | cursor: ");
35717330f729Sjoerg   PrintCursor(info->cursor, NULL);
35727330f729Sjoerg   printf(" | loc: ");
35737330f729Sjoerg   printCXIndexLoc(info->loc, client_data);
35747330f729Sjoerg }
35757330f729Sjoerg 
printProtocolList(const CXIdxObjCProtocolRefListInfo * ProtoInfo,CXClientData client_data)35767330f729Sjoerg static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
35777330f729Sjoerg                               CXClientData client_data) {
35787330f729Sjoerg   unsigned i;
35797330f729Sjoerg   for (i = 0; i < ProtoInfo->numProtocols; ++i) {
35807330f729Sjoerg     printEntityInfo("     <protocol>", client_data,
35817330f729Sjoerg                     ProtoInfo->protocols[i]->protocol);
35827330f729Sjoerg     printf(" | cursor: ");
35837330f729Sjoerg     PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
35847330f729Sjoerg     printf(" | loc: ");
35857330f729Sjoerg     printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
35867330f729Sjoerg     printf("\n");
35877330f729Sjoerg   }
35887330f729Sjoerg }
35897330f729Sjoerg 
printSymbolRole(CXSymbolRole role)35907330f729Sjoerg static void printSymbolRole(CXSymbolRole role) {
35917330f729Sjoerg   if (role & CXSymbolRole_Declaration)
35927330f729Sjoerg     printf(" decl");
35937330f729Sjoerg   if (role & CXSymbolRole_Definition)
35947330f729Sjoerg     printf(" def");
35957330f729Sjoerg   if (role & CXSymbolRole_Reference)
35967330f729Sjoerg     printf(" ref");
35977330f729Sjoerg   if (role & CXSymbolRole_Read)
35987330f729Sjoerg     printf(" read");
35997330f729Sjoerg   if (role & CXSymbolRole_Write)
36007330f729Sjoerg     printf(" write");
36017330f729Sjoerg   if (role & CXSymbolRole_Call)
36027330f729Sjoerg     printf(" call");
36037330f729Sjoerg   if (role & CXSymbolRole_Dynamic)
36047330f729Sjoerg     printf(" dyn");
36057330f729Sjoerg   if (role & CXSymbolRole_AddressOf)
36067330f729Sjoerg     printf(" addr");
36077330f729Sjoerg   if (role & CXSymbolRole_Implicit)
36087330f729Sjoerg     printf(" implicit");
36097330f729Sjoerg }
36107330f729Sjoerg 
index_diagnostic(CXClientData client_data,CXDiagnosticSet diagSet,void * reserved)36117330f729Sjoerg static void index_diagnostic(CXClientData client_data,
36127330f729Sjoerg                              CXDiagnosticSet diagSet, void *reserved) {
36137330f729Sjoerg   CXString str;
36147330f729Sjoerg   const char *cstr;
36157330f729Sjoerg   unsigned numDiags, i;
36167330f729Sjoerg   CXDiagnostic diag;
36177330f729Sjoerg   IndexData *index_data;
36187330f729Sjoerg   index_data = (IndexData *)client_data;
36197330f729Sjoerg   printCheck(index_data);
36207330f729Sjoerg 
36217330f729Sjoerg   numDiags = clang_getNumDiagnosticsInSet(diagSet);
36227330f729Sjoerg   for (i = 0; i != numDiags; ++i) {
36237330f729Sjoerg     diag = clang_getDiagnosticInSet(diagSet, i);
36247330f729Sjoerg     str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
36257330f729Sjoerg     cstr = clang_getCString(str);
36267330f729Sjoerg     printf("[diagnostic]: %s\n", cstr);
36277330f729Sjoerg     clang_disposeString(str);
36287330f729Sjoerg 
36297330f729Sjoerg     if (getenv("CINDEXTEST_FAILONERROR") &&
36307330f729Sjoerg         clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
36317330f729Sjoerg       index_data->fail_for_error = 1;
36327330f729Sjoerg     }
36337330f729Sjoerg   }
36347330f729Sjoerg }
36357330f729Sjoerg 
index_enteredMainFile(CXClientData client_data,CXFile file,void * reserved)36367330f729Sjoerg static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
36377330f729Sjoerg                                        CXFile file, void *reserved) {
36387330f729Sjoerg   IndexData *index_data;
36397330f729Sjoerg 
36407330f729Sjoerg   index_data = (IndexData *)client_data;
36417330f729Sjoerg   printCheck(index_data);
36427330f729Sjoerg 
36437330f729Sjoerg   index_data->main_filename = clang_getFileName(file);
36447330f729Sjoerg 
36457330f729Sjoerg   printf("[enteredMainFile]: ");
36467330f729Sjoerg   printCXIndexFile((CXIdxClientFile)file);
36477330f729Sjoerg   printf("\n");
36487330f729Sjoerg 
36497330f729Sjoerg   return (CXIdxClientFile)file;
36507330f729Sjoerg }
36517330f729Sjoerg 
index_ppIncludedFile(CXClientData client_data,const CXIdxIncludedFileInfo * info)36527330f729Sjoerg static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
36537330f729Sjoerg                                             const CXIdxIncludedFileInfo *info) {
36547330f729Sjoerg   IndexData *index_data;
36557330f729Sjoerg   CXModule Mod;
36567330f729Sjoerg   index_data = (IndexData *)client_data;
36577330f729Sjoerg   printCheck(index_data);
36587330f729Sjoerg 
36597330f729Sjoerg   printf("[ppIncludedFile]: ");
36607330f729Sjoerg   printCXIndexFile((CXIdxClientFile)info->file);
36617330f729Sjoerg   printf(" | name: \"%s\"", info->filename);
36627330f729Sjoerg   printf(" | hash loc: ");
36637330f729Sjoerg   printCXIndexLoc(info->hashLoc, client_data);
36647330f729Sjoerg   printf(" | isImport: %d | isAngled: %d | isModule: %d",
36657330f729Sjoerg          info->isImport, info->isAngled, info->isModuleImport);
36667330f729Sjoerg 
36677330f729Sjoerg   Mod = clang_getModuleForFile(index_data->TU, (CXFile)info->file);
36687330f729Sjoerg   if (Mod) {
36697330f729Sjoerg     CXString str = clang_Module_getFullName(Mod);
36707330f729Sjoerg     const char *cstr = clang_getCString(str);
36717330f729Sjoerg     printf(" | module: %s", cstr);
36727330f729Sjoerg     clang_disposeString(str);
36737330f729Sjoerg   }
36747330f729Sjoerg 
36757330f729Sjoerg   printf("\n");
36767330f729Sjoerg 
36777330f729Sjoerg   return (CXIdxClientFile)info->file;
36787330f729Sjoerg }
36797330f729Sjoerg 
index_importedASTFile(CXClientData client_data,const CXIdxImportedASTFileInfo * info)36807330f729Sjoerg static CXIdxClientFile index_importedASTFile(CXClientData client_data,
36817330f729Sjoerg                                          const CXIdxImportedASTFileInfo *info) {
36827330f729Sjoerg   IndexData *index_data;
36837330f729Sjoerg   index_data = (IndexData *)client_data;
36847330f729Sjoerg   printCheck(index_data);
36857330f729Sjoerg 
36867330f729Sjoerg   if (index_data->importedASTs) {
36877330f729Sjoerg     CXString filename = clang_getFileName(info->file);
36887330f729Sjoerg     importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
36897330f729Sjoerg     clang_disposeString(filename);
36907330f729Sjoerg   }
36917330f729Sjoerg 
36927330f729Sjoerg   printf("[importedASTFile]: ");
36937330f729Sjoerg   printCXIndexFile((CXIdxClientFile)info->file);
36947330f729Sjoerg   if (info->module) {
36957330f729Sjoerg     CXString name = clang_Module_getFullName(info->module);
36967330f729Sjoerg     printf(" | loc: ");
36977330f729Sjoerg     printCXIndexLoc(info->loc, client_data);
36987330f729Sjoerg     printf(" | name: \"%s\"", clang_getCString(name));
36997330f729Sjoerg     printf(" | isImplicit: %d\n", info->isImplicit);
37007330f729Sjoerg     clang_disposeString(name);
37017330f729Sjoerg   } else {
37027330f729Sjoerg     /* PCH file, the rest are not relevant. */
37037330f729Sjoerg     printf("\n");
37047330f729Sjoerg   }
37057330f729Sjoerg 
37067330f729Sjoerg   return (CXIdxClientFile)info->file;
37077330f729Sjoerg }
37087330f729Sjoerg 
37097330f729Sjoerg static CXIdxClientContainer
index_startedTranslationUnit(CXClientData client_data,void * reserved)37107330f729Sjoerg index_startedTranslationUnit(CXClientData client_data, void *reserved) {
37117330f729Sjoerg   IndexData *index_data;
37127330f729Sjoerg   index_data = (IndexData *)client_data;
37137330f729Sjoerg   printCheck(index_data);
37147330f729Sjoerg 
37157330f729Sjoerg   printf("[startedTranslationUnit]\n");
37167330f729Sjoerg   return (CXIdxClientContainer)"TU";
37177330f729Sjoerg }
37187330f729Sjoerg 
index_indexDeclaration(CXClientData client_data,const CXIdxDeclInfo * info)37197330f729Sjoerg static void index_indexDeclaration(CXClientData client_data,
37207330f729Sjoerg                                    const CXIdxDeclInfo *info) {
37217330f729Sjoerg   IndexData *index_data;
37227330f729Sjoerg   const CXIdxObjCCategoryDeclInfo *CatInfo;
37237330f729Sjoerg   const CXIdxObjCInterfaceDeclInfo *InterInfo;
37247330f729Sjoerg   const CXIdxObjCProtocolRefListInfo *ProtoInfo;
37257330f729Sjoerg   const CXIdxObjCPropertyDeclInfo *PropInfo;
37267330f729Sjoerg   const CXIdxCXXClassDeclInfo *CXXClassInfo;
37277330f729Sjoerg   unsigned i;
37287330f729Sjoerg   index_data = (IndexData *)client_data;
37297330f729Sjoerg 
37307330f729Sjoerg   printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
37317330f729Sjoerg   printf(" | cursor: ");
37327330f729Sjoerg   PrintCursor(info->cursor, NULL);
37337330f729Sjoerg   printf(" | loc: ");
37347330f729Sjoerg   printCXIndexLoc(info->loc, client_data);
37357330f729Sjoerg   printf(" | semantic-container: ");
37367330f729Sjoerg   printCXIndexContainer(info->semanticContainer);
37377330f729Sjoerg   printf(" | lexical-container: ");
37387330f729Sjoerg   printCXIndexContainer(info->lexicalContainer);
37397330f729Sjoerg   printf(" | isRedecl: %d", info->isRedeclaration);
37407330f729Sjoerg   printf(" | isDef: %d", info->isDefinition);
37417330f729Sjoerg   if (info->flags & CXIdxDeclFlag_Skipped) {
37427330f729Sjoerg     assert(!info->isContainer);
37437330f729Sjoerg     printf(" | isContainer: skipped");
37447330f729Sjoerg   } else {
37457330f729Sjoerg     printf(" | isContainer: %d", info->isContainer);
37467330f729Sjoerg   }
37477330f729Sjoerg   printf(" | isImplicit: %d\n", info->isImplicit);
37487330f729Sjoerg 
37497330f729Sjoerg   for (i = 0; i != info->numAttributes; ++i) {
37507330f729Sjoerg     const CXIdxAttrInfo *Attr = info->attributes[i];
37517330f729Sjoerg     printf("     <attribute>: ");
37527330f729Sjoerg     PrintCursor(Attr->cursor, NULL);
37537330f729Sjoerg     printf("\n");
37547330f729Sjoerg   }
37557330f729Sjoerg 
37567330f729Sjoerg   if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
37577330f729Sjoerg     const char *kindName = 0;
37587330f729Sjoerg     CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
37597330f729Sjoerg     switch (K) {
37607330f729Sjoerg     case CXIdxObjCContainer_ForwardRef:
37617330f729Sjoerg       kindName = "forward-ref"; break;
37627330f729Sjoerg     case CXIdxObjCContainer_Interface:
37637330f729Sjoerg       kindName = "interface"; break;
37647330f729Sjoerg     case CXIdxObjCContainer_Implementation:
37657330f729Sjoerg       kindName = "implementation"; break;
37667330f729Sjoerg     }
37677330f729Sjoerg     printCheck(index_data);
37687330f729Sjoerg     printf("     <ObjCContainerInfo>: kind: %s\n", kindName);
37697330f729Sjoerg   }
37707330f729Sjoerg 
37717330f729Sjoerg   if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
37727330f729Sjoerg     printEntityInfo("     <ObjCCategoryInfo>: class", client_data,
37737330f729Sjoerg                     CatInfo->objcClass);
37747330f729Sjoerg     printf(" | cursor: ");
37757330f729Sjoerg     PrintCursor(CatInfo->classCursor, NULL);
37767330f729Sjoerg     printf(" | loc: ");
37777330f729Sjoerg     printCXIndexLoc(CatInfo->classLoc, client_data);
37787330f729Sjoerg     printf("\n");
37797330f729Sjoerg   }
37807330f729Sjoerg 
37817330f729Sjoerg   if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
37827330f729Sjoerg     if (InterInfo->superInfo) {
37837330f729Sjoerg       printBaseClassInfo(client_data, InterInfo->superInfo);
37847330f729Sjoerg       printf("\n");
37857330f729Sjoerg     }
37867330f729Sjoerg   }
37877330f729Sjoerg 
37887330f729Sjoerg   if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
37897330f729Sjoerg     printProtocolList(ProtoInfo, client_data);
37907330f729Sjoerg   }
37917330f729Sjoerg 
37927330f729Sjoerg   if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
37937330f729Sjoerg     if (PropInfo->getter) {
37947330f729Sjoerg       printEntityInfo("     <getter>", client_data, PropInfo->getter);
37957330f729Sjoerg       printf("\n");
37967330f729Sjoerg     }
37977330f729Sjoerg     if (PropInfo->setter) {
37987330f729Sjoerg       printEntityInfo("     <setter>", client_data, PropInfo->setter);
37997330f729Sjoerg       printf("\n");
38007330f729Sjoerg     }
38017330f729Sjoerg   }
38027330f729Sjoerg 
38037330f729Sjoerg   if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
38047330f729Sjoerg     for (i = 0; i != CXXClassInfo->numBases; ++i) {
38057330f729Sjoerg       printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
38067330f729Sjoerg       printf("\n");
38077330f729Sjoerg     }
38087330f729Sjoerg   }
38097330f729Sjoerg 
38107330f729Sjoerg   if (info->declAsContainer)
38117330f729Sjoerg     clang_index_setClientContainer(
38127330f729Sjoerg         info->declAsContainer,
38137330f729Sjoerg         makeClientContainer(client_data, info->entityInfo, info->loc));
38147330f729Sjoerg }
38157330f729Sjoerg 
index_indexEntityReference(CXClientData client_data,const CXIdxEntityRefInfo * info)38167330f729Sjoerg static void index_indexEntityReference(CXClientData client_data,
38177330f729Sjoerg                                        const CXIdxEntityRefInfo *info) {
38187330f729Sjoerg   printEntityInfo("[indexEntityReference]", client_data,
38197330f729Sjoerg                   info->referencedEntity);
38207330f729Sjoerg   printf(" | cursor: ");
38217330f729Sjoerg   PrintCursor(info->cursor, NULL);
38227330f729Sjoerg   printf(" | loc: ");
38237330f729Sjoerg   printCXIndexLoc(info->loc, client_data);
38247330f729Sjoerg   printEntityInfo(" | <parent>:", client_data, info->parentEntity);
38257330f729Sjoerg   printf(" | container: ");
38267330f729Sjoerg   printCXIndexContainer(info->container);
38277330f729Sjoerg   printf(" | refkind: ");
38287330f729Sjoerg   switch (info->kind) {
38297330f729Sjoerg     case CXIdxEntityRef_Direct: printf("direct"); break;
38307330f729Sjoerg     case CXIdxEntityRef_Implicit: printf("implicit"); break;
38317330f729Sjoerg   }
38327330f729Sjoerg   printf(" | role:");
38337330f729Sjoerg   printSymbolRole(info->role);
38347330f729Sjoerg   printf("\n");
38357330f729Sjoerg }
38367330f729Sjoerg 
index_abortQuery(CXClientData client_data,void * reserved)38377330f729Sjoerg static int index_abortQuery(CXClientData client_data, void *reserved) {
38387330f729Sjoerg   IndexData *index_data;
38397330f729Sjoerg   index_data = (IndexData *)client_data;
38407330f729Sjoerg   return index_data->abort;
38417330f729Sjoerg }
38427330f729Sjoerg 
38437330f729Sjoerg static IndexerCallbacks IndexCB = {
38447330f729Sjoerg   index_abortQuery,
38457330f729Sjoerg   index_diagnostic,
38467330f729Sjoerg   index_enteredMainFile,
38477330f729Sjoerg   index_ppIncludedFile,
38487330f729Sjoerg   index_importedASTFile,
38497330f729Sjoerg   index_startedTranslationUnit,
38507330f729Sjoerg   index_indexDeclaration,
38517330f729Sjoerg   index_indexEntityReference
38527330f729Sjoerg };
38537330f729Sjoerg 
getIndexOptions(void)38547330f729Sjoerg static unsigned getIndexOptions(void) {
38557330f729Sjoerg   unsigned index_opts;
38567330f729Sjoerg   index_opts = 0;
38577330f729Sjoerg   if (getenv("CINDEXTEST_SUPPRESSREFS"))
38587330f729Sjoerg     index_opts |= CXIndexOpt_SuppressRedundantRefs;
38597330f729Sjoerg   if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
38607330f729Sjoerg     index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
38617330f729Sjoerg   if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
38627330f729Sjoerg     index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
38637330f729Sjoerg   if (getenv("CINDEXTEST_INDEXIMPLICITTEMPLATEINSTANTIATIONS"))
38647330f729Sjoerg     index_opts |= CXIndexOpt_IndexImplicitTemplateInstantiations;
38657330f729Sjoerg 
38667330f729Sjoerg   return index_opts;
38677330f729Sjoerg }
38687330f729Sjoerg 
index_compile_args(int num_args,const char ** args,CXIndexAction idxAction,ImportedASTFilesData * importedASTs,const char * check_prefix)38697330f729Sjoerg static int index_compile_args(int num_args, const char **args,
38707330f729Sjoerg                               CXIndexAction idxAction,
38717330f729Sjoerg                               ImportedASTFilesData *importedASTs,
38727330f729Sjoerg                               const char *check_prefix) {
38737330f729Sjoerg   IndexData index_data;
38747330f729Sjoerg   unsigned index_opts;
38757330f729Sjoerg   int result;
38767330f729Sjoerg 
38777330f729Sjoerg   if (num_args == 0) {
38787330f729Sjoerg     fprintf(stderr, "no compiler arguments\n");
38797330f729Sjoerg     return -1;
38807330f729Sjoerg   }
38817330f729Sjoerg 
38827330f729Sjoerg   index_data.check_prefix = check_prefix;
38837330f729Sjoerg   index_data.first_check_printed = 0;
38847330f729Sjoerg   index_data.fail_for_error = 0;
38857330f729Sjoerg   index_data.abort = 0;
38867330f729Sjoerg   index_data.main_filename = createCXString("");
38877330f729Sjoerg   index_data.importedASTs = importedASTs;
38887330f729Sjoerg   index_data.strings = NULL;
38897330f729Sjoerg   index_data.TU = NULL;
38907330f729Sjoerg 
38917330f729Sjoerg   index_opts = getIndexOptions();
38927330f729Sjoerg   result = clang_indexSourceFile(idxAction, &index_data,
38937330f729Sjoerg                                  &IndexCB,sizeof(IndexCB), index_opts,
38947330f729Sjoerg                                  0, args, num_args, 0, 0, 0,
38957330f729Sjoerg                                  getDefaultParsingOptions());
38967330f729Sjoerg   if (result != CXError_Success)
38977330f729Sjoerg     describeLibclangFailure(result);
38987330f729Sjoerg 
38997330f729Sjoerg   if (index_data.fail_for_error)
39007330f729Sjoerg     result = -1;
39017330f729Sjoerg 
39027330f729Sjoerg   clang_disposeString(index_data.main_filename);
39037330f729Sjoerg   free_client_data(&index_data);
39047330f729Sjoerg   return result;
39057330f729Sjoerg }
39067330f729Sjoerg 
index_ast_file(const char * ast_file,CXIndex Idx,CXIndexAction idxAction,ImportedASTFilesData * importedASTs,const char * check_prefix)39077330f729Sjoerg static int index_ast_file(const char *ast_file,
39087330f729Sjoerg                           CXIndex Idx,
39097330f729Sjoerg                           CXIndexAction idxAction,
39107330f729Sjoerg                           ImportedASTFilesData *importedASTs,
39117330f729Sjoerg                           const char *check_prefix) {
39127330f729Sjoerg   CXTranslationUnit TU;
39137330f729Sjoerg   IndexData index_data;
39147330f729Sjoerg   unsigned index_opts;
39157330f729Sjoerg   int result;
39167330f729Sjoerg 
39177330f729Sjoerg   if (!CreateTranslationUnit(Idx, ast_file, &TU))
39187330f729Sjoerg     return -1;
39197330f729Sjoerg 
39207330f729Sjoerg   index_data.check_prefix = check_prefix;
39217330f729Sjoerg   index_data.first_check_printed = 0;
39227330f729Sjoerg   index_data.fail_for_error = 0;
39237330f729Sjoerg   index_data.abort = 0;
39247330f729Sjoerg   index_data.main_filename = createCXString("");
39257330f729Sjoerg   index_data.importedASTs = importedASTs;
39267330f729Sjoerg   index_data.strings = NULL;
39277330f729Sjoerg   index_data.TU = TU;
39287330f729Sjoerg 
39297330f729Sjoerg   index_opts = getIndexOptions();
39307330f729Sjoerg   result = clang_indexTranslationUnit(idxAction, &index_data,
39317330f729Sjoerg                                       &IndexCB,sizeof(IndexCB),
39327330f729Sjoerg                                       index_opts, TU);
39337330f729Sjoerg   if (index_data.fail_for_error)
39347330f729Sjoerg     result = -1;
39357330f729Sjoerg 
39367330f729Sjoerg   clang_disposeTranslationUnit(TU);
39377330f729Sjoerg   clang_disposeString(index_data.main_filename);
39387330f729Sjoerg   free_client_data(&index_data);
39397330f729Sjoerg   return result;
39407330f729Sjoerg }
39417330f729Sjoerg 
index_file(int argc,const char ** argv,int full)39427330f729Sjoerg static int index_file(int argc, const char **argv, int full) {
39437330f729Sjoerg   const char *check_prefix;
39447330f729Sjoerg   CXIndex Idx;
39457330f729Sjoerg   CXIndexAction idxAction;
39467330f729Sjoerg   ImportedASTFilesData *importedASTs;
39477330f729Sjoerg   int result;
39487330f729Sjoerg 
39497330f729Sjoerg   check_prefix = 0;
39507330f729Sjoerg   if (argc > 0) {
39517330f729Sjoerg     if (strstr(argv[0], "-check-prefix=") == argv[0]) {
39527330f729Sjoerg       check_prefix = argv[0] + strlen("-check-prefix=");
39537330f729Sjoerg       ++argv;
39547330f729Sjoerg       --argc;
39557330f729Sjoerg     }
39567330f729Sjoerg   }
39577330f729Sjoerg 
39587330f729Sjoerg   if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
39597330f729Sjoerg                                 /* displayDiagnostics=*/1))) {
39607330f729Sjoerg     fprintf(stderr, "Could not create Index\n");
39617330f729Sjoerg     return 1;
39627330f729Sjoerg   }
39637330f729Sjoerg   idxAction = clang_IndexAction_create(Idx);
39647330f729Sjoerg   importedASTs = 0;
39657330f729Sjoerg   if (full)
39667330f729Sjoerg     importedASTs = importedASTs_create();
39677330f729Sjoerg 
39687330f729Sjoerg   result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
39697330f729Sjoerg   if (result != 0)
39707330f729Sjoerg     goto finished;
39717330f729Sjoerg 
39727330f729Sjoerg   if (full) {
39737330f729Sjoerg     unsigned i;
39747330f729Sjoerg     for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
39757330f729Sjoerg       result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
39767330f729Sjoerg                               importedASTs, check_prefix);
39777330f729Sjoerg     }
39787330f729Sjoerg   }
39797330f729Sjoerg 
39807330f729Sjoerg finished:
39817330f729Sjoerg   importedASTs_dispose(importedASTs);
39827330f729Sjoerg   clang_IndexAction_dispose(idxAction);
39837330f729Sjoerg   clang_disposeIndex(Idx);
39847330f729Sjoerg   return result;
39857330f729Sjoerg }
39867330f729Sjoerg 
index_tu(int argc,const char ** argv)39877330f729Sjoerg static int index_tu(int argc, const char **argv) {
39887330f729Sjoerg   const char *check_prefix;
39897330f729Sjoerg   CXIndex Idx;
39907330f729Sjoerg   CXIndexAction idxAction;
39917330f729Sjoerg   int result;
39927330f729Sjoerg 
39937330f729Sjoerg   check_prefix = 0;
39947330f729Sjoerg   if (argc > 0) {
39957330f729Sjoerg     if (strstr(argv[0], "-check-prefix=") == argv[0]) {
39967330f729Sjoerg       check_prefix = argv[0] + strlen("-check-prefix=");
39977330f729Sjoerg       ++argv;
39987330f729Sjoerg       --argc;
39997330f729Sjoerg     }
40007330f729Sjoerg   }
40017330f729Sjoerg 
40027330f729Sjoerg   if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
40037330f729Sjoerg                                 /* displayDiagnostics=*/1))) {
40047330f729Sjoerg     fprintf(stderr, "Could not create Index\n");
40057330f729Sjoerg     return 1;
40067330f729Sjoerg   }
40077330f729Sjoerg   idxAction = clang_IndexAction_create(Idx);
40087330f729Sjoerg 
40097330f729Sjoerg   result = index_ast_file(argv[0], Idx, idxAction,
40107330f729Sjoerg                           /*importedASTs=*/0, check_prefix);
40117330f729Sjoerg 
40127330f729Sjoerg   clang_IndexAction_dispose(idxAction);
40137330f729Sjoerg   clang_disposeIndex(Idx);
40147330f729Sjoerg   return result;
40157330f729Sjoerg }
40167330f729Sjoerg 
index_compile_db(int argc,const char ** argv)40177330f729Sjoerg static int index_compile_db(int argc, const char **argv) {
40187330f729Sjoerg   const char *check_prefix;
40197330f729Sjoerg   CXIndex Idx;
40207330f729Sjoerg   CXIndexAction idxAction;
40217330f729Sjoerg   int errorCode = 0;
40227330f729Sjoerg 
40237330f729Sjoerg   check_prefix = 0;
40247330f729Sjoerg   if (argc > 0) {
40257330f729Sjoerg     if (strstr(argv[0], "-check-prefix=") == argv[0]) {
40267330f729Sjoerg       check_prefix = argv[0] + strlen("-check-prefix=");
40277330f729Sjoerg       ++argv;
40287330f729Sjoerg       --argc;
40297330f729Sjoerg     }
40307330f729Sjoerg   }
40317330f729Sjoerg 
40327330f729Sjoerg   if (argc == 0) {
40337330f729Sjoerg     fprintf(stderr, "no compilation database\n");
40347330f729Sjoerg     return -1;
40357330f729Sjoerg   }
40367330f729Sjoerg 
40377330f729Sjoerg   if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
40387330f729Sjoerg                                 /* displayDiagnostics=*/1))) {
40397330f729Sjoerg     fprintf(stderr, "Could not create Index\n");
40407330f729Sjoerg     return 1;
40417330f729Sjoerg   }
40427330f729Sjoerg   idxAction = clang_IndexAction_create(Idx);
40437330f729Sjoerg 
40447330f729Sjoerg   {
40457330f729Sjoerg     const char *database = argv[0];
40467330f729Sjoerg     CXCompilationDatabase db = 0;
40477330f729Sjoerg     CXCompileCommands CCmds = 0;
40487330f729Sjoerg     CXCompileCommand CCmd;
40497330f729Sjoerg     CXCompilationDatabase_Error ec;
40507330f729Sjoerg     CXString wd;
40517330f729Sjoerg #define MAX_COMPILE_ARGS 512
40527330f729Sjoerg     CXString cxargs[MAX_COMPILE_ARGS];
40537330f729Sjoerg     const char *args[MAX_COMPILE_ARGS];
40547330f729Sjoerg     char *tmp;
40557330f729Sjoerg     unsigned len;
40567330f729Sjoerg     char *buildDir;
40577330f729Sjoerg     int i, a, numCmds, numArgs;
40587330f729Sjoerg 
40597330f729Sjoerg     len = strlen(database);
40607330f729Sjoerg     tmp = (char *) malloc(len+1);
40617330f729Sjoerg     assert(tmp);
40627330f729Sjoerg     memcpy(tmp, database, len+1);
40637330f729Sjoerg     buildDir = dirname(tmp);
40647330f729Sjoerg 
40657330f729Sjoerg     db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
40667330f729Sjoerg 
40677330f729Sjoerg     if (db) {
40687330f729Sjoerg 
40697330f729Sjoerg       if (ec!=CXCompilationDatabase_NoError) {
40707330f729Sjoerg         printf("unexpected error %d code while loading compilation database\n", ec);
40717330f729Sjoerg         errorCode = -1;
40727330f729Sjoerg         goto cdb_end;
40737330f729Sjoerg       }
40747330f729Sjoerg 
40757330f729Sjoerg       if (chdir(buildDir) != 0) {
40767330f729Sjoerg         printf("Could not chdir to %s\n", buildDir);
40777330f729Sjoerg         errorCode = -1;
40787330f729Sjoerg         goto cdb_end;
40797330f729Sjoerg       }
40807330f729Sjoerg 
40817330f729Sjoerg       CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
40827330f729Sjoerg       if (!CCmds) {
40837330f729Sjoerg         printf("compilation db is empty\n");
40847330f729Sjoerg         errorCode = -1;
40857330f729Sjoerg         goto cdb_end;
40867330f729Sjoerg       }
40877330f729Sjoerg 
40887330f729Sjoerg       numCmds = clang_CompileCommands_getSize(CCmds);
40897330f729Sjoerg 
40907330f729Sjoerg       if (numCmds==0) {
40917330f729Sjoerg         fprintf(stderr, "should not get an empty compileCommand set\n");
40927330f729Sjoerg         errorCode = -1;
40937330f729Sjoerg         goto cdb_end;
40947330f729Sjoerg       }
40957330f729Sjoerg 
40967330f729Sjoerg       for (i=0; i<numCmds && errorCode == 0; ++i) {
40977330f729Sjoerg         CCmd = clang_CompileCommands_getCommand(CCmds, i);
40987330f729Sjoerg 
40997330f729Sjoerg         wd = clang_CompileCommand_getDirectory(CCmd);
41007330f729Sjoerg         if (chdir(clang_getCString(wd)) != 0) {
41017330f729Sjoerg           printf("Could not chdir to %s\n", clang_getCString(wd));
41027330f729Sjoerg           errorCode = -1;
41037330f729Sjoerg           goto cdb_end;
41047330f729Sjoerg         }
41057330f729Sjoerg         clang_disposeString(wd);
41067330f729Sjoerg 
41077330f729Sjoerg         numArgs = clang_CompileCommand_getNumArgs(CCmd);
41087330f729Sjoerg         if (numArgs > MAX_COMPILE_ARGS){
41097330f729Sjoerg           fprintf(stderr, "got more compile arguments than maximum\n");
41107330f729Sjoerg           errorCode = -1;
41117330f729Sjoerg           goto cdb_end;
41127330f729Sjoerg         }
41137330f729Sjoerg         for (a=0; a<numArgs; ++a) {
41147330f729Sjoerg           cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
41157330f729Sjoerg           args[a] = clang_getCString(cxargs[a]);
41167330f729Sjoerg         }
41177330f729Sjoerg 
41187330f729Sjoerg         errorCode = index_compile_args(numArgs, args, idxAction,
41197330f729Sjoerg                                        /*importedASTs=*/0, check_prefix);
41207330f729Sjoerg 
41217330f729Sjoerg         for (a=0; a<numArgs; ++a)
41227330f729Sjoerg           clang_disposeString(cxargs[a]);
41237330f729Sjoerg       }
41247330f729Sjoerg     } else {
41257330f729Sjoerg       printf("database loading failed with error code %d.\n", ec);
41267330f729Sjoerg       errorCode = -1;
41277330f729Sjoerg     }
41287330f729Sjoerg 
41297330f729Sjoerg   cdb_end:
41307330f729Sjoerg     clang_CompileCommands_dispose(CCmds);
41317330f729Sjoerg     clang_CompilationDatabase_dispose(db);
41327330f729Sjoerg     free(tmp);
41337330f729Sjoerg 
41347330f729Sjoerg   }
41357330f729Sjoerg 
41367330f729Sjoerg   clang_IndexAction_dispose(idxAction);
41377330f729Sjoerg   clang_disposeIndex(Idx);
41387330f729Sjoerg   return errorCode;
41397330f729Sjoerg }
41407330f729Sjoerg 
perform_token_annotation(int argc,const char ** argv)41417330f729Sjoerg int perform_token_annotation(int argc, const char **argv) {
41427330f729Sjoerg   const char *input = argv[1];
41437330f729Sjoerg   char *filename = 0;
41447330f729Sjoerg   unsigned line, second_line;
41457330f729Sjoerg   unsigned column, second_column;
41467330f729Sjoerg   CXIndex CIdx;
41477330f729Sjoerg   CXTranslationUnit TU = 0;
41487330f729Sjoerg   int errorCode;
41497330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
41507330f729Sjoerg   int num_unsaved_files = 0;
41517330f729Sjoerg   CXToken *tokens;
41527330f729Sjoerg   unsigned num_tokens;
41537330f729Sjoerg   CXSourceRange range;
41547330f729Sjoerg   CXSourceLocation startLoc, endLoc;
41557330f729Sjoerg   CXFile file = 0;
41567330f729Sjoerg   CXCursor *cursors = 0;
41577330f729Sjoerg   CXSourceRangeList *skipped_ranges = 0;
41587330f729Sjoerg   enum CXErrorCode Err;
41597330f729Sjoerg   unsigned i;
41607330f729Sjoerg 
41617330f729Sjoerg   input += strlen("-test-annotate-tokens=");
41627330f729Sjoerg   if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
41637330f729Sjoerg                                           &second_line, &second_column)))
41647330f729Sjoerg     return errorCode;
41657330f729Sjoerg 
41667330f729Sjoerg   if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
41677330f729Sjoerg     free(filename);
41687330f729Sjoerg     return -1;
41697330f729Sjoerg   }
41707330f729Sjoerg 
41717330f729Sjoerg   CIdx = clang_createIndex(0, 1);
41727330f729Sjoerg   Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
41737330f729Sjoerg                                     argv + num_unsaved_files + 2,
41747330f729Sjoerg                                     argc - num_unsaved_files - 3,
41757330f729Sjoerg                                     unsaved_files,
41767330f729Sjoerg                                     num_unsaved_files,
41777330f729Sjoerg                                     getDefaultParsingOptions(), &TU);
41787330f729Sjoerg   if (Err != CXError_Success) {
41797330f729Sjoerg     fprintf(stderr, "unable to parse input\n");
41807330f729Sjoerg     describeLibclangFailure(Err);
41817330f729Sjoerg     clang_disposeIndex(CIdx);
41827330f729Sjoerg     free(filename);
41837330f729Sjoerg     free_remapped_files(unsaved_files, num_unsaved_files);
41847330f729Sjoerg     return -1;
41857330f729Sjoerg   }
41867330f729Sjoerg   errorCode = 0;
41877330f729Sjoerg 
41887330f729Sjoerg   if (checkForErrors(TU) != 0) {
41897330f729Sjoerg     errorCode = -1;
41907330f729Sjoerg     goto teardown;
41917330f729Sjoerg   }
41927330f729Sjoerg 
41937330f729Sjoerg   if (getenv("CINDEXTEST_EDITING")) {
41947330f729Sjoerg     for (i = 0; i < 5; ++i) {
41957330f729Sjoerg       Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
41967330f729Sjoerg                                          clang_defaultReparseOptions(TU));
41977330f729Sjoerg       if (Err != CXError_Success) {
41987330f729Sjoerg         fprintf(stderr, "Unable to reparse translation unit!\n");
41997330f729Sjoerg         describeLibclangFailure(Err);
42007330f729Sjoerg         errorCode = -1;
42017330f729Sjoerg         goto teardown;
42027330f729Sjoerg       }
42037330f729Sjoerg     }
42047330f729Sjoerg   }
42057330f729Sjoerg 
42067330f729Sjoerg   if (checkForErrors(TU) != 0) {
42077330f729Sjoerg     errorCode = -1;
42087330f729Sjoerg     goto teardown;
42097330f729Sjoerg   }
42107330f729Sjoerg 
42117330f729Sjoerg   file = clang_getFile(TU, filename);
42127330f729Sjoerg   if (!file) {
42137330f729Sjoerg     fprintf(stderr, "file %s is not in this translation unit\n", filename);
42147330f729Sjoerg     errorCode = -1;
42157330f729Sjoerg     goto teardown;
42167330f729Sjoerg   }
42177330f729Sjoerg 
42187330f729Sjoerg   startLoc = clang_getLocation(TU, file, line, column);
42197330f729Sjoerg   if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
42207330f729Sjoerg     fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
42217330f729Sjoerg             column);
42227330f729Sjoerg     errorCode = -1;
42237330f729Sjoerg     goto teardown;
42247330f729Sjoerg   }
42257330f729Sjoerg 
42267330f729Sjoerg   endLoc = clang_getLocation(TU, file, second_line, second_column);
42277330f729Sjoerg   if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
42287330f729Sjoerg     fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
42297330f729Sjoerg             second_line, second_column);
42307330f729Sjoerg     errorCode = -1;
42317330f729Sjoerg     goto teardown;
42327330f729Sjoerg   }
42337330f729Sjoerg 
42347330f729Sjoerg   range = clang_getRange(startLoc, endLoc);
42357330f729Sjoerg   clang_tokenize(TU, range, &tokens, &num_tokens);
42367330f729Sjoerg 
42377330f729Sjoerg   if (checkForErrors(TU) != 0) {
42387330f729Sjoerg     errorCode = -1;
42397330f729Sjoerg     goto teardown;
42407330f729Sjoerg   }
42417330f729Sjoerg 
42427330f729Sjoerg   cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
42437330f729Sjoerg   assert(cursors);
42447330f729Sjoerg   clang_annotateTokens(TU, tokens, num_tokens, cursors);
42457330f729Sjoerg 
42467330f729Sjoerg   if (checkForErrors(TU) != 0) {
42477330f729Sjoerg     errorCode = -1;
42487330f729Sjoerg     goto teardown;
42497330f729Sjoerg   }
42507330f729Sjoerg 
42517330f729Sjoerg   skipped_ranges = clang_getSkippedRanges(TU, file);
42527330f729Sjoerg   for (i = 0; i != skipped_ranges->count; ++i) {
42537330f729Sjoerg     unsigned start_line, start_column, end_line, end_column;
42547330f729Sjoerg     clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
42557330f729Sjoerg                               0, &start_line, &start_column, 0);
42567330f729Sjoerg     clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
42577330f729Sjoerg                               0, &end_line, &end_column, 0);
42587330f729Sjoerg     printf("Skipping: ");
42597330f729Sjoerg     PrintExtent(stdout, start_line, start_column, end_line, end_column);
42607330f729Sjoerg     printf("\n");
42617330f729Sjoerg   }
42627330f729Sjoerg   clang_disposeSourceRangeList(skipped_ranges);
42637330f729Sjoerg 
42647330f729Sjoerg   for (i = 0; i != num_tokens; ++i) {
42657330f729Sjoerg     const char *kind = "<unknown>";
42667330f729Sjoerg     CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
42677330f729Sjoerg     CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
42687330f729Sjoerg     unsigned start_line, start_column, end_line, end_column;
42697330f729Sjoerg 
42707330f729Sjoerg     switch (clang_getTokenKind(tokens[i])) {
42717330f729Sjoerg     case CXToken_Punctuation: kind = "Punctuation"; break;
42727330f729Sjoerg     case CXToken_Keyword: kind = "Keyword"; break;
42737330f729Sjoerg     case CXToken_Identifier: kind = "Identifier"; break;
42747330f729Sjoerg     case CXToken_Literal: kind = "Literal"; break;
42757330f729Sjoerg     case CXToken_Comment: kind = "Comment"; break;
42767330f729Sjoerg     }
42777330f729Sjoerg     clang_getSpellingLocation(clang_getRangeStart(extent),
42787330f729Sjoerg                               0, &start_line, &start_column, 0);
42797330f729Sjoerg     clang_getSpellingLocation(clang_getRangeEnd(extent),
42807330f729Sjoerg                               0, &end_line, &end_column, 0);
42817330f729Sjoerg     printf("%s: \"%s\" ", kind, clang_getCString(spelling));
42827330f729Sjoerg     clang_disposeString(spelling);
42837330f729Sjoerg     PrintExtent(stdout, start_line, start_column, end_line, end_column);
42847330f729Sjoerg     if (!clang_isInvalid(cursors[i].kind)) {
42857330f729Sjoerg       printf(" ");
42867330f729Sjoerg       PrintCursor(cursors[i], NULL);
42877330f729Sjoerg     }
42887330f729Sjoerg     printf("\n");
42897330f729Sjoerg   }
42907330f729Sjoerg   free(cursors);
42917330f729Sjoerg   clang_disposeTokens(TU, tokens, num_tokens);
42927330f729Sjoerg 
42937330f729Sjoerg  teardown:
42947330f729Sjoerg   PrintDiagnostics(TU);
42957330f729Sjoerg   clang_disposeTranslationUnit(TU);
42967330f729Sjoerg   clang_disposeIndex(CIdx);
42977330f729Sjoerg   free(filename);
42987330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
42997330f729Sjoerg   return errorCode;
43007330f729Sjoerg }
43017330f729Sjoerg 
43027330f729Sjoerg static int
perform_test_compilation_db(const char * database,int argc,const char ** argv)43037330f729Sjoerg perform_test_compilation_db(const char *database, int argc, const char **argv) {
43047330f729Sjoerg   CXCompilationDatabase db;
43057330f729Sjoerg   CXCompileCommands CCmds;
43067330f729Sjoerg   CXCompileCommand CCmd;
43077330f729Sjoerg   CXCompilationDatabase_Error ec;
43087330f729Sjoerg   CXString wd;
43097330f729Sjoerg   CXString arg;
43107330f729Sjoerg   int errorCode = 0;
43117330f729Sjoerg   char *tmp;
43127330f729Sjoerg   unsigned len;
43137330f729Sjoerg   char *buildDir;
43147330f729Sjoerg   int i, j, a, numCmds, numArgs;
43157330f729Sjoerg 
43167330f729Sjoerg   len = strlen(database);
43177330f729Sjoerg   tmp = (char *) malloc(len+1);
43187330f729Sjoerg   assert(tmp);
43197330f729Sjoerg   memcpy(tmp, database, len+1);
43207330f729Sjoerg   buildDir = dirname(tmp);
43217330f729Sjoerg 
43227330f729Sjoerg   db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
43237330f729Sjoerg 
43247330f729Sjoerg   if (db) {
43257330f729Sjoerg 
43267330f729Sjoerg     if (ec!=CXCompilationDatabase_NoError) {
43277330f729Sjoerg       printf("unexpected error %d code while loading compilation database\n", ec);
43287330f729Sjoerg       errorCode = -1;
43297330f729Sjoerg       goto cdb_end;
43307330f729Sjoerg     }
43317330f729Sjoerg 
43327330f729Sjoerg     for (i=0; i<argc && errorCode==0; ) {
43337330f729Sjoerg       if (strcmp(argv[i],"lookup")==0){
43347330f729Sjoerg         CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
43357330f729Sjoerg 
43367330f729Sjoerg         if (!CCmds) {
43377330f729Sjoerg           printf("file %s not found in compilation db\n", argv[i+1]);
43387330f729Sjoerg           errorCode = -1;
43397330f729Sjoerg           break;
43407330f729Sjoerg         }
43417330f729Sjoerg 
43427330f729Sjoerg         numCmds = clang_CompileCommands_getSize(CCmds);
43437330f729Sjoerg 
43447330f729Sjoerg         if (numCmds==0) {
43457330f729Sjoerg           fprintf(stderr, "should not get an empty compileCommand set for file"
43467330f729Sjoerg                           " '%s'\n", argv[i+1]);
43477330f729Sjoerg           errorCode = -1;
43487330f729Sjoerg           break;
43497330f729Sjoerg         }
43507330f729Sjoerg 
43517330f729Sjoerg         for (j=0; j<numCmds; ++j) {
43527330f729Sjoerg           CCmd = clang_CompileCommands_getCommand(CCmds, j);
43537330f729Sjoerg 
43547330f729Sjoerg           wd = clang_CompileCommand_getDirectory(CCmd);
43557330f729Sjoerg           printf("workdir:'%s'", clang_getCString(wd));
43567330f729Sjoerg           clang_disposeString(wd);
43577330f729Sjoerg 
43587330f729Sjoerg           printf(" cmdline:'");
43597330f729Sjoerg           numArgs = clang_CompileCommand_getNumArgs(CCmd);
43607330f729Sjoerg           for (a=0; a<numArgs; ++a) {
43617330f729Sjoerg             if (a) printf(" ");
43627330f729Sjoerg             arg = clang_CompileCommand_getArg(CCmd, a);
43637330f729Sjoerg             printf("%s", clang_getCString(arg));
43647330f729Sjoerg             clang_disposeString(arg);
43657330f729Sjoerg           }
43667330f729Sjoerg           printf("'\n");
43677330f729Sjoerg         }
43687330f729Sjoerg 
43697330f729Sjoerg         clang_CompileCommands_dispose(CCmds);
43707330f729Sjoerg 
43717330f729Sjoerg         i += 2;
43727330f729Sjoerg       }
43737330f729Sjoerg     }
43747330f729Sjoerg     clang_CompilationDatabase_dispose(db);
43757330f729Sjoerg   } else {
43767330f729Sjoerg     printf("database loading failed with error code %d.\n", ec);
43777330f729Sjoerg     errorCode = -1;
43787330f729Sjoerg   }
43797330f729Sjoerg 
43807330f729Sjoerg cdb_end:
43817330f729Sjoerg   free(tmp);
43827330f729Sjoerg 
43837330f729Sjoerg   return errorCode;
43847330f729Sjoerg }
43857330f729Sjoerg 
43867330f729Sjoerg /******************************************************************************/
43877330f729Sjoerg /* USR printing.                                                              */
43887330f729Sjoerg /******************************************************************************/
43897330f729Sjoerg 
insufficient_usr(const char * kind,const char * usage)43907330f729Sjoerg static int insufficient_usr(const char *kind, const char *usage) {
43917330f729Sjoerg   fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
43927330f729Sjoerg   return 1;
43937330f729Sjoerg }
43947330f729Sjoerg 
isUSR(const char * s)43957330f729Sjoerg static unsigned isUSR(const char *s) {
43967330f729Sjoerg   return s[0] == 'c' && s[1] == ':';
43977330f729Sjoerg }
43987330f729Sjoerg 
not_usr(const char * s,const char * arg)43997330f729Sjoerg static int not_usr(const char *s, const char *arg) {
44007330f729Sjoerg   fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
44017330f729Sjoerg   return 1;
44027330f729Sjoerg }
44037330f729Sjoerg 
print_usr(CXString usr)44047330f729Sjoerg static void print_usr(CXString usr) {
44057330f729Sjoerg   const char *s = clang_getCString(usr);
44067330f729Sjoerg   printf("%s\n", s);
44077330f729Sjoerg   clang_disposeString(usr);
44087330f729Sjoerg }
44097330f729Sjoerg 
display_usrs()44107330f729Sjoerg static void display_usrs() {
44117330f729Sjoerg   fprintf(stderr, "-print-usrs options:\n"
44127330f729Sjoerg         " ObjCCategory <class name> <category name>\n"
44137330f729Sjoerg         " ObjCClass <class name>\n"
44147330f729Sjoerg         " ObjCIvar <ivar name> <class USR>\n"
44157330f729Sjoerg         " ObjCMethod <selector> [0=class method|1=instance method] "
44167330f729Sjoerg             "<class USR>\n"
44177330f729Sjoerg           " ObjCProperty <property name> <class USR>\n"
44187330f729Sjoerg           " ObjCProtocol <protocol name>\n");
44197330f729Sjoerg }
44207330f729Sjoerg 
print_usrs(const char ** I,const char ** E)44217330f729Sjoerg int print_usrs(const char **I, const char **E) {
44227330f729Sjoerg   while (I != E) {
44237330f729Sjoerg     const char *kind = *I;
44247330f729Sjoerg     unsigned len = strlen(kind);
44257330f729Sjoerg     switch (len) {
44267330f729Sjoerg       case 8:
44277330f729Sjoerg         if (memcmp(kind, "ObjCIvar", 8) == 0) {
44287330f729Sjoerg           if (I + 2 >= E)
44297330f729Sjoerg             return insufficient_usr(kind, "<ivar name> <class USR>");
44307330f729Sjoerg           if (!isUSR(I[2]))
44317330f729Sjoerg             return not_usr("<class USR>", I[2]);
44327330f729Sjoerg           else {
44337330f729Sjoerg             CXString x = createCXString(I[2]);
44347330f729Sjoerg             print_usr(clang_constructUSR_ObjCIvar(I[1], x));
44357330f729Sjoerg           }
44367330f729Sjoerg 
44377330f729Sjoerg           I += 3;
44387330f729Sjoerg           continue;
44397330f729Sjoerg         }
44407330f729Sjoerg         break;
44417330f729Sjoerg       case 9:
44427330f729Sjoerg         if (memcmp(kind, "ObjCClass", 9) == 0) {
44437330f729Sjoerg           if (I + 1 >= E)
44447330f729Sjoerg             return insufficient_usr(kind, "<class name>");
44457330f729Sjoerg           print_usr(clang_constructUSR_ObjCClass(I[1]));
44467330f729Sjoerg           I += 2;
44477330f729Sjoerg           continue;
44487330f729Sjoerg         }
44497330f729Sjoerg         break;
44507330f729Sjoerg       case 10:
44517330f729Sjoerg         if (memcmp(kind, "ObjCMethod", 10) == 0) {
44527330f729Sjoerg           if (I + 3 >= E)
44537330f729Sjoerg             return insufficient_usr(kind, "<method selector> "
44547330f729Sjoerg                 "[0=class method|1=instance method] <class USR>");
44557330f729Sjoerg           if (!isUSR(I[3]))
44567330f729Sjoerg             return not_usr("<class USR>", I[3]);
44577330f729Sjoerg           else {
44587330f729Sjoerg             CXString x = createCXString(I[3]);
44597330f729Sjoerg             print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
44607330f729Sjoerg           }
44617330f729Sjoerg           I += 4;
44627330f729Sjoerg           continue;
44637330f729Sjoerg         }
44647330f729Sjoerg         break;
44657330f729Sjoerg       case 12:
44667330f729Sjoerg         if (memcmp(kind, "ObjCCategory", 12) == 0) {
44677330f729Sjoerg           if (I + 2 >= E)
44687330f729Sjoerg             return insufficient_usr(kind, "<class name> <category name>");
44697330f729Sjoerg           print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
44707330f729Sjoerg           I += 3;
44717330f729Sjoerg           continue;
44727330f729Sjoerg         }
44737330f729Sjoerg         if (memcmp(kind, "ObjCProtocol", 12) == 0) {
44747330f729Sjoerg           if (I + 1 >= E)
44757330f729Sjoerg             return insufficient_usr(kind, "<protocol name>");
44767330f729Sjoerg           print_usr(clang_constructUSR_ObjCProtocol(I[1]));
44777330f729Sjoerg           I += 2;
44787330f729Sjoerg           continue;
44797330f729Sjoerg         }
44807330f729Sjoerg         if (memcmp(kind, "ObjCProperty", 12) == 0) {
44817330f729Sjoerg           if (I + 2 >= E)
44827330f729Sjoerg             return insufficient_usr(kind, "<property name> <class USR>");
44837330f729Sjoerg           if (!isUSR(I[2]))
44847330f729Sjoerg             return not_usr("<class USR>", I[2]);
44857330f729Sjoerg           else {
44867330f729Sjoerg             CXString x = createCXString(I[2]);
44877330f729Sjoerg             print_usr(clang_constructUSR_ObjCProperty(I[1], x));
44887330f729Sjoerg           }
44897330f729Sjoerg           I += 3;
44907330f729Sjoerg           continue;
44917330f729Sjoerg         }
44927330f729Sjoerg         break;
44937330f729Sjoerg       default:
44947330f729Sjoerg         break;
44957330f729Sjoerg     }
44967330f729Sjoerg     break;
44977330f729Sjoerg   }
44987330f729Sjoerg 
44997330f729Sjoerg   if (I != E) {
45007330f729Sjoerg     fprintf(stderr, "Invalid USR kind: %s\n", *I);
45017330f729Sjoerg     display_usrs();
45027330f729Sjoerg     return 1;
45037330f729Sjoerg   }
45047330f729Sjoerg   return 0;
45057330f729Sjoerg }
45067330f729Sjoerg 
print_usrs_file(const char * file_name)45077330f729Sjoerg int print_usrs_file(const char *file_name) {
45087330f729Sjoerg   char line[2048];
45097330f729Sjoerg   const char *args[128];
45107330f729Sjoerg   unsigned numChars = 0;
45117330f729Sjoerg 
45127330f729Sjoerg   FILE *fp = fopen(file_name, "r");
45137330f729Sjoerg   if (!fp) {
45147330f729Sjoerg     fprintf(stderr, "error: cannot open '%s'\n", file_name);
45157330f729Sjoerg     return 1;
45167330f729Sjoerg   }
45177330f729Sjoerg 
45187330f729Sjoerg   /* This code is not really all that safe, but it works fine for testing. */
45197330f729Sjoerg   while (!feof(fp)) {
45207330f729Sjoerg     char c = fgetc(fp);
45217330f729Sjoerg     if (c == '\n') {
45227330f729Sjoerg       unsigned i = 0;
45237330f729Sjoerg       const char *s = 0;
45247330f729Sjoerg 
45257330f729Sjoerg       if (numChars == 0)
45267330f729Sjoerg         continue;
45277330f729Sjoerg 
45287330f729Sjoerg       line[numChars] = '\0';
45297330f729Sjoerg       numChars = 0;
45307330f729Sjoerg 
45317330f729Sjoerg       if (line[0] == '/' && line[1] == '/')
45327330f729Sjoerg         continue;
45337330f729Sjoerg 
45347330f729Sjoerg       s = strtok(line, " ");
45357330f729Sjoerg       while (s) {
45367330f729Sjoerg         args[i] = s;
45377330f729Sjoerg         ++i;
45387330f729Sjoerg         s = strtok(0, " ");
45397330f729Sjoerg       }
45407330f729Sjoerg       if (print_usrs(&args[0], &args[i]))
45417330f729Sjoerg         return 1;
45427330f729Sjoerg     }
45437330f729Sjoerg     else
45447330f729Sjoerg       line[numChars++] = c;
45457330f729Sjoerg   }
45467330f729Sjoerg 
45477330f729Sjoerg   fclose(fp);
45487330f729Sjoerg   return 0;
45497330f729Sjoerg }
45507330f729Sjoerg 
45517330f729Sjoerg /******************************************************************************/
45527330f729Sjoerg /* Command line processing.                                                   */
45537330f729Sjoerg /******************************************************************************/
write_pch_file(const char * filename,int argc,const char * argv[])45547330f729Sjoerg int write_pch_file(const char *filename, int argc, const char *argv[]) {
45557330f729Sjoerg   CXIndex Idx;
45567330f729Sjoerg   CXTranslationUnit TU;
45577330f729Sjoerg   struct CXUnsavedFile *unsaved_files = 0;
45587330f729Sjoerg   int num_unsaved_files = 0;
45597330f729Sjoerg   enum CXErrorCode Err;
45607330f729Sjoerg   int result = 0;
45617330f729Sjoerg 
45627330f729Sjoerg   Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
45637330f729Sjoerg 
45647330f729Sjoerg   if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
45657330f729Sjoerg     clang_disposeIndex(Idx);
45667330f729Sjoerg     return -1;
45677330f729Sjoerg   }
45687330f729Sjoerg 
45697330f729Sjoerg   Err = clang_parseTranslationUnit2(
45707330f729Sjoerg       Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files,
45717330f729Sjoerg       unsaved_files, num_unsaved_files,
45727330f729Sjoerg       CXTranslationUnit_Incomplete |
45737330f729Sjoerg           CXTranslationUnit_DetailedPreprocessingRecord |
45747330f729Sjoerg           CXTranslationUnit_ForSerialization,
45757330f729Sjoerg       &TU);
45767330f729Sjoerg   if (Err != CXError_Success) {
45777330f729Sjoerg     fprintf(stderr, "Unable to load translation unit!\n");
45787330f729Sjoerg     describeLibclangFailure(Err);
45797330f729Sjoerg     free_remapped_files(unsaved_files, num_unsaved_files);
45807330f729Sjoerg     clang_disposeTranslationUnit(TU);
45817330f729Sjoerg     clang_disposeIndex(Idx);
45827330f729Sjoerg     return 1;
45837330f729Sjoerg   }
45847330f729Sjoerg 
45857330f729Sjoerg   switch (clang_saveTranslationUnit(TU, filename,
45867330f729Sjoerg                                     clang_defaultSaveOptions(TU))) {
45877330f729Sjoerg   case CXSaveError_None:
45887330f729Sjoerg     break;
45897330f729Sjoerg 
45907330f729Sjoerg   case CXSaveError_TranslationErrors:
45917330f729Sjoerg     fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
45927330f729Sjoerg             filename);
45937330f729Sjoerg     result = 2;
45947330f729Sjoerg     break;
45957330f729Sjoerg 
45967330f729Sjoerg   case CXSaveError_InvalidTU:
45977330f729Sjoerg     fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
45987330f729Sjoerg             filename);
45997330f729Sjoerg     result = 3;
46007330f729Sjoerg     break;
46017330f729Sjoerg 
46027330f729Sjoerg   case CXSaveError_Unknown:
46037330f729Sjoerg   default:
46047330f729Sjoerg     fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
46057330f729Sjoerg     result = 1;
46067330f729Sjoerg     break;
46077330f729Sjoerg   }
46087330f729Sjoerg 
46097330f729Sjoerg   clang_disposeTranslationUnit(TU);
46107330f729Sjoerg   free_remapped_files(unsaved_files, num_unsaved_files);
46117330f729Sjoerg   clang_disposeIndex(Idx);
46127330f729Sjoerg   return result;
46137330f729Sjoerg }
46147330f729Sjoerg 
46157330f729Sjoerg /******************************************************************************/
46167330f729Sjoerg /* Serialized diagnostics.                                                    */
46177330f729Sjoerg /******************************************************************************/
46187330f729Sjoerg 
getDiagnosticCodeStr(enum CXLoadDiag_Error error)46197330f729Sjoerg static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
46207330f729Sjoerg   switch (error) {
46217330f729Sjoerg     case CXLoadDiag_CannotLoad: return "Cannot Load File";
46227330f729Sjoerg     case CXLoadDiag_None: break;
46237330f729Sjoerg     case CXLoadDiag_Unknown: return "Unknown";
46247330f729Sjoerg     case CXLoadDiag_InvalidFile: return "Invalid File";
46257330f729Sjoerg   }
46267330f729Sjoerg   return "None";
46277330f729Sjoerg }
46287330f729Sjoerg 
getSeverityString(enum CXDiagnosticSeverity severity)46297330f729Sjoerg static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
46307330f729Sjoerg   switch (severity) {
46317330f729Sjoerg     case CXDiagnostic_Note: return "note";
46327330f729Sjoerg     case CXDiagnostic_Error: return "error";
46337330f729Sjoerg     case CXDiagnostic_Fatal: return "fatal";
46347330f729Sjoerg     case CXDiagnostic_Ignored: return "ignored";
46357330f729Sjoerg     case CXDiagnostic_Warning: return "warning";
46367330f729Sjoerg   }
46377330f729Sjoerg   return "unknown";
46387330f729Sjoerg }
46397330f729Sjoerg 
printIndent(unsigned indent)46407330f729Sjoerg static void printIndent(unsigned indent) {
46417330f729Sjoerg   if (indent == 0)
46427330f729Sjoerg     return;
46437330f729Sjoerg   fprintf(stderr, "+");
46447330f729Sjoerg   --indent;
46457330f729Sjoerg   while (indent > 0) {
46467330f729Sjoerg     fprintf(stderr, "-");
46477330f729Sjoerg     --indent;
46487330f729Sjoerg   }
46497330f729Sjoerg }
46507330f729Sjoerg 
printLocation(CXSourceLocation L)46517330f729Sjoerg static void printLocation(CXSourceLocation L) {
46527330f729Sjoerg   CXFile File;
46537330f729Sjoerg   CXString FileName;
46547330f729Sjoerg   unsigned line, column, offset;
46557330f729Sjoerg 
46567330f729Sjoerg   clang_getExpansionLocation(L, &File, &line, &column, &offset);
46577330f729Sjoerg   FileName = clang_getFileName(File);
46587330f729Sjoerg 
46597330f729Sjoerg   fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
46607330f729Sjoerg   clang_disposeString(FileName);
46617330f729Sjoerg }
46627330f729Sjoerg 
printRanges(CXDiagnostic D,unsigned indent)46637330f729Sjoerg static void printRanges(CXDiagnostic D, unsigned indent) {
46647330f729Sjoerg   unsigned i, n = clang_getDiagnosticNumRanges(D);
46657330f729Sjoerg 
46667330f729Sjoerg   for (i = 0; i < n; ++i) {
46677330f729Sjoerg     CXSourceLocation Start, End;
46687330f729Sjoerg     CXSourceRange SR = clang_getDiagnosticRange(D, i);
46697330f729Sjoerg     Start = clang_getRangeStart(SR);
46707330f729Sjoerg     End = clang_getRangeEnd(SR);
46717330f729Sjoerg 
46727330f729Sjoerg     printIndent(indent);
46737330f729Sjoerg     fprintf(stderr, "Range: ");
46747330f729Sjoerg     printLocation(Start);
46757330f729Sjoerg     fprintf(stderr, " ");
46767330f729Sjoerg     printLocation(End);
46777330f729Sjoerg     fprintf(stderr, "\n");
46787330f729Sjoerg   }
46797330f729Sjoerg }
46807330f729Sjoerg 
printFixIts(CXDiagnostic D,unsigned indent)46817330f729Sjoerg static void printFixIts(CXDiagnostic D, unsigned indent) {
46827330f729Sjoerg   unsigned i, n = clang_getDiagnosticNumFixIts(D);
46837330f729Sjoerg   fprintf(stderr, "Number FIXITs = %d\n", n);
46847330f729Sjoerg   for (i = 0 ; i < n; ++i) {
46857330f729Sjoerg     CXSourceRange ReplacementRange;
46867330f729Sjoerg     CXString text;
46877330f729Sjoerg     text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
46887330f729Sjoerg 
46897330f729Sjoerg     printIndent(indent);
46907330f729Sjoerg     fprintf(stderr, "FIXIT: (");
46917330f729Sjoerg     printLocation(clang_getRangeStart(ReplacementRange));
46927330f729Sjoerg     fprintf(stderr, " - ");
46937330f729Sjoerg     printLocation(clang_getRangeEnd(ReplacementRange));
46947330f729Sjoerg     fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
46957330f729Sjoerg     clang_disposeString(text);
46967330f729Sjoerg   }
46977330f729Sjoerg }
46987330f729Sjoerg 
printDiagnosticSet(CXDiagnosticSet Diags,unsigned indent)46997330f729Sjoerg static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
47007330f729Sjoerg   unsigned i, n;
47017330f729Sjoerg 
47027330f729Sjoerg   if (!Diags)
47037330f729Sjoerg     return;
47047330f729Sjoerg 
47057330f729Sjoerg   n = clang_getNumDiagnosticsInSet(Diags);
47067330f729Sjoerg   for (i = 0; i < n; ++i) {
47077330f729Sjoerg     CXSourceLocation DiagLoc;
47087330f729Sjoerg     CXDiagnostic D;
47097330f729Sjoerg     CXFile File;
47107330f729Sjoerg     CXString FileName, DiagSpelling, DiagOption, DiagCat;
47117330f729Sjoerg     unsigned line, column, offset;
47127330f729Sjoerg     const char *FileNameStr = 0, *DiagOptionStr = 0, *DiagCatStr = 0;
47137330f729Sjoerg 
47147330f729Sjoerg     D = clang_getDiagnosticInSet(Diags, i);
47157330f729Sjoerg     DiagLoc = clang_getDiagnosticLocation(D);
47167330f729Sjoerg     clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
47177330f729Sjoerg     FileName = clang_getFileName(File);
47187330f729Sjoerg     FileNameStr = clang_getCString(FileName);
47197330f729Sjoerg     DiagSpelling = clang_getDiagnosticSpelling(D);
47207330f729Sjoerg 
47217330f729Sjoerg     printIndent(indent);
47227330f729Sjoerg 
47237330f729Sjoerg     fprintf(stderr, "%s:%d:%d: %s: %s",
47247330f729Sjoerg             FileNameStr ? FileNameStr : "(null)",
47257330f729Sjoerg             line,
47267330f729Sjoerg             column,
47277330f729Sjoerg             getSeverityString(clang_getDiagnosticSeverity(D)),
47287330f729Sjoerg             clang_getCString(DiagSpelling));
47297330f729Sjoerg 
47307330f729Sjoerg     DiagOption = clang_getDiagnosticOption(D, 0);
47317330f729Sjoerg     DiagOptionStr = clang_getCString(DiagOption);
47327330f729Sjoerg     if (DiagOptionStr) {
47337330f729Sjoerg       fprintf(stderr, " [%s]", DiagOptionStr);
47347330f729Sjoerg     }
47357330f729Sjoerg 
47367330f729Sjoerg     DiagCat = clang_getDiagnosticCategoryText(D);
47377330f729Sjoerg     DiagCatStr = clang_getCString(DiagCat);
47387330f729Sjoerg     if (DiagCatStr) {
47397330f729Sjoerg       fprintf(stderr, " [%s]", DiagCatStr);
47407330f729Sjoerg     }
47417330f729Sjoerg 
47427330f729Sjoerg     fprintf(stderr, "\n");
47437330f729Sjoerg 
47447330f729Sjoerg     printRanges(D, indent);
47457330f729Sjoerg     printFixIts(D, indent);
47467330f729Sjoerg 
47477330f729Sjoerg     /* Print subdiagnostics. */
47487330f729Sjoerg     printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
47497330f729Sjoerg 
47507330f729Sjoerg     clang_disposeString(FileName);
47517330f729Sjoerg     clang_disposeString(DiagSpelling);
47527330f729Sjoerg     clang_disposeString(DiagOption);
47537330f729Sjoerg     clang_disposeString(DiagCat);
47547330f729Sjoerg   }
47557330f729Sjoerg }
47567330f729Sjoerg 
read_diagnostics(const char * filename)47577330f729Sjoerg static int read_diagnostics(const char *filename) {
47587330f729Sjoerg   enum CXLoadDiag_Error error;
47597330f729Sjoerg   CXString errorString;
47607330f729Sjoerg   CXDiagnosticSet Diags = 0;
47617330f729Sjoerg 
47627330f729Sjoerg   Diags = clang_loadDiagnostics(filename, &error, &errorString);
47637330f729Sjoerg   if (!Diags) {
47647330f729Sjoerg     fprintf(stderr, "Trouble deserializing file (%s): %s\n",
47657330f729Sjoerg             getDiagnosticCodeStr(error),
47667330f729Sjoerg             clang_getCString(errorString));
47677330f729Sjoerg     clang_disposeString(errorString);
47687330f729Sjoerg     return 1;
47697330f729Sjoerg   }
47707330f729Sjoerg 
47717330f729Sjoerg   printDiagnosticSet(Diags, 0);
47727330f729Sjoerg   fprintf(stderr, "Number of diagnostics: %d\n",
47737330f729Sjoerg           clang_getNumDiagnosticsInSet(Diags));
47747330f729Sjoerg   clang_disposeDiagnosticSet(Diags);
47757330f729Sjoerg   return 0;
47767330f729Sjoerg }
47777330f729Sjoerg 
perform_print_build_session_timestamp(void)47787330f729Sjoerg static int perform_print_build_session_timestamp(void) {
47797330f729Sjoerg   printf("%lld\n", clang_getBuildSessionTimestamp());
47807330f729Sjoerg   return 0;
47817330f729Sjoerg }
47827330f729Sjoerg 
47837330f729Sjoerg /******************************************************************************/
47847330f729Sjoerg /* Command line processing.                                                   */
47857330f729Sjoerg /******************************************************************************/
47867330f729Sjoerg 
GetVisitor(const char * s)47877330f729Sjoerg static CXCursorVisitor GetVisitor(const char *s) {
47887330f729Sjoerg   if (s[0] == '\0')
47897330f729Sjoerg     return FilteredPrintingVisitor;
47907330f729Sjoerg   if (strcmp(s, "-usrs") == 0)
47917330f729Sjoerg     return USRVisitor;
47927330f729Sjoerg   if (strncmp(s, "-memory-usage", 13) == 0)
47937330f729Sjoerg     return GetVisitor(s + 13);
47947330f729Sjoerg   return NULL;
47957330f729Sjoerg }
47967330f729Sjoerg 
print_usage(void)47977330f729Sjoerg static void print_usage(void) {
47987330f729Sjoerg   fprintf(stderr,
47997330f729Sjoerg     "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
48007330f729Sjoerg     "       c-index-test -code-completion-timing=<site> <compiler arguments>\n"
48017330f729Sjoerg     "       c-index-test -cursor-at=<site> <compiler arguments>\n"
48027330f729Sjoerg     "       c-index-test -evaluate-cursor-at=<site> <compiler arguments>\n"
48037330f729Sjoerg     "       c-index-test -get-macro-info-cursor-at=<site> <compiler arguments>\n"
48047330f729Sjoerg     "       c-index-test -file-refs-at=<site> <compiler arguments>\n"
48057330f729Sjoerg     "       c-index-test -file-includes-in=<filename> <compiler arguments>\n");
48067330f729Sjoerg   fprintf(stderr,
48077330f729Sjoerg     "       c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
48087330f729Sjoerg     "       c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
48097330f729Sjoerg     "       c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
48107330f729Sjoerg     "       c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
48117330f729Sjoerg     "       c-index-test -test-file-scan <AST file> <source file> "
48127330f729Sjoerg           "[FileCheck prefix]\n");
48137330f729Sjoerg   fprintf(stderr,
48147330f729Sjoerg     "       c-index-test -test-load-tu <AST file> <symbol filter> "
48157330f729Sjoerg           "[FileCheck prefix]\n"
48167330f729Sjoerg     "       c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
48177330f729Sjoerg            "[FileCheck prefix]\n"
48187330f729Sjoerg     "       c-index-test -test-load-source <symbol filter> {<args>}*\n");
48197330f729Sjoerg   fprintf(stderr,
48207330f729Sjoerg     "       c-index-test -test-load-source-memory-usage "
48217330f729Sjoerg     "<symbol filter> {<args>}*\n"
48227330f729Sjoerg     "       c-index-test -test-load-source-reparse <trials> <symbol filter> "
48237330f729Sjoerg     "          {<args>}*\n"
48247330f729Sjoerg     "       c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
48257330f729Sjoerg     "       c-index-test -test-load-source-usrs-memory-usage "
48267330f729Sjoerg           "<symbol filter> {<args>}*\n"
48277330f729Sjoerg     "       c-index-test -test-annotate-tokens=<range> {<args>}*\n"
48287330f729Sjoerg     "       c-index-test -test-inclusion-stack-source {<args>}*\n"
48297330f729Sjoerg     "       c-index-test -test-inclusion-stack-tu <AST file>\n");
48307330f729Sjoerg   fprintf(stderr,
48317330f729Sjoerg     "       c-index-test -test-print-linkage-source {<args>}*\n"
48327330f729Sjoerg     "       c-index-test -test-print-visibility {<args>}*\n"
48337330f729Sjoerg     "       c-index-test -test-print-type {<args>}*\n"
48347330f729Sjoerg     "       c-index-test -test-print-type-size {<args>}*\n"
48357330f729Sjoerg     "       c-index-test -test-print-bitwidth {<args>}*\n"
48367330f729Sjoerg     "       c-index-test -test-print-target-info {<args>}*\n"
48377330f729Sjoerg     "       c-index-test -test-print-type-declaration {<args>}*\n"
48387330f729Sjoerg     "       c-index-test -print-usr [<CursorKind> {<args>}]*\n"
48397330f729Sjoerg     "       c-index-test -print-usr-file <file>\n");
48407330f729Sjoerg   fprintf(stderr,
48417330f729Sjoerg     "       c-index-test -write-pch <file> <compiler arguments>\n"
48427330f729Sjoerg     "       c-index-test -compilation-db [lookup <filename>] database\n");
48437330f729Sjoerg   fprintf(stderr,
48447330f729Sjoerg     "       c-index-test -print-build-session-timestamp\n");
48457330f729Sjoerg   fprintf(stderr,
48467330f729Sjoerg     "       c-index-test -read-diagnostics <file>\n\n");
48477330f729Sjoerg   fprintf(stderr,
48487330f729Sjoerg     " <symbol filter> values:\n%s",
48497330f729Sjoerg     "   all - load all symbols, including those from PCH\n"
48507330f729Sjoerg     "   local - load all symbols except those in PCH\n"
48517330f729Sjoerg     "   category - only load ObjC categories (non-PCH)\n"
48527330f729Sjoerg     "   interface - only load ObjC interfaces (non-PCH)\n"
48537330f729Sjoerg     "   protocol - only load ObjC protocols (non-PCH)\n"
48547330f729Sjoerg     "   function - only load functions (non-PCH)\n"
48557330f729Sjoerg     "   typedef - only load typdefs (non-PCH)\n"
48567330f729Sjoerg     "   scan-function - scan function bodies (non-PCH)\n\n");
48577330f729Sjoerg }
48587330f729Sjoerg 
48597330f729Sjoerg /***/
48607330f729Sjoerg 
cindextest_main(int argc,const char ** argv)48617330f729Sjoerg int cindextest_main(int argc, const char **argv) {
48627330f729Sjoerg   clang_enableStackTraces();
48637330f729Sjoerg   if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
48647330f729Sjoerg       return read_diagnostics(argv[2]);
48657330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
48667330f729Sjoerg     return perform_code_completion(argc, argv, 0);
48677330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
48687330f729Sjoerg     return perform_code_completion(argc, argv, 1);
48697330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
48707330f729Sjoerg     return inspect_cursor_at(argc, argv, "-cursor-at=", inspect_print_cursor);
48717330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-evaluate-cursor-at=") == argv[1])
48727330f729Sjoerg     return inspect_cursor_at(argc, argv, "-evaluate-cursor-at=",
48737330f729Sjoerg                              inspect_evaluate_cursor);
48747330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-get-macro-info-cursor-at=") == argv[1])
48757330f729Sjoerg     return inspect_cursor_at(argc, argv, "-get-macro-info-cursor-at=",
48767330f729Sjoerg                              inspect_macroinfo_cursor);
48777330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
48787330f729Sjoerg     return find_file_refs_at(argc, argv);
48797330f729Sjoerg   if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
48807330f729Sjoerg     return find_file_includes_in(argc, argv);
48817330f729Sjoerg   if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
48827330f729Sjoerg     return index_file(argc - 2, argv + 2, /*full=*/0);
48837330f729Sjoerg   if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
48847330f729Sjoerg     return index_file(argc - 2, argv + 2, /*full=*/1);
48857330f729Sjoerg   if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
48867330f729Sjoerg     return index_tu(argc - 2, argv + 2);
48877330f729Sjoerg   if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
48887330f729Sjoerg     return index_compile_db(argc - 2, argv + 2);
48897330f729Sjoerg   else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
48907330f729Sjoerg     CXCursorVisitor I = GetVisitor(argv[1] + 13);
48917330f729Sjoerg     if (I)
48927330f729Sjoerg       return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
48937330f729Sjoerg                                   NULL);
48947330f729Sjoerg   }
48957330f729Sjoerg   else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
48967330f729Sjoerg     CXCursorVisitor I = GetVisitor(argv[1] + 25);
48977330f729Sjoerg     if (I) {
48987330f729Sjoerg       int trials = atoi(argv[2]);
48997330f729Sjoerg       return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
49007330f729Sjoerg                                          NULL);
49017330f729Sjoerg     }
49027330f729Sjoerg   }
49037330f729Sjoerg   else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
49047330f729Sjoerg     CXCursorVisitor I = GetVisitor(argv[1] + 17);
49057330f729Sjoerg 
49067330f729Sjoerg     PostVisitTU postVisit = 0;
49077330f729Sjoerg     if (strstr(argv[1], "-memory-usage"))
49087330f729Sjoerg       postVisit = PrintMemoryUsage;
49097330f729Sjoerg 
49107330f729Sjoerg     if (I)
49117330f729Sjoerg       return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
49127330f729Sjoerg                                       postVisit);
49137330f729Sjoerg   }
49147330f729Sjoerg   else if (argc >= 3 && strcmp(argv[1], "-single-file-parse") == 0)
49157330f729Sjoerg     return perform_single_file_parse(argv[2]);
49167330f729Sjoerg   else if (argc >= 3 && strcmp(argv[1], "-retain-excluded-conditional-blocks") == 0)
49177330f729Sjoerg     return perform_file_retain_excluded_cb(argv[2]);
49187330f729Sjoerg   else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
49197330f729Sjoerg     return perform_file_scan(argv[2], argv[3],
49207330f729Sjoerg                              argc >= 5 ? argv[4] : 0);
49217330f729Sjoerg   else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
49227330f729Sjoerg     return perform_token_annotation(argc, argv);
49237330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
49247330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
49257330f729Sjoerg                                     PrintInclusionStack);
49267330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
49277330f729Sjoerg     return perform_test_load_tu(argv[2], "all", NULL, NULL,
49287330f729Sjoerg                                 PrintInclusionStack);
49297330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
49307330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
49317330f729Sjoerg                                     NULL);
49327330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-visibility") == 0)
49337330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all", PrintVisibility,
49347330f729Sjoerg                                     NULL);
49357330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
49367330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all",
49377330f729Sjoerg                                     PrintType, 0);
49387330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
49397330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all",
49407330f729Sjoerg                                     PrintTypeSize, 0);
49417330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-type-declaration") == 0)
49427330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all",
49437330f729Sjoerg                                     PrintTypeDeclaration, 0);
49447330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-decl-attributes") == 0)
49457330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all",
49467330f729Sjoerg                                     PrintDeclAttributes, 0);
49477330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
49487330f729Sjoerg     return perform_test_load_source(argc - 2, argv + 2, "all",
49497330f729Sjoerg                                     PrintBitWidth, 0);
49507330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0)
49517330f729Sjoerg     return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL);
49527330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0)
49537330f729Sjoerg     return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL);
49547330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-test-print-target-info") == 0)
49557330f729Sjoerg     return print_target_info(argc - 2, argv + 2);
49567330f729Sjoerg   else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
49577330f729Sjoerg     if (argc > 2)
49587330f729Sjoerg       return print_usrs(argv + 2, argv + argc);
49597330f729Sjoerg     else {
49607330f729Sjoerg       display_usrs();
49617330f729Sjoerg       return 1;
49627330f729Sjoerg     }
49637330f729Sjoerg   }
49647330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
49657330f729Sjoerg     return print_usrs_file(argv[2]);
49667330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
49677330f729Sjoerg     return write_pch_file(argv[2], argc - 3, argv + 3);
49687330f729Sjoerg   else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
49697330f729Sjoerg     return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
49707330f729Sjoerg   else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
49717330f729Sjoerg     return perform_print_build_session_timestamp();
49727330f729Sjoerg 
49737330f729Sjoerg   print_usage();
49747330f729Sjoerg   return 1;
49757330f729Sjoerg }
49767330f729Sjoerg 
49777330f729Sjoerg /***/
49787330f729Sjoerg 
49797330f729Sjoerg /* We intentionally run in a separate thread to ensure we at least minimal
49807330f729Sjoerg  * testing of a multithreaded environment (for example, having a reduced stack
49817330f729Sjoerg  * size). */
49827330f729Sjoerg 
49837330f729Sjoerg typedef struct thread_info {
49847330f729Sjoerg   int (*main_func)(int argc, const char **argv);
49857330f729Sjoerg   int argc;
49867330f729Sjoerg   const char **argv;
49877330f729Sjoerg   int result;
49887330f729Sjoerg } thread_info;
thread_runner(void * client_data_v)49897330f729Sjoerg void thread_runner(void *client_data_v) {
49907330f729Sjoerg   thread_info *client_data = client_data_v;
49917330f729Sjoerg   client_data->result = client_data->main_func(client_data->argc,
49927330f729Sjoerg                                                client_data->argv);
49937330f729Sjoerg }
49947330f729Sjoerg 
flush_atexit(void)49957330f729Sjoerg static void flush_atexit(void) {
49967330f729Sjoerg   /* stdout, and surprisingly even stderr, are not always flushed on process
49977330f729Sjoerg    * and thread exit, particularly when the system is under heavy load. */
49987330f729Sjoerg   fflush(stdout);
49997330f729Sjoerg   fflush(stderr);
50007330f729Sjoerg }
50017330f729Sjoerg 
main(int argc,const char ** argv)50027330f729Sjoerg int main(int argc, const char **argv) {
50037330f729Sjoerg   thread_info client_data;
50047330f729Sjoerg 
50057330f729Sjoerg   atexit(flush_atexit);
50067330f729Sjoerg 
50077330f729Sjoerg #ifdef CLANG_HAVE_LIBXML
50087330f729Sjoerg   LIBXML_TEST_VERSION
50097330f729Sjoerg #endif
50107330f729Sjoerg 
50117330f729Sjoerg   if (argc > 1 && strcmp(argv[1], "core") == 0)
50127330f729Sjoerg     return indextest_core_main(argc, argv);
50137330f729Sjoerg 
50147330f729Sjoerg   client_data.main_func = cindextest_main;
50157330f729Sjoerg   client_data.argc = argc;
50167330f729Sjoerg   client_data.argv = argv;
50177330f729Sjoerg 
50187330f729Sjoerg   if (getenv("CINDEXTEST_NOTHREADS"))
50197330f729Sjoerg     return client_data.main_func(client_data.argc, client_data.argv);
50207330f729Sjoerg 
50217330f729Sjoerg   clang_executeOnThread(thread_runner, &client_data, 0);
50227330f729Sjoerg   return client_data.result;
50237330f729Sjoerg }
5024