c-index-test.c revision 4db64a461cb3442934afe43c83ed3f17f7c11c1d
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/******************************************************************************/
175e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor/* Logic for testing traversal.                                               */
1760d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
1770d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
178fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekstatic const char *FileCheckPrefix = "CHECK";
179fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
180a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregorstatic void PrintCursorExtent(CXCursor C) {
181a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor  CXSourceRange extent = clang_getCursorExtent(C);
1821db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  CXFile begin_file, end_file;
1831db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  unsigned begin_line, begin_column, end_line, end_column;
1841db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor
1851db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  clang_getInstantiationLocation(clang_getRangeStart(extent),
1861db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor                                 &begin_file, &begin_line, &begin_column);
1871db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  clang_getInstantiationLocation(clang_getRangeEnd(extent),
1881db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor                                 &end_file, &end_line, &end_column);
1891db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  if (!begin_file || !end_file)
19070ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    return;
1911db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor
1921db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor  printf(" [Extent=%d:%d:%d:%d]", begin_line, begin_column,
1931db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor         end_line, end_column);
194fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek}
195fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
196e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor/* Data used by all of the visitors. */
197e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregortypedef struct  {
198e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  CXTranslationUnit TU;
199e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  enum CXCursorKind *Filter;
200e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor} VisitorData;
201fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
202625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
203e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorenum CXChildVisitResult FilteredPrintingVisitor(CXCursor Cursor,
204e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                CXCursor Parent,
205e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                CXClientData ClientData) {
206e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
207e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  if (!Data->Filter || (Cursor.kind == *(enum CXCursorKind *)Data->Filter)) {
20898258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    CXSourceLocation Loc = clang_getCursorLocation(Cursor);
2091db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    unsigned line, column;
2101db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    clang_getInstantiationLocation(Loc, 0, &line, &column);
211fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf("// %s: %s:%d:%d: ", FileCheckPrefix,
2121db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor           GetCursorSource(Cursor), line, column);
213af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
214a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor    PrintCursorExtent(Cursor);
21570ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    printf("\n");
216e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Recurse;
217625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  }
218e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
219e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
220625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
221c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff
222e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorstatic enum CXChildVisitResult FunctionScanVisitor(CXCursor Cursor,
223e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                   CXCursor Parent,
224e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                                   CXClientData ClientData) {
225625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  const char *startBuf, *endBuf;
226625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
227625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXCursor Ref;
228e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
229625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
230b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor  if (Cursor.kind != CXCursor_FunctionDecl ||
231b699866820102a69d83d6ac6941985c5ef4e8c40Douglas Gregor      !clang_isCursorDefinition(Cursor))
232e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Continue;
233625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
234625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
235625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &startLine, &startColumn,
236625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &endLine, &endColumn);
237625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  /* Probe the entire body, looking for both decls and refs. */
238625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curLine = startLine;
239625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curColumn = startColumn;
240625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
241625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  while (startBuf < endBuf) {
24298258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    CXSourceLocation Loc;
2431db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    CXFile file;
24498258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    const char *source = 0;
24598258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor
246625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (*startBuf == '\n') {
247625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      startBuf++;
248625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curLine++;
249625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn = 1;
250625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (*startBuf != '\t')
251625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn++;
252fbcb2b716bee88c754684bd189913ed9f8c09086Ted Kremenek
25398258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    Loc = clang_getCursorLocation(Cursor);
2541db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    clang_getInstantiationLocation(Loc, &file, 0, 0);
2551db19dea8d221f27be46332d668d1e2decb7f1abDouglas Gregor    source = clang_getFileName(file);
25698258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor    if (source) {
257b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      CXSourceLocation RefLoc
258b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor        = clang_getLocation(Data->TU, file, curLine, curColumn);
259b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      Ref = clang_getCursor(Data->TU, RefLoc);
26098258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      if (Ref.kind == CXCursor_NoDeclFound) {
26198258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        /* Nothing found here; that's fine. */
26298258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      } else if (Ref.kind != CXCursor_FunctionDecl) {
26398258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
26498258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor               curLine, curColumn);
26598258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        PrintCursor(Ref);
26698258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor        printf("\n");
26798258afae66bab39b0c57a3efb6b20d4fbb5746cDouglas Gregor      }
2684ade6d6eae934f796ca43c81a5aa185e456dde9bSteve Naroff    }
269625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    startBuf++;
2702d4d629d8a0de5112c7ae9d05c03ddbf6dcd956aSteve Naroff  }
271e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
272e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
27389922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff}
27450398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
2757d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
2767d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* USR testing.                                                               */
2777d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
2787d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
279e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorenum CXChildVisitResult USRVisitor(CXCursor C, CXCursor parent,
280e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                                   CXClientData ClientData) {
281e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData *Data = (VisitorData *)ClientData;
282e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  if (!Data->Filter || (C.kind == *(enum CXCursorKind *)Data->Filter)) {
283cf84aa46def41cccf4dd4c51cd0543b70c11e4ebTed Kremenek    CXString USR = clang_getCursorUSR(C);
2847d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (!USR.Spelling) {
2857d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      clang_disposeString(USR);
286e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor      return CXChildVisit_Continue;
2877d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    }
2887d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling);
289a7bde20f8c6334ccc3a7ef4dd77243d0921a8497Douglas Gregor    PrintCursorExtent(C);
2907d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("\n");
2917d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    clang_disposeString(USR);
292e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
293e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return CXChildVisit_Recurse;
294e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  }
295e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
296e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  return CXChildVisit_Continue;
2977d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
2987d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
2997d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
3007d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* Loading ASTs/source.                                                       */
3017d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
3027d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
303625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
30498271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                             const char *filter, const char *prefix,
305e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                             CXCursorVisitor Visitor) {
3060d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind K = CXCursor_NotImplemented;
3070d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind *ck = &K;
308e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  VisitorData Data;
309e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor
310fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek  if (prefix)
311fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    FileCheckPrefix = prefix;
312fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
3130d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  /* Perform some simple filtering. */
3140d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
3150d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
3160d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
3170d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
3180d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
3190d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
320625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
3210d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else {
3220d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
3230d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    return 1;
3240d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  }
3250d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
326e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  Data.TU = TU;
327e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor  Data.Filter = ck;
328b2cd48756119f4d8d2a865b4b3e0e8efd02e26a0Douglas Gregor  clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data);
3290d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  clang_disposeTranslationUnit(TU);
3300d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  return 0;
3310d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek}
3320d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
333fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekint perform_test_load_tu(const char *file, const char *filter,
33498271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                         const char *prefix,
335e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                         CXCursorVisitor Visitor) {
336625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXIndex Idx;
337625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXTranslationUnit TU;
338625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
339625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
340625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          /* displayDiagnostics */ 1);
341625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
342625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (!CreateTranslationUnit(Idx, file, &TU))
343625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return 1;
344625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
34598271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek  return perform_test_load(Idx, TU, filter, prefix, Visitor);
346625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
347625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
34898271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenekint perform_test_load_source(int argc, const char **argv, const char *filter,
349e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor                             CXCursorVisitor Visitor) {
3508506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  const char *UseExternalASTs =
3518506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
352ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXIndex Idx;
353ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXTranslationUnit TU;
3544db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
3554db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int num_unsaved_files = 0;
3564db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  int result;
3574db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
358ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
359ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
360ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          /* displayDiagnostics */ 1);
361ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
3628506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  if (UseExternalASTs && strlen(UseExternalASTs))
3638506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    clang_setUseExternalASTGeneration(Idx, 1);
3648506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar
3654db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files))
3664db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor    return -1;
3674db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
3684db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  TU = clang_createTranslationUnitFromSourceFile(Idx, 0,
3694db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 argc - num_unsaved_files,
3704db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 argv + num_unsaved_files,
3714db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 num_unsaved_files,
3724db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 unsaved_files);
373ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (!TU) {
374ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    fprintf(stderr, "Unable to load translation unit!\n");
375ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return 1;
376ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  }
377ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
3784db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  result = perform_test_load(Idx, TU, filter, NULL, Visitor);
3794db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
3804db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  return result;
381ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar}
382ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
3830d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
3841c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/* Logic for testing clang_getCursor().                                       */
3851c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
3861c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3871c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic void print_cursor_file_scan(CXCursor cursor,
3881c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                   unsigned start_line, unsigned start_col,
3891d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   unsigned end_line, unsigned end_col,
3901d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   const char *prefix) {
3919096a20fc0fd799911b738ce7a9134dbacaf64b7Ted Kremenek  printf("// %s: ", FileCheckPrefix);
3921d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (prefix)
3931d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    printf("-%s", prefix);
3941d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
3951d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          start_line, start_col, end_line, end_col);
3961c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  PrintCursor(cursor);
3971c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printf("\n");
3981c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
3991c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4001d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenekstatic int perform_file_scan(const char *ast_file, const char *source_file,
4011d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             const char *prefix) {
4021c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXIndex Idx;
4031c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXTranslationUnit TU;
4041c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  FILE *fp;
4051c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned line;
4061c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXCursor prevCursor;
407b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor  CXFile file;
4081c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned printed;
4091c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned start_line, start_col, last_line, last_col;
4101c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  size_t i;
4111c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4121c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
4131c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                /* displayDiagnostics */ 1))) {
4141c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not create Index\n");
4151c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4161c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4171c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4181c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!CreateTranslationUnit(Idx, ast_file, &TU))
4191c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4201c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4211c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if ((fp = fopen(source_file, "r")) == NULL) {
4221c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not open '%s'\n", source_file);
4231c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
4241c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4251c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4261c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  line = 0;
4271c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  prevCursor = clang_getNullCursor();
4281c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printed = 0;
4291c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_line = last_line = 1;
4301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_col = last_col = 1;
4311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
432b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor  file = clang_getFile(TU, source_file);
4331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  while (!feof(fp)) {
434a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    size_t len = 0;
435a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    int c;
436a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
437a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    while ((c = fgetc(fp)) != EOF) {
438a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      len++;
439a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      if (c == '\n')
440a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer        break;
441a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    }
442a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
4431c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    ++line;
4441c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4451c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    for (i = 0; i < len ; ++i) {
4461c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      CXCursor cursor;
447b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      cursor = clang_getCursor(TU, clang_getLocation(TU, file, line, i+1));
4481c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4491c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      if (!clang_equalCursors(cursor, prevCursor) &&
4501c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek          prevCursor.kind != CXCursor_InvalidFile) {
4511c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        print_cursor_file_scan(prevCursor, start_line, start_col,
4521d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                               last_line, last_col, prefix);
4531c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 1;
4541c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_line = line;
4551c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_col = (unsigned) i+1;
4561c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
4571c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      else {
4581c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 0;
4591c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
4601c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4611c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      prevCursor = cursor;
4621c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_line = line;
4631c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_col = (unsigned) i+1;
4641c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    }
4651c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4661c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4671c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
4681c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    print_cursor_file_scan(prevCursor, start_line, start_col,
4691d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                           last_line, last_col, prefix);
4701c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
4711c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4721c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  fclose(fp);
4731c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 0;
4741c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
4751c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
4761c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
4770d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_codeComplete().                                    */
4780d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
4790d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
4800c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor/* Parse file:line:column from the input string. Returns 0 on success, non-zero
4810c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   on failure. If successful, the pointer *filename will contain newly-allocated
4820c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   memory (that will be owned by the caller) to store the file name. */
4830c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorint parse_file_line_column(const char *input, char **filename, unsigned *line,
4840c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                           unsigned *column) {
48588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the second colon. */
48688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  const char *second_colon = strrchr(input, ':'), *first_colon;
4870c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *endptr = 0;
48888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (!second_colon || second_colon == input) {
4890c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
4900c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
4910c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
4920c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
4930c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  /* Parse the column number. */
49488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *column = strtol(second_colon + 1, &endptr, 10);
4950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  if (*endptr != 0) {
4960c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse column in '%s'\n", input);
49788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
49888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
49988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
50088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the first colon. */
50188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  first_colon = second_colon - 1;
50288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  while (first_colon != input && *first_colon != ':')
50388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    --first_colon;
50488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (first_colon == input) {
50588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
50688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
50788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
50888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
50988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Parse the line number. */
51088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *line = strtol(first_colon + 1, &endptr, 10);
51188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (*endptr != ':') {
51288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
5130c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
5140c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
5150c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
51688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Copy the file name. */
51788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *filename = (char*)malloc(first_colon - input + 1);
51888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  memcpy(*filename, input, first_colon - input);
51988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  (*filename)[first_colon - input] = 0;
5200c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return 0;
5210c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5220c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5230c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorconst char *
5240c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorclang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
5250c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  switch (Kind) {
5260c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Optional: return "Optional";
5270c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_TypedText: return "TypedText";
5280c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Text: return "Text";
5290c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Placeholder: return "Placeholder";
5300c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Informative: return "Informative";
5310c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
5320c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftParen: return "LeftParen";
5330c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightParen: return "RightParen";
5340c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBracket: return "LeftBracket";
5350c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBracket: return "RightBracket";
5360c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBrace: return "LeftBrace";
5370c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBrace: return "RightBrace";
5380c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftAngle: return "LeftAngle";
5390c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightAngle: return "RightAngle";
5400c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Comma: return "Comma";
541ff5ce6eefc7c253ef6edf4d4bfc996fdd82d09aaDouglas Gregor  case CXCompletionChunk_ResultType: return "ResultType";
54201dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Colon: return "Colon";
54301dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_SemiColon: return "SemiColon";
54401dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Equal: return "Equal";
54501dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
54601dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
5470c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
5480c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5490c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return "Unknown";
5500c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5510c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5523ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_string(CXCompletionString completion_string, FILE *file) {
553f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  int I, N;
5543ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
5553ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  N = clang_getNumCompletionChunks(completion_string);
5560c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  for (I = 0; I != N; ++I) {
557d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    const char *text = 0;
5580c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    enum CXCompletionChunkKind Kind
5593ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      = clang_getCompletionChunkKind(completion_string, I);
5603ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
5613ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    if (Kind == CXCompletionChunk_Optional) {
5623ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "{Optional ");
5633ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      print_completion_string(
5643ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                clang_getCompletionChunkCompletionString(completion_string, I),
5653ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                              file);
5663ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "}");
5673ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      continue;
5683ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    }
5693ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
570d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    text = clang_getCompletionChunkText(completion_string, I);
5710c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(file, "{%s %s}",
5720c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            clang_getCompletionChunkKindSpelling(Kind),
5730c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            text? text : "");
5740c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
5753ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor}
5763ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
5773ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_result(CXCompletionResult *completion_result,
5783ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                             CXClientData client_data) {
5793ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  FILE *file = (FILE *)client_data;
5803ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  fprintf(file, "%s:",
5813ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor          clang_getCursorKindSpelling(completion_result->CursorKind));
5823ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  print_completion_string(completion_result->CompletionString, file);
5830c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  fprintf(file, "\n");
5840c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5850c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
586f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint perform_code_completion(int argc, const char **argv) {
5870c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  const char *input = argv[1];
5880c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *filename = 0;
5890c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned line;
5900c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned column;
591f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CXIndex CIdx;
592f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  int errorCode;
593735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
594735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int num_unsaved_files = 0;
595ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  CXCodeCompleteResults *results = 0;
596f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar
5970c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  input += strlen("-code-completion-at=");
598f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
599f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return errorCode;
6000c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
601735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
602735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return -1;
603735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
604f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CIdx = clang_createIndex(0, 0);
605ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  results = clang_codeComplete(CIdx,
606ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv[argc - 1], argc - num_unsaved_files - 3,
607ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv + num_unsaved_files + 2,
608ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               num_unsaved_files, unsaved_files,
609ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               filename, line, column);
610ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  if (results) {
611ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    unsigned i, n = results->NumResults;
612ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    for (i = 0; i != n; ++i)
613ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor      print_completion_result(results->Results + i, stdout);
614ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    clang_disposeCodeCompleteResults(results);
615ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  }
616ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor
6170c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  clang_disposeIndex(CIdx);
6180c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  free(filename);
619f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
620735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
621735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
622f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  return 0;
6230c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
6240c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
625f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregortypedef struct {
626f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  char *filename;
627f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned line;
628f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned column;
629f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor} CursorSourceLocation;
630f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
631f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregorint inspect_cursor_at(int argc, const char **argv) {
632f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXIndex CIdx;
633f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int errorCode;
634f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
635f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int num_unsaved_files = 0;
636f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXTranslationUnit TU;
637f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXCursor Cursor;
638f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CursorSourceLocation *Locations = 0;
639f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned NumLocations = 0, Loc;
6404db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
641f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Count the number of locations. */
642f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
643f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    ++NumLocations;
644f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
645f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Parse the locations. */
646f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  assert(NumLocations > 0 && "Unable to count locations?");
647f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  Locations = (CursorSourceLocation *)malloc(
648f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  NumLocations * sizeof(CursorSourceLocation));
649f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
650f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    const char *input = argv[Loc + 1] + strlen("-cursor-at=");
651f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
652f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                            &Locations[Loc].line,
653f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                            &Locations[Loc].column)))
654f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor      return errorCode;
655f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
656f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
657f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
658f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                           &num_unsaved_files))
659f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
660f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
661f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CIdx = clang_createIndex(0, 1);
662f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
663f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  argc - num_unsaved_files - 2 - NumLocations,
6644db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                   argv + num_unsaved_files + 1 + NumLocations,
6654db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 num_unsaved_files,
6664db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor                                                 unsaved_files);
667f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (!TU) {
668f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    fprintf(stderr, "unable to parse input\n");
669f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
670f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
671f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
672f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
673b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    CXFile file = clang_getFile(TU, Locations[Loc].filename);
674b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    if (!file)
675b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor      continue;
676b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor
677b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor    Cursor = clang_getCursor(TU,
678b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor                             clang_getLocation(TU, file, Locations[Loc].line,
679b979034b100be14de2223f2b8f6cc7a3275cbe4fDouglas Gregor                                               Locations[Loc].column));
680f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    PrintCursor(Cursor);
681f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    printf("\n");
682f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    free(Locations[Loc].filename);
683f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
684f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
685f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeTranslationUnit(TU);
686f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeIndex(CIdx);
687f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free(Locations);
688f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
689f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  return 0;
690f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor}
691f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
6920d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
6930d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Command line processing.                                                   */
6940d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
695f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
696e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregorstatic CXCursorVisitor GetVisitor(const char *s) {
6977d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (s[0] == '\0')
698e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    return FilteredPrintingVisitor;
6997d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (strcmp(s, "-usrs") == 0)
7007d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    return USRVisitor;
7017d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  return NULL;
7027d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
7037d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
704f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekstatic void print_usage(void) {
705f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  fprintf(stderr,
7060d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
707f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    "       c-index-test -cursor-at=<site> <compiler arguments>\n"
7081d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    "       c-index-test -test-file-scan <AST file> <source file> "
7091d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          "[FileCheck prefix]\n"
710fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    "       c-index-test -test-load-tu <AST file> <symbol filter> "
711fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek          "[FileCheck prefix]\n"
7127d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
7137d40562f83552b7295411e10ee887d8d55470679Ted Kremenek           "[FileCheck prefix]\n"
7147d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-source <symbol filter> {<args>}*\n"
715f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    "       c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n");
716f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  fprintf(stderr,
7177d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    " <symbol filter> values:\n%s",
7180d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   all - load all symbols, including those from PCH\n"
7190d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   local - load all symbols except those in PCH\n"
7200d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   category - only load ObjC categories (non-PCH)\n"
7210d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   interface - only load ObjC interfaces (non-PCH)\n"
7220d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   protocol - only load ObjC protocols (non-PCH)\n"
7230d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   function - only load functions (non-PCH)\n"
724625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   typedef - only load typdefs (non-PCH)\n"
725625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   scan-function - scan function bodies (non-PCH)\n\n");
726f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek}
727f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
728f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint main(int argc, const char **argv) {
729f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
730f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_code_completion(argc, argv);
731f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
732f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return inspect_cursor_at(argc, argv);
7337d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
734e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    CXCursorVisitor I = GetVisitor(argv[1] + 13);
7357d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
7367d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I);
7377d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
7387d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
739e5b72bac8312f83aeb2e29b3988ebfa30f2b4ca2Douglas Gregor    CXCursorVisitor I = GetVisitor(argv[1] + 17);
7407d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
7417d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      return perform_test_load_source(argc - 3, argv + 3, argv[2], I);
7427d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
7437d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
7441d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    return perform_file_scan(argv[2], argv[3],
7451d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             argc >= 5 ? argv[4] : 0);
746f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
747f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  print_usage();
74850398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff  return 1;
74950398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff}
750