c-index-test.c revision 8506dde586459887b7e14e23a30af8ac5be5adb6
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>
7af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff
80d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
90d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Utility functions.                                                         */
100d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
110d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
122e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#ifdef _MSC_VER
132e06fc877a633abea3b40a64950c7316dac29ca8John Thompsonchar *basename(const char* path)
142e06fc877a633abea3b40a64950c7316dac29ca8John Thompson{
152e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base1 = (char*)strrchr(path, '/');
162e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base2 = (char*)strrchr(path, '\\');
172e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    if (base1 && base2)
182e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return((base1 > base2) ? base1 + 1 : base2 + 1);
192e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base1)
202e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base1 + 1);
212e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base2)
222e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base2 + 1);
232e06fc877a633abea3b40a64950c7316dac29ca8John Thompson
242e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    return((char*)path);
252e06fc877a633abea3b40a64950c7316dac29ca8John Thompson}
262e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#else
27ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroffextern char *basename(const char *);
282e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#endif
29ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff
301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                      CXTranslationUnit *TU) {
321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  *TU = clang_createTranslationUnit(Idx, file);
341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!TU) {
351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 0;
371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 1;
391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
410d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
420d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Pretty-printing.                                                           */
430d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
440d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
45af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroffstatic void PrintCursor(CXCursor Cursor) {
4677128ddd3077fc045751a55bb3226802b15d5510Steve Naroff  if (clang_isInvalid(Cursor.kind))
471c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind));
48699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  else {
49f393c3b770c86446b20e6fd4bcf08a31442d1b1dEric Christopher    CXDecl DeclReferenced;
50ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
51ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getCursorSpelling(Cursor);
52ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff    printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
53ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff                      clang_getCString(string));
54ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
55f393c3b770c86446b20e6fd4bcf08a31442d1b1dEric Christopher    DeclReferenced = clang_getCursorDecl(Cursor);
5685e2db72137c28114d3981c044946a8c16ef6011Steve Naroff    if (DeclReferenced)
5785e2db72137c28114d3981c044946a8c16ef6011Steve Naroff      printf(":%d:%d", clang_getDeclLine(DeclReferenced),
5885e2db72137c28114d3981c044946a8c16ef6011Steve Naroff                       clang_getDeclColumn(DeclReferenced));
59699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  }
60af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff}
6189922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff
629298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenekstatic const char* GetCursorSource(CXCursor Cursor) {
639298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  const char *source = clang_getCursorSource(Cursor);
649298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  if (!source)
659298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek    return "<invalid loc>";
669298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  return basename(source);
679298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek}
689298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek
690d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
700d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_loadTranslationUnit().                             */
710d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
720d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
73625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) {
74bce6f62ae7d2c15992617f64e30067803fb5b47fDaniel Dunbar  if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
75ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
769298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek    printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
77ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff                                 clang_getCursorLine(Cursor),
78ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff                                 clang_getCursorColumn(Cursor));
79af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
80ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getDeclSpelling(Dcl);
81ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    printf(" [Context=%s]\n", clang_getCString(string));
82ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
83bce6f62ae7d2c15992617f64e30067803fb5b47fDaniel Dunbar  }
84c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff}
85625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
86c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroffstatic void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
87625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                   CXClientData Filter) {
88c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff  if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
89ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
909298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek    printf("// CHECK: %s:%d:%d: ", GetCursorSource(Cursor),
91ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff                                 clang_getCursorLine(Cursor),
92ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff                                 clang_getCursorColumn(Cursor));
93af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
94ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getTranslationUnitSpelling(Unit);
95ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    printf(" [Context=%s]\n",
96ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff          basename(clang_getCString(string)));
97ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
98ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff
99ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff    clang_loadDeclaration(Cursor.decl, DeclVisitor, 0);
100625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  }
101625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
102c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff
103625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
104625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                CXClientData Filter) {
105625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  const char *startBuf, *endBuf;
106625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
107625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXCursor Ref;
108625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
109625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (Cursor.kind != CXCursor_FunctionDefn)
110625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return;
111625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
112625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
113625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &startLine, &startColumn,
114625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &endLine, &endColumn);
115625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  /* Probe the entire body, looking for both decls and refs. */
116625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curLine = startLine;
117625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curColumn = startColumn;
118625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
119625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  while (startBuf < endBuf) {
120625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (*startBuf == '\n') {
121625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      startBuf++;
122625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curLine++;
123625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn = 1;
124625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (*startBuf != '\t')
125625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn++;
126fbcb2b716bee88c754684bd189913ed9f8c09086Ted Kremenek
127625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
128625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          curLine, curColumn);
129625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (Ref.kind == CXCursor_NoDeclFound) {
130625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      /* Nothing found here; that's fine. */
131625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (Ref.kind != CXCursor_FunctionDecl) {
132625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      CXString string;
133625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      printf("// CHECK: %s:%d:%d: ", GetCursorSource(Ref),
134625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar             curLine, curColumn);
135625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      PrintCursor(Ref);
136625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      string = clang_getDeclSpelling(Ref.decl);
137625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      printf(" [Context:%s]\n", clang_getCString(string));
138625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      clang_disposeString(string);
1394ade6d6eae934f796ca43c81a5aa185e456dde9bSteve Naroff    }
140625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    startBuf++;
1412d4d629d8a0de5112c7ae9d05c03ddbf6dcd956aSteve Naroff  }
14289922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff}
14350398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
144625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
145625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                             const char *filter) {
1460d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind K = CXCursor_NotImplemented;
147625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXTranslationUnitIterator Visitor = TranslationUnitVisitor;
1480d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind *ck = &K;
149625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
1500d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  /* Perform some simple filtering. */
1510d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
1520d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
1530d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
1540d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
1550d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
1560d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
157625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
1580d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else {
1590d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
1600d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    return 1;
1610d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  }
1620d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
163625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_loadTranslationUnit(TU, Visitor, ck);
1640d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  clang_disposeTranslationUnit(TU);
1650d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  return 0;
1660d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek}
1670d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
168625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarint perform_test_load_tu(const char *file, const char *filter) {
169625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXIndex Idx;
170625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXTranslationUnit TU;
171625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
172625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
173625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          /* displayDiagnostics */ 1);
174625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
175625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (!CreateTranslationUnit(Idx, file, &TU))
176625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return 1;
177625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
178625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  return perform_test_load(Idx, TU, filter);
179625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
180625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
181ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbarint perform_test_load_source(int argc, const char **argv, const char *filter) {
1828506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  const char *UseExternalASTs =
1838506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
184ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXIndex Idx;
185ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXTranslationUnit TU;
186ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
187ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
188ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          /* displayDiagnostics */ 1);
189ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
1908506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  if (UseExternalASTs && strlen(UseExternalASTs))
1918506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    clang_setUseExternalASTGeneration(Idx, 1);
1928506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar
193ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv);
194ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (!TU) {
195ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    fprintf(stderr, "Unable to load translation unit!\n");
196ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return 1;
197ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  }
198ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
199625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  return perform_test_load(Idx, TU, filter);
200ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar}
201ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
2020d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
2031c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/* Logic for testing clang_getCursor().                                       */
2041c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
2051c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2061c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic void print_cursor_file_scan(CXCursor cursor,
2071c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                   unsigned start_line, unsigned start_col,
2081d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   unsigned end_line, unsigned end_col,
2091d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   const char *prefix) {
2101d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("// CHECK");
2111d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (prefix)
2121d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    printf("-%s", prefix);
2131d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
2141d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          start_line, start_col, end_line, end_col);
2151c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  PrintCursor(cursor);
2161c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printf("\n");
2171c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
2181c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2191d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenekstatic int perform_file_scan(const char *ast_file, const char *source_file,
2201d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             const char *prefix) {
2211c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXIndex Idx;
2221c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXTranslationUnit TU;
2231c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  FILE *fp;
2241c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned line;
2251c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXCursor prevCursor;
2261c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned printed;
2271c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned start_line, start_col, last_line, last_col;
2281c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  size_t i;
2291c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
2311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                /* displayDiagnostics */ 1))) {
2321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not create Index\n");
2331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!CreateTranslationUnit(Idx, ast_file, &TU))
2371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if ((fp = fopen(source_file, "r")) == NULL) {
2401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not open '%s'\n", source_file);
2411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2421c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2431c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2441c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  line = 0;
2451c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  prevCursor = clang_getNullCursor();
2461c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printed = 0;
2471c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_line = last_line = 1;
2481c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_col = last_col = 1;
2491c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2501c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  while (!feof(fp)) {
251a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    size_t len = 0;
252a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    int c;
253a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
254a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    while ((c = fgetc(fp)) != EOF) {
255a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      len++;
256a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      if (c == '\n')
257a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer        break;
258a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    }
259a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
2601c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    ++line;
2611c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2621c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    for (i = 0; i < len ; ++i) {
2631c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      CXCursor cursor;
2641c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      cursor = clang_getCursor(TU, source_file, line, i+1);
2651c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2661c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      if (!clang_equalCursors(cursor, prevCursor) &&
2671c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek          prevCursor.kind != CXCursor_InvalidFile) {
2681c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        print_cursor_file_scan(prevCursor, start_line, start_col,
2691d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                               last_line, last_col, prefix);
2701c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 1;
2711c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_line = line;
2721c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_col = (unsigned) i+1;
2731c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
2741c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      else {
2751c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 0;
2761c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
2771c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2781c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      prevCursor = cursor;
2791c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_line = line;
2801c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_col = (unsigned) i+1;
2811c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    }
2821c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2831c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2841c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
2851c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    print_cursor_file_scan(prevCursor, start_line, start_col,
2861d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                           last_line, last_col, prefix);
2871c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2881c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2891c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  fclose(fp);
2901c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 0;
2911c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
2921c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2931c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
2940d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_codeComplete().                                    */
2950d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
2960d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
2970c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor/* Parse file:line:column from the input string. Returns 0 on success, non-zero
2980c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   on failure. If successful, the pointer *filename will contain newly-allocated
2990c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   memory (that will be owned by the caller) to store the file name. */
3000c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorint parse_file_line_column(const char *input, char **filename, unsigned *line,
3010c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                           unsigned *column) {
30288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the second colon. */
30388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  const char *second_colon = strrchr(input, ':'), *first_colon;
3040c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *endptr = 0;
30588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (!second_colon || second_colon == input) {
3060c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
3070c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3080c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3090c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3100c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  /* Parse the column number. */
31188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *column = strtol(second_colon + 1, &endptr, 10);
3120c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  if (*endptr != 0) {
3130c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse column in '%s'\n", input);
31488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
31588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
31688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
31788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the first colon. */
31888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  first_colon = second_colon - 1;
31988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  while (first_colon != input && *first_colon != ':')
32088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    --first_colon;
32188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (first_colon == input) {
32288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
32388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
32488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
32588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
32688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Parse the line number. */
32788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *line = strtol(first_colon + 1, &endptr, 10);
32888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (*endptr != ':') {
32988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
3300c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3310c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3320c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
33388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Copy the file name. */
33488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *filename = (char*)malloc(first_colon - input + 1);
33588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  memcpy(*filename, input, first_colon - input);
33688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  (*filename)[first_colon - input] = 0;
3370c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return 0;
3380c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3390c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3400c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorconst char *
3410c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorclang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
3420c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  switch (Kind) {
3430c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Optional: return "Optional";
3440c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_TypedText: return "TypedText";
3450c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Text: return "Text";
3460c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Placeholder: return "Placeholder";
3470c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Informative: return "Informative";
3480c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
3490c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftParen: return "LeftParen";
3500c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightParen: return "RightParen";
3510c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBracket: return "LeftBracket";
3520c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBracket: return "RightBracket";
3530c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBrace: return "LeftBrace";
3540c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBrace: return "RightBrace";
3550c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftAngle: return "LeftAngle";
3560c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightAngle: return "RightAngle";
3570c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Comma: return "Comma";
3580c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3590c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3600c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return "Unknown";
3610c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3620c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3633ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_string(CXCompletionString completion_string, FILE *file) {
364f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  int I, N;
3653ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3663ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  N = clang_getNumCompletionChunks(completion_string);
3670c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  for (I = 0; I != N; ++I) {
368d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    const char *text = 0;
3690c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    enum CXCompletionChunkKind Kind
3703ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      = clang_getCompletionChunkKind(completion_string, I);
3713ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3723ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    if (Kind == CXCompletionChunk_Optional) {
3733ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "{Optional ");
3743ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      print_completion_string(
3753ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                clang_getCompletionChunkCompletionString(completion_string, I),
3763ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                              file);
3773ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "}");
3783ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      continue;
3793ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    }
3803ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
381d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    text = clang_getCompletionChunkText(completion_string, I);
3820c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(file, "{%s %s}",
3830c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            clang_getCompletionChunkKindSpelling(Kind),
3840c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            text? text : "");
3850c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3863ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor}
3873ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3883ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_result(CXCompletionResult *completion_result,
3893ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                             CXClientData client_data) {
3903ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  FILE *file = (FILE *)client_data;
3913ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  fprintf(file, "%s:",
3923ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor          clang_getCursorKindSpelling(completion_result->CursorKind));
3933ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  print_completion_string(completion_result->CompletionString, file);
3940c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  fprintf(file, "\n");
3950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3960c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
397735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorvoid free_remapped_files(struct CXUnsavedFile *unsaved_files,
398735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         int num_unsaved_files) {
399735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
400735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (i = 0; i != num_unsaved_files; ++i) {
401735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Filename);
402735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Contents);
403735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
404735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
405735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
406735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorint parse_remapped_files(int argc, const char **argv, int start_arg,
407735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         struct CXUnsavedFile **unsaved_files,
408735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                          int *num_unsaved_files) {
409735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
410735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int arg;
411735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int prefix_len = strlen("-remap-file=");
412735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files = 0;
413735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *num_unsaved_files = 0;
414735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
415735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  /* Count the number of remapped files. */
416735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg; arg < argc; ++arg) {
417735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (strncmp(argv[arg], "-remap-file=", prefix_len))
418735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      break;
419735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
420735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    ++*num_unsaved_files;
421735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
422735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
423735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (*num_unsaved_files == 0)
424735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return 0;
425735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
426735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files
427735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
428735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                                     *num_unsaved_files);
429735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
430735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    struct CXUnsavedFile *unsaved = *unsaved_files + i;
431735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *arg_string = argv[arg] + prefix_len;
432735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    int filename_len;
433735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *filename;
434735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *contents;
435735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    FILE *to_file;
436735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *semi = strchr(arg_string, ';');
437735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!semi) {
438735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr,
439735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              "error: -remap-file=from;to argument is missing semicolon\n");
440735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
441735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
442735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
443735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
444735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
445735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
446735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Open the file that we're remapping to. */
447735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    to_file = fopen(semi + 1, "r");
448735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!to_file) {
449735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
450735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              semi + 1);
451735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
452735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
453735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
454735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
455735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
456735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
457735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Determine the length of the file we're remapping to. */
458735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_END);
459735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Length = ftell(to_file);
460735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_SET);
461735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
462735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Read the contents of the file we're remapping to. */
463735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents = (char *)malloc(unsaved->Length + 1);
464735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fread(contents, 1, unsaved->Length, to_file);
465735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents[unsaved->Length] = 0;
466735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Contents = contents;
467735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
468735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Close the file. */
469735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fclose(to_file);
470735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
471735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Copy the file name that we're remapping from. */
472735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename_len = semi - arg_string;
473735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename = (char *)malloc(filename_len + 1);
474735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    memcpy(filename, arg_string, filename_len);
475735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename[filename_len] = 0;
476735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Filename = filename;
477735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
478735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
479735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  return 0;
480735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
481735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
482f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint perform_code_completion(int argc, const char **argv) {
4830c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  const char *input = argv[1];
4840c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *filename = 0;
4850c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned line;
4860c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned column;
487f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CXIndex CIdx;
488f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  int errorCode;
489735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
490735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int num_unsaved_files = 0;
491f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar
4920c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  input += strlen("-code-completion-at=");
493f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
494f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return errorCode;
4950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
496735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
497735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return -1;
498735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
499f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CIdx = clang_createIndex(0, 0);
500735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  clang_codeComplete(CIdx, argv[argc - 1], argc - num_unsaved_files - 3,
501735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                     argv + num_unsaved_files + 2,
502735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                     num_unsaved_files, unsaved_files,
5030c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                     filename, line, column, &print_completion_result, stdout);
5040c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  clang_disposeIndex(CIdx);
5050c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  free(filename);
506f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
507735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
508735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
509f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  return 0;
5100c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5110c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5120d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
5130d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Command line processing.                                                   */
5140d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
515f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
516f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekstatic void print_usage(void) {
517f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  fprintf(stderr,
5180d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
5191d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    "       c-index-test -test-file-scan <AST file> <source file> "
5201d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          "[FileCheck prefix]\n"
5210d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "       c-index-test -test-load-tu <AST file> <symbol filter>\n\n"
522ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    "       c-index-test -test-load-source <symbol filter> {<args>}*\n\n"
523ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    " <symbol filter> options for -test-load-tu and -test-load-source:\n%s",
5240d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   all - load all symbols, including those from PCH\n"
5250d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   local - load all symbols except those in PCH\n"
5260d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   category - only load ObjC categories (non-PCH)\n"
5270d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   interface - only load ObjC interfaces (non-PCH)\n"
5280d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   protocol - only load ObjC protocols (non-PCH)\n"
5290d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   function - only load functions (non-PCH)\n"
530625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   typedef - only load typdefs (non-PCH)\n"
531625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   scan-function - scan function bodies (non-PCH)\n\n");
532f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek}
533f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
534f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint main(int argc, const char **argv) {
535f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
536f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_code_completion(argc, argv);
537f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0)
538f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_test_load_tu(argv[2], argv[3]);
539ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0)
540ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return perform_test_load_source(argc - 3, argv + 3, argv[2]);
5411d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
5421d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    return perform_file_scan(argv[2], argv[3],
5431d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             argc >= 5 ? argv[4] : 0);
544f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
545f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  print_usage();
54650398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff  return 1;
54750398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff}
548