c-index-test.c revision ce2ae88f834c740a28b7e074a4477039918f9bb0
12b8ee6c2994f738e5162ff46b638974870f51662Steve Naroff/* c-index-test.c */
250398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
350398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff#include "clang-c/Index.h"
40c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor#include <stdlib.h>
589922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff#include <stdio.h>
6af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff#include <string.h>
7f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor#include <assert.h>
8af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff
90d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
100d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Utility functions.                                                         */
110d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
120d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
132e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#ifdef _MSC_VER
142e06fc877a633abea3b40a64950c7316dac29ca8John Thompsonchar *basename(const char* path)
152e06fc877a633abea3b40a64950c7316dac29ca8John Thompson{
162e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base1 = (char*)strrchr(path, '/');
172e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base2 = (char*)strrchr(path, '\\');
182e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    if (base1 && base2)
192e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return((base1 > base2) ? base1 + 1 : base2 + 1);
202e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base1)
212e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base1 + 1);
222e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base2)
232e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base2 + 1);
242e06fc877a633abea3b40a64950c7316dac29ca8John Thompson
252e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    return((char*)path);
262e06fc877a633abea3b40a64950c7316dac29ca8John Thompson}
272e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#else
28ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroffextern char *basename(const char *);
292e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#endif
30ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff
311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                      CXTranslationUnit *TU) {
331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  *TU = clang_createTranslationUnit(Idx, file);
351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!TU) {
361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 0;
381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 1;
401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
424db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregorvoid free_remapped_files(struct CXUnsavedFile *unsaved_files,
434db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                         int num_unsaved_files) {
444db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int i;
454db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  for (i = 0; i != num_unsaved_files; ++i) {
464db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    free((char *)unsaved_files[i].Filename);
474db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    free((char *)unsaved_files[i].Contents);
484db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  }
494db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor}
504db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
514db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregorint parse_remapped_files(int argc, const char **argv, int start_arg,
524db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                         struct CXUnsavedFile **unsaved_files,
534db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                         int *num_unsaved_files) {
544db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int i;
554db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int arg;
564db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int prefix_len = strlen("-remap-file=");
574db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  *unsaved_files = 0;
584db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  *num_unsaved_files = 0;
594db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
604db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  /* Count the number of remapped files. */
614db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  for (arg = start_arg; arg < argc; ++arg) {
624db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    if (strncmp(argv[arg], "-remap-file=", prefix_len))
634db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      break;
644db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
654db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    ++*num_unsaved_files;
664db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  }
674db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
684db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  if (*num_unsaved_files == 0)
694db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    return 0;
704db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
714db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  *unsaved_files
724db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
734db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                   *num_unsaved_files);
744db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
754db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    struct CXUnsavedFile *unsaved = *unsaved_files + i;
764db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    const char *arg_string = argv[arg] + prefix_len;
774db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    int filename_len;
784db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    char *filename;
794db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    char *contents;
804db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    FILE *to_file;
814db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    const char *semi = strchr(arg_string, ';');
824db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    if (!semi) {
834db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      fprintf(stderr,
844db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor              "error: -remap-file=from;to argument is missing semicolon\n");
854db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      free_remapped_files(*unsaved_files, i);
864db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *unsaved_files = 0;
874db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *num_unsaved_files = 0;
884db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      return -1;
894db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    }
904db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
914db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    /* Open the file that we're remapping to. */
924db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    to_file = fopen(semi + 1, "r");
934db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    if (!to_file) {
944db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
954db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor              semi + 1);
964db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      free_remapped_files(*unsaved_files, i);
974db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *unsaved_files = 0;
984db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *num_unsaved_files = 0;
994db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      return -1;
1004db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    }
1014db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1024db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    /* Determine the length of the file we're remapping to. */
1034db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    fseek(to_file, 0, SEEK_END);
1044db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    unsaved->Length = ftell(to_file);
1054db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    fseek(to_file, 0, SEEK_SET);
1064db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1074db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    /* Read the contents of the file we're remapping to. */
1084db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    contents = (char *)malloc(unsaved->Length + 1);
1094db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
1104db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
1114db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor              (feof(to_file) ? "EOF" : "error"), semi + 1);
1124db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      fclose(to_file);
1134db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      free_remapped_files(*unsaved_files, i);
1144db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *unsaved_files = 0;
1154db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      *num_unsaved_files = 0;
1164db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor      return -1;
1174db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    }
1184db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    contents[unsaved->Length] = 0;
1194db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    unsaved->Contents = contents;
1204db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1214db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    /* Close the file. */
1224db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    fclose(to_file);
1234db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1244db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    /* Copy the file name that we're remapping from. */
1254db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    filename_len = semi - arg_string;
1264db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    filename = (char *)malloc(filename_len + 1);
1274db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    memcpy(filename, arg_string, filename_len);
1284db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    filename[filename_len] = 0;
1294db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    unsaved->Filename = filename;
1304db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  }
1314db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1324db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  return 0;
1334db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor}
1344db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1350d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
1360d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Pretty-printing.                                                           */
1370d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
1380d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
139af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroffstatic void PrintCursor(CXCursor Cursor) {
14077128ddd3077fc045751a55bb3226802b15d5510Steve Naroff  if (clang_isInvalid(Cursor.kind))
1411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind));
142699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  else {
143ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
144c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor    CXCursor Referenced;
1451db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    unsigned line, column;
146ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getCursorSpelling(Cursor);
147ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff    printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
148ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff                      clang_getCString(string));
149ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
150c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor
151c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor    Referenced = clang_getCursorReferenced(Cursor);
152c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor    if (!clang_equalCursors(Referenced, clang_getNullCursor())) {
153c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor      CXSourceLocation Loc = clang_getCursorLocation(Referenced);
1541db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor      clang_getInstantiationLocation(Loc, 0, &line, &column);
1551db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor      printf(":%d:%d", line, column);
156c5d1e9375d71e66d22456e7cc52cc7c0a5c65c3fDouglas Gregor    }
157b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor
158b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor    if (clang_isCursorDefinition(Cursor))
159b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor      printf(" (Definition)");
160699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  }
161af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff}
16289922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff
1639298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenekstatic const char* GetCursorSource(CXCursor Cursor) {
1641db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  CXSourceLocation Loc = clang_getCursorLocation(Cursor);
1651db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  const char *source;
1661db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  CXFile file;
1671db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  clang_getInstantiationLocation(Loc, &file, 0, 0);
1681db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  source = clang_getFileName(file);
1699298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  if (!source)
1709298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek    return "<invalid loc>";
1719298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  return basename(source);
1729298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek}
1739298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek
1740d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
175ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek/* Callbacks.                                                                 */
176ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek/******************************************************************************/
177ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek
178ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenektypedef void (*PostVisitTU)(CXTranslationUnit);
179ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek
180ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek/******************************************************************************/
181e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor/* Logic for testing traversal.                                               */
1820d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
1830d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
184fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekstatic const char *FileCheckPrefix = "CHECK";
185fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
186a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregorstatic void PrintCursorExtent(CXCursor C) {
187a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor  CXSourceRange extent = clang_getCursorExtent(C);
1881db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  CXFile begin_file, end_file;
1891db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  unsigned begin_line, begin_column, end_line, end_column;
1901db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor
1911db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  clang_getInstantiationLocation(clang_getRangeStart(extent),
1921db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor                                 &begin_file, &begin_line, &begin_column);
1931db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  clang_getInstantiationLocation(clang_getRangeEnd(extent),
1941db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor                                 &end_file, &end_line, &end_column);
1951db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  if (!begin_file || !end_file)
19670ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    return;
1971db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor
1981db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column,
1991db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor         end_line, end_column);
200fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek}
201fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
202e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor/* Data used by all of the visitors. */
203e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregortypedef struct  {
204e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  CXTranslationUnit TU;
205e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  enum CXCursorKind *Filter;
206e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor} VisitorData;
207fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
208625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
209e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorenum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
210e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                CXCursor Parent,
211e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                CXClientData ClientData) {
212e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
213e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
21498258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    CXSourceLocation Loc = clang_getCursorLocation(Cursor);
2151db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    unsigned line, column;
2161db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    clang_getInstantiationLocation(Loc, 0, &line, &column);
217fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf("// %s: %s:%d:%d: ", FileCheckPrefix,
2181db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor           GetCursorSource(Cursor), line, column);
219af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
220a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor    PrintCursorExtent(Cursor);
22170ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    printf("\n");
222e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Recurse;
223625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  }
224e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
225e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
226625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
227c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff
228e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorstatic enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
229e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                   CXCursor Parent,
230e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                   CXClientData ClientData) {
231625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  const char *startBuf, *endBuf;
232625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
233625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXCursor Ref;
234e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
235625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
236b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor  if (Cursor.kind != CXCursor_FunctionDecl ||
237b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor      !clang_isCursorDefinition(Cursor))
238e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Continue;
239625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
240625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
241625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &startLine, &startColumn,
242625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &endLine, &endColumn);
243625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  /* Probe the entire body, looking for both decls and refs. */
244625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curLine = startLine;
245625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curColumn = startColumn;
246625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
247625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  while (startBuf < endBuf) {
24898258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    CXSourceLocation Loc;
2491db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    CXFile file;
25098258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    const char *source = 0;
25198258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor
252625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (*startBuf == '\n') {
253625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      startBuf++;
254625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curLine++;
255625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn = 1;
256625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (*startBuf != '\t')
257625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn++;
258fbcb2b716bee88c754684bd189913ed9f8c09086Ted Kremenek
25998258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    Loc = clang_getCursorLocation(Cursor);
2601db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    clang_getInstantiationLocation(Loc, &file, 0, 0);
2611db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    source = clang_getFileName(file);
26298258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    if (source) {
263b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      CXSourceLocation RefLoc
264b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor        = clang_getLocation(Data->TU, file, curLine, curColumn);
265b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      Ref = clang_getCursor(Data->TU, RefLoc);
26698258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      if (Ref.kind == CXCursor_NoDeclFound) {
26798258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        /* Nothing found here; that's fine. */
26898258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      } else if (Ref.kind != CXCursor_FunctionDecl) {
26998258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
27098258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor               curLine, curColumn);
27198258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        PrintCursor(Ref);
27298258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        printf("\n");
27398258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      }
2744ade6d6eae934f796ca43c81a5aa185e456dde9bSteve Naroff    }
275625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    startBuf++;
2762d4d629d8a0de5112c7ae9d05c03ddbf6dcd956aSteve Naroff  }
277e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
278e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
27989922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff}
28050398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
2817d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
2827d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* USR testing.                                                               */
2837d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
2847d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
285e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorenum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
286e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                   CXClientData ClientData) {
287e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
288e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
289cf84aa46def41cccf4dd4c51cd0543b70c11e4ebTed Kremenek    CXString USR = clang_getCursorUSR(C);
2907d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (!USR.Spelling) {
2917d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      clang_disposeString(USR);
292e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor      return CXChildVisit_Continue;
2937d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    }
2947d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling);
295a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor    PrintCursorExtent(C);
2967d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("\n");
2977d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    clang_disposeString(USR);
298e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
299e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Recurse;
300e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  }
301e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
302e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
3037d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
3047d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
3057d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
3067d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* Loading ASTs/source.                                                       */
3077d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
3087d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
309625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
31098271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                             const char *filter, const char *prefix,
311ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                             CXCursorVisitor Visitor,
312ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                             PostVisitTU PV) {
313e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
314fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek  if (prefix)
315fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    FileCheckPrefix = prefix;
316e3ee02a324559829142f387f75daf3da118442beTed Kremenek
317e3ee02a324559829142f387f75daf3da118442beTed Kremenek  if (Visitor) {
318e3ee02a324559829142f387f75daf3da118442beTed Kremenek    enum CXCursorKind K = CXCursor_NotImplemented;
319e3ee02a324559829142f387f75daf3da118442beTed Kremenek    enum CXCursorKind *ck = &K;
320e3ee02a324559829142f387f75daf3da118442beTed Kremenek    VisitorData Data;
321fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
322e3ee02a324559829142f387f75daf3da118442beTed Kremenek    /* Perform some simple filtering. */
323e3ee02a324559829142f387f75daf3da118442beTed Kremenek    if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
324e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
325e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
326e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
327e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
328e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
329e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
330e3ee02a324559829142f387f75daf3da118442beTed Kremenek    else {
331e3ee02a324559829142f387f75daf3da118442beTed Kremenek      fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
332e3ee02a324559829142f387f75daf3da118442beTed Kremenek      return 1;
333e3ee02a324559829142f387f75daf3da118442beTed Kremenek    }
3340d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
335e3ee02a324559829142f387f75daf3da118442beTed Kremenek    Data.TU = TU;
336e3ee02a324559829142f387f75daf3da118442beTed Kremenek    Data.Filter = ck;
337e3ee02a324559829142f387f75daf3da118442beTed Kremenek    clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
338e3ee02a324559829142f387f75daf3da118442beTed Kremenek  }
339ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek
340ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek  if (PV)
341ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek    PV(TU);
342e3ee02a324559829142f387f75daf3da118442beTed Kremenek
3430d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  clang_disposeTranslationUnit(TU);
3440d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  return 0;
3450d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek}
3460d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
347fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekint perform_test_load_tu(const char *file, const char *filter,
348ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                         const char *prefix, CXCursorVisitor Visitor,
349ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                         PostVisitTU PV) {
350625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXIndex Idx;
351625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXTranslationUnit TU;
352625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
353625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
354625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          /* displayDiagnostics */ 1);
355625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
356625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (!CreateTranslationUnit(Idx, file, &TU))
357625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return 1;
358625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
359ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek  return perform_test_load(Idx, TU, filter, prefix, Visitor, PV);
360625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
361625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
362ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenekint perform_test_load_source(int argc, const char **argv,
363ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                             const char *filter, CXCursorVisitor Visitor,
364ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                             PostVisitTU PV) {
3658506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  const char *UseExternalASTs =
3668506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
367ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXIndex Idx;
368ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXTranslationUnit TU;
3694db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
3704db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int num_unsaved_files = 0;
3714db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int result;
3724db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
373ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
374ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
375ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          /* displayDiagnostics */ 1);
376ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
3778506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  if (UseExternalASTs && strlen(UseExternalASTs))
3788506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    clang_setUseExternalASTGeneration(Idx, 1);
3798506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar
3804db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files))
3814db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    return -1;
3824db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
3834db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  TU = clang_createTranslationUnitFromSourceFile(Idx, 0,
3844db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 argc - num_unsaved_files,
3854db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 argv + num_unsaved_files,
3864db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 num_unsaved_files,
3874db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 unsaved_files);
388ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (!TU) {
389ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    fprintf(stderr, "Unable to load translation unit!\n");
390ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return 1;
391ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  }
392ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
393ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek  result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV);
3944db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
3954db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  return result;
396ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar}
397ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
3980d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
3991c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/* Logic for testing clang_getCursor().                                       */
4001c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
4011c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4021c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic void print_cursor_file_scan(CXCursor cursor,
4031c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                   unsigned start_line, unsigned start_col,
4041d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   unsigned end_line, unsigned end_col,
4051d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   const char *prefix) {
4069096a20fc0fd799911b738ce7a9134dbacaf64b7Ted Kremenek  printf("// %s: ", FileCheckPrefix);
4071d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (prefix)
4081d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    printf("-%s", prefix);
4091d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
4101d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          start_line, start_col, end_line, end_col);
4111c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  PrintCursor(cursor);
4121c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printf("\n");
4131c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
4141c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4151d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenekstatic int perform_file_scan(const char *ast_file, const char *source_file,
4161d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             const char *prefix) {
4171c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXIndex Idx;
4181c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXTranslationUnit TU;
4191c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  FILE *fp;
4201c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned line;
4211c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXCursor prevCursor;
422b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor  CXFile file;
4231c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned printed;
4241c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned start_line, start_col, last_line, last_col;
4251c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  size_t i;
4261c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4271c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
4281c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                /* displayDiagnostics */ 1))) {
4291c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not create Index\n");
4301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!CreateTranslationUnit(Idx, ast_file, &TU))
4341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if ((fp = fopen(source_file, "r")) == NULL) {
4371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not open '%s'\n", source_file);
4381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  line = 0;
4421c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  prevCursor = clang_getNullCursor();
4431c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printed = 0;
4441c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_line = last_line = 1;
4451c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_col = last_col = 1;
4461c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
447b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor  file = clang_getFile(TU, source_file);
4481c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  while (!feof(fp)) {
449a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    size_t len = 0;
450a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    int c;
451a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
452a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    while ((c = fgetc(fp)) != EOF) {
453a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      len++;
454a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      if (c == '\n')
455a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer        break;
456a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    }
457a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
4581c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    ++line;
4591c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4601c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    for (i = 0; i < len ; ++i) {
4611c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      CXCursor cursor;
462b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, i+1));
4631c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4641c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      if (!clang_equalCursors(cursor, prevCursor) &&
4651c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek          prevCursor.kind != CXCursor_InvalidFile) {
4661c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        print_cursor_file_scan(prevCursor, start_line, start_col,
4671d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                               last_line, last_col, prefix);
4681c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 1;
4691c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_line = line;
4701c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_col = (unsigned) i+1;
4711c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
4721c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      else {
4731c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 0;
4741c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
4751c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4761c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      prevCursor = cursor;
4771c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_line = line;
4781c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_col = (unsigned) i+1;
4791c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    }
4801c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4811c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4821c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
4831c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    print_cursor_file_scan(prevCursor, start_line, start_col,
4841d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                           last_line, last_col, prefix);
4851c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4861c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4871c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  fclose(fp);
4881c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 0;
4891c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
4901c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4911c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
4920d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_codeComplete().                                    */
4930d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
4940d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
4950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor/* Parse file:line:column from the input string. Returns 0 on success, non-zero
4960c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   on failure. If successful, the pointer *filename will contain newly-allocated
4970c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   memory (that will be owned by the caller) to store the file name. */
4980c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorint parse_file_line_column(const char *input, char **filename, unsigned *line,
499fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                           unsigned *column, unsigned *second_line,
500fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                           unsigned *second_column) {
50188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the second colon. */
502fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  const char *last_colon = strrchr(input, ':');
503fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned values[4], i;
504fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned num_values = (second_line && second_column)? 4 : 2;
505fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
5060c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *endptr = 0;
507fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (!last_colon || last_colon == input) {
508fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    if (num_values == 4)
509fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      fprintf(stderr, "could not parse filename:line:column:line:column in "
510fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor              "'%s'\n", input);
511fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    else
512fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
5130c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
5140c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
5150c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
516fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  for (i = 0; i != num_values; ++i) {
517fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    const char *prev_colon;
51888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
519fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    /* Parse the next line or column. */
520fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    values[num_values - i - 1] = strtol(last_colon + 1, &endptr, 10);
521fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    if (*endptr != 0 && *endptr != ':') {
522fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      fprintf(stderr, "could not parse %s in '%s'\n",
523fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor              (i % 2 ? "column" : "line"), input);
524fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      return 1;
525fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    }
526fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
527fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    if (i + 1 == num_values)
528fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      break;
52988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
530fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    /* Find the previous colon. */
531fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    prev_colon = last_colon - 1;
532fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    while (prev_colon != input && *prev_colon != ':')
533fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      --prev_colon;
534fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    if (prev_colon == input) {
535fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      fprintf(stderr, "could not parse %s in '%s'\n",
536fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor              (i % 2 == 0? "column" : "line"), input);
537fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor      return 1;
538fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    }
539fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
540fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    last_colon = prev_colon;
5410c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
542fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
543fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  *line = values[0];
544fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  *column = values[1];
5450c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
546fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (second_line && second_column) {
547fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    *second_line = values[2];
548fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    *second_column = values[3];
549fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
550fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
55188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Copy the file name. */
552fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  *filename = (char*)malloc(last_colon - input + 1);
553fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  memcpy(*filename, input, last_colon - input);
554fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  (*filename)[last_colon - input] = 0;
5550c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return 0;
5560c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5570c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5580c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorconst char *
5590c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorclang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
5600c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  switch (Kind) {
5610c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Optional: return "Optional";
5620c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_TypedText: return "TypedText";
5630c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Text: return "Text";
5640c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Placeholder: return "Placeholder";
5650c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Informative: return "Informative";
5660c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
5670c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftParen: return "LeftParen";
5680c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightParen: return "RightParen";
5690c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBracket: return "LeftBracket";
5700c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBracket: return "RightBracket";
5710c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBrace: return "LeftBrace";
5720c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBrace: return "RightBrace";
5730c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftAngle: return "LeftAngle";
5740c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightAngle: return "RightAngle";
5750c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Comma: return "Comma";
576ff5ce6eefc7c253ef6edf4d4bfc996fdd82d09aaDouglas Gregor  case CXCompletionChunk_ResultType: return "ResultType";
57701dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Colon: return "Colon";
57801dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_SemiColon: return "SemiColon";
57901dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Equal: return "Equal";
58001dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
58101dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
5820c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
5830c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5840c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return "Unknown";
5850c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5860c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5873ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_string(CXCompletionString completion_string, FILE *file) {
588f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  int I, N;
5893ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
5903ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  N = clang_getNumCompletionChunks(completion_string);
5910c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  for (I = 0; I != N; ++I) {
592d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    const char *text = 0;
5930c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    enum CXCompletionChunkKind Kind
5943ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      = clang_getCompletionChunkKind(completion_string, I);
5953ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
5963ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    if (Kind == CXCompletionChunk_Optional) {
5973ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "{Optional ");
5983ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      print_completion_string(
5993ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                clang_getCompletionChunkCompletionString(completion_string, I),
6003ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                              file);
6013ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "}");
6023ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      continue;
6033ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    }
6043ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
605d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    text = clang_getCompletionChunkText(completion_string, I);
6060c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(file, "{%s %s}",
6070c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            clang_getCompletionChunkKindSpelling(Kind),
6080c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            text? text : "");
6090c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
6103ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor}
6113ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
6123ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_result(CXCompletionResult *completion_result,
6133ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                             CXClientData client_data) {
6143ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  FILE *file = (FILE *)client_data;
6153ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  fprintf(file, "%s:",
6163ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor          clang_getCursorKindSpelling(completion_result->CursorKind));
6173ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  print_completion_string(completion_result->CompletionString, file);
6180c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  fprintf(file, "\n");
6190c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
6200c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
621f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint perform_code_completion(int argc, const char **argv) {
6220c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  const char *input = argv[1];
6230c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *filename = 0;
6240c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned line;
6250c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned column;
626f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CXIndex CIdx;
627f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  int errorCode;
628735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
629735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int num_unsaved_files = 0;
630ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  CXCodeCompleteResults *results = 0;
631f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar
6320c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  input += strlen("-code-completion-at=");
633fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
634fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                          0, 0)))
635f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return errorCode;
6360c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
637735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
638735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return -1;
639735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
640f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CIdx = clang_createIndex(0, 0);
641ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  results = clang_codeComplete(CIdx,
642ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv[argc - 1], argc - num_unsaved_files - 3,
643ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv + num_unsaved_files + 2,
644ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               num_unsaved_files, unsaved_files,
645ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               filename, line, column);
646ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  if (results) {
647ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    unsigned i, n = results->NumResults;
648ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    for (i = 0; i != n; ++i)
649ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor      print_completion_result(results->Results + i, stdout);
650ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    clang_disposeCodeCompleteResults(results);
651ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  }
652ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor
6530c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  clang_disposeIndex(CIdx);
6540c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  free(filename);
655f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
656735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
657735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
658f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  return 0;
6590c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
6600c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
661f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregortypedef struct {
662f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  char *filename;
663f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned line;
664f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned column;
665f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor} CursorSourceLocation;
666f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
667f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregorint inspect_cursor_at(int argc, const char **argv) {
668f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXIndex CIdx;
669f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int errorCode;
670f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
671f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int num_unsaved_files = 0;
672f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXTranslationUnit TU;
673f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXCursor Cursor;
674f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CursorSourceLocation *Locations = 0;
675f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned NumLocations = 0, Loc;
6764db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
677f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Count the number of locations. */
678f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
679f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    ++NumLocations;
680f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
681f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Parse the locations. */
682f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  assert(NumLocations > 0 && "Unable to count locations?");
683f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  Locations = (CursorSourceLocation *)malloc(
684f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  NumLocations * sizeof(CursorSourceLocation));
685f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
686f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    const char *input = argv[Loc + 1] + strlen("-cursor-at=");
687f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
688f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                            &Locations[Loc].line,
689fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                            &Locations[Loc].column, 0, 0)))
690f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor      return errorCode;
691f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
692f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
693f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
694f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                           &num_unsaved_files))
695f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
696f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
697f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CIdx = clang_createIndex(0, 1);
698f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
699f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  argc - num_unsaved_files - 2 - NumLocations,
7004db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                   argv + num_unsaved_files + 1 + NumLocations,
7014db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 num_unsaved_files,
7024db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 unsaved_files);
703f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (!TU) {
704f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    fprintf(stderr, "unable to parse input\n");
705f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
706f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
707f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
708f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
709b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    CXFile file = clang_getFile(TU, Locations[Loc].filename);
710b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    if (!file)
711b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      continue;
712b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor
713b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    Cursor = clang_getCursor(TU,
714b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor                             clang_getLocation(TU, file, Locations[Loc].line,
715b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor                                               Locations[Loc].column));
716f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    PrintCursor(Cursor);
717f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    printf("\n");
718f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    free(Locations[Loc].filename);
719f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
720f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
721f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeTranslationUnit(TU);
722f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeIndex(CIdx);
723f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free(Locations);
724f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
725f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  return 0;
726f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor}
727f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
728fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregorint perform_token_annotation(int argc, const char **argv) {
729fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  const char *input = argv[1];
730fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  char *filename = 0;
731fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned line, second_line;
732fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned column, second_column;
733fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXIndex CIdx;
734fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXTranslationUnit TU = 0;
735fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  int errorCode;
736fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
737fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  int num_unsaved_files = 0;
738fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXToken *tokens;
739fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned num_tokens;
740fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXSourceRange range;
741fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXSourceLocation startLoc, endLoc;
742fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXFile file = 0;
743fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CXCursor *cursors = 0;
744fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  unsigned i;
745fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
746fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  input += strlen("-test-annotate-tokens=");
747fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if ((errorCode = parse_file_line_column(input, &filename, &line, &column,
748fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                          &second_line, &second_column)))
749fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    return errorCode;
750fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
751fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
752fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    return -1;
753fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
754fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  CIdx = clang_createIndex(0, 0);
755fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
756fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                                 argc - num_unsaved_files - 3,
757fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                                 argv + num_unsaved_files + 2,
758fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                                 num_unsaved_files,
759fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                                 unsaved_files);
760fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (!TU) {
761fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    fprintf(stderr, "unable to parse input\n");
762fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    clang_disposeIndex(CIdx);
763fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    free(filename);
764fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    free_remapped_files(unsaved_files, num_unsaved_files);
765fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    return -1;
766fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
767fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  errorCode = 0;
768fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
769fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  file = clang_getFile(TU, filename);
770fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (!file) {
771fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    fprintf(stderr, "file %s is not in this translation unit\n", filename);
772fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    errorCode = -1;
773fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    goto teardown;
774fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
775fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
776fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  startLoc = clang_getLocation(TU, file, line, column);
777fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (clang_equalLocations(clang_getNullLocation(), startLoc)) {
778fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    fprintf(stderr, "invalid source location %s:%d:%d\n", filename, line,
779fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor            column);
780fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    errorCode = -1;
781fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    goto teardown;
782fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
783fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
784fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  endLoc = clang_getLocation(TU, file, second_line, second_column);
785fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  if (clang_equalLocations(clang_getNullLocation(), endLoc)) {
786fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    fprintf(stderr, "invalid source location %s:%d:%d\n", filename,
787fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor            second_line, second_column);
788fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    errorCode = -1;
789fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    goto teardown;
790fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
791fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
792fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  range = clang_getRange(startLoc, endLoc);
793fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  clang_tokenize(TU, range, &tokens, &num_tokens);
794fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  cursors = (CXCursor *)malloc(num_tokens * sizeof(CXCursor));
795fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  clang_annotateTokens(TU, tokens, num_tokens, cursors);
796fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  for (i = 0; i != num_tokens; ++i) {
797fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    const char *kind = "<unknown>";
798fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    CXString spelling = clang_getTokenSpelling(TU, tokens[i]);
799fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    CXSourceRange extent = clang_getTokenExtent(TU, tokens[i]);
800fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    unsigned start_line, start_column, end_line, end_column;
801fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
802fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    switch (clang_getTokenKind(tokens[i])) {
803fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    case CXToken_Punctuation: kind = "Punctuation"; break;
804fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    case CXToken_Keyword: kind = "Keyword"; break;
805fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    case CXToken_Identifier: kind = "Identifier"; break;
806fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    case CXToken_Literal: kind = "Literal"; break;
807fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    case CXToken_Comment: kind = "Comment"; break;
808fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    }
809fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    clang_getInstantiationLocation(clang_getRangeStart(extent),
810fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                   0, &start_line, &start_column);
811fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    clang_getInstantiationLocation(clang_getRangeEnd(extent),
812fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor                                   0, &end_line, &end_column);
813fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    printf("%s: \"%s\" [%d:%d - %d:%d]\n", kind, clang_getCString(spelling),
814fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor           start_line, start_column, end_line, end_column);
815fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  }
816fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  free(cursors);
817fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
818fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor teardown:
819fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  clang_disposeTranslationUnit(TU);
820fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  clang_disposeIndex(CIdx);
821fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  free(filename);
822fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
823fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  return errorCode;
824fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor}
825fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor
8260d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
8270d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Command line processing.                                                   */
8280d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
829f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
830e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorstatic CXCursorVisitor GetVisitor(const char *s) {
8317d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (s[0] == '\0')
832e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return FilteredPrintingVisitor;
8337d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (strcmp(s, "-usrs") == 0)
8347d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    return USRVisitor;
8357d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  return NULL;
8367d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
8377d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
838f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekstatic void print_usage(void) {
839f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  fprintf(stderr,
8400d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
841f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    "       c-index-test -cursor-at=<site> <compiler arguments>\n"
8421d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    "       c-index-test -test-file-scan <AST file> <source file> "
8431d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          "[FileCheck prefix]\n"
844fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    "       c-index-test -test-load-tu <AST file> <symbol filter> "
845fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek          "[FileCheck prefix]\n"
8467d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
8477d40562f83552b7295411e10ee887d8d55470679Ted Kremenek           "[FileCheck prefix]\n"
8487d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-source <symbol filter> {<args>}*\n"
849fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    "       c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n");
850f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  fprintf(stderr,
851fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    "       c-index-test -test-annotate-tokens=<range> {<args>}* \n\n"
8527d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    " <symbol filter> values:\n%s",
8530d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   all - load all symbols, including those from PCH\n"
8540d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   local - load all symbols except those in PCH\n"
8550d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   category - only load ObjC categories (non-PCH)\n"
8560d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   interface - only load ObjC interfaces (non-PCH)\n"
8570d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   protocol - only load ObjC protocols (non-PCH)\n"
8580d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   function - only load functions (non-PCH)\n"
859625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   typedef - only load typdefs (non-PCH)\n"
860625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   scan-function - scan function bodies (non-PCH)\n\n");
861f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek}
862f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
863f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint main(int argc, const char **argv) {
864f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
865f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_code_completion(argc, argv);
866f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
867f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return inspect_cursor_at(argc, argv);
8687d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
869e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    CXCursorVisitor I = GetVisitor(argv[1] + 13);
8707d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
871ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek      return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I,
872ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek                                  NULL);
8737d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
8747d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
875e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    CXCursorVisitor I = GetVisitor(argv[1] + 17);
8767d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
877ce2ae88f834c740a28b7e074a4477039918f9bb0Ted Kremenek      return perform_test_load_source(argc - 3, argv + 3, argv[2], I, NULL);
8787d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
8797d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
8801d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    return perform_file_scan(argv[2], argv[3],
8811d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             argc >= 5 ? argv[4] : 0);
882fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor  else if (argc > 2 && strstr(argv[1], "-test-annotate-tokens=") == argv[1])
883fc8ea23eb6cbaaa5046f2abb4c033e24c8659efdDouglas Gregor    return perform_token_annotation(argc, argv);
884f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  print_usage();
88550398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff  return 1;
88650398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff}
887