blob: 3a47ae4badd8a0a4242b9900ae663e9d4e29f7d1 [file] [log] [blame]
Steve Naroff69b10fd2009-09-01 15:55:40 +00001/* c-index-test.c */
Steve Naroffa1c72842009-08-28 15:28:48 +00002
3#include "clang-c/Index.h"
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00004#include "clang-c/CXCompilationDatabase.h"
Dmitri Gribenkof430da42014-02-12 10:33:14 +00005#include "clang-c/BuildSystem.h"
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00006#include "llvm/Config/config.h"
Douglas Gregor49f67ce2010-08-26 13:48:20 +00007#include <ctype.h>
Douglas Gregor9eb77012009-11-07 00:00:49 +00008#include <stdlib.h>
Steve Naroff1054e602009-08-31 00:59:03 +00009#include <stdio.h>
Steve Naroff38c1a7b2009-09-03 15:49:00 +000010#include <string.h>
Douglas Gregor082c3e62010-01-15 19:40:17 +000011#include <assert.h>
Steve Naroff38c1a7b2009-09-03 15:49:00 +000012
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +000013#ifdef CLANG_HAVE_LIBXML
14#include <libxml/parser.h>
15#include <libxml/relaxng.h>
16#include <libxml/xmlerror.h>
17#endif
18
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +000019#ifdef _WIN32
20# include <direct.h>
21#else
22# include <unistd.h>
23#endif
24
Ted Kremenek1cd27d52009-11-17 18:13:31 +000025/******************************************************************************/
26/* Utility functions. */
27/******************************************************************************/
28
John Thompsonde258b52009-10-27 13:42:56 +000029#ifdef _MSC_VER
30char *basename(const char* path)
31{
32 char* base1 = (char*)strrchr(path, '/');
33 char* base2 = (char*)strrchr(path, '\\');
34 if (base1 && base2)
35 return((base1 > base2) ? base1 + 1 : base2 + 1);
36 else if (base1)
37 return(base1 + 1);
38 else if (base2)
39 return(base2 + 1);
40
41 return((char*)path);
42}
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +000043char *dirname(char* path)
44{
45 char* base1 = (char*)strrchr(path, '/');
46 char* base2 = (char*)strrchr(path, '\\');
47 if (base1 && base2)
48 if (base1 > base2)
49 *base1 = 0;
50 else
51 *base2 = 0;
52 else if (base1)
NAKAMURA Takumi1e43baa62012-06-30 11:47:18 +000053 *base1 = 0;
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +000054 else if (base2)
NAKAMURA Takumi1e43baa62012-06-30 11:47:18 +000055 *base2 = 0;
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +000056
57 return path;
58}
John Thompsonde258b52009-10-27 13:42:56 +000059#else
Steve Naroffa7753c42009-09-24 20:03:06 +000060extern char *basename(const char *);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +000061extern char *dirname(char *);
John Thompsonde258b52009-10-27 13:42:56 +000062#endif
Steve Naroffa7753c42009-09-24 20:03:06 +000063
Douglas Gregorf2430ba2010-07-25 17:39:21 +000064/** \brief Return the default parsing options. */
Douglas Gregorbe2d8c62010-07-23 00:33:23 +000065static unsigned getDefaultParsingOptions() {
66 unsigned options = CXTranslationUnit_DetailedPreprocessingRecord;
67
68 if (getenv("CINDEXTEST_EDITING"))
Douglas Gregor4a47bca2010-08-09 22:28:58 +000069 options |= clang_defaultEditingTranslationUnitOptions();
Douglas Gregorb14904c2010-08-13 22:48:40 +000070 if (getenv("CINDEXTEST_COMPLETION_CACHING"))
71 options |= CXTranslationUnit_CacheCompletionResults;
Argyrios Kyrtzidiscb373e32011-11-03 02:20:25 +000072 if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
73 options &= ~CXTranslationUnit_CacheCompletionResults;
Erik Verbruggen6e922512012-04-12 10:11:59 +000074 if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
75 options |= CXTranslationUnit_SkipFunctionBodies;
Dmitri Gribenko3292d062012-07-02 17:35:10 +000076 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
77 options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion;
Douglas Gregorbe2d8c62010-07-23 00:33:23 +000078
79 return options;
80}
81
Patrik Hagglund55701d22014-02-17 11:54:08 +000082/** \brief Returns 0 in case of success, non-zero in case of a failure. */
Argyrios Kyrtzidise74e8222011-11-13 22:08:33 +000083static int checkForErrors(CXTranslationUnit TU);
84
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +000085static void describeLibclangFailure(enum CXErrorCode Err) {
86 switch (Err) {
87 case CXError_Success:
88 fprintf(stderr, "Success\n");
89 return;
90
91 case CXError_Failure:
92 fprintf(stderr, "Failure (no details available)\n");
93 return;
94
95 case CXError_Crashed:
96 fprintf(stderr, "Failure: libclang crashed\n");
97 return;
98
99 case CXError_InvalidArguments:
100 fprintf(stderr, "Failure: invalid arguments passed to a libclang routine\n");
101 return;
102
103 case CXError_ASTReadError:
104 fprintf(stderr, "Failure: AST deserialization error occurred\n");
105 return;
106 }
107}
108
Daniel Dunbar98c07e02010-02-14 08:32:24 +0000109static void PrintExtent(FILE *out, unsigned begin_line, unsigned begin_column,
110 unsigned end_line, unsigned end_column) {
111 fprintf(out, "[%d:%d - %d:%d]", begin_line, begin_column,
Daniel Dunbar02968e52010-02-14 10:02:57 +0000112 end_line, end_column);
Daniel Dunbar98c07e02010-02-14 08:32:24 +0000113}
114
Ted Kremenek2df52dc2009-11-17 19:37:36 +0000115static unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
116 CXTranslationUnit *TU) {
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +0000117 enum CXErrorCode Err = clang_createTranslationUnit2(Idx, file, TU);
118 if (Err != CXError_Success) {
Ted Kremenek2df52dc2009-11-17 19:37:36 +0000119 fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +0000120 describeLibclangFailure(Err);
121 *TU = 0;
Ted Kremenek2df52dc2009-11-17 19:37:36 +0000122 return 0;
Ted Kremenek29004672010-02-17 00:41:32 +0000123 }
Ted Kremenek2df52dc2009-11-17 19:37:36 +0000124 return 1;
125}
126
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000127void free_remapped_files(struct CXUnsavedFile *unsaved_files,
128 int num_unsaved_files) {
129 int i;
130 for (i = 0; i != num_unsaved_files; ++i) {
131 free((char *)unsaved_files[i].Filename);
132 free((char *)unsaved_files[i].Contents);
133 }
Douglas Gregor0e3da272010-08-19 20:50:29 +0000134 free(unsaved_files);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000135}
136
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000137static int parse_remapped_files_with_opt(const char *opt_name,
138 int argc, const char **argv,
139 int start_arg,
140 struct CXUnsavedFile **unsaved_files,
141 int *num_unsaved_files) {
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000142 int i;
143 int arg;
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000144 int prefix_len = strlen(opt_name);
145 int arg_indices[20];
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000146 *unsaved_files = 0;
147 *num_unsaved_files = 0;
Ted Kremenek29004672010-02-17 00:41:32 +0000148
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000149 /* Count the number of remapped files. */
150 for (arg = start_arg; arg < argc; ++arg) {
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000151 if (strncmp(argv[arg], opt_name, prefix_len))
152 continue;
Ted Kremenek29004672010-02-17 00:41:32 +0000153
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000154 assert(*num_unsaved_files < (int)(sizeof(arg_indices)/sizeof(int)));
155 arg_indices[*num_unsaved_files] = arg;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000156 ++*num_unsaved_files;
157 }
Ted Kremenek29004672010-02-17 00:41:32 +0000158
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000159 if (*num_unsaved_files == 0)
160 return 0;
Ted Kremenek29004672010-02-17 00:41:32 +0000161
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000162 *unsaved_files
Douglas Gregor0e3da272010-08-19 20:50:29 +0000163 = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
164 *num_unsaved_files);
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000165 for (i = 0; i != *num_unsaved_files; ++i) {
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000166 struct CXUnsavedFile *unsaved = *unsaved_files + i;
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000167 const char *arg_string = argv[arg_indices[i]] + prefix_len;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000168 int filename_len;
169 char *filename;
170 char *contents;
171 FILE *to_file;
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000172 const char *sep = strchr(arg_string, ',');
173 if (!sep) {
Ted Kremenek29004672010-02-17 00:41:32 +0000174 fprintf(stderr,
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000175 "error: %sfrom:to argument is missing comma\n", opt_name);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000176 free_remapped_files(*unsaved_files, i);
177 *unsaved_files = 0;
178 *num_unsaved_files = 0;
179 return -1;
180 }
Ted Kremenek29004672010-02-17 00:41:32 +0000181
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000182 /* Open the file that we're remapping to. */
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000183 to_file = fopen(sep + 1, "rb");
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000184 if (!to_file) {
185 fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000186 sep + 1);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000187 free_remapped_files(*unsaved_files, i);
188 *unsaved_files = 0;
189 *num_unsaved_files = 0;
190 return -1;
191 }
Ted Kremenek29004672010-02-17 00:41:32 +0000192
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000193 /* Determine the length of the file we're remapping to. */
194 fseek(to_file, 0, SEEK_END);
195 unsaved->Length = ftell(to_file);
196 fseek(to_file, 0, SEEK_SET);
Ted Kremenek29004672010-02-17 00:41:32 +0000197
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000198 /* Read the contents of the file we're remapping to. */
199 contents = (char *)malloc(unsaved->Length + 1);
200 if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
201 fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000202 (feof(to_file) ? "EOF" : "error"), sep + 1);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000203 fclose(to_file);
204 free_remapped_files(*unsaved_files, i);
Richard Smith1ea42eb2012-07-05 08:20:49 +0000205 free(contents);
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000206 *unsaved_files = 0;
207 *num_unsaved_files = 0;
208 return -1;
209 }
210 contents[unsaved->Length] = 0;
211 unsaved->Contents = contents;
Ted Kremenek29004672010-02-17 00:41:32 +0000212
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000213 /* Close the file. */
214 fclose(to_file);
Ted Kremenek29004672010-02-17 00:41:32 +0000215
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000216 /* Copy the file name that we're remapping from. */
Argyrios Kyrtzidis5899e892013-12-05 20:13:27 +0000217 filename_len = sep - arg_string;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000218 filename = (char *)malloc(filename_len + 1);
219 memcpy(filename, arg_string, filename_len);
220 filename[filename_len] = 0;
221 unsaved->Filename = filename;
222 }
Ted Kremenek29004672010-02-17 00:41:32 +0000223
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000224 return 0;
225}
226
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +0000227static int parse_remapped_files(int argc, const char **argv, int start_arg,
228 struct CXUnsavedFile **unsaved_files,
229 int *num_unsaved_files) {
230 return parse_remapped_files_with_opt("-remap-file=", argc, argv, start_arg,
231 unsaved_files, num_unsaved_files);
232}
233
234static int parse_remapped_files_with_try(int try_idx,
235 int argc, const char **argv,
236 int start_arg,
237 struct CXUnsavedFile **unsaved_files,
238 int *num_unsaved_files) {
239 struct CXUnsavedFile *unsaved_files_no_try_idx;
240 int num_unsaved_files_no_try_idx;
241 struct CXUnsavedFile *unsaved_files_try_idx;
242 int num_unsaved_files_try_idx;
243 int ret;
244 char opt_name[32];
245
246 ret = parse_remapped_files(argc, argv, start_arg,
247 &unsaved_files_no_try_idx, &num_unsaved_files_no_try_idx);
248 if (ret)
249 return ret;
250
251 sprintf(opt_name, "-remap-file-%d=", try_idx);
252 ret = parse_remapped_files_with_opt(opt_name, argc, argv, start_arg,
253 &unsaved_files_try_idx, &num_unsaved_files_try_idx);
254 if (ret)
255 return ret;
256
257 *num_unsaved_files = num_unsaved_files_no_try_idx + num_unsaved_files_try_idx;
258 *unsaved_files
259 = (struct CXUnsavedFile *)realloc(unsaved_files_no_try_idx,
260 sizeof(struct CXUnsavedFile) *
261 *num_unsaved_files);
262 memcpy(*unsaved_files + num_unsaved_files_no_try_idx,
263 unsaved_files_try_idx, sizeof(struct CXUnsavedFile) *
264 num_unsaved_files_try_idx);
265 free(unsaved_files_try_idx);
266 return 0;
267}
268
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000269static const char *parse_comments_schema(int argc, const char **argv) {
270 const char *CommentsSchemaArg = "-comments-xml-schema=";
271 const char *CommentSchemaFile = NULL;
272
273 if (argc == 0)
274 return CommentSchemaFile;
275
276 if (!strncmp(argv[0], CommentsSchemaArg, strlen(CommentsSchemaArg)))
277 CommentSchemaFile = argv[0] + strlen(CommentsSchemaArg);
278
279 return CommentSchemaFile;
280}
281
Ted Kremenek1cd27d52009-11-17 18:13:31 +0000282/******************************************************************************/
283/* Pretty-printing. */
284/******************************************************************************/
285
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000286static const char *FileCheckPrefix = "CHECK";
287
288static void PrintCString(const char *CStr) {
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000289 if (CStr != NULL && CStr[0] != '\0') {
290 for ( ; *CStr; ++CStr) {
291 const char C = *CStr;
292 switch (C) {
293 case '\n': printf("\\n"); break;
294 case '\r': printf("\\r"); break;
295 case '\t': printf("\\t"); break;
296 case '\v': printf("\\v"); break;
297 case '\f': printf("\\f"); break;
298 default: putchar(C); break;
299 }
300 }
301 }
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000302}
303
304static void PrintCStringWithPrefix(const char *Prefix, const char *CStr) {
305 printf(" %s=[", Prefix);
306 PrintCString(CStr);
Dmitri Gribenko5188c4b2012-06-26 20:39:18 +0000307 printf("]");
308}
309
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000310static void PrintCXStringAndDispose(CXString Str) {
311 PrintCString(clang_getCString(Str));
312 clang_disposeString(Str);
313}
314
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000315static void PrintCXStringWithPrefix(const char *Prefix, CXString Str) {
316 PrintCStringWithPrefix(Prefix, clang_getCString(Str));
317}
318
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000319static void PrintCXStringWithPrefixAndDispose(const char *Prefix,
320 CXString Str) {
321 PrintCStringWithPrefix(Prefix, clang_getCString(Str));
322 clang_disposeString(Str);
323}
324
Douglas Gregorc1679ec2011-07-25 17:48:11 +0000325static void PrintRange(CXSourceRange R, const char *str) {
326 CXFile begin_file, end_file;
327 unsigned begin_line, begin_column, end_line, end_column;
328
329 clang_getSpellingLocation(clang_getRangeStart(R),
330 &begin_file, &begin_line, &begin_column, 0);
331 clang_getSpellingLocation(clang_getRangeEnd(R),
332 &end_file, &end_line, &end_column, 0);
333 if (!begin_file || !end_file)
334 return;
335
Argyrios Kyrtzidis191a6a82012-03-30 20:58:35 +0000336 if (str)
337 printf(" %s=", str);
Douglas Gregorc1679ec2011-07-25 17:48:11 +0000338 PrintExtent(stdout, begin_line, begin_column, end_line, end_column);
339}
340
Douglas Gregor97c75712010-10-02 22:49:11 +0000341int want_display_name = 0;
342
Douglas Gregord6225d32012-05-08 00:14:45 +0000343static void printVersion(const char *Prefix, CXVersion Version) {
344 if (Version.Major < 0)
345 return;
346 printf("%s%d", Prefix, Version.Major);
347
348 if (Version.Minor < 0)
349 return;
350 printf(".%d", Version.Minor);
351
352 if (Version.Subminor < 0)
353 return;
354 printf(".%d", Version.Subminor);
355}
356
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000357struct CommentASTDumpingContext {
358 int IndentLevel;
359};
360
361static void DumpCXCommentInternal(struct CommentASTDumpingContext *Ctx,
362 CXComment Comment) {
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000363 unsigned i;
364 unsigned e;
365 enum CXCommentKind Kind = clang_Comment_getKind(Comment);
366
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000367 Ctx->IndentLevel++;
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000368 for (i = 0, e = Ctx->IndentLevel; i != e; ++i)
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000369 printf(" ");
370
371 printf("(");
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000372 switch (Kind) {
373 case CXComment_Null:
374 printf("CXComment_Null");
375 break;
376 case CXComment_Text:
377 printf("CXComment_Text");
378 PrintCXStringWithPrefixAndDispose("Text",
379 clang_TextComment_getText(Comment));
380 if (clang_Comment_isWhitespace(Comment))
381 printf(" IsWhitespace");
382 if (clang_InlineContentComment_hasTrailingNewline(Comment))
383 printf(" HasTrailingNewline");
384 break;
385 case CXComment_InlineCommand:
386 printf("CXComment_InlineCommand");
387 PrintCXStringWithPrefixAndDispose(
388 "CommandName",
389 clang_InlineCommandComment_getCommandName(Comment));
Dmitri Gribenkod73e4ce2012-07-23 16:43:01 +0000390 switch (clang_InlineCommandComment_getRenderKind(Comment)) {
391 case CXCommentInlineCommandRenderKind_Normal:
392 printf(" RenderNormal");
393 break;
394 case CXCommentInlineCommandRenderKind_Bold:
395 printf(" RenderBold");
396 break;
397 case CXCommentInlineCommandRenderKind_Monospaced:
398 printf(" RenderMonospaced");
399 break;
400 case CXCommentInlineCommandRenderKind_Emphasized:
401 printf(" RenderEmphasized");
402 break;
403 }
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000404 for (i = 0, e = clang_InlineCommandComment_getNumArgs(Comment);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000405 i != e; ++i) {
406 printf(" Arg[%u]=", i);
407 PrintCXStringAndDispose(
408 clang_InlineCommandComment_getArgText(Comment, i));
409 }
410 if (clang_InlineContentComment_hasTrailingNewline(Comment))
411 printf(" HasTrailingNewline");
412 break;
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000413 case CXComment_HTMLStartTag: {
414 unsigned NumAttrs;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000415 printf("CXComment_HTMLStartTag");
416 PrintCXStringWithPrefixAndDispose(
417 "Name",
418 clang_HTMLTagComment_getTagName(Comment));
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000419 NumAttrs = clang_HTMLStartTag_getNumAttrs(Comment);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000420 if (NumAttrs != 0) {
421 printf(" Attrs:");
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000422 for (i = 0; i != NumAttrs; ++i) {
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000423 printf(" ");
424 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrName(Comment, i));
425 printf("=");
426 PrintCXStringAndDispose(clang_HTMLStartTag_getAttrValue(Comment, i));
427 }
428 }
429 if (clang_HTMLStartTagComment_isSelfClosing(Comment))
430 printf(" SelfClosing");
431 if (clang_InlineContentComment_hasTrailingNewline(Comment))
432 printf(" HasTrailingNewline");
433 break;
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000434 }
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000435 case CXComment_HTMLEndTag:
436 printf("CXComment_HTMLEndTag");
437 PrintCXStringWithPrefixAndDispose(
438 "Name",
439 clang_HTMLTagComment_getTagName(Comment));
440 if (clang_InlineContentComment_hasTrailingNewline(Comment))
441 printf(" HasTrailingNewline");
442 break;
443 case CXComment_Paragraph:
444 printf("CXComment_Paragraph");
445 if (clang_Comment_isWhitespace(Comment))
446 printf(" IsWhitespace");
447 break;
448 case CXComment_BlockCommand:
449 printf("CXComment_BlockCommand");
450 PrintCXStringWithPrefixAndDispose(
451 "CommandName",
452 clang_BlockCommandComment_getCommandName(Comment));
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000453 for (i = 0, e = clang_BlockCommandComment_getNumArgs(Comment);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000454 i != e; ++i) {
455 printf(" Arg[%u]=", i);
456 PrintCXStringAndDispose(
457 clang_BlockCommandComment_getArgText(Comment, i));
458 }
459 break;
460 case CXComment_ParamCommand:
461 printf("CXComment_ParamCommand");
462 switch (clang_ParamCommandComment_getDirection(Comment)) {
463 case CXCommentParamPassDirection_In:
464 printf(" in");
465 break;
466 case CXCommentParamPassDirection_Out:
467 printf(" out");
468 break;
469 case CXCommentParamPassDirection_InOut:
470 printf(" in,out");
471 break;
472 }
473 if (clang_ParamCommandComment_isDirectionExplicit(Comment))
474 printf(" explicitly");
475 else
476 printf(" implicitly");
477 PrintCXStringWithPrefixAndDispose(
478 "ParamName",
479 clang_ParamCommandComment_getParamName(Comment));
480 if (clang_ParamCommandComment_isParamIndexValid(Comment))
481 printf(" ParamIndex=%u", clang_ParamCommandComment_getParamIndex(Comment));
482 else
483 printf(" ParamIndex=Invalid");
484 break;
Dmitri Gribenko34df2202012-07-31 22:37:06 +0000485 case CXComment_TParamCommand:
486 printf("CXComment_TParamCommand");
487 PrintCXStringWithPrefixAndDispose(
488 "ParamName",
489 clang_TParamCommandComment_getParamName(Comment));
490 if (clang_TParamCommandComment_isParamPositionValid(Comment)) {
491 printf(" ParamPosition={");
492 for (i = 0, e = clang_TParamCommandComment_getDepth(Comment);
493 i != e; ++i) {
494 printf("%u", clang_TParamCommandComment_getIndex(Comment, i));
495 if (i != e - 1)
496 printf(", ");
497 }
498 printf("}");
499 } else
500 printf(" ParamPosition=Invalid");
501 break;
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000502 case CXComment_VerbatimBlockCommand:
503 printf("CXComment_VerbatimBlockCommand");
504 PrintCXStringWithPrefixAndDispose(
505 "CommandName",
506 clang_BlockCommandComment_getCommandName(Comment));
507 break;
508 case CXComment_VerbatimBlockLine:
509 printf("CXComment_VerbatimBlockLine");
510 PrintCXStringWithPrefixAndDispose(
511 "Text",
512 clang_VerbatimBlockLineComment_getText(Comment));
513 break;
514 case CXComment_VerbatimLine:
515 printf("CXComment_VerbatimLine");
516 PrintCXStringWithPrefixAndDispose(
517 "Text",
518 clang_VerbatimLineComment_getText(Comment));
519 break;
520 case CXComment_FullComment:
521 printf("CXComment_FullComment");
522 break;
523 }
524 if (Kind != CXComment_Null) {
525 const unsigned NumChildren = clang_Comment_getNumChildren(Comment);
Dmitri Gribenkof267c872012-07-20 22:00:35 +0000526 unsigned i;
527 for (i = 0; i != NumChildren; ++i) {
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000528 printf("\n// %s: ", FileCheckPrefix);
529 DumpCXCommentInternal(Ctx, clang_Comment_getChild(Comment, i));
530 }
531 }
532 printf(")");
533 Ctx->IndentLevel--;
534}
535
536static void DumpCXComment(CXComment Comment) {
537 struct CommentASTDumpingContext Ctx;
538 Ctx.IndentLevel = 1;
539 printf("\n// %s: CommentAST=[\n// %s:", FileCheckPrefix, FileCheckPrefix);
540 DumpCXCommentInternal(&Ctx, Comment);
541 printf("]");
542}
543
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000544typedef struct {
545 const char *CommentSchemaFile;
546#ifdef CLANG_HAVE_LIBXML
547 xmlRelaxNGParserCtxtPtr RNGParser;
548 xmlRelaxNGPtr Schema;
549#endif
550} CommentXMLValidationData;
551
552static void ValidateCommentXML(const char *Str,
553 CommentXMLValidationData *ValidationData) {
554#ifdef CLANG_HAVE_LIBXML
555 xmlDocPtr Doc;
556 xmlRelaxNGValidCtxtPtr ValidationCtxt;
557 int status;
558
559 if (!ValidationData || !ValidationData->CommentSchemaFile)
560 return;
561
562 if (!ValidationData->RNGParser) {
563 ValidationData->RNGParser =
564 xmlRelaxNGNewParserCtxt(ValidationData->CommentSchemaFile);
565 ValidationData->Schema = xmlRelaxNGParse(ValidationData->RNGParser);
566 }
567 if (!ValidationData->RNGParser) {
568 printf(" libXMLError");
569 return;
570 }
571
572 Doc = xmlParseDoc((const xmlChar *) Str);
573
574 if (!Doc) {
575 xmlErrorPtr Error = xmlGetLastError();
576 printf(" CommentXMLInvalid [not well-formed XML: %s]", Error->message);
577 return;
578 }
579
580 ValidationCtxt = xmlRelaxNGNewValidCtxt(ValidationData->Schema);
581 status = xmlRelaxNGValidateDoc(ValidationCtxt, Doc);
582 if (!status)
583 printf(" CommentXMLValid");
584 else if (status > 0) {
585 xmlErrorPtr Error = xmlGetLastError();
586 printf(" CommentXMLInvalid [not vaild XML: %s]", Error->message);
587 } else
588 printf(" libXMLError");
589
590 xmlRelaxNGFreeValidCtxt(ValidationCtxt);
591 xmlFreeDoc(Doc);
592#endif
593}
594
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000595static void PrintCursorComments(CXCursor Cursor,
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000596 CommentXMLValidationData *ValidationData) {
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000597 {
598 CXString RawComment;
599 const char *RawCommentCString;
600 CXString BriefComment;
601 const char *BriefCommentCString;
602
603 RawComment = clang_Cursor_getRawCommentText(Cursor);
604 RawCommentCString = clang_getCString(RawComment);
605 if (RawCommentCString != NULL && RawCommentCString[0] != '\0') {
606 PrintCStringWithPrefix("RawComment", RawCommentCString);
607 PrintRange(clang_Cursor_getCommentRange(Cursor), "RawCommentRange");
608
609 BriefComment = clang_Cursor_getBriefCommentText(Cursor);
610 BriefCommentCString = clang_getCString(BriefComment);
611 if (BriefCommentCString != NULL && BriefCommentCString[0] != '\0')
612 PrintCStringWithPrefix("BriefComment", BriefCommentCString);
613 clang_disposeString(BriefComment);
614 }
615 clang_disposeString(RawComment);
616 }
617
618 {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000619 CXComment Comment = clang_Cursor_getParsedComment(Cursor);
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000620 if (clang_Comment_getKind(Comment) != CXComment_Null) {
621 PrintCXStringWithPrefixAndDispose("FullCommentAsHTML",
622 clang_FullComment_getAsHTML(Comment));
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000623 {
624 CXString XML;
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000625 XML = clang_FullComment_getAsXML(Comment);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000626 PrintCXStringWithPrefix("FullCommentAsXML", XML);
627 ValidateCommentXML(clang_getCString(XML), ValidationData);
628 clang_disposeString(XML);
629 }
630
Dmitri Gribenko5e4fe002012-07-20 21:34:34 +0000631 DumpCXComment(Comment);
632 }
633 }
634}
635
Argyrios Kyrtzidis079ff5c2012-08-22 23:15:52 +0000636typedef struct {
637 unsigned line;
638 unsigned col;
639} LineCol;
640
641static int lineCol_cmp(const void *p1, const void *p2) {
642 const LineCol *lhs = p1;
643 const LineCol *rhs = p2;
644 if (lhs->line != rhs->line)
645 return (int)lhs->line - (int)rhs->line;
646 return (int)lhs->col - (int)rhs->col;
647}
648
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +0000649static void PrintCursor(CXCursor Cursor,
650 CommentXMLValidationData *ValidationData) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +0000651 CXTranslationUnit TU = clang_Cursor_getTranslationUnit(Cursor);
Ted Kremenek29004672010-02-17 00:41:32 +0000652 if (clang_isInvalid(Cursor.kind)) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000653 CXString ks = clang_getCursorKindSpelling(Cursor.kind);
Ted Kremenek29004672010-02-17 00:41:32 +0000654 printf("Invalid Cursor => %s", clang_getCString(ks));
655 clang_disposeString(ks);
656 }
Steve Naroff63f475a2009-09-25 21:32:34 +0000657 else {
Ted Kremenek29004672010-02-17 00:41:32 +0000658 CXString string, ks;
Douglas Gregorad27e8b2010-01-19 01:20:04 +0000659 CXCursor Referenced;
Douglas Gregor4f46e782010-01-19 21:36:55 +0000660 unsigned line, column;
Douglas Gregord3f48bd2010-09-02 00:07:54 +0000661 CXCursor SpecializationOf;
Douglas Gregor99a26af2010-10-01 20:25:15 +0000662 CXCursor *overridden;
663 unsigned num_overridden;
Douglas Gregorc1679ec2011-07-25 17:48:11 +0000664 unsigned RefNameRangeNr;
665 CXSourceRange CursorExtent;
666 CXSourceRange RefNameRange;
Douglas Gregord6225d32012-05-08 00:14:45 +0000667 int AlwaysUnavailable;
668 int AlwaysDeprecated;
669 CXString UnavailableMessage;
670 CXString DeprecatedMessage;
671 CXPlatformAvailability PlatformAvailability[2];
672 int NumPlatformAvailability;
673 int I;
Dmitri Gribenkoaab83832012-06-20 00:34:58 +0000674
Ted Kremenek29004672010-02-17 00:41:32 +0000675 ks = clang_getCursorKindSpelling(Cursor.kind);
Douglas Gregor97c75712010-10-02 22:49:11 +0000676 string = want_display_name? clang_getCursorDisplayName(Cursor)
677 : clang_getCursorSpelling(Cursor);
Ted Kremenek29004672010-02-17 00:41:32 +0000678 printf("%s=%s", clang_getCString(ks),
679 clang_getCString(string));
680 clang_disposeString(ks);
Steve Naroff8675d5c2009-11-09 17:45:52 +0000681 clang_disposeString(string);
Ted Kremenek29004672010-02-17 00:41:32 +0000682
Douglas Gregorad27e8b2010-01-19 01:20:04 +0000683 Referenced = clang_getCursorReferenced(Cursor);
684 if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
Douglas Gregor16a2bdd2010-09-13 22:52:57 +0000685 if (clang_getCursorKind(Referenced) == CXCursor_OverloadedDeclRef) {
686 unsigned I, N = clang_getNumOverloadedDecls(Referenced);
687 printf("[");
688 for (I = 0; I != N; ++I) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000689 CXCursor Ovl = clang_getOverloadedDecl(Referenced, I);
Douglas Gregor2967e282010-09-14 00:20:32 +0000690 CXSourceLocation Loc;
Douglas Gregor16a2bdd2010-09-13 22:52:57 +0000691 if (I)
692 printf(", ");
693
Douglas Gregor2967e282010-09-14 00:20:32 +0000694 Loc = clang_getCursorLocation(Ovl);
Douglas Gregor229bebd2010-11-09 06:24:54 +0000695 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
Douglas Gregor16a2bdd2010-09-13 22:52:57 +0000696 printf("%d:%d", line, column);
697 }
698 printf("]");
699 } else {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000700 CXSourceLocation Loc = clang_getCursorLocation(Referenced);
Douglas Gregor229bebd2010-11-09 06:24:54 +0000701 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
Douglas Gregor16a2bdd2010-09-13 22:52:57 +0000702 printf(":%d:%d", line, column);
703 }
Douglas Gregorad27e8b2010-01-19 01:20:04 +0000704 }
Douglas Gregor6b8232f2010-01-19 19:34:47 +0000705
706 if (clang_isCursorDefinition(Cursor))
707 printf(" (Definition)");
Douglas Gregorf757a122010-08-23 23:00:57 +0000708
709 switch (clang_getCursorAvailability(Cursor)) {
710 case CXAvailability_Available:
711 break;
712
713 case CXAvailability_Deprecated:
714 printf(" (deprecated)");
715 break;
716
717 case CXAvailability_NotAvailable:
718 printf(" (unavailable)");
719 break;
Erik Verbruggen2e657ff2011-10-06 07:27:49 +0000720
721 case CXAvailability_NotAccessible:
722 printf(" (inaccessible)");
723 break;
Douglas Gregorf757a122010-08-23 23:00:57 +0000724 }
Ted Kremeneka5940822010-08-26 01:42:22 +0000725
Douglas Gregord6225d32012-05-08 00:14:45 +0000726 NumPlatformAvailability
727 = clang_getCursorPlatformAvailability(Cursor,
728 &AlwaysDeprecated,
729 &DeprecatedMessage,
730 &AlwaysUnavailable,
731 &UnavailableMessage,
732 PlatformAvailability, 2);
733 if (AlwaysUnavailable) {
734 printf(" (always unavailable: \"%s\")",
735 clang_getCString(UnavailableMessage));
736 } else if (AlwaysDeprecated) {
737 printf(" (always deprecated: \"%s\")",
738 clang_getCString(DeprecatedMessage));
739 } else {
740 for (I = 0; I != NumPlatformAvailability; ++I) {
741 if (I >= 2)
742 break;
743
744 printf(" (%s", clang_getCString(PlatformAvailability[I].Platform));
745 if (PlatformAvailability[I].Unavailable)
746 printf(", unavailable");
747 else {
748 printVersion(", introduced=", PlatformAvailability[I].Introduced);
749 printVersion(", deprecated=", PlatformAvailability[I].Deprecated);
750 printVersion(", obsoleted=", PlatformAvailability[I].Obsoleted);
751 }
752 if (clang_getCString(PlatformAvailability[I].Message)[0])
753 printf(", message=\"%s\"",
754 clang_getCString(PlatformAvailability[I].Message));
755 printf(")");
756 }
757 }
758 for (I = 0; I != NumPlatformAvailability; ++I) {
759 if (I >= 2)
760 break;
761 clang_disposeCXPlatformAvailability(PlatformAvailability + I);
762 }
763
764 clang_disposeString(DeprecatedMessage);
765 clang_disposeString(UnavailableMessage);
766
Douglas Gregora8d0c772011-05-13 15:54:42 +0000767 if (clang_CXXMethod_isStatic(Cursor))
768 printf(" (static)");
769 if (clang_CXXMethod_isVirtual(Cursor))
770 printf(" (virtual)");
Dmitri Gribenko62770be2013-05-17 18:38:35 +0000771 if (clang_CXXMethod_isPureVirtual(Cursor))
772 printf(" (pure)");
Argyrios Kyrtzidis23814e42013-04-18 23:53:05 +0000773 if (clang_Cursor_isVariadic(Cursor))
774 printf(" (variadic)");
Argyrios Kyrtzidis7b50fc52013-07-05 20:44:37 +0000775 if (clang_Cursor_isObjCOptional(Cursor))
776 printf(" (@optional)");
777
Ted Kremeneka5940822010-08-26 01:42:22 +0000778 if (Cursor.kind == CXCursor_IBOutletCollectionAttr) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000779 CXType T =
780 clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor));
781 CXString S = clang_getTypeKindSpelling(T.kind);
Ted Kremeneka5940822010-08-26 01:42:22 +0000782 printf(" [IBOutletCollection=%s]", clang_getCString(S));
783 clang_disposeString(S);
784 }
Ted Kremenekae9e2212010-08-27 21:34:58 +0000785
786 if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
787 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
788 unsigned isVirtual = clang_isVirtualBase(Cursor);
789 const char *accessStr = 0;
790
791 switch (access) {
792 case CX_CXXInvalidAccessSpecifier:
793 accessStr = "invalid"; break;
794 case CX_CXXPublic:
795 accessStr = "public"; break;
796 case CX_CXXProtected:
797 accessStr = "protected"; break;
798 case CX_CXXPrivate:
799 accessStr = "private"; break;
800 }
801
802 printf(" [access=%s isVirtual=%s]", accessStr,
803 isVirtual ? "true" : "false");
804 }
Douglas Gregord3f48bd2010-09-02 00:07:54 +0000805
806 SpecializationOf = clang_getSpecializedCursorTemplate(Cursor);
807 if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000808 CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf);
809 CXString Name = clang_getCursorSpelling(SpecializationOf);
Douglas Gregor229bebd2010-11-09 06:24:54 +0000810 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
Douglas Gregord3f48bd2010-09-02 00:07:54 +0000811 printf(" [Specialization of %s:%d:%d]",
812 clang_getCString(Name), line, column);
813 clang_disposeString(Name);
814 }
Douglas Gregor99a26af2010-10-01 20:25:15 +0000815
816 clang_getOverriddenCursors(Cursor, &overridden, &num_overridden);
817 if (num_overridden) {
818 unsigned I;
Argyrios Kyrtzidis079ff5c2012-08-22 23:15:52 +0000819 LineCol lineCols[50];
820 assert(num_overridden <= 50);
Douglas Gregor99a26af2010-10-01 20:25:15 +0000821 printf(" [Overrides ");
822 for (I = 0; I != num_overridden; ++I) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000823 CXSourceLocation Loc = clang_getCursorLocation(overridden[I]);
Douglas Gregor229bebd2010-11-09 06:24:54 +0000824 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
Argyrios Kyrtzidis079ff5c2012-08-22 23:15:52 +0000825 lineCols[I].line = line;
826 lineCols[I].col = column;
827 }
Michael Liaob94f47a2012-08-30 00:45:32 +0000828 /* Make the order of the override list deterministic. */
Argyrios Kyrtzidis079ff5c2012-08-22 23:15:52 +0000829 qsort(lineCols, num_overridden, sizeof(LineCol), lineCol_cmp);
830 for (I = 0; I != num_overridden; ++I) {
Douglas Gregor99a26af2010-10-01 20:25:15 +0000831 if (I)
832 printf(", ");
Argyrios Kyrtzidis079ff5c2012-08-22 23:15:52 +0000833 printf("@%d:%d", lineCols[I].line, lineCols[I].col);
Douglas Gregor99a26af2010-10-01 20:25:15 +0000834 }
835 printf("]");
836 clang_disposeOverriddenCursors(overridden);
837 }
Douglas Gregor796d76a2010-10-20 22:00:55 +0000838
839 if (Cursor.kind == CXCursor_InclusionDirective) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000840 CXFile File = clang_getIncludedFile(Cursor);
841 CXString Included = clang_getFileName(File);
Douglas Gregor796d76a2010-10-20 22:00:55 +0000842 printf(" (%s)", clang_getCString(Included));
843 clang_disposeString(Included);
Douglas Gregor37aa4932011-05-04 00:14:37 +0000844
845 if (clang_isFileMultipleIncludeGuarded(TU, File))
846 printf(" [multi-include guarded]");
Douglas Gregor796d76a2010-10-20 22:00:55 +0000847 }
Douglas Gregorc1679ec2011-07-25 17:48:11 +0000848
849 CursorExtent = clang_getCursorExtent(Cursor);
850 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
851 CXNameRange_WantQualifier
852 | CXNameRange_WantSinglePiece
853 | CXNameRange_WantTemplateArgs,
854 0);
855 if (!clang_equalRanges(CursorExtent, RefNameRange))
856 PrintRange(RefNameRange, "SingleRefName");
857
858 for (RefNameRangeNr = 0; 1; RefNameRangeNr++) {
859 RefNameRange = clang_getCursorReferenceNameRange(Cursor,
860 CXNameRange_WantQualifier
861 | CXNameRange_WantTemplateArgs,
862 RefNameRangeNr);
863 if (clang_equalRanges(clang_getNullRange(), RefNameRange))
864 break;
865 if (!clang_equalRanges(CursorExtent, RefNameRange))
866 PrintRange(RefNameRange, "RefName");
867 }
Dmitri Gribenkoaab83832012-06-20 00:34:58 +0000868
Dmitri Gribenko7acbf002012-09-10 20:32:42 +0000869 PrintCursorComments(Cursor, ValidationData);
Argyrios Kyrtzidis9adfd8a2013-04-18 22:15:49 +0000870
871 {
872 unsigned PropAttrs = clang_Cursor_getObjCPropertyAttributes(Cursor, 0);
873 if (PropAttrs != CXObjCPropertyAttr_noattr) {
874 printf(" [");
875 #define PRINT_PROP_ATTR(A) \
876 if (PropAttrs & CXObjCPropertyAttr_##A) printf(#A ",")
877 PRINT_PROP_ATTR(readonly);
878 PRINT_PROP_ATTR(getter);
879 PRINT_PROP_ATTR(assign);
880 PRINT_PROP_ATTR(readwrite);
881 PRINT_PROP_ATTR(retain);
882 PRINT_PROP_ATTR(copy);
883 PRINT_PROP_ATTR(nonatomic);
884 PRINT_PROP_ATTR(setter);
885 PRINT_PROP_ATTR(atomic);
886 PRINT_PROP_ATTR(weak);
887 PRINT_PROP_ATTR(strong);
888 PRINT_PROP_ATTR(unsafe_unretained);
889 printf("]");
890 }
891 }
Argyrios Kyrtzidis9d9bc012013-04-18 23:29:12 +0000892
893 {
894 unsigned QT = clang_Cursor_getObjCDeclQualifiers(Cursor);
895 if (QT != CXObjCDeclQualifier_None) {
896 printf(" [");
897 #define PRINT_OBJC_QUAL(A) \
898 if (QT & CXObjCDeclQualifier_##A) printf(#A ",")
899 PRINT_OBJC_QUAL(In);
900 PRINT_OBJC_QUAL(Inout);
901 PRINT_OBJC_QUAL(Out);
902 PRINT_OBJC_QUAL(Bycopy);
903 PRINT_OBJC_QUAL(Byref);
904 PRINT_OBJC_QUAL(Oneway);
905 printf("]");
906 }
907 }
Steve Naroff63f475a2009-09-25 21:32:34 +0000908 }
Steve Naroff38c1a7b2009-09-03 15:49:00 +0000909}
Steve Naroff1054e602009-08-31 00:59:03 +0000910
Ted Kremenek29004672010-02-17 00:41:32 +0000911static const char* GetCursorSource(CXCursor Cursor) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000912 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
Ted Kremenekc560b682010-02-17 00:41:20 +0000913 CXString source;
Douglas Gregor4f46e782010-01-19 21:36:55 +0000914 CXFile file;
Argyrios Kyrtzidis7ca77352011-11-03 02:20:36 +0000915 clang_getExpansionLocation(Loc, &file, 0, 0, 0);
Douglas Gregor4f46e782010-01-19 21:36:55 +0000916 source = clang_getFileName(file);
Ted Kremenek29004672010-02-17 00:41:32 +0000917 if (!clang_getCString(source)) {
Ted Kremenekc560b682010-02-17 00:41:20 +0000918 clang_disposeString(source);
919 return "<invalid loc>";
920 }
921 else {
Ted Kremenek29004672010-02-17 00:41:32 +0000922 const char *b = basename(clang_getCString(source));
Ted Kremenekc560b682010-02-17 00:41:20 +0000923 clang_disposeString(source);
924 return b;
925 }
Ted Kremenek4c4d6432009-11-17 05:31:58 +0000926}
927
Ted Kremenek1cd27d52009-11-17 18:13:31 +0000928/******************************************************************************/
Ted Kremenekb478ff42010-01-26 17:59:48 +0000929/* Callbacks. */
930/******************************************************************************/
931
932typedef void (*PostVisitTU)(CXTranslationUnit);
933
Douglas Gregor33cdd812010-02-18 18:08:43 +0000934void PrintDiagnostic(CXDiagnostic Diagnostic) {
935 FILE *out = stderr;
Douglas Gregor4f9c3762010-01-28 00:27:43 +0000936 CXFile file;
Douglas Gregord770f732010-02-22 23:17:23 +0000937 CXString Msg;
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000938 unsigned display_opts = CXDiagnostic_DisplaySourceLocation
Douglas Gregora750e8e2010-11-19 16:18:16 +0000939 | CXDiagnostic_DisplayColumn | CXDiagnostic_DisplaySourceRanges
940 | CXDiagnostic_DisplayOption;
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000941 unsigned i, num_fixits;
Ted Kremenek599d73a2010-03-25 02:00:39 +0000942
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000943 if (clang_getDiagnosticSeverity(Diagnostic) == CXDiagnostic_Ignored)
Douglas Gregor4f9c3762010-01-28 00:27:43 +0000944 return;
Ted Kremenek29004672010-02-17 00:41:32 +0000945
Douglas Gregord770f732010-02-22 23:17:23 +0000946 Msg = clang_formatDiagnostic(Diagnostic, display_opts);
947 fprintf(stderr, "%s\n", clang_getCString(Msg));
948 clang_disposeString(Msg);
Ted Kremenek599d73a2010-03-25 02:00:39 +0000949
Douglas Gregor229bebd2010-11-09 06:24:54 +0000950 clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
951 &file, 0, 0, 0);
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000952 if (!file)
953 return;
Ted Kremenek29004672010-02-17 00:41:32 +0000954
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000955 num_fixits = clang_getDiagnosticNumFixIts(Diagnostic);
Ted Kremenek4a642302012-03-20 20:49:45 +0000956 fprintf(stderr, "Number FIX-ITs = %d\n", num_fixits);
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000957 for (i = 0; i != num_fixits; ++i) {
Douglas Gregor836ec942010-02-19 18:16:06 +0000958 CXSourceRange range;
Enea Zaffanella476f38a2013-07-22 20:58:30 +0000959 CXString insertion_text = clang_getDiagnosticFixIt(Diagnostic, i, &range);
960 CXSourceLocation start = clang_getRangeStart(range);
961 CXSourceLocation end = clang_getRangeEnd(range);
Douglas Gregor836ec942010-02-19 18:16:06 +0000962 unsigned start_line, start_column, end_line, end_column;
963 CXFile start_file, end_file;
Douglas Gregor229bebd2010-11-09 06:24:54 +0000964 clang_getSpellingLocation(start, &start_file, &start_line,
965 &start_column, 0);
966 clang_getSpellingLocation(end, &end_file, &end_line, &end_column, 0);
Douglas Gregor836ec942010-02-19 18:16:06 +0000967 if (clang_equalLocations(start, end)) {
968 /* Insertion. */
969 if (start_file == file)
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000970 fprintf(out, "FIX-IT: Insert \"%s\" at %d:%d\n",
Douglas Gregor836ec942010-02-19 18:16:06 +0000971 clang_getCString(insertion_text), start_line, start_column);
972 } else if (strcmp(clang_getCString(insertion_text), "") == 0) {
973 /* Removal. */
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000974 if (start_file == file && end_file == file) {
975 fprintf(out, "FIX-IT: Remove ");
976 PrintExtent(out, start_line, start_column, end_line, end_column);
977 fprintf(out, "\n");
Douglas Gregor60b11f62010-01-29 00:41:11 +0000978 }
Douglas Gregor836ec942010-02-19 18:16:06 +0000979 } else {
980 /* Replacement. */
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000981 if (start_file == end_file) {
982 fprintf(out, "FIX-IT: Replace ");
983 PrintExtent(out, start_line, start_column, end_line, end_column);
Douglas Gregor836ec942010-02-19 18:16:06 +0000984 fprintf(out, " with \"%s\"\n", clang_getCString(insertion_text));
Douglas Gregor9773e3d2010-02-18 22:27:07 +0000985 }
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000986 break;
987 }
Douglas Gregor836ec942010-02-19 18:16:06 +0000988 clang_disposeString(insertion_text);
Douglas Gregor60b11f62010-01-29 00:41:11 +0000989 }
Douglas Gregor4f9c3762010-01-28 00:27:43 +0000990}
991
Ted Kremenek914c7e62012-02-14 02:46:03 +0000992void PrintDiagnosticSet(CXDiagnosticSet Set) {
993 int i = 0, n = clang_getNumDiagnosticsInSet(Set);
994 for ( ; i != n ; ++i) {
995 CXDiagnostic Diag = clang_getDiagnosticInSet(Set, i);
996 CXDiagnosticSet ChildDiags = clang_getChildDiagnostics(Diag);
Douglas Gregor33cdd812010-02-18 18:08:43 +0000997 PrintDiagnostic(Diag);
Ted Kremenek914c7e62012-02-14 02:46:03 +0000998 if (ChildDiags)
999 PrintDiagnosticSet(ChildDiags);
1000 }
1001}
1002
1003void PrintDiagnostics(CXTranslationUnit TU) {
1004 CXDiagnosticSet TUSet = clang_getDiagnosticSetFromTU(TU);
1005 PrintDiagnosticSet(TUSet);
1006 clang_disposeDiagnosticSet(TUSet);
Douglas Gregor33cdd812010-02-18 18:08:43 +00001007}
1008
Ted Kremenek83f642e2011-04-18 22:47:10 +00001009void PrintMemoryUsage(CXTranslationUnit TU) {
Matt Beaumont-Gayd6238f42011-08-29 16:37:29 +00001010 unsigned long total = 0;
Ted Kremenek11d1a422011-04-18 23:42:53 +00001011 unsigned i = 0;
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001012 CXTUResourceUsage usage = clang_getCXTUResourceUsage(TU);
Francois Pichet45cc5462011-04-18 23:33:22 +00001013 fprintf(stderr, "Memory usage:\n");
Ted Kremenek11d1a422011-04-18 23:42:53 +00001014 for (i = 0 ; i != usage.numEntries; ++i) {
Ted Kremenek23324122011-04-20 16:41:07 +00001015 const char *name = clang_getTUResourceUsageName(usage.entries[i].kind);
Ted Kremenek83f642e2011-04-18 22:47:10 +00001016 unsigned long amount = usage.entries[i].amount;
1017 total += amount;
Ted Kremenek11d1a422011-04-18 23:42:53 +00001018 fprintf(stderr, " %s : %ld bytes (%f MBytes)\n", name, amount,
Ted Kremenek83f642e2011-04-18 22:47:10 +00001019 ((double) amount)/(1024*1024));
1020 }
Ted Kremenek11d1a422011-04-18 23:42:53 +00001021 fprintf(stderr, " TOTAL = %ld bytes (%f MBytes)\n", total,
Ted Kremenek83f642e2011-04-18 22:47:10 +00001022 ((double) total)/(1024*1024));
Ted Kremenek23324122011-04-20 16:41:07 +00001023 clang_disposeCXTUResourceUsage(usage);
Ted Kremenek83f642e2011-04-18 22:47:10 +00001024}
1025
Ted Kremenekb478ff42010-01-26 17:59:48 +00001026/******************************************************************************/
Douglas Gregor720d0052010-01-20 21:32:04 +00001027/* Logic for testing traversal. */
Ted Kremenek1cd27d52009-11-17 18:13:31 +00001028/******************************************************************************/
1029
Douglas Gregor33c34ac2010-01-19 00:34:46 +00001030static void PrintCursorExtent(CXCursor C) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001031 CXSourceRange extent = clang_getCursorExtent(C);
1032 PrintRange(extent, "Extent");
Ted Kremeneka44d99c2010-01-05 23:18:49 +00001033}
1034
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001035/* Data used by the visitors. */
1036typedef struct {
Douglas Gregor720d0052010-01-20 21:32:04 +00001037 CXTranslationUnit TU;
1038 enum CXCursorKind *Filter;
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001039 CommentXMLValidationData ValidationData;
Douglas Gregor720d0052010-01-20 21:32:04 +00001040} VisitorData;
Ted Kremeneka44d99c2010-01-05 23:18:49 +00001041
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001042
Ted Kremenek29004672010-02-17 00:41:32 +00001043enum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
Douglas Gregor720d0052010-01-20 21:32:04 +00001044 CXCursor Parent,
1045 CXClientData ClientData) {
1046 VisitorData *Data = (VisitorData *)ClientData;
1047 if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001048 CXSourceLocation Loc = clang_getCursorLocation(Cursor);
Douglas Gregor4f46e782010-01-19 21:36:55 +00001049 unsigned line, column;
Douglas Gregor229bebd2010-11-09 06:24:54 +00001050 clang_getSpellingLocation(Loc, 0, &line, &column, 0);
Ted Kremeneka44d99c2010-01-05 23:18:49 +00001051 printf("// %s: %s:%d:%d: ", FileCheckPrefix,
Douglas Gregor4f46e782010-01-19 21:36:55 +00001052 GetCursorSource(Cursor), line, column);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001053 PrintCursor(Cursor, &Data->ValidationData);
Douglas Gregor33c34ac2010-01-19 00:34:46 +00001054 PrintCursorExtent(Cursor);
Argyrios Kyrtzidis1ab09cc2013-04-11 17:02:10 +00001055 if (clang_isDeclaration(Cursor.kind)) {
1056 enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
1057 const char *accessStr = 0;
1058
1059 switch (access) {
1060 case CX_CXXInvalidAccessSpecifier: break;
1061 case CX_CXXPublic:
1062 accessStr = "public"; break;
1063 case CX_CXXProtected:
1064 accessStr = "protected"; break;
1065 case CX_CXXPrivate:
1066 accessStr = "private"; break;
1067 }
1068
1069 if (accessStr)
1070 printf(" [access=%s]", accessStr);
1071 }
Ted Kremenek29004672010-02-17 00:41:32 +00001072 printf("\n");
Douglas Gregor720d0052010-01-20 21:32:04 +00001073 return CXChildVisit_Recurse;
Steve Naroff772c1a42009-08-31 14:26:51 +00001074 }
Ted Kremenek29004672010-02-17 00:41:32 +00001075
Douglas Gregor720d0052010-01-20 21:32:04 +00001076 return CXChildVisit_Continue;
Steve Naroff1054e602009-08-31 00:59:03 +00001077}
Steve Naroffa1c72842009-08-28 15:28:48 +00001078
Ted Kremenek29004672010-02-17 00:41:32 +00001079static enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
Douglas Gregor720d0052010-01-20 21:32:04 +00001080 CXCursor Parent,
1081 CXClientData ClientData) {
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001082 const char *startBuf, *endBuf;
1083 unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
1084 CXCursor Ref;
Douglas Gregor720d0052010-01-20 21:32:04 +00001085 VisitorData *Data = (VisitorData *)ClientData;
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001086
Douglas Gregor6b8232f2010-01-19 19:34:47 +00001087 if (Cursor.kind != CXCursor_FunctionDecl ||
1088 !clang_isCursorDefinition(Cursor))
Douglas Gregor720d0052010-01-20 21:32:04 +00001089 return CXChildVisit_Continue;
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001090
1091 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
1092 &startLine, &startColumn,
1093 &endLine, &endColumn);
1094 /* Probe the entire body, looking for both decls and refs. */
1095 curLine = startLine;
1096 curColumn = startColumn;
1097
1098 while (startBuf < endBuf) {
Douglas Gregor66a58812010-01-18 22:46:11 +00001099 CXSourceLocation Loc;
Douglas Gregor4f46e782010-01-19 21:36:55 +00001100 CXFile file;
Ted Kremenekc560b682010-02-17 00:41:20 +00001101 CXString source;
Ted Kremenek29004672010-02-17 00:41:32 +00001102
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001103 if (*startBuf == '\n') {
1104 startBuf++;
1105 curLine++;
1106 curColumn = 1;
1107 } else if (*startBuf != '\t')
1108 curColumn++;
Ted Kremenek29004672010-02-17 00:41:32 +00001109
Douglas Gregor66a58812010-01-18 22:46:11 +00001110 Loc = clang_getCursorLocation(Cursor);
Douglas Gregor229bebd2010-11-09 06:24:54 +00001111 clang_getSpellingLocation(Loc, &file, 0, 0, 0);
Ted Kremenek29004672010-02-17 00:41:32 +00001112
Douglas Gregor4f46e782010-01-19 21:36:55 +00001113 source = clang_getFileName(file);
Ted Kremenek29004672010-02-17 00:41:32 +00001114 if (clang_getCString(source)) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001115 CXSourceLocation RefLoc
1116 = clang_getLocation(Data->TU, file, curLine, curColumn);
Douglas Gregor816fd362010-01-22 21:44:22 +00001117 Ref = clang_getCursor(Data->TU, RefLoc);
Douglas Gregor66a58812010-01-18 22:46:11 +00001118 if (Ref.kind == CXCursor_NoDeclFound) {
1119 /* Nothing found here; that's fine. */
1120 } else if (Ref.kind != CXCursor_FunctionDecl) {
1121 printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
1122 curLine, curColumn);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001123 PrintCursor(Ref, &Data->ValidationData);
Douglas Gregor66a58812010-01-18 22:46:11 +00001124 printf("\n");
1125 }
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001126 }
Ted Kremenekc560b682010-02-17 00:41:20 +00001127 clang_disposeString(source);
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001128 startBuf++;
1129 }
Ted Kremenek29004672010-02-17 00:41:32 +00001130
Douglas Gregor720d0052010-01-20 21:32:04 +00001131 return CXChildVisit_Continue;
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001132}
1133
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001134/******************************************************************************/
1135/* USR testing. */
1136/******************************************************************************/
1137
Douglas Gregor720d0052010-01-20 21:32:04 +00001138enum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
1139 CXClientData ClientData) {
1140 VisitorData *Data = (VisitorData *)ClientData;
1141 if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001142 CXString USR = clang_getCursorUSR(C);
1143 const char *cstr = clang_getCString(USR);
Ted Kremenek6d159c12010-04-20 23:15:40 +00001144 if (!cstr || cstr[0] == '\0') {
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001145 clang_disposeString(USR);
Ted Kremenek7afa85b2010-04-16 21:31:52 +00001146 return CXChildVisit_Recurse;
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001147 }
Ted Kremenek6d159c12010-04-20 23:15:40 +00001148 printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), cstr);
1149
Douglas Gregor33c34ac2010-01-19 00:34:46 +00001150 PrintCursorExtent(C);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001151 printf("\n");
1152 clang_disposeString(USR);
Ted Kremenek29004672010-02-17 00:41:32 +00001153
Douglas Gregor720d0052010-01-20 21:32:04 +00001154 return CXChildVisit_Recurse;
Ted Kremenek29004672010-02-17 00:41:32 +00001155 }
1156
Douglas Gregor720d0052010-01-20 21:32:04 +00001157 return CXChildVisit_Continue;
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001158}
1159
1160/******************************************************************************/
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00001161/* Inclusion stack testing. */
1162/******************************************************************************/
1163
1164void InclusionVisitor(CXFile includedFile, CXSourceLocation *includeStack,
1165 unsigned includeStackLen, CXClientData data) {
Ted Kremenek29004672010-02-17 00:41:32 +00001166
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00001167 unsigned i;
Ted Kremenekc560b682010-02-17 00:41:20 +00001168 CXString fname;
1169
1170 fname = clang_getFileName(includedFile);
Ted Kremenek29004672010-02-17 00:41:32 +00001171 printf("file: %s\nincluded by:\n", clang_getCString(fname));
Ted Kremenekc560b682010-02-17 00:41:20 +00001172 clang_disposeString(fname);
Ted Kremenek29004672010-02-17 00:41:32 +00001173
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00001174 for (i = 0; i < includeStackLen; ++i) {
1175 CXFile includingFile;
1176 unsigned line, column;
Douglas Gregor229bebd2010-11-09 06:24:54 +00001177 clang_getSpellingLocation(includeStack[i], &includingFile, &line,
1178 &column, 0);
Ted Kremenekc560b682010-02-17 00:41:20 +00001179 fname = clang_getFileName(includingFile);
Ted Kremenek29004672010-02-17 00:41:32 +00001180 printf(" %s:%d:%d\n", clang_getCString(fname), line, column);
Ted Kremenekc560b682010-02-17 00:41:20 +00001181 clang_disposeString(fname);
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00001182 }
1183 printf("\n");
1184}
1185
1186void PrintInclusionStack(CXTranslationUnit TU) {
Ted Kremenek29004672010-02-17 00:41:32 +00001187 clang_getInclusions(TU, InclusionVisitor, NULL);
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00001188}
1189
1190/******************************************************************************/
Ted Kremenek83b28a22010-03-03 06:37:58 +00001191/* Linkage testing. */
1192/******************************************************************************/
1193
1194static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p,
1195 CXClientData d) {
1196 const char *linkage = 0;
1197
1198 if (clang_isInvalid(clang_getCursorKind(cursor)))
1199 return CXChildVisit_Recurse;
1200
1201 switch (clang_getCursorLinkage(cursor)) {
1202 case CXLinkage_Invalid: break;
Douglas Gregor0b466502010-03-04 19:36:27 +00001203 case CXLinkage_NoLinkage: linkage = "NoLinkage"; break;
1204 case CXLinkage_Internal: linkage = "Internal"; break;
1205 case CXLinkage_UniqueExternal: linkage = "UniqueExternal"; break;
1206 case CXLinkage_External: linkage = "External"; break;
Ted Kremenek83b28a22010-03-03 06:37:58 +00001207 }
1208
1209 if (linkage) {
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001210 PrintCursor(cursor, NULL);
Ted Kremenek83b28a22010-03-03 06:37:58 +00001211 printf("linkage=%s\n", linkage);
1212 }
1213
1214 return CXChildVisit_Recurse;
1215}
1216
1217/******************************************************************************/
Ted Kremenek6bca9842010-05-14 21:29:26 +00001218/* Typekind testing. */
1219/******************************************************************************/
1220
Dmitri Gribenko00353722013-02-15 21:15:49 +00001221static void PrintTypeAndTypeKind(CXType T, const char *Format) {
1222 CXString TypeSpelling, TypeKindSpelling;
1223
1224 TypeSpelling = clang_getTypeSpelling(T);
1225 TypeKindSpelling = clang_getTypeKindSpelling(T.kind);
1226 printf(Format,
1227 clang_getCString(TypeSpelling),
1228 clang_getCString(TypeKindSpelling));
1229 clang_disposeString(TypeSpelling);
1230 clang_disposeString(TypeKindSpelling);
1231}
1232
1233static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
1234 CXClientData d) {
Ted Kremenek6bca9842010-05-14 21:29:26 +00001235 if (!clang_isInvalid(clang_getCursorKind(cursor))) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001236 CXType T = clang_getCursorType(cursor);
Argyrios Kyrtzidisadff3ae2013-10-11 19:58:38 +00001237 enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001238 PrintCursor(cursor, NULL);
Dmitri Gribenko00353722013-02-15 21:15:49 +00001239 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
Douglas Gregor56a63802011-01-27 16:27:11 +00001240 if (clang_isConstQualifiedType(T))
1241 printf(" const");
1242 if (clang_isVolatileQualifiedType(T))
1243 printf(" volatile");
1244 if (clang_isRestrictQualifiedType(T))
1245 printf(" restrict");
Argyrios Kyrtzidisadff3ae2013-10-11 19:58:38 +00001246 if (RQ == CXRefQualifier_LValue)
1247 printf(" lvalue-ref-qualifier");
1248 if (RQ == CXRefQualifier_RValue)
1249 printf(" rvalue-ref-qualifier");
Benjamin Kramer1e63c742010-06-22 09:29:44 +00001250 /* Print the canonical type if it is different. */
Ted Kremenekc1508872010-06-21 20:15:39 +00001251 {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001252 CXType CT = clang_getCanonicalType(T);
Ted Kremenekc1508872010-06-21 20:15:39 +00001253 if (!clang_equalTypes(T, CT)) {
Dmitri Gribenko00353722013-02-15 21:15:49 +00001254 PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]");
Ted Kremenekc1508872010-06-21 20:15:39 +00001255 }
1256 }
Benjamin Kramer1e63c742010-06-22 09:29:44 +00001257 /* Print the return type if it exists. */
Ted Kremenekc1508872010-06-21 20:15:39 +00001258 {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001259 CXType RT = clang_getCursorResultType(cursor);
Ted Kremenekc1508872010-06-21 20:15:39 +00001260 if (RT.kind != CXType_Invalid) {
Dmitri Gribenko00353722013-02-15 21:15:49 +00001261 PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]");
Ted Kremenekc1508872010-06-21 20:15:39 +00001262 }
1263 }
Argyrios Kyrtzidis0c27e4b2012-04-11 19:32:19 +00001264 /* Print the argument types if they exist. */
1265 {
1266 int numArgs = clang_Cursor_getNumArguments(cursor);
1267 if (numArgs != -1 && numArgs != 0) {
Argyrios Kyrtzidis08804172012-04-11 19:54:09 +00001268 int i;
Argyrios Kyrtzidis0c27e4b2012-04-11 19:32:19 +00001269 printf(" [args=");
Argyrios Kyrtzidis08804172012-04-11 19:54:09 +00001270 for (i = 0; i < numArgs; ++i) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001271 CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i));
Argyrios Kyrtzidis0c27e4b2012-04-11 19:32:19 +00001272 if (T.kind != CXType_Invalid) {
Dmitri Gribenko00353722013-02-15 21:15:49 +00001273 PrintTypeAndTypeKind(T, " [%s] [%s]");
Argyrios Kyrtzidis0c27e4b2012-04-11 19:32:19 +00001274 }
1275 }
1276 printf("]");
1277 }
1278 }
Ted Kremenek0c7476a2010-07-30 00:14:11 +00001279 /* Print if this is a non-POD type. */
1280 printf(" [isPOD=%d]", clang_isPODType(T));
Ted Kremenekc1508872010-06-21 20:15:39 +00001281
Ted Kremenek6bca9842010-05-14 21:29:26 +00001282 printf("\n");
1283 }
1284 return CXChildVisit_Recurse;
1285}
1286
Argyrios Kyrtzidise822f582013-04-11 01:20:11 +00001287static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
1288 CXClientData d) {
1289 CXType T;
1290 enum CXCursorKind K = clang_getCursorKind(cursor);
1291 if (clang_isInvalid(K))
1292 return CXChildVisit_Recurse;
1293 T = clang_getCursorType(cursor);
1294 PrintCursor(cursor, NULL);
1295 PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
1296 /* Print the type sizeof if applicable. */
1297 {
1298 long long Size = clang_Type_getSizeOf(T);
1299 if (Size >= 0 || Size < -1 ) {
1300 printf(" [sizeof=%lld]", Size);
1301 }
1302 }
1303 /* Print the type alignof if applicable. */
1304 {
1305 long long Align = clang_Type_getAlignOf(T);
1306 if (Align >= 0 || Align < -1) {
1307 printf(" [alignof=%lld]", Align);
1308 }
1309 }
1310 /* Print the record field offset if applicable. */
1311 {
1312 const char *FieldName = clang_getCString(clang_getCursorSpelling(cursor));
1313 /* recurse to get the root anonymous record parent */
1314 CXCursor Parent, Root;
1315 if (clang_getCursorKind(cursor) == CXCursor_FieldDecl ) {
1316 const char *RootParentName;
1317 Root = Parent = p;
1318 do {
1319 Root = Parent;
1320 RootParentName = clang_getCString(clang_getCursorSpelling(Root));
1321 Parent = clang_getCursorSemanticParent(Root);
1322 } while ( clang_getCursorType(Parent).kind == CXType_Record &&
1323 !strcmp(RootParentName, "") );
1324 /* if RootParentName is "", record is anonymous. */
1325 {
1326 long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Root),
1327 FieldName);
1328 printf(" [offsetof=%lld]", Offset);
1329 }
1330 }
1331 }
1332 /* Print if its a bitfield */
1333 {
1334 int IsBitfield = clang_Cursor_isBitField(cursor);
1335 if (IsBitfield)
1336 printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
1337 }
1338 printf("\n");
1339 return CXChildVisit_Recurse;
1340}
1341
Dmitri Gribenkob506ba12012-12-04 15:13:46 +00001342/******************************************************************************/
1343/* Bitwidth testing. */
1344/******************************************************************************/
1345
1346static enum CXChildVisitResult PrintBitWidth(CXCursor cursor, CXCursor p,
1347 CXClientData d) {
NAKAMURA Takumidfaed1b2012-12-04 15:32:03 +00001348 int Bitwidth;
Dmitri Gribenkob506ba12012-12-04 15:13:46 +00001349 if (clang_getCursorKind(cursor) != CXCursor_FieldDecl)
1350 return CXChildVisit_Recurse;
1351
NAKAMURA Takumidfaed1b2012-12-04 15:32:03 +00001352 Bitwidth = clang_getFieldDeclBitWidth(cursor);
Dmitri Gribenkob506ba12012-12-04 15:13:46 +00001353 if (Bitwidth >= 0) {
1354 PrintCursor(cursor, NULL);
1355 printf(" bitwidth=%d\n", Bitwidth);
1356 }
1357
1358 return CXChildVisit_Recurse;
1359}
Ted Kremenek6bca9842010-05-14 21:29:26 +00001360
1361/******************************************************************************/
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00001362/* Loading ASTs/source. */
1363/******************************************************************************/
1364
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001365static int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
Ted Kremenek73eccd22010-01-12 18:53:15 +00001366 const char *filter, const char *prefix,
Ted Kremenekb478ff42010-01-26 17:59:48 +00001367 CXCursorVisitor Visitor,
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001368 PostVisitTU PV,
1369 const char *CommentSchemaFile) {
Ted Kremenek29004672010-02-17 00:41:32 +00001370
Ted Kremeneka44d99c2010-01-05 23:18:49 +00001371 if (prefix)
Ted Kremenek29004672010-02-17 00:41:32 +00001372 FileCheckPrefix = prefix;
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001373
1374 if (Visitor) {
1375 enum CXCursorKind K = CXCursor_NotImplemented;
1376 enum CXCursorKind *ck = &K;
1377 VisitorData Data;
Ted Kremenek29004672010-02-17 00:41:32 +00001378
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001379 /* Perform some simple filtering. */
1380 if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
Douglas Gregor97c75712010-10-02 22:49:11 +00001381 else if (!strcmp(filter, "all-display") ||
1382 !strcmp(filter, "local-display")) {
1383 ck = NULL;
1384 want_display_name = 1;
1385 }
Daniel Dunbard64ce7b2010-02-10 20:42:40 +00001386 else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0;
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001387 else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
1388 else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
1389 else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
1390 else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
1391 else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
1392 else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
1393 else {
1394 fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
1395 return 1;
1396 }
Ted Kremenek29004672010-02-17 00:41:32 +00001397
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001398 Data.TU = TU;
1399 Data.Filter = ck;
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001400 Data.ValidationData.CommentSchemaFile = CommentSchemaFile;
1401#ifdef CLANG_HAVE_LIBXML
1402 Data.ValidationData.RNGParser = NULL;
1403 Data.ValidationData.Schema = NULL;
1404#endif
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001405 clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
Ted Kremenek1cd27d52009-11-17 18:13:31 +00001406 }
Ted Kremenek29004672010-02-17 00:41:32 +00001407
Ted Kremenekb478ff42010-01-26 17:59:48 +00001408 if (PV)
1409 PV(TU);
Ted Kremeneka97a5cd2010-01-26 17:55:33 +00001410
Douglas Gregor33cdd812010-02-18 18:08:43 +00001411 PrintDiagnostics(TU);
Argyrios Kyrtzidis70480492011-11-13 23:39:14 +00001412 if (checkForErrors(TU) != 0) {
1413 clang_disposeTranslationUnit(TU);
1414 return -1;
1415 }
1416
Ted Kremenek1cd27d52009-11-17 18:13:31 +00001417 clang_disposeTranslationUnit(TU);
1418 return 0;
1419}
1420
Ted Kremeneka44d99c2010-01-05 23:18:49 +00001421int perform_test_load_tu(const char *file, const char *filter,
Ted Kremenekb478ff42010-01-26 17:59:48 +00001422 const char *prefix, CXCursorVisitor Visitor,
1423 PostVisitTU PV) {
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001424 CXIndex Idx;
1425 CXTranslationUnit TU;
Ted Kremenek50228be2010-02-11 07:41:25 +00001426 int result;
Ted Kremenek29004672010-02-17 00:41:32 +00001427 Idx = clang_createIndex(/* excludeDeclsFromPCH */
Douglas Gregor1e21cc72010-02-18 23:07:20 +00001428 !strcmp(filter, "local") ? 1 : 0,
Stefanus Du Toitb3318502013-03-01 21:41:22 +00001429 /* displayDiagnostics=*/1);
Ted Kremenek29004672010-02-17 00:41:32 +00001430
Ted Kremenek50228be2010-02-11 07:41:25 +00001431 if (!CreateTranslationUnit(Idx, file, &TU)) {
1432 clang_disposeIndex(Idx);
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001433 return 1;
Ted Kremenek50228be2010-02-11 07:41:25 +00001434 }
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001435
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001436 result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL);
Ted Kremenek50228be2010-02-11 07:41:25 +00001437 clang_disposeIndex(Idx);
1438 return result;
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00001439}
1440
Ted Kremenekb478ff42010-01-26 17:59:48 +00001441int perform_test_load_source(int argc, const char **argv,
1442 const char *filter, CXCursorVisitor Visitor,
1443 PostVisitTU PV) {
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001444 CXIndex Idx;
1445 CXTranslationUnit TU;
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001446 const char *CommentSchemaFile;
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001447 struct CXUnsavedFile *unsaved_files = 0;
1448 int num_unsaved_files = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001449 enum CXErrorCode Err;
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001450 int result;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001451
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001452 Idx = clang_createIndex(/* excludeDeclsFromPCH */
Douglas Gregor97c75712010-10-02 22:49:11 +00001453 (!strcmp(filter, "local") ||
1454 !strcmp(filter, "local-display"))? 1 : 0,
Argyrios Kyrtzidisbcc8a5a2013-04-09 20:29:24 +00001455 /* displayDiagnostics=*/1);
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001456
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001457 if ((CommentSchemaFile = parse_comments_schema(argc, argv))) {
1458 argc--;
1459 argv++;
1460 }
1461
Ted Kremenek50228be2010-02-11 07:41:25 +00001462 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1463 clang_disposeIndex(Idx);
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001464 return -1;
Ted Kremenek50228be2010-02-11 07:41:25 +00001465 }
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001466
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001467 Err = clang_parseTranslationUnit2(Idx, 0,
1468 argv + num_unsaved_files,
1469 argc - num_unsaved_files,
1470 unsaved_files, num_unsaved_files,
1471 getDefaultParsingOptions(), &TU);
1472 if (Err != CXError_Success) {
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001473 fprintf(stderr, "Unable to load translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001474 describeLibclangFailure(Err);
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001475 free_remapped_files(unsaved_files, num_unsaved_files);
Ted Kremenek50228be2010-02-11 07:41:25 +00001476 clang_disposeIndex(Idx);
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001477 return 1;
1478 }
1479
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001480 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV,
1481 CommentSchemaFile);
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001482 free_remapped_files(unsaved_files, num_unsaved_files);
Ted Kremenek50228be2010-02-11 07:41:25 +00001483 clang_disposeIndex(Idx);
Douglas Gregoraa98ed92010-01-23 00:14:00 +00001484 return result;
Daniel Dunbar3e535d72009-12-01 02:03:10 +00001485}
1486
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001487int perform_test_reparse_source(int argc, const char **argv, int trials,
1488 const char *filter, CXCursorVisitor Visitor,
1489 PostVisitTU PV) {
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001490 CXIndex Idx;
1491 CXTranslationUnit TU;
1492 struct CXUnsavedFile *unsaved_files = 0;
1493 int num_unsaved_files = 0;
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +00001494 int compiler_arg_idx = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001495 enum CXErrorCode Err;
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +00001496 int result, i;
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001497 int trial;
Argyrios Kyrtzidis3405baa2011-09-12 18:09:31 +00001498 int remap_after_trial = 0;
1499 char *endptr = 0;
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001500
1501 Idx = clang_createIndex(/* excludeDeclsFromPCH */
1502 !strcmp(filter, "local") ? 1 : 0,
Argyrios Kyrtzidisbcc8a5a2013-04-09 20:29:24 +00001503 /* displayDiagnostics=*/1);
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001504
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001505 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
1506 clang_disposeIndex(Idx);
1507 return -1;
1508 }
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +00001509
1510 for (i = 0; i < argc; ++i) {
1511 if (strcmp(argv[i], "--") == 0)
1512 break;
1513 }
1514 if (i < argc)
1515 compiler_arg_idx = i+1;
1516 if (num_unsaved_files > compiler_arg_idx)
1517 compiler_arg_idx = num_unsaved_files;
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001518
Daniel Dunbarec29d712010-08-18 23:09:16 +00001519 /* Load the initial translation unit -- we do this without honoring remapped
1520 * files, so that we have a way to test results after changing the source. */
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001521 Err = clang_parseTranslationUnit2(Idx, 0,
1522 argv + compiler_arg_idx,
1523 argc - compiler_arg_idx,
1524 0, 0, getDefaultParsingOptions(), &TU);
1525 if (Err != CXError_Success) {
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001526 fprintf(stderr, "Unable to load translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001527 describeLibclangFailure(Err);
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001528 free_remapped_files(unsaved_files, num_unsaved_files);
1529 clang_disposeIndex(Idx);
1530 return 1;
1531 }
1532
Argyrios Kyrtzidise74e8222011-11-13 22:08:33 +00001533 if (checkForErrors(TU) != 0)
1534 return -1;
1535
Argyrios Kyrtzidis3405baa2011-09-12 18:09:31 +00001536 if (getenv("CINDEXTEST_REMAP_AFTER_TRIAL")) {
1537 remap_after_trial =
1538 strtol(getenv("CINDEXTEST_REMAP_AFTER_TRIAL"), &endptr, 10);
1539 }
1540
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001541 for (trial = 0; trial < trials; ++trial) {
Argyrios Kyrtzidis011e6a52013-12-05 08:19:23 +00001542 free_remapped_files(unsaved_files, num_unsaved_files);
1543 if (parse_remapped_files_with_try(trial, argc, argv, 0,
1544 &unsaved_files, &num_unsaved_files)) {
1545 clang_disposeTranslationUnit(TU);
1546 clang_disposeIndex(Idx);
1547 return -1;
1548 }
1549
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001550 Err = clang_reparseTranslationUnit(
1551 TU,
1552 trial >= remap_after_trial ? num_unsaved_files : 0,
1553 trial >= remap_after_trial ? unsaved_files : 0,
1554 clang_defaultReparseOptions(TU));
1555 if (Err != CXError_Success) {
Daniel Dunbarec29d712010-08-18 23:09:16 +00001556 fprintf(stderr, "Unable to reparse translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001557 describeLibclangFailure(Err);
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001558 clang_disposeTranslationUnit(TU);
1559 free_remapped_files(unsaved_files, num_unsaved_files);
1560 clang_disposeIndex(Idx);
1561 return -1;
1562 }
Argyrios Kyrtzidise74e8222011-11-13 22:08:33 +00001563
1564 if (checkForErrors(TU) != 0)
1565 return -1;
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001566 }
1567
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001568 result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL);
Argyrios Kyrtzidise74e8222011-11-13 22:08:33 +00001569
Douglas Gregoraa21cc42010-07-19 21:46:24 +00001570 free_remapped_files(unsaved_files, num_unsaved_files);
1571 clang_disposeIndex(Idx);
1572 return result;
1573}
1574
Ted Kremenek1cd27d52009-11-17 18:13:31 +00001575/******************************************************************************/
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001576/* Logic for testing clang_getCursor(). */
1577/******************************************************************************/
1578
Douglas Gregor37aa4932011-05-04 00:14:37 +00001579static void print_cursor_file_scan(CXTranslationUnit TU, CXCursor cursor,
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001580 unsigned start_line, unsigned start_col,
Ted Kremenek0469b7e2009-11-18 02:02:52 +00001581 unsigned end_line, unsigned end_col,
1582 const char *prefix) {
Ted Kremenekb58514e2010-01-07 01:17:12 +00001583 printf("// %s: ", FileCheckPrefix);
Ted Kremenek0469b7e2009-11-18 02:02:52 +00001584 if (prefix)
1585 printf("-%s", prefix);
Daniel Dunbar98c07e02010-02-14 08:32:24 +00001586 PrintExtent(stdout, start_line, start_col, end_line, end_col);
1587 printf(" ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00001588 PrintCursor(cursor, NULL);
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001589 printf("\n");
1590}
1591
Ted Kremenek0469b7e2009-11-18 02:02:52 +00001592static int perform_file_scan(const char *ast_file, const char *source_file,
1593 const char *prefix) {
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001594 CXIndex Idx;
1595 CXTranslationUnit TU;
1596 FILE *fp;
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001597 CXCursor prevCursor = clang_getNullCursor();
Douglas Gregor816fd362010-01-22 21:44:22 +00001598 CXFile file;
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001599 unsigned line = 1, col = 1;
Daniel Dunbar6092d502010-02-14 08:32:51 +00001600 unsigned start_line = 1, start_col = 1;
Ted Kremenek29004672010-02-17 00:41:32 +00001601
Douglas Gregor1e21cc72010-02-18 23:07:20 +00001602 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
Stefanus Du Toitb3318502013-03-01 21:41:22 +00001603 /* displayDiagnostics=*/1))) {
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001604 fprintf(stderr, "Could not create Index\n");
1605 return 1;
1606 }
Ted Kremenek29004672010-02-17 00:41:32 +00001607
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001608 if (!CreateTranslationUnit(Idx, ast_file, &TU))
1609 return 1;
Ted Kremenek29004672010-02-17 00:41:32 +00001610
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001611 if ((fp = fopen(source_file, "r")) == NULL) {
1612 fprintf(stderr, "Could not open '%s'\n", source_file);
1613 return 1;
1614 }
Ted Kremenek29004672010-02-17 00:41:32 +00001615
Douglas Gregor816fd362010-01-22 21:44:22 +00001616 file = clang_getFile(TU, source_file);
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001617 for (;;) {
1618 CXCursor cursor;
1619 int c = fgetc(fp);
Benjamin Kramer10d083172009-11-17 20:51:40 +00001620
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001621 if (c == '\n') {
1622 ++line;
1623 col = 1;
1624 } else
1625 ++col;
1626
1627 /* Check the cursor at this position, and dump the previous one if we have
1628 * found something new.
1629 */
1630 cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, col));
1631 if ((c == EOF || !clang_equalCursors(cursor, prevCursor)) &&
1632 prevCursor.kind != CXCursor_InvalidFile) {
Douglas Gregor37aa4932011-05-04 00:14:37 +00001633 print_cursor_file_scan(TU, prevCursor, start_line, start_col,
Daniel Dunbar02968e52010-02-14 10:02:57 +00001634 line, col, prefix);
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001635 start_line = line;
1636 start_col = col;
Benjamin Kramer10d083172009-11-17 20:51:40 +00001637 }
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001638 if (c == EOF)
1639 break;
Benjamin Kramer10d083172009-11-17 20:51:40 +00001640
Daniel Dunbareb27e7d2010-02-14 08:32:32 +00001641 prevCursor = cursor;
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001642 }
Ted Kremenek29004672010-02-17 00:41:32 +00001643
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001644 fclose(fp);
Douglas Gregor7a964ad2011-01-31 22:04:05 +00001645 clang_disposeTranslationUnit(TU);
1646 clang_disposeIndex(Idx);
Ted Kremenek2df52dc2009-11-17 19:37:36 +00001647 return 0;
1648}
1649
1650/******************************************************************************/
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00001651/* Logic for testing clang code completion. */
Ted Kremenek1cd27d52009-11-17 18:13:31 +00001652/******************************************************************************/
1653
Douglas Gregor9eb77012009-11-07 00:00:49 +00001654/* Parse file:line:column from the input string. Returns 0 on success, non-zero
1655 on failure. If successful, the pointer *filename will contain newly-allocated
1656 memory (that will be owned by the caller) to store the file name. */
Ted Kremenek29004672010-02-17 00:41:32 +00001657int parse_file_line_column(const char *input, char **filename, unsigned *line,
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001658 unsigned *column, unsigned *second_line,
1659 unsigned *second_column) {
Douglas Gregorf96ea292009-11-09 18:19:57 +00001660 /* Find the second colon. */
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001661 const char *last_colon = strrchr(input, ':');
1662 unsigned values[4], i;
1663 unsigned num_values = (second_line && second_column)? 4 : 2;
1664
Douglas Gregor9eb77012009-11-07 00:00:49 +00001665 char *endptr = 0;
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001666 if (!last_colon || last_colon == input) {
1667 if (num_values == 4)
1668 fprintf(stderr, "could not parse filename:line:column:line:column in "
1669 "'%s'\n", input);
1670 else
1671 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
Douglas Gregor9eb77012009-11-07 00:00:49 +00001672 return 1;
1673 }
1674
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001675 for (i = 0; i != num_values; ++i) {
1676 const char *prev_colon;
1677
1678 /* Parse the next line or column. */
1679 values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
1680 if (*endptr != 0 && *endptr != ':') {
Ted Kremenek29004672010-02-17 00:41:32 +00001681 fprintf(stderr, "could not parse %s in '%s'\n",
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001682 (i % 2 ? "column" : "line"), input);
1683 return 1;
1684 }
Ted Kremenek29004672010-02-17 00:41:32 +00001685
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001686 if (i + 1 == num_values)
1687 break;
1688
1689 /* Find the previous colon. */
1690 prev_colon = last_colon - 1;
1691 while (prev_colon != input && *prev_colon != ':')
1692 --prev_colon;
1693 if (prev_colon == input) {
Ted Kremenek29004672010-02-17 00:41:32 +00001694 fprintf(stderr, "could not parse %s in '%s'\n",
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001695 (i % 2 == 0? "column" : "line"), input);
Ted Kremenek29004672010-02-17 00:41:32 +00001696 return 1;
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001697 }
1698
1699 last_colon = prev_colon;
Douglas Gregorf96ea292009-11-09 18:19:57 +00001700 }
1701
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001702 *line = values[0];
1703 *column = values[1];
Ted Kremenek29004672010-02-17 00:41:32 +00001704
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001705 if (second_line && second_column) {
1706 *second_line = values[2];
1707 *second_column = values[3];
1708 }
1709
Douglas Gregorf96ea292009-11-09 18:19:57 +00001710 /* Copy the file name. */
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001711 *filename = (char*)malloc(last_colon - input + 1);
1712 memcpy(*filename, input, last_colon - input);
1713 (*filename)[last_colon - input] = 0;
Douglas Gregor9eb77012009-11-07 00:00:49 +00001714 return 0;
1715}
1716
1717const char *
1718clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
1719 switch (Kind) {
1720 case CXCompletionChunk_Optional: return "Optional";
1721 case CXCompletionChunk_TypedText: return "TypedText";
1722 case CXCompletionChunk_Text: return "Text";
1723 case CXCompletionChunk_Placeholder: return "Placeholder";
1724 case CXCompletionChunk_Informative: return "Informative";
1725 case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
1726 case CXCompletionChunk_LeftParen: return "LeftParen";
1727 case CXCompletionChunk_RightParen: return "RightParen";
1728 case CXCompletionChunk_LeftBracket: return "LeftBracket";
1729 case CXCompletionChunk_RightBracket: return "RightBracket";
1730 case CXCompletionChunk_LeftBrace: return "LeftBrace";
1731 case CXCompletionChunk_RightBrace: return "RightBrace";
1732 case CXCompletionChunk_LeftAngle: return "LeftAngle";
1733 case CXCompletionChunk_RightAngle: return "RightAngle";
1734 case CXCompletionChunk_Comma: return "Comma";
Douglas Gregorb3fa9192009-12-18 18:53:37 +00001735 case CXCompletionChunk_ResultType: return "ResultType";
Douglas Gregor504a6ae2010-01-10 23:08:15 +00001736 case CXCompletionChunk_Colon: return "Colon";
1737 case CXCompletionChunk_SemiColon: return "SemiColon";
1738 case CXCompletionChunk_Equal: return "Equal";
1739 case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
1740 case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
Douglas Gregor9eb77012009-11-07 00:00:49 +00001741 }
Ted Kremenek29004672010-02-17 00:41:32 +00001742
Douglas Gregor9eb77012009-11-07 00:00:49 +00001743 return "Unknown";
1744}
1745
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00001746static int checkForErrors(CXTranslationUnit TU) {
1747 unsigned Num, i;
1748 CXDiagnostic Diag;
1749 CXString DiagStr;
1750
1751 if (!getenv("CINDEXTEST_FAILONERROR"))
1752 return 0;
1753
1754 Num = clang_getNumDiagnostics(TU);
1755 for (i = 0; i != Num; ++i) {
1756 Diag = clang_getDiagnostic(TU, i);
1757 if (clang_getDiagnosticSeverity(Diag) >= CXDiagnostic_Error) {
1758 DiagStr = clang_formatDiagnostic(Diag,
1759 clang_defaultDiagnosticDisplayOptions());
1760 fprintf(stderr, "%s\n", clang_getCString(DiagStr));
1761 clang_disposeString(DiagStr);
1762 clang_disposeDiagnostic(Diag);
1763 return -1;
1764 }
1765 clang_disposeDiagnostic(Diag);
1766 }
1767
1768 return 0;
1769}
1770
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001771void print_completion_string(CXCompletionString completion_string, FILE *file) {
Daniel Dunbar4ba3b292009-11-07 18:34:24 +00001772 int I, N;
Ted Kremenek29004672010-02-17 00:41:32 +00001773
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001774 N = clang_getNumCompletionChunks(completion_string);
Douglas Gregor9eb77012009-11-07 00:00:49 +00001775 for (I = 0; I != N; ++I) {
Ted Kremenekf602f962010-02-17 01:42:24 +00001776 CXString text;
1777 const char *cstr;
Douglas Gregor9eb77012009-11-07 00:00:49 +00001778 enum CXCompletionChunkKind Kind
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001779 = clang_getCompletionChunkKind(completion_string, I);
Ted Kremenek29004672010-02-17 00:41:32 +00001780
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001781 if (Kind == CXCompletionChunk_Optional) {
1782 fprintf(file, "{Optional ");
1783 print_completion_string(
Ted Kremenek29004672010-02-17 00:41:32 +00001784 clang_getCompletionChunkCompletionString(completion_string, I),
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001785 file);
1786 fprintf(file, "}");
1787 continue;
Douglas Gregor8ed5b772010-10-08 20:39:29 +00001788 }
1789
1790 if (Kind == CXCompletionChunk_VerticalSpace) {
1791 fprintf(file, "{VerticalSpace }");
1792 continue;
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001793 }
Ted Kremenek29004672010-02-17 00:41:32 +00001794
Douglas Gregorf81f5282009-11-09 17:05:28 +00001795 text = clang_getCompletionChunkText(completion_string, I);
Ted Kremenekf602f962010-02-17 01:42:24 +00001796 cstr = clang_getCString(text);
Ted Kremenek29004672010-02-17 00:41:32 +00001797 fprintf(file, "{%s %s}",
Douglas Gregor9eb77012009-11-07 00:00:49 +00001798 clang_getCompletionChunkKindSpelling(Kind),
Ted Kremenekf602f962010-02-17 01:42:24 +00001799 cstr ? cstr : "");
1800 clang_disposeString(text);
Douglas Gregor9eb77012009-11-07 00:00:49 +00001801 }
Ted Kremenekf602f962010-02-17 01:42:24 +00001802
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001803}
1804
1805void print_completion_result(CXCompletionResult *completion_result,
1806 CXClientData client_data) {
1807 FILE *file = (FILE *)client_data;
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001808 CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
Erik Verbruggen98ea7f62011-10-14 15:31:08 +00001809 unsigned annotationCount;
Douglas Gregor78254c82012-03-27 23:34:16 +00001810 enum CXCursorKind ParentKind;
1811 CXString ParentName;
Dmitri Gribenko3292d062012-07-02 17:35:10 +00001812 CXString BriefComment;
1813 const char *BriefCommentCString;
Douglas Gregor78254c82012-03-27 23:34:16 +00001814
Ted Kremenek29004672010-02-17 00:41:32 +00001815 fprintf(file, "%s:", clang_getCString(ks));
1816 clang_disposeString(ks);
1817
Douglas Gregor8b14f8f2009-11-09 16:04:45 +00001818 print_completion_string(completion_result->CompletionString, file);
Douglas Gregorf757a122010-08-23 23:00:57 +00001819 fprintf(file, " (%u)",
Douglas Gregora2db7932010-05-26 22:00:08 +00001820 clang_getCompletionPriority(completion_result->CompletionString));
Douglas Gregorf757a122010-08-23 23:00:57 +00001821 switch (clang_getCompletionAvailability(completion_result->CompletionString)){
1822 case CXAvailability_Available:
1823 break;
1824
1825 case CXAvailability_Deprecated:
1826 fprintf(file, " (deprecated)");
1827 break;
1828
1829 case CXAvailability_NotAvailable:
1830 fprintf(file, " (unavailable)");
1831 break;
Erik Verbruggen2e657ff2011-10-06 07:27:49 +00001832
1833 case CXAvailability_NotAccessible:
1834 fprintf(file, " (inaccessible)");
1835 break;
Douglas Gregorf757a122010-08-23 23:00:57 +00001836 }
Erik Verbruggen98ea7f62011-10-14 15:31:08 +00001837
1838 annotationCount = clang_getCompletionNumAnnotations(
1839 completion_result->CompletionString);
1840 if (annotationCount) {
1841 unsigned i;
1842 fprintf(file, " (");
1843 for (i = 0; i < annotationCount; ++i) {
1844 if (i != 0)
1845 fprintf(file, ", ");
1846 fprintf(file, "\"%s\"",
1847 clang_getCString(clang_getCompletionAnnotation(
1848 completion_result->CompletionString, i)));
1849 }
1850 fprintf(file, ")");
1851 }
1852
Douglas Gregor78254c82012-03-27 23:34:16 +00001853 if (!getenv("CINDEXTEST_NO_COMPLETION_PARENTS")) {
1854 ParentName = clang_getCompletionParent(completion_result->CompletionString,
1855 &ParentKind);
1856 if (ParentKind != CXCursor_NotImplemented) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00001857 CXString KindSpelling = clang_getCursorKindSpelling(ParentKind);
Douglas Gregor78254c82012-03-27 23:34:16 +00001858 fprintf(file, " (parent: %s '%s')",
1859 clang_getCString(KindSpelling),
1860 clang_getCString(ParentName));
1861 clang_disposeString(KindSpelling);
1862 }
1863 clang_disposeString(ParentName);
1864 }
Dmitri Gribenko3292d062012-07-02 17:35:10 +00001865
1866 BriefComment = clang_getCompletionBriefComment(
1867 completion_result->CompletionString);
1868 BriefCommentCString = clang_getCString(BriefComment);
1869 if (BriefCommentCString && *BriefCommentCString != '\0') {
1870 fprintf(file, "(brief comment: %s)", BriefCommentCString);
1871 }
1872 clang_disposeString(BriefComment);
Douglas Gregor78254c82012-03-27 23:34:16 +00001873
Douglas Gregorf757a122010-08-23 23:00:57 +00001874 fprintf(file, "\n");
Douglas Gregor9eb77012009-11-07 00:00:49 +00001875}
1876
Douglas Gregor21325842011-07-07 16:03:39 +00001877void print_completion_contexts(unsigned long long contexts, FILE *file) {
1878 fprintf(file, "Completion contexts:\n");
1879 if (contexts == CXCompletionContext_Unknown) {
1880 fprintf(file, "Unknown\n");
1881 }
1882 if (contexts & CXCompletionContext_AnyType) {
1883 fprintf(file, "Any type\n");
1884 }
1885 if (contexts & CXCompletionContext_AnyValue) {
1886 fprintf(file, "Any value\n");
1887 }
1888 if (contexts & CXCompletionContext_ObjCObjectValue) {
1889 fprintf(file, "Objective-C object value\n");
1890 }
1891 if (contexts & CXCompletionContext_ObjCSelectorValue) {
1892 fprintf(file, "Objective-C selector value\n");
1893 }
1894 if (contexts & CXCompletionContext_CXXClassTypeValue) {
1895 fprintf(file, "C++ class type value\n");
1896 }
1897 if (contexts & CXCompletionContext_DotMemberAccess) {
1898 fprintf(file, "Dot member access\n");
1899 }
1900 if (contexts & CXCompletionContext_ArrowMemberAccess) {
1901 fprintf(file, "Arrow member access\n");
1902 }
1903 if (contexts & CXCompletionContext_ObjCPropertyAccess) {
1904 fprintf(file, "Objective-C property access\n");
1905 }
1906 if (contexts & CXCompletionContext_EnumTag) {
1907 fprintf(file, "Enum tag\n");
1908 }
1909 if (contexts & CXCompletionContext_UnionTag) {
1910 fprintf(file, "Union tag\n");
1911 }
1912 if (contexts & CXCompletionContext_StructTag) {
1913 fprintf(file, "Struct tag\n");
1914 }
1915 if (contexts & CXCompletionContext_ClassTag) {
1916 fprintf(file, "Class name\n");
1917 }
1918 if (contexts & CXCompletionContext_Namespace) {
1919 fprintf(file, "Namespace or namespace alias\n");
1920 }
1921 if (contexts & CXCompletionContext_NestedNameSpecifier) {
1922 fprintf(file, "Nested name specifier\n");
1923 }
1924 if (contexts & CXCompletionContext_ObjCInterface) {
1925 fprintf(file, "Objective-C interface\n");
1926 }
1927 if (contexts & CXCompletionContext_ObjCProtocol) {
1928 fprintf(file, "Objective-C protocol\n");
1929 }
1930 if (contexts & CXCompletionContext_ObjCCategory) {
1931 fprintf(file, "Objective-C category\n");
1932 }
1933 if (contexts & CXCompletionContext_ObjCInstanceMessage) {
1934 fprintf(file, "Objective-C instance method\n");
1935 }
1936 if (contexts & CXCompletionContext_ObjCClassMessage) {
1937 fprintf(file, "Objective-C class method\n");
1938 }
1939 if (contexts & CXCompletionContext_ObjCSelectorName) {
1940 fprintf(file, "Objective-C selector name\n");
1941 }
1942 if (contexts & CXCompletionContext_MacroName) {
1943 fprintf(file, "Macro name\n");
1944 }
1945 if (contexts & CXCompletionContext_NaturalLanguage) {
1946 fprintf(file, "Natural language\n");
1947 }
1948}
1949
Douglas Gregor49f67ce2010-08-26 13:48:20 +00001950int my_stricmp(const char *s1, const char *s2) {
1951 while (*s1 && *s2) {
NAKAMURA Takumid3cc2202011-03-09 03:02:28 +00001952 int c1 = tolower((unsigned char)*s1), c2 = tolower((unsigned char)*s2);
Douglas Gregor49f67ce2010-08-26 13:48:20 +00001953 if (c1 < c2)
1954 return -1;
1955 else if (c1 > c2)
1956 return 1;
1957
1958 ++s1;
1959 ++s2;
1960 }
1961
1962 if (*s1)
1963 return 1;
1964 else if (*s2)
1965 return -1;
1966 return 0;
1967}
1968
Douglas Gregor47815d52010-07-12 18:38:41 +00001969int perform_code_completion(int argc, const char **argv, int timing_only) {
Douglas Gregor9eb77012009-11-07 00:00:49 +00001970 const char *input = argv[1];
1971 char *filename = 0;
1972 unsigned line;
1973 unsigned column;
Daniel Dunbar4ba3b292009-11-07 18:34:24 +00001974 CXIndex CIdx;
Ted Kremenekef3339b2009-11-17 18:09:14 +00001975 int errorCode;
Douglas Gregor9485bf92009-12-02 09:21:34 +00001976 struct CXUnsavedFile *unsaved_files = 0;
1977 int num_unsaved_files = 0;
Douglas Gregorf72b6ac2009-12-18 16:20:58 +00001978 CXCodeCompleteResults *results = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00001979 enum CXErrorCode Err;
1980 CXTranslationUnit TU;
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00001981 unsigned I, Repeats = 1;
1982 unsigned completionOptions = clang_defaultCodeCompleteOptions();
1983
1984 if (getenv("CINDEXTEST_CODE_COMPLETE_PATTERNS"))
1985 completionOptions |= CXCodeComplete_IncludeCodePatterns;
Dmitri Gribenko3292d062012-07-02 17:35:10 +00001986 if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS"))
1987 completionOptions |= CXCodeComplete_IncludeBriefComments;
Douglas Gregor028d3e42010-08-09 20:45:32 +00001988
Douglas Gregor47815d52010-07-12 18:38:41 +00001989 if (timing_only)
1990 input += strlen("-code-completion-timing=");
1991 else
1992 input += strlen("-code-completion-at=");
1993
Ted Kremenek29004672010-02-17 00:41:32 +00001994 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
Douglas Gregor27b4fa92010-01-26 17:06:03 +00001995 0, 0)))
Ted Kremenekef3339b2009-11-17 18:09:14 +00001996 return errorCode;
Douglas Gregor9eb77012009-11-07 00:00:49 +00001997
Douglas Gregor9485bf92009-12-02 09:21:34 +00001998 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
1999 return -1;
2000
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00002001 CIdx = clang_createIndex(0, 0);
2002
2003 if (getenv("CINDEXTEST_EDITING"))
2004 Repeats = 5;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002005
2006 Err = clang_parseTranslationUnit2(CIdx, 0,
2007 argv + num_unsaved_files + 2,
2008 argc - num_unsaved_files - 2,
2009 0, 0, getDefaultParsingOptions(), &TU);
2010 if (Err != CXError_Success) {
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00002011 fprintf(stderr, "Unable to load translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002012 describeLibclangFailure(Err);
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00002013 return 1;
2014 }
Douglas Gregorc6592922010-11-15 23:00:34 +00002015
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002016 Err = clang_reparseTranslationUnit(TU, 0, 0,
2017 clang_defaultReparseOptions(TU));
2018
2019 if (Err != CXError_Success) {
Douglas Gregorc6592922010-11-15 23:00:34 +00002020 fprintf(stderr, "Unable to reparse translation init!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002021 describeLibclangFailure(Err);
2022 clang_disposeTranslationUnit(TU);
Douglas Gregorc6592922010-11-15 23:00:34 +00002023 return 1;
2024 }
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002025
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00002026 for (I = 0; I != Repeats; ++I) {
2027 results = clang_codeCompleteAt(TU, filename, line, column,
2028 unsaved_files, num_unsaved_files,
2029 completionOptions);
2030 if (!results) {
2031 fprintf(stderr, "Unable to perform code completion!\n");
Daniel Dunbar186f7422010-08-19 23:44:06 +00002032 return 1;
2033 }
Douglas Gregor36e3b5c2010-10-11 21:37:58 +00002034 if (I != Repeats-1)
2035 clang_disposeCodeCompleteResults(results);
2036 }
Douglas Gregorba965fb2010-01-28 00:56:43 +00002037
Douglas Gregorf72b6ac2009-12-18 16:20:58 +00002038 if (results) {
Douglas Gregor63745d52011-07-21 01:05:26 +00002039 unsigned i, n = results->NumResults, containerIsIncomplete = 0;
Douglas Gregor21325842011-07-07 16:03:39 +00002040 unsigned long long contexts;
Douglas Gregor63745d52011-07-21 01:05:26 +00002041 enum CXCursorKind containerKind;
Douglas Gregorea777402011-07-26 15:24:30 +00002042 CXString objCSelector;
2043 const char *selectorString;
Douglas Gregor49f67ce2010-08-26 13:48:20 +00002044 if (!timing_only) {
2045 /* Sort the code-completion results based on the typed text. */
2046 clang_sortCodeCompletionResults(results->Results, results->NumResults);
2047
Douglas Gregor47815d52010-07-12 18:38:41 +00002048 for (i = 0; i != n; ++i)
2049 print_completion_result(results->Results + i, stdout);
Douglas Gregor49f67ce2010-08-26 13:48:20 +00002050 }
Douglas Gregor33cdd812010-02-18 18:08:43 +00002051 n = clang_codeCompleteGetNumDiagnostics(results);
2052 for (i = 0; i != n; ++i) {
2053 CXDiagnostic diag = clang_codeCompleteGetDiagnostic(results, i);
2054 PrintDiagnostic(diag);
2055 clang_disposeDiagnostic(diag);
2056 }
Douglas Gregor21325842011-07-07 16:03:39 +00002057
2058 contexts = clang_codeCompleteGetContexts(results);
2059 print_completion_contexts(contexts, stdout);
2060
Douglas Gregorea777402011-07-26 15:24:30 +00002061 containerKind = clang_codeCompleteGetContainerKind(results,
2062 &containerIsIncomplete);
Douglas Gregor63745d52011-07-21 01:05:26 +00002063
2064 if (containerKind != CXCursor_InvalidCode) {
2065 /* We have found a container */
2066 CXString containerUSR, containerKindSpelling;
2067 containerKindSpelling = clang_getCursorKindSpelling(containerKind);
2068 printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
2069 clang_disposeString(containerKindSpelling);
2070
2071 if (containerIsIncomplete) {
2072 printf("Container is incomplete\n");
2073 }
2074 else {
2075 printf("Container is complete\n");
2076 }
2077
2078 containerUSR = clang_codeCompleteGetContainerUSR(results);
2079 printf("Container USR: %s\n", clang_getCString(containerUSR));
2080 clang_disposeString(containerUSR);
2081 }
2082
Douglas Gregorea777402011-07-26 15:24:30 +00002083 objCSelector = clang_codeCompleteGetObjCSelector(results);
2084 selectorString = clang_getCString(objCSelector);
2085 if (selectorString && strlen(selectorString) > 0) {
2086 printf("Objective-C selector: %s\n", selectorString);
2087 }
2088 clang_disposeString(objCSelector);
2089
Douglas Gregorf72b6ac2009-12-18 16:20:58 +00002090 clang_disposeCodeCompleteResults(results);
2091 }
Douglas Gregor028d3e42010-08-09 20:45:32 +00002092 clang_disposeTranslationUnit(TU);
Douglas Gregor9eb77012009-11-07 00:00:49 +00002093 clang_disposeIndex(CIdx);
2094 free(filename);
Ted Kremenek29004672010-02-17 00:41:32 +00002095
Douglas Gregor9485bf92009-12-02 09:21:34 +00002096 free_remapped_files(unsaved_files, num_unsaved_files);
2097
Ted Kremenekef3339b2009-11-17 18:09:14 +00002098 return 0;
Douglas Gregor9eb77012009-11-07 00:00:49 +00002099}
2100
Douglas Gregor082c3e62010-01-15 19:40:17 +00002101typedef struct {
2102 char *filename;
2103 unsigned line;
2104 unsigned column;
2105} CursorSourceLocation;
2106
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002107static int inspect_cursor_at(int argc, const char **argv) {
Douglas Gregor082c3e62010-01-15 19:40:17 +00002108 CXIndex CIdx;
2109 int errorCode;
2110 struct CXUnsavedFile *unsaved_files = 0;
2111 int num_unsaved_files = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002112 enum CXErrorCode Err;
Douglas Gregor082c3e62010-01-15 19:40:17 +00002113 CXTranslationUnit TU;
2114 CXCursor Cursor;
2115 CursorSourceLocation *Locations = 0;
2116 unsigned NumLocations = 0, Loc;
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002117 unsigned Repeats = 1;
Douglas Gregorb42f34b2010-11-30 06:04:54 +00002118 unsigned I;
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002119
Ted Kremenek29004672010-02-17 00:41:32 +00002120 /* Count the number of locations. */
Douglas Gregor082c3e62010-01-15 19:40:17 +00002121 while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
2122 ++NumLocations;
Ted Kremenek29004672010-02-17 00:41:32 +00002123
Douglas Gregor082c3e62010-01-15 19:40:17 +00002124 /* Parse the locations. */
2125 assert(NumLocations > 0 && "Unable to count locations?");
2126 Locations = (CursorSourceLocation *)malloc(
2127 NumLocations * sizeof(CursorSourceLocation));
2128 for (Loc = 0; Loc < NumLocations; ++Loc) {
2129 const char *input = argv[Loc + 1] + strlen("-cursor-at=");
Ted Kremenek29004672010-02-17 00:41:32 +00002130 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2131 &Locations[Loc].line,
Douglas Gregor27b4fa92010-01-26 17:06:03 +00002132 &Locations[Loc].column, 0, 0)))
Douglas Gregor082c3e62010-01-15 19:40:17 +00002133 return errorCode;
2134 }
Ted Kremenek29004672010-02-17 00:41:32 +00002135
2136 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
Douglas Gregor082c3e62010-01-15 19:40:17 +00002137 &num_unsaved_files))
2138 return -1;
Ted Kremenek29004672010-02-17 00:41:32 +00002139
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002140 if (getenv("CINDEXTEST_EDITING"))
2141 Repeats = 5;
2142
2143 /* Parse the translation unit. When we're testing clang_getCursor() after
2144 reparsing, don't remap unsaved files until the second parse. */
2145 CIdx = clang_createIndex(1, 1);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002146 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2147 argv + num_unsaved_files + 1 + NumLocations,
2148 argc - num_unsaved_files - 2 - NumLocations,
2149 unsaved_files,
2150 Repeats > 1? 0 : num_unsaved_files,
2151 getDefaultParsingOptions(), &TU);
2152 if (Err != CXError_Success) {
Douglas Gregor082c3e62010-01-15 19:40:17 +00002153 fprintf(stderr, "unable to parse input\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002154 describeLibclangFailure(Err);
Douglas Gregor082c3e62010-01-15 19:40:17 +00002155 return -1;
2156 }
Ted Kremenek29004672010-02-17 00:41:32 +00002157
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002158 if (checkForErrors(TU) != 0)
2159 return -1;
2160
Douglas Gregorb42f34b2010-11-30 06:04:54 +00002161 for (I = 0; I != Repeats; ++I) {
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002162 if (Repeats > 1) {
2163 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2164 clang_defaultReparseOptions(TU));
2165 if (Err != CXError_Success) {
2166 describeLibclangFailure(Err);
2167 clang_disposeTranslationUnit(TU);
2168 return 1;
2169 }
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002170 }
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002171
2172 if (checkForErrors(TU) != 0)
2173 return -1;
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002174
2175 for (Loc = 0; Loc < NumLocations; ++Loc) {
2176 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2177 if (!file)
2178 continue;
Ted Kremenek29004672010-02-17 00:41:32 +00002179
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002180 Cursor = clang_getCursor(TU,
2181 clang_getLocation(TU, file, Locations[Loc].line,
2182 Locations[Loc].column));
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002183
2184 if (checkForErrors(TU) != 0)
2185 return -1;
2186
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002187 if (I + 1 == Repeats) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002188 CXCompletionString completionString = clang_getCursorCompletionString(
2189 Cursor);
2190 CXSourceLocation CursorLoc = clang_getCursorLocation(Cursor);
Argyrios Kyrtzidis7aa274f2012-03-30 00:19:05 +00002191 CXString Spelling;
2192 const char *cspell;
2193 unsigned line, column;
2194 clang_getSpellingLocation(CursorLoc, 0, &line, &column, 0);
2195 printf("%d:%d ", line, column);
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002196 PrintCursor(Cursor, NULL);
Argyrios Kyrtzidis7aa274f2012-03-30 00:19:05 +00002197 PrintCursorExtent(Cursor);
2198 Spelling = clang_getCursorSpelling(Cursor);
2199 cspell = clang_getCString(Spelling);
Argyrios Kyrtzidis191a6a82012-03-30 20:58:35 +00002200 if (cspell && strlen(cspell) != 0) {
2201 unsigned pieceIndex;
Argyrios Kyrtzidis191a6a82012-03-30 20:58:35 +00002202 printf(" Spelling=%s (", cspell);
2203 for (pieceIndex = 0; ; ++pieceIndex) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002204 CXSourceRange range =
2205 clang_Cursor_getSpellingNameRange(Cursor, pieceIndex, 0);
Argyrios Kyrtzidis191a6a82012-03-30 20:58:35 +00002206 if (clang_Range_isNull(range))
2207 break;
2208 PrintRange(range, 0);
2209 }
2210 printf(")");
2211 }
Argyrios Kyrtzidis7aa274f2012-03-30 00:19:05 +00002212 clang_disposeString(Spelling);
Argyrios Kyrtzidis210f29f2012-03-30 22:15:48 +00002213 if (clang_Cursor_getObjCSelectorIndex(Cursor) != -1)
2214 printf(" Selector index=%d",clang_Cursor_getObjCSelectorIndex(Cursor));
Argyrios Kyrtzidisb6df68212012-07-02 23:54:36 +00002215 if (clang_Cursor_isDynamicCall(Cursor))
2216 printf(" Dynamic-call");
Argyrios Kyrtzidisb26a24c2012-11-01 02:01:34 +00002217 if (Cursor.kind == CXCursor_ObjCMessageExpr) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002218 CXType T = clang_Cursor_getReceiverType(Cursor);
2219 CXString S = clang_getTypeKindSpelling(T.kind);
Argyrios Kyrtzidisb26a24c2012-11-01 02:01:34 +00002220 printf(" Receiver-type=%s", clang_getCString(S));
2221 clang_disposeString(S);
2222 }
Argyrios Kyrtzidisb6df68212012-07-02 23:54:36 +00002223
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002224 {
2225 CXModule mod = clang_Cursor_getModule(Cursor);
Argyrios Kyrtzidis12fdb9e2013-04-26 22:47:49 +00002226 CXFile astFile;
2227 CXString name, astFilename;
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002228 unsigned i, numHeaders;
2229 if (mod) {
Argyrios Kyrtzidis12fdb9e2013-04-26 22:47:49 +00002230 astFile = clang_Module_getASTFile(mod);
2231 astFilename = clang_getFileName(astFile);
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002232 name = clang_Module_getFullName(mod);
Argyrios Kyrtzidis3c5305c2013-03-13 21:13:43 +00002233 numHeaders = clang_Module_getNumTopLevelHeaders(TU, mod);
Argyrios Kyrtzidis12fdb9e2013-04-26 22:47:49 +00002234 printf(" ModuleName=%s (%s) Headers(%d):",
2235 clang_getCString(name), clang_getCString(astFilename),
2236 numHeaders);
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002237 clang_disposeString(name);
Argyrios Kyrtzidis12fdb9e2013-04-26 22:47:49 +00002238 clang_disposeString(astFilename);
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002239 for (i = 0; i < numHeaders; ++i) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002240 CXFile file = clang_Module_getTopLevelHeader(TU, mod, i);
2241 CXString filename = clang_getFileName(file);
Argyrios Kyrtzidis2b9b5bb2012-10-05 00:22:37 +00002242 printf("\n%s", clang_getCString(filename));
2243 clang_disposeString(filename);
2244 }
2245 }
2246 }
2247
Douglas Gregor3f35bb22011-08-04 20:04:59 +00002248 if (completionString != NULL) {
2249 printf("\nCompletion string: ");
2250 print_completion_string(completionString, stdout);
2251 }
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002252 printf("\n");
2253 free(Locations[Loc].filename);
2254 }
2255 }
Douglas Gregor082c3e62010-01-15 19:40:17 +00002256 }
Douglas Gregor2f6358b2010-11-30 05:52:55 +00002257
Douglas Gregor33cdd812010-02-18 18:08:43 +00002258 PrintDiagnostics(TU);
Douglas Gregor082c3e62010-01-15 19:40:17 +00002259 clang_disposeTranslationUnit(TU);
2260 clang_disposeIndex(CIdx);
2261 free(Locations);
2262 free_remapped_files(unsaved_files, num_unsaved_files);
2263 return 0;
2264}
2265
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002266static enum CXVisitorResult findFileRefsVisit(void *context,
2267 CXCursor cursor, CXSourceRange range) {
2268 if (clang_Range_isNull(range))
2269 return CXVisit_Continue;
2270
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002271 PrintCursor(cursor, NULL);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002272 PrintRange(range, "");
2273 printf("\n");
2274 return CXVisit_Continue;
2275}
2276
2277static int find_file_refs_at(int argc, const char **argv) {
2278 CXIndex CIdx;
2279 int errorCode;
2280 struct CXUnsavedFile *unsaved_files = 0;
2281 int num_unsaved_files = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002282 enum CXErrorCode Err;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002283 CXTranslationUnit TU;
2284 CXCursor Cursor;
2285 CursorSourceLocation *Locations = 0;
2286 unsigned NumLocations = 0, Loc;
2287 unsigned Repeats = 1;
2288 unsigned I;
2289
2290 /* Count the number of locations. */
2291 while (strstr(argv[NumLocations+1], "-file-refs-at=") == argv[NumLocations+1])
2292 ++NumLocations;
2293
2294 /* Parse the locations. */
2295 assert(NumLocations > 0 && "Unable to count locations?");
2296 Locations = (CursorSourceLocation *)malloc(
2297 NumLocations * sizeof(CursorSourceLocation));
2298 for (Loc = 0; Loc < NumLocations; ++Loc) {
2299 const char *input = argv[Loc + 1] + strlen("-file-refs-at=");
2300 if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
2301 &Locations[Loc].line,
2302 &Locations[Loc].column, 0, 0)))
2303 return errorCode;
2304 }
2305
2306 if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
2307 &num_unsaved_files))
2308 return -1;
2309
2310 if (getenv("CINDEXTEST_EDITING"))
2311 Repeats = 5;
2312
2313 /* Parse the translation unit. When we're testing clang_getCursor() after
2314 reparsing, don't remap unsaved files until the second parse. */
2315 CIdx = clang_createIndex(1, 1);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002316 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
2317 argv + num_unsaved_files + 1 + NumLocations,
2318 argc - num_unsaved_files - 2 - NumLocations,
2319 unsaved_files,
2320 Repeats > 1? 0 : num_unsaved_files,
2321 getDefaultParsingOptions(), &TU);
2322 if (Err != CXError_Success) {
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002323 fprintf(stderr, "unable to parse input\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002324 describeLibclangFailure(Err);
2325 clang_disposeTranslationUnit(TU);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002326 return -1;
2327 }
2328
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002329 if (checkForErrors(TU) != 0)
2330 return -1;
2331
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002332 for (I = 0; I != Repeats; ++I) {
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002333 if (Repeats > 1) {
2334 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2335 clang_defaultReparseOptions(TU));
2336 if (Err != CXError_Success) {
2337 describeLibclangFailure(Err);
2338 clang_disposeTranslationUnit(TU);
2339 return 1;
2340 }
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002341 }
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002342
2343 if (checkForErrors(TU) != 0)
2344 return -1;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002345
2346 for (Loc = 0; Loc < NumLocations; ++Loc) {
2347 CXFile file = clang_getFile(TU, Locations[Loc].filename);
2348 if (!file)
2349 continue;
2350
2351 Cursor = clang_getCursor(TU,
2352 clang_getLocation(TU, file, Locations[Loc].line,
2353 Locations[Loc].column));
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002354
2355 if (checkForErrors(TU) != 0)
2356 return -1;
2357
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002358 if (I + 1 == Repeats) {
Erik Verbruggen338b55c2011-10-06 11:38:08 +00002359 CXCursorAndRangeVisitor visitor = { 0, findFileRefsVisit };
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002360 PrintCursor(Cursor, NULL);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002361 printf("\n");
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002362 clang_findReferencesInFile(Cursor, file, visitor);
2363 free(Locations[Loc].filename);
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002364
2365 if (checkForErrors(TU) != 0)
2366 return -1;
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00002367 }
2368 }
2369 }
2370
2371 PrintDiagnostics(TU);
2372 clang_disposeTranslationUnit(TU);
2373 clang_disposeIndex(CIdx);
2374 free(Locations);
2375 free_remapped_files(unsaved_files, num_unsaved_files);
2376 return 0;
2377}
2378
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002379static enum CXVisitorResult findFileIncludesVisit(void *context,
2380 CXCursor cursor, CXSourceRange range) {
2381 PrintCursor(cursor, NULL);
2382 PrintRange(range, "");
2383 printf("\n");
2384 return CXVisit_Continue;
2385}
2386
2387static int find_file_includes_in(int argc, const char **argv) {
2388 CXIndex CIdx;
2389 struct CXUnsavedFile *unsaved_files = 0;
2390 int num_unsaved_files = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002391 enum CXErrorCode Err;
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002392 CXTranslationUnit TU;
2393 const char **Filenames = 0;
2394 unsigned NumFilenames = 0;
2395 unsigned Repeats = 1;
2396 unsigned I, FI;
2397
2398 /* Count the number of locations. */
2399 while (strstr(argv[NumFilenames+1], "-file-includes-in=") == argv[NumFilenames+1])
2400 ++NumFilenames;
2401
2402 /* Parse the locations. */
2403 assert(NumFilenames > 0 && "Unable to count filenames?");
2404 Filenames = (const char **)malloc(NumFilenames * sizeof(const char *));
2405 for (I = 0; I < NumFilenames; ++I) {
2406 const char *input = argv[I + 1] + strlen("-file-includes-in=");
2407 /* Copy the file name. */
2408 Filenames[I] = input;
2409 }
2410
2411 if (parse_remapped_files(argc, argv, NumFilenames + 1, &unsaved_files,
2412 &num_unsaved_files))
2413 return -1;
2414
2415 if (getenv("CINDEXTEST_EDITING"))
2416 Repeats = 2;
2417
2418 /* Parse the translation unit. When we're testing clang_getCursor() after
2419 reparsing, don't remap unsaved files until the second parse. */
2420 CIdx = clang_createIndex(1, 1);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002421 Err = clang_parseTranslationUnit2(
2422 CIdx, argv[argc - 1],
2423 argv + num_unsaved_files + 1 + NumFilenames,
2424 argc - num_unsaved_files - 2 - NumFilenames,
2425 unsaved_files,
2426 Repeats > 1 ? 0 : num_unsaved_files, getDefaultParsingOptions(), &TU);
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002427
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002428 if (Err != CXError_Success) {
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002429 fprintf(stderr, "unable to parse input\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002430 describeLibclangFailure(Err);
2431 clang_disposeTranslationUnit(TU);
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002432 return -1;
2433 }
2434
2435 if (checkForErrors(TU) != 0)
2436 return -1;
2437
2438 for (I = 0; I != Repeats; ++I) {
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002439 if (Repeats > 1) {
2440 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
2441 clang_defaultReparseOptions(TU));
2442 if (Err != CXError_Success) {
2443 describeLibclangFailure(Err);
2444 clang_disposeTranslationUnit(TU);
2445 return 1;
2446 }
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002447 }
2448
2449 if (checkForErrors(TU) != 0)
2450 return -1;
2451
2452 for (FI = 0; FI < NumFilenames; ++FI) {
2453 CXFile file = clang_getFile(TU, Filenames[FI]);
2454 if (!file)
2455 continue;
2456
2457 if (checkForErrors(TU) != 0)
2458 return -1;
2459
2460 if (I + 1 == Repeats) {
2461 CXCursorAndRangeVisitor visitor = { 0, findFileIncludesVisit };
2462 clang_findIncludesInFile(TU, file, visitor);
2463
2464 if (checkForErrors(TU) != 0)
2465 return -1;
2466 }
2467 }
2468 }
2469
2470 PrintDiagnostics(TU);
2471 clang_disposeTranslationUnit(TU);
2472 clang_disposeIndex(CIdx);
Argyrios Kyrtzidis1b5b1ce2013-03-11 16:03:17 +00002473 free((void *)Filenames);
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00002474 free_remapped_files(unsaved_files, num_unsaved_files);
2475 return 0;
2476}
2477
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00002478#define MAX_IMPORTED_ASTFILES 200
2479
2480typedef struct {
2481 char **filenames;
2482 unsigned num_files;
2483} ImportedASTFilesData;
2484
2485static ImportedASTFilesData *importedASTs_create() {
2486 ImportedASTFilesData *p;
2487 p = malloc(sizeof(ImportedASTFilesData));
2488 p->filenames = malloc(MAX_IMPORTED_ASTFILES * sizeof(const char *));
2489 p->num_files = 0;
2490 return p;
2491}
2492
2493static void importedASTs_dispose(ImportedASTFilesData *p) {
2494 unsigned i;
2495 if (!p)
2496 return;
2497
2498 for (i = 0; i < p->num_files; ++i)
2499 free(p->filenames[i]);
2500 free(p->filenames);
2501 free(p);
2502}
2503
2504static void importedASTS_insert(ImportedASTFilesData *p, const char *file) {
2505 unsigned i;
2506 assert(p && file);
2507 for (i = 0; i < p->num_files; ++i)
2508 if (strcmp(file, p->filenames[i]) == 0)
2509 return;
2510 assert(p->num_files + 1 < MAX_IMPORTED_ASTFILES);
2511 p->filenames[p->num_files++] = strdup(file);
2512}
2513
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002514typedef struct {
2515 const char *check_prefix;
2516 int first_check_printed;
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002517 int fail_for_error;
Argyrios Kyrtzidisb11f5a42011-11-28 04:56:00 +00002518 int abort;
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002519 const char *main_filename;
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00002520 ImportedASTFilesData *importedASTs;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002521} IndexData;
2522
2523static void printCheck(IndexData *data) {
2524 if (data->check_prefix) {
2525 if (data->first_check_printed) {
2526 printf("// %s-NEXT: ", data->check_prefix);
2527 } else {
2528 printf("// %s : ", data->check_prefix);
2529 data->first_check_printed = 1;
2530 }
2531 }
2532}
2533
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002534static void printCXIndexFile(CXIdxClientFile file) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002535 CXString filename = clang_getFileName((CXFile)file);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002536 printf("%s", clang_getCString(filename));
2537 clang_disposeString(filename);
2538}
2539
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002540static void printCXIndexLoc(CXIdxLoc loc, CXClientData client_data) {
2541 IndexData *index_data;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002542 CXString filename;
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002543 const char *cname;
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002544 CXIdxClientFile file;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002545 unsigned line, column;
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002546 int isMainFile;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002547
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002548 index_data = (IndexData *)client_data;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002549 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
2550 if (line == 0) {
Argyrios Kyrtzidis9f571862012-10-11 19:00:44 +00002551 printf("<invalid>");
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002552 return;
2553 }
Argyrios Kyrtzidisccdf8272011-12-13 18:47:35 +00002554 if (!file) {
2555 printf("<no idxfile>");
2556 return;
2557 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002558 filename = clang_getFileName((CXFile)file);
2559 cname = clang_getCString(filename);
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002560 if (strcmp(cname, index_data->main_filename) == 0)
2561 isMainFile = 1;
2562 else
2563 isMainFile = 0;
2564 clang_disposeString(filename);
2565
2566 if (!isMainFile) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002567 printCXIndexFile(file);
2568 printf(":");
2569 }
2570 printf("%d:%d", line, column);
2571}
2572
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002573static unsigned digitCount(unsigned val) {
2574 unsigned c = 1;
2575 while (1) {
2576 if (val < 10)
2577 return c;
2578 ++c;
2579 val /= 10;
2580 }
2581}
2582
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002583static CXIdxClientContainer makeClientContainer(const CXIdxEntityInfo *info,
2584 CXIdxLoc loc) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002585 const char *name;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002586 char *newStr;
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002587 CXIdxClientFile file;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002588 unsigned line, column;
2589
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002590 name = info->name;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002591 if (!name)
2592 name = "<anon-tag>";
2593
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002594 clang_indexLoc_getFileLocation(loc, &file, 0, &line, &column, 0);
Argyrios Kyrtzidis90068072011-10-20 17:21:46 +00002595 /* FIXME: free these.*/
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002596 newStr = (char *)malloc(strlen(name) +
2597 digitCount(line) + digitCount(column) + 3);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002598 sprintf(newStr, "%s:%d:%d", name, line, column);
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002599 return (CXIdxClientContainer)newStr;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002600}
2601
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002602static void printCXIndexContainer(const CXIdxContainerInfo *info) {
2603 CXIdxClientContainer container;
2604 container = clang_index_getClientContainer(info);
Argyrios Kyrtzidisdf15c202011-11-16 02:35:05 +00002605 if (!container)
2606 printf("[<<NULL>>]");
2607 else
2608 printf("[%s]", (const char *)container);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002609}
2610
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002611static const char *getEntityKindString(CXIdxEntityKind kind) {
2612 switch (kind) {
2613 case CXIdxEntity_Unexposed: return "<<UNEXPOSED>>";
2614 case CXIdxEntity_Typedef: return "typedef";
2615 case CXIdxEntity_Function: return "function";
2616 case CXIdxEntity_Variable: return "variable";
2617 case CXIdxEntity_Field: return "field";
2618 case CXIdxEntity_EnumConstant: return "enumerator";
2619 case CXIdxEntity_ObjCClass: return "objc-class";
2620 case CXIdxEntity_ObjCProtocol: return "objc-protocol";
2621 case CXIdxEntity_ObjCCategory: return "objc-category";
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002622 case CXIdxEntity_ObjCInstanceMethod: return "objc-instance-method";
2623 case CXIdxEntity_ObjCClassMethod: return "objc-class-method";
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002624 case CXIdxEntity_ObjCProperty: return "objc-property";
2625 case CXIdxEntity_ObjCIvar: return "objc-ivar";
2626 case CXIdxEntity_Enum: return "enum";
2627 case CXIdxEntity_Struct: return "struct";
2628 case CXIdxEntity_Union: return "union";
2629 case CXIdxEntity_CXXClass: return "c++-class";
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002630 case CXIdxEntity_CXXNamespace: return "namespace";
2631 case CXIdxEntity_CXXNamespaceAlias: return "namespace-alias";
2632 case CXIdxEntity_CXXStaticVariable: return "c++-static-var";
2633 case CXIdxEntity_CXXStaticMethod: return "c++-static-method";
2634 case CXIdxEntity_CXXInstanceMethod: return "c++-instance-method";
2635 case CXIdxEntity_CXXConstructor: return "constructor";
2636 case CXIdxEntity_CXXDestructor: return "destructor";
2637 case CXIdxEntity_CXXConversionFunction: return "conversion-func";
2638 case CXIdxEntity_CXXTypeAlias: return "type-alias";
David Blaikiedcefd952012-08-31 21:55:26 +00002639 case CXIdxEntity_CXXInterface: return "c++-__interface";
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002640 }
2641 assert(0 && "Garbage entity kind");
2642 return 0;
2643}
2644
2645static const char *getEntityTemplateKindString(CXIdxEntityCXXTemplateKind kind) {
2646 switch (kind) {
2647 case CXIdxEntity_NonTemplate: return "";
2648 case CXIdxEntity_Template: return "-template";
2649 case CXIdxEntity_TemplatePartialSpecialization:
2650 return "-template-partial-spec";
2651 case CXIdxEntity_TemplateSpecialization: return "-template-spec";
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002652 }
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002653 assert(0 && "Garbage entity kind");
2654 return 0;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002655}
2656
Argyrios Kyrtzidis52002882011-12-07 20:44:12 +00002657static const char *getEntityLanguageString(CXIdxEntityLanguage kind) {
2658 switch (kind) {
2659 case CXIdxEntityLang_None: return "<none>";
2660 case CXIdxEntityLang_C: return "C";
2661 case CXIdxEntityLang_ObjC: return "ObjC";
2662 case CXIdxEntityLang_CXX: return "C++";
2663 }
2664 assert(0 && "Garbage language kind");
2665 return 0;
2666}
2667
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002668static void printEntityInfo(const char *cb,
2669 CXClientData client_data,
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002670 const CXIdxEntityInfo *info) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002671 const char *name;
2672 IndexData *index_data;
Argyrios Kyrtzidis4d873b72011-12-15 00:05:00 +00002673 unsigned i;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002674 index_data = (IndexData *)client_data;
2675 printCheck(index_data);
2676
Argyrios Kyrtzidise4acd232011-11-16 02:34:59 +00002677 if (!info) {
2678 printf("%s: <<NULL>>", cb);
2679 return;
2680 }
2681
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002682 name = info->name;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002683 if (!name)
2684 name = "<anon-tag>";
2685
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002686 printf("%s: kind: %s%s", cb, getEntityKindString(info->kind),
2687 getEntityTemplateKindString(info->templateKind));
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002688 printf(" | name: %s", name);
2689 printf(" | USR: %s", info->USR);
Argyrios Kyrtzidisccdf8272011-12-13 18:47:35 +00002690 printf(" | lang: %s", getEntityLanguageString(info->lang));
Argyrios Kyrtzidis4d873b72011-12-15 00:05:00 +00002691
2692 for (i = 0; i != info->numAttributes; ++i) {
2693 const CXIdxAttrInfo *Attr = info->attributes[i];
2694 printf(" <attribute>: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002695 PrintCursor(Attr->cursor, NULL);
Argyrios Kyrtzidis4d873b72011-12-15 00:05:00 +00002696 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002697}
2698
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002699static void printBaseClassInfo(CXClientData client_data,
2700 const CXIdxBaseClassInfo *info) {
2701 printEntityInfo(" <base>", client_data, info->base);
2702 printf(" | cursor: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002703 PrintCursor(info->cursor, NULL);
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002704 printf(" | loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002705 printCXIndexLoc(info->loc, client_data);
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002706}
2707
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002708static void printProtocolList(const CXIdxObjCProtocolRefListInfo *ProtoInfo,
2709 CXClientData client_data) {
2710 unsigned i;
2711 for (i = 0; i < ProtoInfo->numProtocols; ++i) {
2712 printEntityInfo(" <protocol>", client_data,
2713 ProtoInfo->protocols[i]->protocol);
2714 printf(" | cursor: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002715 PrintCursor(ProtoInfo->protocols[i]->cursor, NULL);
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002716 printf(" | loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002717 printCXIndexLoc(ProtoInfo->protocols[i]->loc, client_data);
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002718 printf("\n");
2719 }
2720}
2721
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002722static void index_diagnostic(CXClientData client_data,
Argyrios Kyrtzidisf2d99b02011-12-01 02:42:50 +00002723 CXDiagnosticSet diagSet, void *reserved) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002724 CXString str;
2725 const char *cstr;
Argyrios Kyrtzidisf2d99b02011-12-01 02:42:50 +00002726 unsigned numDiags, i;
2727 CXDiagnostic diag;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002728 IndexData *index_data;
2729 index_data = (IndexData *)client_data;
2730 printCheck(index_data);
2731
Argyrios Kyrtzidisf2d99b02011-12-01 02:42:50 +00002732 numDiags = clang_getNumDiagnosticsInSet(diagSet);
2733 for (i = 0; i != numDiags; ++i) {
2734 diag = clang_getDiagnosticInSet(diagSet, i);
2735 str = clang_formatDiagnostic(diag, clang_defaultDiagnosticDisplayOptions());
2736 cstr = clang_getCString(str);
2737 printf("[diagnostic]: %s\n", cstr);
2738 clang_disposeString(str);
2739
2740 if (getenv("CINDEXTEST_FAILONERROR") &&
2741 clang_getDiagnosticSeverity(diag) >= CXDiagnostic_Error) {
2742 index_data->fail_for_error = 1;
2743 }
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00002744 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002745}
2746
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002747static CXIdxClientFile index_enteredMainFile(CXClientData client_data,
2748 CXFile file, void *reserved) {
2749 IndexData *index_data;
Argyrios Kyrtzidisa15f8162012-03-15 18:48:52 +00002750 CXString filename;
2751
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002752 index_data = (IndexData *)client_data;
2753 printCheck(index_data);
2754
Argyrios Kyrtzidisa15f8162012-03-15 18:48:52 +00002755 filename = clang_getFileName(file);
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002756 index_data->main_filename = clang_getCString(filename);
2757 clang_disposeString(filename);
2758
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002759 printf("[enteredMainFile]: ");
2760 printCXIndexFile((CXIdxClientFile)file);
2761 printf("\n");
2762
2763 return (CXIdxClientFile)file;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002764}
2765
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002766static CXIdxClientFile index_ppIncludedFile(CXClientData client_data,
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002767 const CXIdxIncludedFileInfo *info) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002768 IndexData *index_data;
2769 index_data = (IndexData *)client_data;
2770 printCheck(index_data);
2771
Argyrios Kyrtzidis8c258042011-11-05 04:03:35 +00002772 printf("[ppIncludedFile]: ");
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002773 printCXIndexFile((CXIdxClientFile)info->file);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002774 printf(" | name: \"%s\"", info->filename);
2775 printf(" | hash loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002776 printCXIndexLoc(info->hashLoc, client_data);
Argyrios Kyrtzidis5e2ec482012-10-18 00:17:05 +00002777 printf(" | isImport: %d | isAngled: %d | isModule: %d\n",
2778 info->isImport, info->isAngled, info->isModuleImport);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002779
2780 return (CXIdxClientFile)info->file;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002781}
2782
Argyrios Kyrtzidis472eda02012-10-02 16:10:38 +00002783static CXIdxClientFile index_importedASTFile(CXClientData client_data,
2784 const CXIdxImportedASTFileInfo *info) {
2785 IndexData *index_data;
2786 index_data = (IndexData *)client_data;
2787 printCheck(index_data);
2788
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00002789 if (index_data->importedASTs) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002790 CXString filename = clang_getFileName(info->file);
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00002791 importedASTS_insert(index_data->importedASTs, clang_getCString(filename));
2792 clang_disposeString(filename);
2793 }
2794
Argyrios Kyrtzidis472eda02012-10-02 16:10:38 +00002795 printf("[importedASTFile]: ");
2796 printCXIndexFile((CXIdxClientFile)info->file);
Argyrios Kyrtzidisdc78f3e2012-10-05 00:22:40 +00002797 if (info->module) {
Enea Zaffanella476f38a2013-07-22 20:58:30 +00002798 CXString name = clang_Module_getFullName(info->module);
Argyrios Kyrtzidisdc78f3e2012-10-05 00:22:40 +00002799 printf(" | loc: ");
2800 printCXIndexLoc(info->loc, client_data);
2801 printf(" | name: \"%s\"", clang_getCString(name));
2802 printf(" | isImplicit: %d\n", info->isImplicit);
2803 clang_disposeString(name);
Argyrios Kyrtzidis0db720f2012-10-11 16:05:00 +00002804 } else {
NAKAMURA Takumie259d912012-10-12 14:25:52 +00002805 /* PCH file, the rest are not relevant. */
Argyrios Kyrtzidis0db720f2012-10-11 16:05:00 +00002806 printf("\n");
Argyrios Kyrtzidisdc78f3e2012-10-05 00:22:40 +00002807 }
Argyrios Kyrtzidis472eda02012-10-02 16:10:38 +00002808
2809 return (CXIdxClientFile)info->file;
2810}
2811
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002812static CXIdxClientContainer index_startedTranslationUnit(CXClientData client_data,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002813 void *reserved) {
2814 IndexData *index_data;
2815 index_data = (IndexData *)client_data;
2816 printCheck(index_data);
2817
Argyrios Kyrtzidis8c258042011-11-05 04:03:35 +00002818 printf("[startedTranslationUnit]\n");
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002819 return (CXIdxClientContainer)"TU";
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002820}
2821
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002822static void index_indexDeclaration(CXClientData client_data,
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002823 const CXIdxDeclInfo *info) {
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002824 IndexData *index_data;
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002825 const CXIdxObjCCategoryDeclInfo *CatInfo;
2826 const CXIdxObjCInterfaceDeclInfo *InterInfo;
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002827 const CXIdxObjCProtocolRefListInfo *ProtoInfo;
Argyrios Kyrtzidis93db2922012-02-28 17:50:33 +00002828 const CXIdxObjCPropertyDeclInfo *PropInfo;
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002829 const CXIdxCXXClassDeclInfo *CXXClassInfo;
Argyrios Kyrtzidiseffdbf52011-11-18 00:26:51 +00002830 unsigned i;
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002831 index_data = (IndexData *)client_data;
2832
2833 printEntityInfo("[indexDeclaration]", client_data, info->entityInfo);
2834 printf(" | cursor: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002835 PrintCursor(info->cursor, NULL);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002836 printf(" | loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002837 printCXIndexLoc(info->loc, client_data);
Argyrios Kyrtzidis663c8ec2011-12-07 20:44:19 +00002838 printf(" | semantic-container: ");
2839 printCXIndexContainer(info->semanticContainer);
2840 printf(" | lexical-container: ");
2841 printCXIndexContainer(info->lexicalContainer);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002842 printf(" | isRedecl: %d", info->isRedeclaration);
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002843 printf(" | isDef: %d", info->isDefinition);
Argyrios Kyrtzidis8b71bc72012-12-06 19:41:16 +00002844 if (info->flags & CXIdxDeclFlag_Skipped) {
2845 assert(!info->isContainer);
2846 printf(" | isContainer: skipped");
2847 } else {
2848 printf(" | isContainer: %d", info->isContainer);
2849 }
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002850 printf(" | isImplicit: %d\n", info->isImplicit);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002851
Argyrios Kyrtzidiseffdbf52011-11-18 00:26:51 +00002852 for (i = 0; i != info->numAttributes; ++i) {
NAKAMURA Takumi2a4859a2011-11-18 00:51:03 +00002853 const CXIdxAttrInfo *Attr = info->attributes[i];
Argyrios Kyrtzidiseffdbf52011-11-18 00:26:51 +00002854 printf(" <attribute>: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002855 PrintCursor(Attr->cursor, NULL);
Argyrios Kyrtzidiseffdbf52011-11-18 00:26:51 +00002856 printf("\n");
2857 }
2858
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002859 if (clang_index_isEntityObjCContainerKind(info->entityInfo->kind)) {
2860 const char *kindName = 0;
2861 CXIdxObjCContainerKind K = clang_index_getObjCContainerDeclInfo(info)->kind;
2862 switch (K) {
2863 case CXIdxObjCContainer_ForwardRef:
2864 kindName = "forward-ref"; break;
2865 case CXIdxObjCContainer_Interface:
2866 kindName = "interface"; break;
2867 case CXIdxObjCContainer_Implementation:
2868 kindName = "implementation"; break;
2869 }
2870 printCheck(index_data);
2871 printf(" <ObjCContainerInfo>: kind: %s\n", kindName);
2872 }
2873
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002874 if ((CatInfo = clang_index_getObjCCategoryDeclInfo(info))) {
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002875 printEntityInfo(" <ObjCCategoryInfo>: class", client_data,
2876 CatInfo->objcClass);
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00002877 printf(" | cursor: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002878 PrintCursor(CatInfo->classCursor, NULL);
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00002879 printf(" | loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002880 printCXIndexLoc(CatInfo->classLoc, client_data);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002881 printf("\n");
2882 }
2883
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002884 if ((InterInfo = clang_index_getObjCInterfaceDeclInfo(info))) {
2885 if (InterInfo->superInfo) {
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002886 printBaseClassInfo(client_data, InterInfo->superInfo);
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002887 printf("\n");
2888 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002889 }
2890
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002891 if ((ProtoInfo = clang_index_getObjCProtocolRefListInfo(info))) {
2892 printProtocolList(ProtoInfo, client_data);
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002893 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002894
Argyrios Kyrtzidis93db2922012-02-28 17:50:33 +00002895 if ((PropInfo = clang_index_getObjCPropertyDeclInfo(info))) {
2896 if (PropInfo->getter) {
2897 printEntityInfo(" <getter>", client_data, PropInfo->getter);
2898 printf("\n");
2899 }
2900 if (PropInfo->setter) {
2901 printEntityInfo(" <setter>", client_data, PropInfo->setter);
2902 printf("\n");
2903 }
2904 }
2905
Argyrios Kyrtzidisb3c16ba2011-12-07 20:44:15 +00002906 if ((CXXClassInfo = clang_index_getCXXClassDeclInfo(info))) {
2907 for (i = 0; i != CXXClassInfo->numBases; ++i) {
2908 printBaseClassInfo(client_data, CXXClassInfo->bases[i]);
2909 printf("\n");
2910 }
2911 }
2912
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00002913 if (info->declAsContainer)
2914 clang_index_setClientContainer(info->declAsContainer,
2915 makeClientContainer(info->entityInfo, info->loc));
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002916}
2917
2918static void index_indexEntityReference(CXClientData client_data,
Argyrios Kyrtzidis3e429e72011-11-12 02:16:30 +00002919 const CXIdxEntityRefInfo *info) {
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002920 printEntityInfo("[indexEntityReference]", client_data, info->referencedEntity);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002921 printf(" | cursor: ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00002922 PrintCursor(info->cursor, NULL);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002923 printf(" | loc: ");
Argyrios Kyrtzidis0abc5eb2012-03-15 18:07:22 +00002924 printCXIndexLoc(info->loc, client_data);
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002925 printEntityInfo(" | <parent>:", client_data, info->parentEntity);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002926 printf(" | container: ");
2927 printCXIndexContainer(info->container);
Argyrios Kyrtzidis86acd722011-11-14 22:39:19 +00002928 printf(" | refkind: ");
Argyrios Kyrtzidis0c7735e52011-10-18 15:50:50 +00002929 switch (info->kind) {
2930 case CXIdxEntityRef_Direct: printf("direct"); break;
Argyrios Kyrtzidiseffdbf52011-11-18 00:26:51 +00002931 case CXIdxEntityRef_Implicit: printf("implicit"); break;
Argyrios Kyrtzidis0c7735e52011-10-18 15:50:50 +00002932 }
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002933 printf("\n");
2934}
2935
Argyrios Kyrtzidisb11f5a42011-11-28 04:56:00 +00002936static int index_abortQuery(CXClientData client_data, void *reserved) {
2937 IndexData *index_data;
2938 index_data = (IndexData *)client_data;
2939 return index_data->abort;
2940}
2941
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002942static IndexerCallbacks IndexCB = {
Argyrios Kyrtzidisb11f5a42011-11-28 04:56:00 +00002943 index_abortQuery,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002944 index_diagnostic,
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002945 index_enteredMainFile,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002946 index_ppIncludedFile,
Argyrios Kyrtzidis472eda02012-10-02 16:10:38 +00002947 index_importedASTFile,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002948 index_startedTranslationUnit,
Argyrios Kyrtzidis7519c5e2011-11-11 00:23:36 +00002949 index_indexDeclaration,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00002950 index_indexEntityReference
2951};
2952
Argyrios Kyrtzidisfb7d1452012-01-14 00:11:49 +00002953static unsigned getIndexOptions(void) {
2954 unsigned index_opts;
2955 index_opts = 0;
2956 if (getenv("CINDEXTEST_SUPPRESSREFS"))
2957 index_opts |= CXIndexOpt_SuppressRedundantRefs;
2958 if (getenv("CINDEXTEST_INDEXLOCALSYMBOLS"))
2959 index_opts |= CXIndexOpt_IndexFunctionLocalSymbols;
Argyrios Kyrtzidis8b71bc72012-12-06 19:41:16 +00002960 if (!getenv("CINDEXTEST_DISABLE_SKIPPARSEDBODIES"))
2961 index_opts |= CXIndexOpt_SkipParsedBodiesInSession;
Argyrios Kyrtzidisfb7d1452012-01-14 00:11:49 +00002962
2963 return index_opts;
2964}
2965
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00002966static int index_compile_args(int num_args, const char **args,
2967 CXIndexAction idxAction,
2968 ImportedASTFilesData *importedASTs,
2969 const char *check_prefix) {
2970 IndexData index_data;
2971 unsigned index_opts;
2972 int result;
2973
2974 if (num_args == 0) {
2975 fprintf(stderr, "no compiler arguments\n");
2976 return -1;
2977 }
2978
2979 index_data.check_prefix = check_prefix;
2980 index_data.first_check_printed = 0;
2981 index_data.fail_for_error = 0;
2982 index_data.abort = 0;
2983 index_data.main_filename = "";
2984 index_data.importedASTs = importedASTs;
2985
2986 index_opts = getIndexOptions();
2987 result = clang_indexSourceFile(idxAction, &index_data,
2988 &IndexCB,sizeof(IndexCB), index_opts,
2989 0, args, num_args, 0, 0, 0,
2990 getDefaultParsingOptions());
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00002991 if (result != CXError_Success)
2992 describeLibclangFailure(result);
2993
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00002994 if (index_data.fail_for_error)
2995 result = -1;
2996
2997 return result;
2998}
2999
3000static int index_ast_file(const char *ast_file,
3001 CXIndex Idx,
3002 CXIndexAction idxAction,
3003 ImportedASTFilesData *importedASTs,
3004 const char *check_prefix) {
3005 CXTranslationUnit TU;
3006 IndexData index_data;
3007 unsigned index_opts;
3008 int result;
3009
3010 if (!CreateTranslationUnit(Idx, ast_file, &TU))
3011 return -1;
3012
3013 index_data.check_prefix = check_prefix;
3014 index_data.first_check_printed = 0;
3015 index_data.fail_for_error = 0;
3016 index_data.abort = 0;
3017 index_data.main_filename = "";
3018 index_data.importedASTs = importedASTs;
3019
3020 index_opts = getIndexOptions();
3021 result = clang_indexTranslationUnit(idxAction, &index_data,
3022 &IndexCB,sizeof(IndexCB),
3023 index_opts, TU);
3024 if (index_data.fail_for_error)
3025 result = -1;
3026
3027 clang_disposeTranslationUnit(TU);
3028 return result;
3029}
3030
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003031static int index_file(int argc, const char **argv, int full) {
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00003032 const char *check_prefix;
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003033 CXIndex Idx;
3034 CXIndexAction idxAction;
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003035 ImportedASTFilesData *importedASTs;
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00003036 int result;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00003037
3038 check_prefix = 0;
3039 if (argc > 0) {
3040 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3041 check_prefix = argv[0] + strlen("-check-prefix=");
3042 ++argv;
3043 --argc;
3044 }
3045 }
3046
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003047 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
Stefanus Du Toitb3318502013-03-01 21:41:22 +00003048 /* displayDiagnostics=*/1))) {
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003049 fprintf(stderr, "Could not create Index\n");
3050 return 1;
3051 }
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003052 idxAction = clang_IndexAction_create(Idx);
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003053 importedASTs = 0;
3054 if (full)
3055 importedASTs = importedASTs_create();
3056
3057 result = index_compile_args(argc, argv, idxAction, importedASTs, check_prefix);
3058 if (result != 0)
3059 goto finished;
3060
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003061 if (full) {
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003062 unsigned i;
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003063 for (i = 0; i < importedASTs->num_files && result == 0; ++i) {
3064 result = index_ast_file(importedASTs->filenames[i], Idx, idxAction,
3065 importedASTs, check_prefix);
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003066 }
3067 }
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003068
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003069finished:
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003070 importedASTs_dispose(importedASTs);
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003071 clang_IndexAction_dispose(idxAction);
3072 clang_disposeIndex(Idx);
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003073 return result;
3074}
3075
3076static int index_tu(int argc, const char **argv) {
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003077 const char *check_prefix;
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003078 CXIndex Idx;
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003079 CXIndexAction idxAction;
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003080 int result;
3081
3082 check_prefix = 0;
3083 if (argc > 0) {
3084 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3085 check_prefix = argv[0] + strlen("-check-prefix=");
3086 ++argv;
3087 --argc;
3088 }
3089 }
3090
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003091 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
Stefanus Du Toitb3318502013-03-01 21:41:22 +00003092 /* displayDiagnostics=*/1))) {
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003093 fprintf(stderr, "Could not create Index\n");
3094 return 1;
3095 }
3096 idxAction = clang_IndexAction_create(Idx);
3097
3098 result = index_ast_file(argv[0], Idx, idxAction,
3099 /*importedASTs=*/0, check_prefix);
3100
3101 clang_IndexAction_dispose(idxAction);
3102 clang_disposeIndex(Idx);
3103 return result;
3104}
3105
3106static int index_compile_db(int argc, const char **argv) {
3107 const char *check_prefix;
3108 CXIndex Idx;
3109 CXIndexAction idxAction;
3110 int errorCode = 0;
3111
3112 check_prefix = 0;
3113 if (argc > 0) {
3114 if (strstr(argv[0], "-check-prefix=") == argv[0]) {
3115 check_prefix = argv[0] + strlen("-check-prefix=");
3116 ++argv;
3117 --argc;
3118 }
3119 }
3120
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003121 if (argc == 0) {
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003122 fprintf(stderr, "no compilation database\n");
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003123 return -1;
3124 }
3125
3126 if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
Stefanus Du Toitb3318502013-03-01 21:41:22 +00003127 /* displayDiagnostics=*/1))) {
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003128 fprintf(stderr, "Could not create Index\n");
3129 return 1;
3130 }
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003131 idxAction = clang_IndexAction_create(Idx);
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003132
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003133 {
3134 const char *database = argv[0];
3135 CXCompilationDatabase db = 0;
3136 CXCompileCommands CCmds = 0;
3137 CXCompileCommand CCmd;
3138 CXCompilationDatabase_Error ec;
3139 CXString wd;
3140#define MAX_COMPILE_ARGS 512
3141 CXString cxargs[MAX_COMPILE_ARGS];
3142 const char *args[MAX_COMPILE_ARGS];
3143 char *tmp;
3144 unsigned len;
3145 char *buildDir;
3146 int i, a, numCmds, numArgs;
3147
3148 len = strlen(database);
3149 tmp = (char *) malloc(len+1);
3150 memcpy(tmp, database, len+1);
3151 buildDir = dirname(tmp);
3152
3153 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
3154
3155 if (db) {
3156
3157 if (ec!=CXCompilationDatabase_NoError) {
3158 printf("unexpected error %d code while loading compilation database\n", ec);
3159 errorCode = -1;
3160 goto cdb_end;
3161 }
3162
Argyrios Kyrtzidisfdea8132012-12-17 20:19:56 +00003163 if (chdir(buildDir) != 0) {
3164 printf("Could not chdir to %s\n", buildDir);
3165 errorCode = -1;
3166 goto cdb_end;
3167 }
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003168
Argyrios Kyrtzidisfdea8132012-12-17 20:19:56 +00003169 CCmds = clang_CompilationDatabase_getAllCompileCommands(db);
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003170 if (!CCmds) {
3171 printf("compilation db is empty\n");
3172 errorCode = -1;
3173 goto cdb_end;
3174 }
3175
3176 numCmds = clang_CompileCommands_getSize(CCmds);
3177
3178 if (numCmds==0) {
3179 fprintf(stderr, "should not get an empty compileCommand set\n");
3180 errorCode = -1;
3181 goto cdb_end;
3182 }
3183
3184 for (i=0; i<numCmds && errorCode == 0; ++i) {
3185 CCmd = clang_CompileCommands_getCommand(CCmds, i);
3186
3187 wd = clang_CompileCommand_getDirectory(CCmd);
Argyrios Kyrtzidisfdea8132012-12-17 20:19:56 +00003188 if (chdir(clang_getCString(wd)) != 0) {
3189 printf("Could not chdir to %s\n", clang_getCString(wd));
3190 errorCode = -1;
3191 goto cdb_end;
3192 }
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003193 clang_disposeString(wd);
3194
3195 numArgs = clang_CompileCommand_getNumArgs(CCmd);
3196 if (numArgs > MAX_COMPILE_ARGS){
3197 fprintf(stderr, "got more compile arguments than maximum\n");
3198 errorCode = -1;
3199 goto cdb_end;
3200 }
3201 for (a=0; a<numArgs; ++a) {
3202 cxargs[a] = clang_CompileCommand_getArg(CCmd, a);
3203 args[a] = clang_getCString(cxargs[a]);
3204 }
3205
3206 errorCode = index_compile_args(numArgs, args, idxAction,
3207 /*importedASTs=*/0, check_prefix);
3208
3209 for (a=0; a<numArgs; ++a)
3210 clang_disposeString(cxargs[a]);
3211 }
3212 } else {
3213 printf("database loading failed with error code %d.\n", ec);
3214 errorCode = -1;
3215 }
3216
3217 cdb_end:
3218 clang_CompileCommands_dispose(CCmds);
3219 clang_CompilationDatabase_dispose(db);
3220 free(tmp);
3221
3222 }
3223
Argyrios Kyrtzidis4c910b12011-11-22 07:24:51 +00003224 clang_IndexAction_dispose(idxAction);
3225 clang_disposeIndex(Idx);
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003226 return errorCode;
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00003227}
3228
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003229int perform_token_annotation(int argc, const char **argv) {
3230 const char *input = argv[1];
3231 char *filename = 0;
3232 unsigned line, second_line;
3233 unsigned column, second_column;
3234 CXIndex CIdx;
3235 CXTranslationUnit TU = 0;
3236 int errorCode;
3237 struct CXUnsavedFile *unsaved_files = 0;
3238 int num_unsaved_files = 0;
3239 CXToken *tokens;
3240 unsigned num_tokens;
3241 CXSourceRange range;
3242 CXSourceLocation startLoc, endLoc;
3243 CXFile file = 0;
3244 CXCursor *cursors = 0;
Argyrios Kyrtzidis0e282ef2013-12-06 18:55:45 +00003245 CXSourceRangeList *skipped_ranges = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003246 enum CXErrorCode Err;
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003247 unsigned i;
3248
3249 input += strlen("-test-annotate-tokens=");
3250 if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
3251 &second_line, &second_column)))
3252 return errorCode;
3253
Richard Smith1ea42eb2012-07-05 08:20:49 +00003254 if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files)) {
3255 free(filename);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003256 return -1;
Richard Smith1ea42eb2012-07-05 08:20:49 +00003257 }
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003258
Douglas Gregor1e21cc72010-02-18 23:07:20 +00003259 CIdx = clang_createIndex(0, 1);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003260 Err = clang_parseTranslationUnit2(CIdx, argv[argc - 1],
3261 argv + num_unsaved_files + 2,
3262 argc - num_unsaved_files - 3,
3263 unsaved_files,
3264 num_unsaved_files,
3265 getDefaultParsingOptions(), &TU);
3266 if (Err != CXError_Success) {
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003267 fprintf(stderr, "unable to parse input\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003268 describeLibclangFailure(Err);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003269 clang_disposeIndex(CIdx);
3270 free(filename);
3271 free_remapped_files(unsaved_files, num_unsaved_files);
3272 return -1;
Ted Kremenek29004672010-02-17 00:41:32 +00003273 }
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003274 errorCode = 0;
3275
Richard Smith1ea42eb2012-07-05 08:20:49 +00003276 if (checkForErrors(TU) != 0) {
3277 errorCode = -1;
3278 goto teardown;
3279 }
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00003280
Argyrios Kyrtzidis4cdfcae2011-09-26 08:01:41 +00003281 if (getenv("CINDEXTEST_EDITING")) {
3282 for (i = 0; i < 5; ++i) {
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003283 Err = clang_reparseTranslationUnit(TU, num_unsaved_files, unsaved_files,
3284 clang_defaultReparseOptions(TU));
3285 if (Err != CXError_Success) {
Argyrios Kyrtzidis4cdfcae2011-09-26 08:01:41 +00003286 fprintf(stderr, "Unable to reparse translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003287 describeLibclangFailure(Err);
Argyrios Kyrtzidis4cdfcae2011-09-26 08:01:41 +00003288 errorCode = -1;
3289 goto teardown;
3290 }
3291 }
3292 }
3293
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00003294 if (checkForErrors(TU) != 0) {
3295 errorCode = -1;
3296 goto teardown;
3297 }
3298
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003299 file = clang_getFile(TU, filename);
3300 if (!file) {
3301 fprintf(stderr, "file %s is not in this translation unit\n", filename);
3302 errorCode = -1;
3303 goto teardown;
3304 }
3305
3306 startLoc = clang_getLocation(TU, file, line, column);
3307 if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
Ted Kremenek29004672010-02-17 00:41:32 +00003308 fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003309 column);
3310 errorCode = -1;
Ted Kremenek29004672010-02-17 00:41:32 +00003311 goto teardown;
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003312 }
3313
3314 endLoc = clang_getLocation(TU, file, second_line, second_column);
3315 if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
Ted Kremenek29004672010-02-17 00:41:32 +00003316 fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003317 second_line, second_column);
3318 errorCode = -1;
Ted Kremenek29004672010-02-17 00:41:32 +00003319 goto teardown;
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003320 }
3321
3322 range = clang_getRange(startLoc, endLoc);
3323 clang_tokenize(TU, range, &tokens, &num_tokens);
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00003324
3325 if (checkForErrors(TU) != 0) {
3326 errorCode = -1;
3327 goto teardown;
3328 }
3329
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003330 cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
3331 clang_annotateTokens(TU, tokens, num_tokens, cursors);
Argyrios Kyrtzidisa109e002011-10-28 22:54:36 +00003332
3333 if (checkForErrors(TU) != 0) {
3334 errorCode = -1;
3335 goto teardown;
3336 }
3337
Argyrios Kyrtzidis9ef57752013-12-05 08:19:32 +00003338 skipped_ranges = clang_getSkippedRanges(TU, file);
3339 for (i = 0; i != skipped_ranges->count; ++i) {
3340 unsigned start_line, start_column, end_line, end_column;
3341 clang_getSpellingLocation(clang_getRangeStart(skipped_ranges->ranges[i]),
3342 0, &start_line, &start_column, 0);
3343 clang_getSpellingLocation(clang_getRangeEnd(skipped_ranges->ranges[i]),
3344 0, &end_line, &end_column, 0);
3345 printf("Skipping: ");
3346 PrintExtent(stdout, start_line, start_column, end_line, end_column);
3347 printf("\n");
3348 }
Argyrios Kyrtzidis0e282ef2013-12-06 18:55:45 +00003349 clang_disposeSourceRangeList(skipped_ranges);
Argyrios Kyrtzidis9ef57752013-12-05 08:19:32 +00003350
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003351 for (i = 0; i != num_tokens; ++i) {
3352 const char *kind = "<unknown>";
Enea Zaffanella476f38a2013-07-22 20:58:30 +00003353 CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
3354 CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003355 unsigned start_line, start_column, end_line, end_column;
3356
3357 switch (clang_getTokenKind(tokens[i])) {
3358 case CXToken_Punctuation: kind = "Punctuation"; break;
3359 case CXToken_Keyword: kind = "Keyword"; break;
3360 case CXToken_Identifier: kind = "Identifier"; break;
3361 case CXToken_Literal: kind = "Literal"; break;
3362 case CXToken_Comment: kind = "Comment"; break;
3363 }
Douglas Gregor229bebd2010-11-09 06:24:54 +00003364 clang_getSpellingLocation(clang_getRangeStart(extent),
3365 0, &start_line, &start_column, 0);
3366 clang_getSpellingLocation(clang_getRangeEnd(extent),
3367 0, &end_line, &end_column, 0);
Daniel Dunbar98c07e02010-02-14 08:32:24 +00003368 printf("%s: \"%s\" ", kind, clang_getCString(spelling));
Benjamin Krameraf7ae312012-04-14 09:11:51 +00003369 clang_disposeString(spelling);
Daniel Dunbar98c07e02010-02-14 08:32:24 +00003370 PrintExtent(stdout, start_line, start_column, end_line, end_column);
Douglas Gregor61656112010-01-26 18:31:56 +00003371 if (!clang_isInvalid(cursors[i].kind)) {
3372 printf(" ");
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00003373 PrintCursor(cursors[i], NULL);
Douglas Gregor61656112010-01-26 18:31:56 +00003374 }
3375 printf("\n");
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003376 }
3377 free(cursors);
Ted Kremenek983fb5de2010-10-20 21:22:15 +00003378 clang_disposeTokens(TU, tokens, num_tokens);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003379
3380 teardown:
Douglas Gregor33cdd812010-02-18 18:08:43 +00003381 PrintDiagnostics(TU);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003382 clang_disposeTranslationUnit(TU);
3383 clang_disposeIndex(CIdx);
3384 free(filename);
3385 free_remapped_files(unsaved_files, num_unsaved_files);
3386 return errorCode;
3387}
3388
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003389static int
3390perform_test_compilation_db(const char *database, int argc, const char **argv) {
3391 CXCompilationDatabase db;
3392 CXCompileCommands CCmds;
3393 CXCompileCommand CCmd;
3394 CXCompilationDatabase_Error ec;
3395 CXString wd;
3396 CXString arg;
3397 int errorCode = 0;
3398 char *tmp;
3399 unsigned len;
3400 char *buildDir;
3401 int i, j, a, numCmds, numArgs;
3402
3403 len = strlen(database);
3404 tmp = (char *) malloc(len+1);
3405 memcpy(tmp, database, len+1);
3406 buildDir = dirname(tmp);
3407
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003408 db = clang_CompilationDatabase_fromDirectory(buildDir, &ec);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003409
3410 if (db) {
3411
3412 if (ec!=CXCompilationDatabase_NoError) {
3413 printf("unexpected error %d code while loading compilation database\n", ec);
3414 errorCode = -1;
3415 goto cdb_end;
3416 }
3417
3418 for (i=0; i<argc && errorCode==0; ) {
3419 if (strcmp(argv[i],"lookup")==0){
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003420 CCmds = clang_CompilationDatabase_getCompileCommands(db, argv[i+1]);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003421
3422 if (!CCmds) {
3423 printf("file %s not found in compilation db\n", argv[i+1]);
3424 errorCode = -1;
3425 break;
3426 }
3427
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003428 numCmds = clang_CompileCommands_getSize(CCmds);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003429
3430 if (numCmds==0) {
3431 fprintf(stderr, "should not get an empty compileCommand set for file"
3432 " '%s'\n", argv[i+1]);
3433 errorCode = -1;
3434 break;
3435 }
3436
3437 for (j=0; j<numCmds; ++j) {
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003438 CCmd = clang_CompileCommands_getCommand(CCmds, j);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003439
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003440 wd = clang_CompileCommand_getDirectory(CCmd);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003441 printf("workdir:'%s'", clang_getCString(wd));
3442 clang_disposeString(wd);
3443
3444 printf(" cmdline:'");
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003445 numArgs = clang_CompileCommand_getNumArgs(CCmd);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003446 for (a=0; a<numArgs; ++a) {
3447 if (a) printf(" ");
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003448 arg = clang_CompileCommand_getArg(CCmd, a);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003449 printf("%s", clang_getCString(arg));
3450 clang_disposeString(arg);
3451 }
3452 printf("'\n");
3453 }
3454
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003455 clang_CompileCommands_dispose(CCmds);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003456
3457 i += 2;
3458 }
3459 }
Arnaud A. de Grandmaisonfa6d73c2012-07-03 20:38:12 +00003460 clang_CompilationDatabase_dispose(db);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003461 } else {
3462 printf("database loading failed with error code %d.\n", ec);
3463 errorCode = -1;
3464 }
3465
3466cdb_end:
3467 free(tmp);
3468
3469 return errorCode;
3470}
3471
Ted Kremenek1cd27d52009-11-17 18:13:31 +00003472/******************************************************************************/
Ted Kremenek599d73a2010-03-25 02:00:39 +00003473/* USR printing. */
3474/******************************************************************************/
3475
3476static int insufficient_usr(const char *kind, const char *usage) {
3477 fprintf(stderr, "USR for '%s' requires: %s\n", kind, usage);
3478 return 1;
3479}
3480
3481static unsigned isUSR(const char *s) {
3482 return s[0] == 'c' && s[1] == ':';
3483}
3484
3485static int not_usr(const char *s, const char *arg) {
3486 fprintf(stderr, "'%s' argument ('%s') is not a USR\n", s, arg);
3487 return 1;
3488}
3489
3490static void print_usr(CXString usr) {
3491 const char *s = clang_getCString(usr);
3492 printf("%s\n", s);
3493 clang_disposeString(usr);
3494}
3495
3496static void display_usrs() {
3497 fprintf(stderr, "-print-usrs options:\n"
3498 " ObjCCategory <class name> <category name>\n"
3499 " ObjCClass <class name>\n"
3500 " ObjCIvar <ivar name> <class USR>\n"
3501 " ObjCMethod <selector> [0=class method|1=instance method] "
3502 "<class USR>\n"
3503 " ObjCProperty <property name> <class USR>\n"
3504 " ObjCProtocol <protocol name>\n");
3505}
3506
3507int print_usrs(const char **I, const char **E) {
3508 while (I != E) {
3509 const char *kind = *I;
3510 unsigned len = strlen(kind);
3511 switch (len) {
3512 case 8:
3513 if (memcmp(kind, "ObjCIvar", 8) == 0) {
3514 if (I + 2 >= E)
3515 return insufficient_usr(kind, "<ivar name> <class USR>");
3516 if (!isUSR(I[2]))
3517 return not_usr("<class USR>", I[2]);
3518 else {
3519 CXString x;
Ted Kremenek91554282010-11-16 08:15:36 +00003520 x.data = (void*) I[2];
Ted Kremenek4b4f3692010-11-16 01:56:27 +00003521 x.private_flags = 0;
Ted Kremenek599d73a2010-03-25 02:00:39 +00003522 print_usr(clang_constructUSR_ObjCIvar(I[1], x));
3523 }
3524
3525 I += 3;
3526 continue;
3527 }
3528 break;
3529 case 9:
3530 if (memcmp(kind, "ObjCClass", 9) == 0) {
3531 if (I + 1 >= E)
3532 return insufficient_usr(kind, "<class name>");
3533 print_usr(clang_constructUSR_ObjCClass(I[1]));
3534 I += 2;
3535 continue;
3536 }
3537 break;
3538 case 10:
3539 if (memcmp(kind, "ObjCMethod", 10) == 0) {
3540 if (I + 3 >= E)
3541 return insufficient_usr(kind, "<method selector> "
3542 "[0=class method|1=instance method] <class USR>");
3543 if (!isUSR(I[3]))
3544 return not_usr("<class USR>", I[3]);
3545 else {
3546 CXString x;
Ted Kremenek91554282010-11-16 08:15:36 +00003547 x.data = (void*) I[3];
Ted Kremenek4b4f3692010-11-16 01:56:27 +00003548 x.private_flags = 0;
Ted Kremenek599d73a2010-03-25 02:00:39 +00003549 print_usr(clang_constructUSR_ObjCMethod(I[1], atoi(I[2]), x));
3550 }
3551 I += 4;
3552 continue;
3553 }
3554 break;
3555 case 12:
3556 if (memcmp(kind, "ObjCCategory", 12) == 0) {
3557 if (I + 2 >= E)
3558 return insufficient_usr(kind, "<class name> <category name>");
3559 print_usr(clang_constructUSR_ObjCCategory(I[1], I[2]));
3560 I += 3;
3561 continue;
3562 }
3563 if (memcmp(kind, "ObjCProtocol", 12) == 0) {
3564 if (I + 1 >= E)
3565 return insufficient_usr(kind, "<protocol name>");
3566 print_usr(clang_constructUSR_ObjCProtocol(I[1]));
3567 I += 2;
3568 continue;
3569 }
3570 if (memcmp(kind, "ObjCProperty", 12) == 0) {
3571 if (I + 2 >= E)
3572 return insufficient_usr(kind, "<property name> <class USR>");
3573 if (!isUSR(I[2]))
3574 return not_usr("<class USR>", I[2]);
3575 else {
3576 CXString x;
Ted Kremenek91554282010-11-16 08:15:36 +00003577 x.data = (void*) I[2];
Ted Kremenek4b4f3692010-11-16 01:56:27 +00003578 x.private_flags = 0;
Ted Kremenek599d73a2010-03-25 02:00:39 +00003579 print_usr(clang_constructUSR_ObjCProperty(I[1], x));
3580 }
3581 I += 3;
3582 continue;
3583 }
3584 break;
3585 default:
3586 break;
3587 }
3588 break;
3589 }
3590
3591 if (I != E) {
3592 fprintf(stderr, "Invalid USR kind: %s\n", *I);
3593 display_usrs();
3594 return 1;
3595 }
3596 return 0;
3597}
3598
3599int print_usrs_file(const char *file_name) {
3600 char line[2048];
3601 const char *args[128];
3602 unsigned numChars = 0;
3603
3604 FILE *fp = fopen(file_name, "r");
3605 if (!fp) {
3606 fprintf(stderr, "error: cannot open '%s'\n", file_name);
3607 return 1;
3608 }
3609
3610 /* This code is not really all that safe, but it works fine for testing. */
3611 while (!feof(fp)) {
3612 char c = fgetc(fp);
3613 if (c == '\n') {
3614 unsigned i = 0;
3615 const char *s = 0;
3616
3617 if (numChars == 0)
3618 continue;
3619
3620 line[numChars] = '\0';
3621 numChars = 0;
3622
3623 if (line[0] == '/' && line[1] == '/')
3624 continue;
3625
3626 s = strtok(line, " ");
3627 while (s) {
3628 args[i] = s;
3629 ++i;
3630 s = strtok(0, " ");
3631 }
3632 if (print_usrs(&args[0], &args[i]))
3633 return 1;
3634 }
3635 else
3636 line[numChars++] = c;
3637 }
3638
3639 fclose(fp);
3640 return 0;
3641}
3642
3643/******************************************************************************/
Ted Kremenek1cd27d52009-11-17 18:13:31 +00003644/* Command line processing. */
3645/******************************************************************************/
Douglas Gregore9386682010-08-13 05:36:37 +00003646int write_pch_file(const char *filename, int argc, const char *argv[]) {
3647 CXIndex Idx;
3648 CXTranslationUnit TU;
3649 struct CXUnsavedFile *unsaved_files = 0;
3650 int num_unsaved_files = 0;
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003651 enum CXErrorCode Err;
Francois Pichetabcfbec2011-07-06 22:09:44 +00003652 int result = 0;
Douglas Gregore9386682010-08-13 05:36:37 +00003653
Stefanus Du Toitb3318502013-03-01 21:41:22 +00003654 Idx = clang_createIndex(/* excludeDeclsFromPCH */1, /* displayDiagnostics=*/1);
Douglas Gregore9386682010-08-13 05:36:37 +00003655
3656 if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) {
3657 clang_disposeIndex(Idx);
3658 return -1;
3659 }
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003660
3661 Err = clang_parseTranslationUnit2(
3662 Idx, 0, argv + num_unsaved_files, argc - num_unsaved_files,
3663 unsaved_files, num_unsaved_files,
3664 CXTranslationUnit_Incomplete |
3665 CXTranslationUnit_DetailedPreprocessingRecord |
3666 CXTranslationUnit_ForSerialization,
3667 &TU);
3668 if (Err != CXError_Success) {
Douglas Gregore9386682010-08-13 05:36:37 +00003669 fprintf(stderr, "Unable to load translation unit!\n");
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003670 describeLibclangFailure(Err);
Douglas Gregore9386682010-08-13 05:36:37 +00003671 free_remapped_files(unsaved_files, num_unsaved_files);
Dmitri Gribenkoea4d1c32014-02-12 19:12:37 +00003672 clang_disposeTranslationUnit(TU);
Douglas Gregore9386682010-08-13 05:36:37 +00003673 clang_disposeIndex(Idx);
3674 return 1;
3675 }
3676
Douglas Gregor30c80fa2011-07-06 16:43:36 +00003677 switch (clang_saveTranslationUnit(TU, filename,
3678 clang_defaultSaveOptions(TU))) {
3679 case CXSaveError_None:
3680 break;
3681
3682 case CXSaveError_TranslationErrors:
3683 fprintf(stderr, "Unable to write PCH file %s: translation errors\n",
3684 filename);
3685 result = 2;
3686 break;
3687
3688 case CXSaveError_InvalidTU:
3689 fprintf(stderr, "Unable to write PCH file %s: invalid translation unit\n",
3690 filename);
3691 result = 3;
3692 break;
3693
3694 case CXSaveError_Unknown:
3695 default:
3696 fprintf(stderr, "Unable to write PCH file %s: unknown error \n", filename);
3697 result = 1;
3698 break;
3699 }
3700
Douglas Gregore9386682010-08-13 05:36:37 +00003701 clang_disposeTranslationUnit(TU);
3702 free_remapped_files(unsaved_files, num_unsaved_files);
3703 clang_disposeIndex(Idx);
Douglas Gregor30c80fa2011-07-06 16:43:36 +00003704 return result;
Douglas Gregore9386682010-08-13 05:36:37 +00003705}
3706
3707/******************************************************************************/
Ted Kremenekd010ba42011-11-10 08:43:12 +00003708/* Serialized diagnostics. */
3709/******************************************************************************/
3710
3711static const char *getDiagnosticCodeStr(enum CXLoadDiag_Error error) {
3712 switch (error) {
3713 case CXLoadDiag_CannotLoad: return "Cannot Load File";
3714 case CXLoadDiag_None: break;
3715 case CXLoadDiag_Unknown: return "Unknown";
3716 case CXLoadDiag_InvalidFile: return "Invalid File";
3717 }
3718 return "None";
3719}
3720
3721static const char *getSeverityString(enum CXDiagnosticSeverity severity) {
3722 switch (severity) {
3723 case CXDiagnostic_Note: return "note";
3724 case CXDiagnostic_Error: return "error";
3725 case CXDiagnostic_Fatal: return "fatal";
3726 case CXDiagnostic_Ignored: return "ignored";
3727 case CXDiagnostic_Warning: return "warning";
3728 }
3729 return "unknown";
3730}
3731
3732static void printIndent(unsigned indent) {
Ted Kremeneka0e32fc2011-11-11 00:46:43 +00003733 if (indent == 0)
3734 return;
3735 fprintf(stderr, "+");
3736 --indent;
Ted Kremenekd010ba42011-11-10 08:43:12 +00003737 while (indent > 0) {
Ted Kremeneka0e32fc2011-11-11 00:46:43 +00003738 fprintf(stderr, "-");
Ted Kremenekd010ba42011-11-10 08:43:12 +00003739 --indent;
3740 }
3741}
3742
3743static void printLocation(CXSourceLocation L) {
3744 CXFile File;
3745 CXString FileName;
3746 unsigned line, column, offset;
3747
3748 clang_getExpansionLocation(L, &File, &line, &column, &offset);
3749 FileName = clang_getFileName(File);
3750
3751 fprintf(stderr, "%s:%d:%d", clang_getCString(FileName), line, column);
3752 clang_disposeString(FileName);
3753}
3754
3755static void printRanges(CXDiagnostic D, unsigned indent) {
3756 unsigned i, n = clang_getDiagnosticNumRanges(D);
3757
3758 for (i = 0; i < n; ++i) {
3759 CXSourceLocation Start, End;
Enea Zaffanella476f38a2013-07-22 20:58:30 +00003760 CXSourceRange SR = clang_getDiagnosticRange(D, i);
Ted Kremenekd010ba42011-11-10 08:43:12 +00003761 Start = clang_getRangeStart(SR);
3762 End = clang_getRangeEnd(SR);
3763
3764 printIndent(indent);
3765 fprintf(stderr, "Range: ");
3766 printLocation(Start);
3767 fprintf(stderr, " ");
3768 printLocation(End);
3769 fprintf(stderr, "\n");
3770 }
3771}
3772
3773static void printFixIts(CXDiagnostic D, unsigned indent) {
3774 unsigned i, n = clang_getDiagnosticNumFixIts(D);
Ted Kremenek4a642302012-03-20 20:49:45 +00003775 fprintf(stderr, "Number FIXITs = %d\n", n);
Ted Kremenekd010ba42011-11-10 08:43:12 +00003776 for (i = 0 ; i < n; ++i) {
3777 CXSourceRange ReplacementRange;
3778 CXString text;
3779 text = clang_getDiagnosticFixIt(D, i, &ReplacementRange);
3780
3781 printIndent(indent);
3782 fprintf(stderr, "FIXIT: (");
3783 printLocation(clang_getRangeStart(ReplacementRange));
3784 fprintf(stderr, " - ");
3785 printLocation(clang_getRangeEnd(ReplacementRange));
3786 fprintf(stderr, "): \"%s\"\n", clang_getCString(text));
3787 clang_disposeString(text);
3788 }
3789}
3790
3791static void printDiagnosticSet(CXDiagnosticSet Diags, unsigned indent) {
NAKAMURA Takumi77d97392011-11-10 09:30:15 +00003792 unsigned i, n;
3793
Ted Kremenekd010ba42011-11-10 08:43:12 +00003794 if (!Diags)
3795 return;
3796
NAKAMURA Takumi77d97392011-11-10 09:30:15 +00003797 n = clang_getNumDiagnosticsInSet(Diags);
Ted Kremenekd010ba42011-11-10 08:43:12 +00003798 for (i = 0; i < n; ++i) {
3799 CXSourceLocation DiagLoc;
3800 CXDiagnostic D;
3801 CXFile File;
Ted Kremenek26a6d492012-04-12 00:03:31 +00003802 CXString FileName, DiagSpelling, DiagOption, DiagCat;
Ted Kremenekd010ba42011-11-10 08:43:12 +00003803 unsigned line, column, offset;
Ted Kremenek26a6d492012-04-12 00:03:31 +00003804 const char *DiagOptionStr = 0, *DiagCatStr = 0;
Ted Kremenekd010ba42011-11-10 08:43:12 +00003805
3806 D = clang_getDiagnosticInSet(Diags, i);
3807 DiagLoc = clang_getDiagnosticLocation(D);
3808 clang_getExpansionLocation(DiagLoc, &File, &line, &column, &offset);
3809 FileName = clang_getFileName(File);
3810 DiagSpelling = clang_getDiagnosticSpelling(D);
3811
3812 printIndent(indent);
3813
3814 fprintf(stderr, "%s:%d:%d: %s: %s",
3815 clang_getCString(FileName),
3816 line,
3817 column,
3818 getSeverityString(clang_getDiagnosticSeverity(D)),
3819 clang_getCString(DiagSpelling));
3820
3821 DiagOption = clang_getDiagnosticOption(D, 0);
3822 DiagOptionStr = clang_getCString(DiagOption);
3823 if (DiagOptionStr) {
3824 fprintf(stderr, " [%s]", DiagOptionStr);
3825 }
3826
Ted Kremenek26a6d492012-04-12 00:03:31 +00003827 DiagCat = clang_getDiagnosticCategoryText(D);
3828 DiagCatStr = clang_getCString(DiagCat);
3829 if (DiagCatStr) {
3830 fprintf(stderr, " [%s]", DiagCatStr);
3831 }
3832
Ted Kremenekd010ba42011-11-10 08:43:12 +00003833 fprintf(stderr, "\n");
3834
3835 printRanges(D, indent);
3836 printFixIts(D, indent);
3837
NAKAMURA Takumi27dd3962011-11-10 10:07:57 +00003838 /* Print subdiagnostics. */
Ted Kremenekd010ba42011-11-10 08:43:12 +00003839 printDiagnosticSet(clang_getChildDiagnostics(D), indent+2);
3840
3841 clang_disposeString(FileName);
3842 clang_disposeString(DiagSpelling);
3843 clang_disposeString(DiagOption);
3844 }
3845}
3846
3847static int read_diagnostics(const char *filename) {
3848 enum CXLoadDiag_Error error;
3849 CXString errorString;
3850 CXDiagnosticSet Diags = 0;
3851
3852 Diags = clang_loadDiagnostics(filename, &error, &errorString);
3853 if (!Diags) {
3854 fprintf(stderr, "Trouble deserializing file (%s): %s\n",
3855 getDiagnosticCodeStr(error),
3856 clang_getCString(errorString));
3857 clang_disposeString(errorString);
3858 return 1;
3859 }
3860
3861 printDiagnosticSet(Diags, 0);
Ted Kremeneka0e32fc2011-11-11 00:46:43 +00003862 fprintf(stderr, "Number of diagnostics: %d\n",
3863 clang_getNumDiagnosticsInSet(Diags));
Ted Kremenekd010ba42011-11-10 08:43:12 +00003864 clang_disposeDiagnosticSet(Diags);
3865 return 0;
3866}
3867
Dmitri Gribenkof430da42014-02-12 10:33:14 +00003868static int perform_print_build_session_timestamp(void) {
3869 printf("%lld\n", clang_getBuildSessionTimestamp());
3870 return 0;
3871}
3872
Ted Kremenekd010ba42011-11-10 08:43:12 +00003873/******************************************************************************/
Douglas Gregore9386682010-08-13 05:36:37 +00003874/* Command line processing. */
3875/******************************************************************************/
Ted Kremenekef3339b2009-11-17 18:09:14 +00003876
Douglas Gregor720d0052010-01-20 21:32:04 +00003877static CXCursorVisitor GetVisitor(const char *s) {
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003878 if (s[0] == '\0')
Douglas Gregor720d0052010-01-20 21:32:04 +00003879 return FilteredPrintingVisitor;
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003880 if (strcmp(s, "-usrs") == 0)
3881 return USRVisitor;
Ted Kremenek83f642e2011-04-18 22:47:10 +00003882 if (strncmp(s, "-memory-usage", 13) == 0)
3883 return GetVisitor(s + 13);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003884 return NULL;
3885}
3886
Ted Kremenekef3339b2009-11-17 18:09:14 +00003887static void print_usage(void) {
3888 fprintf(stderr,
Ted Kremenek1cd27d52009-11-17 18:13:31 +00003889 "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
Douglas Gregor47815d52010-07-12 18:38:41 +00003890 " c-index-test -code-completion-timing=<site> <compiler arguments>\n"
Douglas Gregor082c3e62010-01-15 19:40:17 +00003891 " c-index-test -cursor-at=<site> <compiler arguments>\n"
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00003892 " c-index-test -file-refs-at=<site> <compiler arguments>\n"
3893 " c-index-test -file-includes-in=<filename> <compiler arguments>\n");
NAKAMURA Takumi4deb9a92012-10-24 22:52:04 +00003894 fprintf(stderr,
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00003895 " c-index-test -index-file [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003896 " c-index-test -index-file-full [-check-prefix=<FileCheck prefix>] <compiler arguments>\n"
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003897 " c-index-test -index-tu [-check-prefix=<FileCheck prefix>] <AST file>\n"
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003898 " c-index-test -index-compile-db [-check-prefix=<FileCheck prefix>] <compilation database>\n"
Ted Kremenek0469b7e2009-11-18 02:02:52 +00003899 " c-index-test -test-file-scan <AST file> <source file> "
Erik Verbruggen338b55c2011-10-06 11:38:08 +00003900 "[FileCheck prefix]\n");
3901 fprintf(stderr,
Ted Kremeneka44d99c2010-01-05 23:18:49 +00003902 " c-index-test -test-load-tu <AST file> <symbol filter> "
3903 "[FileCheck prefix]\n"
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003904 " c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
3905 "[FileCheck prefix]\n"
Douglas Gregor47815d52010-07-12 18:38:41 +00003906 " c-index-test -test-load-source <symbol filter> {<args>}*\n");
Douglas Gregor082c3e62010-01-15 19:40:17 +00003907 fprintf(stderr,
Ted Kremenek83f642e2011-04-18 22:47:10 +00003908 " c-index-test -test-load-source-memory-usage "
3909 "<symbol filter> {<args>}*\n"
Douglas Gregoraa21cc42010-07-19 21:46:24 +00003910 " c-index-test -test-load-source-reparse <trials> <symbol filter> "
3911 " {<args>}*\n"
Douglas Gregor47815d52010-07-12 18:38:41 +00003912 " c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n"
Ted Kremenek83f642e2011-04-18 22:47:10 +00003913 " c-index-test -test-load-source-usrs-memory-usage "
3914 "<symbol filter> {<args>}*\n"
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00003915 " c-index-test -test-annotate-tokens=<range> {<args>}*\n"
3916 " c-index-test -test-inclusion-stack-source {<args>}*\n"
Ted Kremenek11d1a422011-04-18 23:42:53 +00003917 " c-index-test -test-inclusion-stack-tu <AST file>\n");
Chandler Carruth718df592010-07-22 06:29:13 +00003918 fprintf(stderr,
Ted Kremenek11d1a422011-04-18 23:42:53 +00003919 " c-index-test -test-print-linkage-source {<args>}*\n"
Dmitri Gribenko00353722013-02-15 21:15:49 +00003920 " c-index-test -test-print-type {<args>}*\n"
Argyrios Kyrtzidise822f582013-04-11 01:20:11 +00003921 " c-index-test -test-print-type-size {<args>}*\n"
Dmitri Gribenkob506ba12012-12-04 15:13:46 +00003922 " c-index-test -test-print-bitwidth {<args>}*\n"
Ted Kremenek83f642e2011-04-18 22:47:10 +00003923 " c-index-test -print-usr [<CursorKind> {<args>}]*\n"
Douglas Gregore9386682010-08-13 05:36:37 +00003924 " c-index-test -print-usr-file <file>\n"
Ted Kremenekd010ba42011-11-10 08:43:12 +00003925 " c-index-test -write-pch <file> <compiler arguments>\n");
3926 fprintf(stderr,
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00003927 " c-index-test -compilation-db [lookup <filename>] database\n");
3928 fprintf(stderr,
Dmitri Gribenkof430da42014-02-12 10:33:14 +00003929 " c-index-test -print-build-session-timestamp\n");
3930 fprintf(stderr,
Ted Kremenekd010ba42011-11-10 08:43:12 +00003931 " c-index-test -read-diagnostics <file>\n\n");
Douglas Gregor73a18fd2010-07-20 14:34:35 +00003932 fprintf(stderr,
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003933 " <symbol filter> values:\n%s",
Ted Kremenek1cd27d52009-11-17 18:13:31 +00003934 " all - load all symbols, including those from PCH\n"
3935 " local - load all symbols except those in PCH\n"
3936 " category - only load ObjC categories (non-PCH)\n"
3937 " interface - only load ObjC interfaces (non-PCH)\n"
3938 " protocol - only load ObjC protocols (non-PCH)\n"
3939 " function - only load functions (non-PCH)\n"
Daniel Dunbar5442bfc2009-12-01 02:35:37 +00003940 " typedef - only load typdefs (non-PCH)\n"
3941 " scan-function - scan function bodies (non-PCH)\n\n");
Ted Kremenekef3339b2009-11-17 18:09:14 +00003942}
3943
Daniel Dunbar08b33d02010-09-30 20:39:47 +00003944/***/
3945
3946int cindextest_main(int argc, const char **argv) {
Douglas Gregor1e21cc72010-02-18 23:07:20 +00003947 clang_enableStackTraces();
Ted Kremenekd010ba42011-11-10 08:43:12 +00003948 if (argc > 2 && strcmp(argv[1], "-read-diagnostics") == 0)
3949 return read_diagnostics(argv[2]);
Ted Kremenekef3339b2009-11-17 18:09:14 +00003950 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
Douglas Gregor47815d52010-07-12 18:38:41 +00003951 return perform_code_completion(argc, argv, 0);
3952 if (argc > 2 && strstr(argv[1], "-code-completion-timing=") == argv[1])
3953 return perform_code_completion(argc, argv, 1);
Douglas Gregor082c3e62010-01-15 19:40:17 +00003954 if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
3955 return inspect_cursor_at(argc, argv);
Argyrios Kyrtzidiscddafd32011-10-06 07:00:54 +00003956 if (argc > 2 && strstr(argv[1], "-file-refs-at=") == argv[1])
3957 return find_file_refs_at(argc, argv);
Argyrios Kyrtzidis503c83a2013-03-08 02:32:34 +00003958 if (argc > 2 && strstr(argv[1], "-file-includes-in=") == argv[1])
3959 return find_file_includes_in(argc, argv);
Argyrios Kyrtzidisdc199a32011-10-17 19:48:19 +00003960 if (argc > 2 && strcmp(argv[1], "-index-file") == 0)
Argyrios Kyrtzidise26c5572012-10-24 18:29:15 +00003961 return index_file(argc - 2, argv + 2, /*full=*/0);
3962 if (argc > 2 && strcmp(argv[1], "-index-file-full") == 0)
3963 return index_file(argc - 2, argv + 2, /*full=*/1);
Argyrios Kyrtzidisd992e142011-11-15 06:20:16 +00003964 if (argc > 2 && strcmp(argv[1], "-index-tu") == 0)
3965 return index_tu(argc - 2, argv + 2);
Argyrios Kyrtzidisf75d4982012-12-05 21:53:37 +00003966 if (argc > 2 && strcmp(argv[1], "-index-compile-db") == 0)
3967 return index_compile_db(argc - 2, argv + 2);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003968 else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
Douglas Gregor720d0052010-01-20 21:32:04 +00003969 CXCursorVisitor I = GetVisitor(argv[1] + 13);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003970 if (I)
Ted Kremenekb478ff42010-01-26 17:59:48 +00003971 return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
3972 NULL);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003973 }
Douglas Gregoraa21cc42010-07-19 21:46:24 +00003974 else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){
3975 CXCursorVisitor I = GetVisitor(argv[1] + 25);
3976 if (I) {
3977 int trials = atoi(argv[2]);
3978 return perform_test_reparse_source(argc - 4, argv + 4, trials, argv[3], I,
3979 NULL);
3980 }
3981 }
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003982 else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
Douglas Gregor720d0052010-01-20 21:32:04 +00003983 CXCursorVisitor I = GetVisitor(argv[1] + 17);
Ted Kremenek83f642e2011-04-18 22:47:10 +00003984
3985 PostVisitTU postVisit = 0;
3986 if (strstr(argv[1], "-memory-usage"))
3987 postVisit = PrintMemoryUsage;
3988
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003989 if (I)
Ted Kremenek83f642e2011-04-18 22:47:10 +00003990 return perform_test_load_source(argc - 3, argv + 3, argv[2], I,
3991 postVisit);
Ted Kremenek58a6a8e2010-01-12 23:34:26 +00003992 }
3993 else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
Ted Kremenek0469b7e2009-11-18 02:02:52 +00003994 return perform_file_scan(argv[2], argv[3],
3995 argc >= 5 ? argv[4] : 0);
Douglas Gregor27b4fa92010-01-26 17:06:03 +00003996 else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
3997 return perform_token_annotation(argc, argv);
Ted Kremenek0b86e3a2010-01-26 19:31:51 +00003998 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-source") == 0)
3999 return perform_test_load_source(argc - 2, argv + 2, "all", NULL,
4000 PrintInclusionStack);
4001 else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0)
4002 return perform_test_load_tu(argv[2], "all", NULL, NULL,
4003 PrintInclusionStack);
Ted Kremenek83b28a22010-03-03 06:37:58 +00004004 else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0)
4005 return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage,
4006 NULL);
Dmitri Gribenko00353722013-02-15 21:15:49 +00004007 else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
Ted Kremenek6bca9842010-05-14 21:29:26 +00004008 return perform_test_load_source(argc - 2, argv + 2, "all",
Dmitri Gribenko00353722013-02-15 21:15:49 +00004009 PrintType, 0);
Argyrios Kyrtzidise822f582013-04-11 01:20:11 +00004010 else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
4011 return perform_test_load_source(argc - 2, argv + 2, "all",
4012 PrintTypeSize, 0);
Dmitri Gribenkob506ba12012-12-04 15:13:46 +00004013 else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
4014 return perform_test_load_source(argc - 2, argv + 2, "all",
4015 PrintBitWidth, 0);
Ted Kremenek599d73a2010-03-25 02:00:39 +00004016 else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) {
4017 if (argc > 2)
4018 return print_usrs(argv + 2, argv + argc);
4019 else {
4020 display_usrs();
4021 return 1;
4022 }
4023 }
4024 else if (argc > 2 && strcmp(argv[1], "-print-usr-file") == 0)
4025 return print_usrs_file(argv[2]);
Douglas Gregore9386682010-08-13 05:36:37 +00004026 else if (argc > 2 && strcmp(argv[1], "-write-pch") == 0)
4027 return write_pch_file(argv[2], argc - 3, argv + 3);
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00004028 else if (argc > 2 && strcmp(argv[1], "-compilation-db") == 0)
4029 return perform_test_compilation_db(argv[argc-1], argc - 3, argv + 2);
Dmitri Gribenkof430da42014-02-12 10:33:14 +00004030 else if (argc == 2 && strcmp(argv[1], "-print-build-session-timestamp") == 0)
4031 return perform_print_build_session_timestamp();
Arnaud A. de Grandmaison0fe28a12012-06-30 11:27:57 +00004032
Ted Kremenekef3339b2009-11-17 18:09:14 +00004033 print_usage();
4034 return 1;
Steve Naroffa1c72842009-08-28 15:28:48 +00004035}
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004036
4037/***/
4038
4039/* We intentionally run in a separate thread to ensure we at least minimal
4040 * testing of a multithreaded environment (for example, having a reduced stack
4041 * size). */
4042
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004043typedef struct thread_info {
4044 int argc;
4045 const char **argv;
4046 int result;
4047} thread_info;
Benjamin Kramer112fc6c2010-11-04 19:11:31 +00004048void thread_runner(void *client_data_v) {
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004049 thread_info *client_data = client_data_v;
4050 client_data->result = cindextest_main(client_data->argc, client_data->argv);
NAKAMURA Takumia7d49882012-04-07 06:59:28 +00004051#ifdef __CYGWIN__
4052 fflush(stdout); /* stdout is not flushed on Cygwin. */
4053#endif
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004054}
4055
4056int main(int argc, const char **argv) {
Benjamin Kramer3a913ed2012-08-10 10:06:13 +00004057 thread_info client_data;
4058
Dmitri Gribenko740c0fb2012-08-07 17:54:38 +00004059#ifdef CLANG_HAVE_LIBXML
4060 LIBXML_TEST_VERSION
4061#endif
4062
Douglas Gregorf428bf82010-10-27 16:00:01 +00004063 if (getenv("CINDEXTEST_NOTHREADS"))
4064 return cindextest_main(argc, argv);
4065
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004066 client_data.argc = argc;
4067 client_data.argv = argv;
Daniel Dunbar23397c32010-11-04 01:26:31 +00004068 clang_executeOnThread(thread_runner, &client_data, 0);
Daniel Dunbar08b33d02010-09-30 20:39:47 +00004069 return client_data.result;
4070}