Coverage Report

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