Coverage Report

Created: 2020-02-18 08:44

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