c-index-test.c revision 735df88a38e80c1ca70daa889aa516b8b9f54b50
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) {
182ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXIndex Idx;
183ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXTranslationUnit TU;
184ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
185ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
186ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          /* displayDiagnostics */ 1);
187ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
188ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv);
189ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (!TU) {
190ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    fprintf(stderr, "Unable to load translation unit!\n");
191ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return 1;
192ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  }
193ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
194625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  return perform_test_load(Idx, TU, filter);
195ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar}
196ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
1970d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
1981c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/* Logic for testing clang_getCursor().                                       */
1991c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
2001c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2011c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic void print_cursor_file_scan(CXCursor cursor,
2021c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                   unsigned start_line, unsigned start_col,
2031d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   unsigned end_line, unsigned end_col,
2041d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   const char *prefix) {
2051d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("// CHECK");
2061d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (prefix)
2071d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    printf("-%s", prefix);
2081d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
2091d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          start_line, start_col, end_line, end_col);
2101c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  PrintCursor(cursor);
2111c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printf("\n");
2121c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
2131c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2141d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenekstatic int perform_file_scan(const char *ast_file, const char *source_file,
2151d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             const char *prefix) {
2161c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXIndex Idx;
2171c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXTranslationUnit TU;
2181c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  FILE *fp;
2191c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned line;
2201c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXCursor prevCursor;
2211c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned printed;
2221c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned start_line, start_col, last_line, last_col;
2231c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  size_t i;
2241c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2251c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
2261c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                /* displayDiagnostics */ 1))) {
2271c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not create Index\n");
2281c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2291c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!CreateTranslationUnit(Idx, ast_file, &TU))
2321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if ((fp = fopen(source_file, "r")) == NULL) {
2351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not open '%s'\n", source_file);
2361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  line = 0;
2401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  prevCursor = clang_getNullCursor();
2411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printed = 0;
2421c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_line = last_line = 1;
2431c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_col = last_col = 1;
2441c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2451c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  while (!feof(fp)) {
246a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    size_t len = 0;
247a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    int c;
248a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
249a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    while ((c = fgetc(fp)) != EOF) {
250a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      len++;
251a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      if (c == '\n')
252a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer        break;
253a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    }
254a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
2551c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    ++line;
2561c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2571c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    for (i = 0; i < len ; ++i) {
2581c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      CXCursor cursor;
2591c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      cursor = clang_getCursor(TU, source_file, line, i+1);
2601c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2611c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      if (!clang_equalCursors(cursor, prevCursor) &&
2621c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek          prevCursor.kind != CXCursor_InvalidFile) {
2631c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        print_cursor_file_scan(prevCursor, start_line, start_col,
2641d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                               last_line, last_col, prefix);
2651c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 1;
2661c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_line = line;
2671c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_col = (unsigned) i+1;
2681c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
2691c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      else {
2701c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 0;
2711c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
2721c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2731c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      prevCursor = cursor;
2741c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_line = line;
2751c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_col = (unsigned) i+1;
2761c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    }
2771c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2781c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2791c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
2801c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    print_cursor_file_scan(prevCursor, start_line, start_col,
2811d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                           last_line, last_col, prefix);
2821c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2831c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2841c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  fclose(fp);
2851c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 0;
2861c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
2871c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2881c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
2890d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_codeComplete().                                    */
2900d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
2910d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
2920c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor/* Parse file:line:column from the input string. Returns 0 on success, non-zero
2930c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   on failure. If successful, the pointer *filename will contain newly-allocated
2940c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   memory (that will be owned by the caller) to store the file name. */
2950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorint parse_file_line_column(const char *input, char **filename, unsigned *line,
2960c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                           unsigned *column) {
29788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the second colon. */
29888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  const char *second_colon = strrchr(input, ':'), *first_colon;
2990c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *endptr = 0;
30088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (!second_colon || second_colon == input) {
3010c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
3020c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3030c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3040c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3050c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  /* Parse the column number. */
30688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *column = strtol(second_colon + 1, &endptr, 10);
3070c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  if (*endptr != 0) {
3080c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse column in '%s'\n", input);
30988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
31088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
31188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
31288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the first colon. */
31388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  first_colon = second_colon - 1;
31488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  while (first_colon != input && *first_colon != ':')
31588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    --first_colon;
31688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (first_colon == input) {
31788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
31888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
31988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
32088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
32188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Parse the line number. */
32288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *line = strtol(first_colon + 1, &endptr, 10);
32388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (*endptr != ':') {
32488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
3250c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3260c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3270c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
32888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Copy the file name. */
32988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *filename = (char*)malloc(first_colon - input + 1);
33088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  memcpy(*filename, input, first_colon - input);
33188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  (*filename)[first_colon - input] = 0;
3320c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return 0;
3330c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3340c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3350c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorconst char *
3360c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorclang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
3370c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  switch (Kind) {
3380c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Optional: return "Optional";
3390c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_TypedText: return "TypedText";
3400c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Text: return "Text";
3410c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Placeholder: return "Placeholder";
3420c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Informative: return "Informative";
3430c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
3440c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftParen: return "LeftParen";
3450c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightParen: return "RightParen";
3460c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBracket: return "LeftBracket";
3470c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBracket: return "RightBracket";
3480c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBrace: return "LeftBrace";
3490c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBrace: return "RightBrace";
3500c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftAngle: return "LeftAngle";
3510c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightAngle: return "RightAngle";
3520c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Comma: return "Comma";
3530c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3540c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3550c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return "Unknown";
3560c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3570c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3583ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_string(CXCompletionString completion_string, FILE *file) {
359f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  int I, N;
3603ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3613ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  N = clang_getNumCompletionChunks(completion_string);
3620c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  for (I = 0; I != N; ++I) {
363d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    const char *text = 0;
3640c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    enum CXCompletionChunkKind Kind
3653ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      = clang_getCompletionChunkKind(completion_string, I);
3663ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3673ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    if (Kind == CXCompletionChunk_Optional) {
3683ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "{Optional ");
3693ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      print_completion_string(
3703ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                clang_getCompletionChunkCompletionString(completion_string, I),
3713ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                              file);
3723ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "}");
3733ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      continue;
3743ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    }
3753ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
376d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    text = clang_getCompletionChunkText(completion_string, I);
3770c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(file, "{%s %s}",
3780c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            clang_getCompletionChunkKindSpelling(Kind),
3790c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            text? text : "");
3800c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3813ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor}
3823ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
3833ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_result(CXCompletionResult *completion_result,
3843ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                             CXClientData client_data) {
3853ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  FILE *file = (FILE *)client_data;
3863ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  fprintf(file, "%s:",
3873ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor          clang_getCursorKindSpelling(completion_result->CursorKind));
3883ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  print_completion_string(completion_result->CompletionString, file);
3890c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  fprintf(file, "\n");
3900c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
3910c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
392735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorvoid free_remapped_files(struct CXUnsavedFile *unsaved_files,
393735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         int num_unsaved_files) {
394735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
395735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (i = 0; i != num_unsaved_files; ++i) {
396735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Filename);
397735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Contents);
398735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
399735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
400735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
401735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorint parse_remapped_files(int argc, const char **argv, int start_arg,
402735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         struct CXUnsavedFile **unsaved_files,
403735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                          int *num_unsaved_files) {
404735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
405735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int arg;
406735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int prefix_len = strlen("-remap-file=");
407735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files = 0;
408735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *num_unsaved_files = 0;
409735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
410735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  /* Count the number of remapped files. */
411735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg; arg < argc; ++arg) {
412735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (strncmp(argv[arg], "-remap-file=", prefix_len))
413735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      break;
414735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
415735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    ++*num_unsaved_files;
416735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
417735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
418735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (*num_unsaved_files == 0)
419735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return 0;
420735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
421735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files
422735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
423735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                                     *num_unsaved_files);
424735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
425735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    struct CXUnsavedFile *unsaved = *unsaved_files + i;
426735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *arg_string = argv[arg] + prefix_len;
427735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    int filename_len;
428735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *filename;
429735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *contents;
430735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    FILE *to_file;
431735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *semi = strchr(arg_string, ';');
432735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!semi) {
433735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr,
434735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              "error: -remap-file=from;to argument is missing semicolon\n");
435735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
436735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
437735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
438735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
439735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
440735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
441735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Open the file that we're remapping to. */
442735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    to_file = fopen(semi + 1, "r");
443735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!to_file) {
444735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
445735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              semi + 1);
446735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
447735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
448735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
449735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
450735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
451735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
452735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Determine the length of the file we're remapping to. */
453735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_END);
454735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Length = ftell(to_file);
455735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_SET);
456735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
457735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Read the contents of the file we're remapping to. */
458735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents = (char *)malloc(unsaved->Length + 1);
459735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fread(contents, 1, unsaved->Length, to_file);
460735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents[unsaved->Length] = 0;
461735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Contents = contents;
462735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
463735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Close the file. */
464735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fclose(to_file);
465735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
466735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Copy the file name that we're remapping from. */
467735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename_len = semi - arg_string;
468735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename = (char *)malloc(filename_len + 1);
469735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    memcpy(filename, arg_string, filename_len);
470735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename[filename_len] = 0;
471735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Filename = filename;
472735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
473735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
474735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  return 0;
475735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
476735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
477f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint perform_code_completion(int argc, const char **argv) {
4780c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  const char *input = argv[1];
4790c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *filename = 0;
4800c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned line;
4810c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned column;
482f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CXIndex CIdx;
483f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  int errorCode;
484735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
485735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int num_unsaved_files = 0;
486f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar
4870c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  input += strlen("-code-completion-at=");
488f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
489f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return errorCode;
4900c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
491735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
492735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return -1;
493735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
494f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CIdx = clang_createIndex(0, 0);
495735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  clang_codeComplete(CIdx, argv[argc - 1], argc - num_unsaved_files - 3,
496735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                     argv + num_unsaved_files + 2,
497735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                     num_unsaved_files, unsaved_files,
4980c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                     filename, line, column, &print_completion_result, stdout);
4990c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  clang_disposeIndex(CIdx);
5000c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  free(filename);
501f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
502735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
503735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
504f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  return 0;
5050c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5060c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
5070d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
5080d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Command line processing.                                                   */
5090d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
510f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
511f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekstatic void print_usage(void) {
512f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  fprintf(stderr,
5130d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
5141d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    "       c-index-test -test-file-scan <AST file> <source file> "
5151d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          "[FileCheck prefix]\n"
5160d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "       c-index-test -test-load-tu <AST file> <symbol filter>\n\n"
517ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    "       c-index-test -test-load-source <symbol filter> {<args>}*\n\n"
518ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    " <symbol filter> options for -test-load-tu and -test-load-source:\n%s",
5190d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   all - load all symbols, including those from PCH\n"
5200d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   local - load all symbols except those in PCH\n"
5210d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   category - only load ObjC categories (non-PCH)\n"
5220d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   interface - only load ObjC interfaces (non-PCH)\n"
5230d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   protocol - only load ObjC protocols (non-PCH)\n"
5240d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   function - only load functions (non-PCH)\n"
525625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   typedef - only load typdefs (non-PCH)\n"
526625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   scan-function - scan function bodies (non-PCH)\n\n");
527f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek}
528f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
529f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint main(int argc, const char **argv) {
530f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
531f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_code_completion(argc, argv);
532f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc == 4 && strcmp(argv[1], "-test-load-tu") == 0)
533f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_test_load_tu(argv[2], argv[3]);
534ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (argc >= 4 && strcmp(argv[1], "-test-load-source") == 0)
535ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return perform_test_load_source(argc - 3, argv + 3, argv[2]);
5361d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
5371d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    return perform_file_scan(argv[2], argv[3],
5381d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             argc >= 5 ? argv[4] : 0);
539f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
540f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  print_usage();
54150398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff  return 1;
54250398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff}
543