Coverage Report

Created: 2020-09-15 12:33

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