c-index-test.c revision 70ee54258035c860ebc71f7e5f803b74f3186889
12b8ee6c2994f738e5162ff46b638974870f51662Steve Naroff/* c-index-test.c */
250398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
350398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff#include "clang-c/Index.h"
40c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor#include <stdlib.h>
589922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff#include <stdio.h>
6af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff#include <string.h>
7f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor#include <assert.h>
8af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff
90d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
100d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Utility functions.                                                         */
110d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
120d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
132e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#ifdef _MSC_VER
142e06fc877a633abea3b40a64950c7316dac29ca8John Thompsonchar *basename(const char* path)
152e06fc877a633abea3b40a64950c7316dac29ca8John Thompson{
162e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base1 = (char*)strrchr(path, '/');
172e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    char* base2 = (char*)strrchr(path, '\\');
182e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    if (base1 && base2)
192e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return((base1 > base2) ? base1 + 1 : base2 + 1);
202e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base1)
212e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base1 + 1);
222e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    else if (base2)
232e06fc877a633abea3b40a64950c7316dac29ca8John Thompson        return(base2 + 1);
242e06fc877a633abea3b40a64950c7316dac29ca8John Thompson
252e06fc877a633abea3b40a64950c7316dac29ca8John Thompson    return((char*)path);
262e06fc877a633abea3b40a64950c7316dac29ca8John Thompson}
272e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#else
28ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroffextern char *basename(const char *);
292e06fc877a633abea3b40a64950c7316dac29ca8John Thompson#endif
30ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff
311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic unsigned CreateTranslationUnit(CXIndex Idx, const char *file,
321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                      CXTranslationUnit *TU) {
331c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  *TU = clang_createTranslationUnit(Idx, file);
351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!TU) {
361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Unable to load translation unit from '%s'!\n", file);
371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 0;
381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 1;
401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
420d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
430d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Pretty-printing.                                                           */
440d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
450d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
46af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroffstatic void PrintCursor(CXCursor Cursor) {
4777128ddd3077fc045751a55bb3226802b15d5510Steve Naroff  if (clang_isInvalid(Cursor.kind))
481c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    printf("Invalid Cursor => %s", clang_getCursorKindSpelling(Cursor.kind));
49699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  else {
50f393c3b770c86446b20e6fd4bcf08a31442d1b1dEric Christopher    CXDecl DeclReferenced;
51ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
52ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getCursorSpelling(Cursor);
53ff9e18cb3863defa98257500ef49d93a9d2bc216Steve Naroff    printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind),
54ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff                      clang_getCString(string));
55ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
56f393c3b770c86446b20e6fd4bcf08a31442d1b1dEric Christopher    DeclReferenced = clang_getCursorDecl(Cursor);
5785e2db72137c28114d3981c044946a8c16ef6011Steve Naroff    if (DeclReferenced)
5885e2db72137c28114d3981c044946a8c16ef6011Steve Naroff      printf(":%d:%d", clang_getDeclLine(DeclReferenced),
5985e2db72137c28114d3981c044946a8c16ef6011Steve Naroff                       clang_getDeclColumn(DeclReferenced));
60699a07d8a0b1579c5178b3baf4bcf9edb6b38108Steve Naroff  }
61af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff}
6289922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff
639298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenekstatic const char* GetCursorSource(CXCursor Cursor) {
649298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  const char *source = clang_getCursorSource(Cursor);
659298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  if (!source)
669298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek    return "<invalid loc>";
679298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek  return basename(source);
689298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek}
699298cfc7475c48fa42b168c37f628663d65ddde7Ted Kremenek
700d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
710d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_loadTranslationUnit().                             */
720d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
730d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
74fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekstatic const char *FileCheckPrefix = "CHECK";
75fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
76fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekstatic void PrintDeclExtent(CXDecl Dcl) {
7770ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek  CXSourceExtent extent;
7870ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek  if (!Dcl)
7970ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    return;
8070ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek  extent = clang_getDeclExtent(Dcl);
81fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek  printf(" [Extent=%d:%d:%d:%d]", extent.begin.line, extent.begin.column,
82fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek         extent.end.line, extent.end.column);
83fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek}
84fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
85625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) {
86bce6f62ae7d2c15992617f64e30067803fb5b47fDaniel Dunbar  if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
87ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
88fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf("// %s: %s:%d:%d: ", FileCheckPrefix,
89fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek                                GetCursorSource(Cursor),
90fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek                                clang_getCursorLine(Cursor),
91fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek                                clang_getCursorColumn(Cursor));
92af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
93fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
94ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getDeclSpelling(Dcl);
95fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf(" [Context=%s]", clang_getCString(string));
96ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
97fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
98fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    PrintDeclExtent(clang_getCursorDecl(Cursor));
99fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
100fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf("\n");
101bce6f62ae7d2c15992617f64e30067803fb5b47fDaniel Dunbar  }
102c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff}
103625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
104c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroffstatic void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor,
105625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                   CXClientData Filter) {
106c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff  if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) {
10770ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    CXDecl D;
108ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    CXString string;
109fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf("// %s: %s:%d:%d: ", FileCheckPrefix,
110fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek           GetCursorSource(Cursor), clang_getCursorLine(Cursor),
111fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek           clang_getCursorColumn(Cursor));
112af08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1Steve Naroff    PrintCursor(Cursor);
113ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    string = clang_getTranslationUnitSpelling(Unit);
114fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    printf(" [Context=%s]",
115ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff          basename(clang_getCString(string)));
116ef0cef6cec8de5fc60e469a93436eed7212e0dc2Steve Naroff    clang_disposeString(string);
117fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
11870ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    D = clang_getCursorDecl(Cursor);
11970ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    if (!D) {
12070ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek      printf("\n");
12170ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek      return;
12270ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    }
123fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
12470ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    PrintDeclExtent(D);
12570ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    printf("\n");
12670ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    clang_loadDeclaration(D, DeclVisitor, 0);
127625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  }
128625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
129c857ea4d22e1e6dd9ede1f0e84d48b157c6924fdSteve Naroff
130625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic void FunctionScanVisitor(CXTranslationUnit Unit, CXCursor Cursor,
131625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                CXClientData Filter) {
132625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  const char *startBuf, *endBuf;
133625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  unsigned startLine, startColumn, endLine, endColumn, curLine, curColumn;
134625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXCursor Ref;
135625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
136625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (Cursor.kind != CXCursor_FunctionDefn)
137625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return;
138625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
139625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf,
140625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &startLine, &startColumn,
141625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                                       &endLine, &endColumn);
142625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  /* Probe the entire body, looking for both decls and refs. */
143625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curLine = startLine;
144625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  curColumn = startColumn;
145625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
146625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  while (startBuf < endBuf) {
147625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (*startBuf == '\n') {
148625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      startBuf++;
149625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curLine++;
150625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn = 1;
151625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (*startBuf != '\t')
152625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      curColumn++;
153fbcb2b716bee88c754684bd189913ed9f8c09086Ted Kremenek
154625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor),
155625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          curLine, curColumn);
156625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    if (Ref.kind == CXCursor_NoDeclFound) {
157625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      /* Nothing found here; that's fine. */
158625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    } else if (Ref.kind != CXCursor_FunctionDecl) {
159625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      CXString string;
160fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek      printf("// %s: %s:%d:%d: ", FileCheckPrefix, GetCursorSource(Ref),
161625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar             curLine, curColumn);
162625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      PrintCursor(Ref);
163283cae37b03047c14ef918503bc46b08405c3b69Douglas Gregor      string = clang_getDeclSpelling(Ref.data[0]);
164625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      printf(" [Context:%s]\n", clang_getCString(string));
165625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar      clang_disposeString(string);
1664ade6d6eae934f796ca43c81a5aa185e456dde9bSteve Naroff    }
167625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    startBuf++;
1682d4d629d8a0de5112c7ae9d05c03ddbf6dcd956aSteve Naroff  }
16989922f86f4e7da383af2a62ef04ad8b93b941220Steve Naroff}
17050398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff
1717d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
1727d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* USR testing.                                                               */
1737d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
1747d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
1757d40562f83552b7295411e10ee887d8d55470679Ted Kremenekstatic void USRDeclVisitor(CXDecl D, CXCursor C, CXClientData Filter) {
1767d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (!Filter || (C.kind == *(enum CXCursorKind *)Filter)) {
177283cae37b03047c14ef918503bc46b08405c3b69Douglas Gregor    CXString USR = clang_getDeclUSR(C.data[0]);
1787d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (!USR.Spelling) {
1797d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      clang_disposeString(USR);
1807d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      return;
1817d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    }
1827d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("// %s: %s %s", FileCheckPrefix, GetCursorSource(C), USR.Spelling);
183283cae37b03047c14ef918503bc46b08405c3b69Douglas Gregor    PrintDeclExtent(C.data[0]);
1847d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    printf("\n");
1857d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    clang_disposeString(USR);
1867d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
1877d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
1887d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
1897d40562f83552b7295411e10ee887d8d55470679Ted Kremenekstatic void USRVisitor(CXTranslationUnit Unit, CXCursor Cursor,
19070ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek                       CXClientData Filter) {
19170ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek  CXDecl D = clang_getCursorDecl(Cursor);
19270ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek  if (D) {
1937d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    /* USRDeclVisitor(Unit, Cursor.decl, Cursor, Filter);*/
19470ee54258035c860ebc71f7e5f803b74f3186889Ted Kremenek    clang_loadDeclaration(D, USRDeclVisitor, 0);
1957d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
1967d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
1977d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
1987d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
1997d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/* Loading ASTs/source.                                                       */
2007d40562f83552b7295411e10ee887d8d55470679Ted Kremenek/******************************************************************************/
2017d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
202625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbarstatic int perform_test_load(CXIndex Idx, CXTranslationUnit TU,
20398271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                             const char *filter, const char *prefix,
20498271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                             CXTranslationUnitIterator Visitor) {
2050d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind K = CXCursor_NotImplemented;
2060d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  enum CXCursorKind *ck = &K;
207625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
208fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek  if (prefix)
209fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    FileCheckPrefix = prefix;
210fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek
2110d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  /* Perform some simple filtering. */
2120d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL;
2130d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl;
2140d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl;
2150d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl;
2160d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl;
2170d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl;
218625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor;
2190d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  else {
2200d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter);
2210d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    return 1;
2220d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  }
2230d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
224625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  clang_loadTranslationUnit(TU, Visitor, ck);
2250d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  clang_disposeTranslationUnit(TU);
2260d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek  return 0;
2270d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek}
2280d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
229fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenekint perform_test_load_tu(const char *file, const char *filter,
23098271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                         const char *prefix,
23198271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                         CXTranslationUnitIterator Visitor) {
232625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXIndex Idx;
233625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  CXTranslationUnit TU;
234625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
235625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
236625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar                          /* displayDiagnostics */ 1);
237625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
238625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar  if (!CreateTranslationUnit(Idx, file, &TU))
239625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    return 1;
240625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
24198271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek  return perform_test_load(Idx, TU, filter, prefix, Visitor);
242625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar}
243625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar
24498271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenekint perform_test_load_source(int argc, const char **argv, const char *filter,
24598271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek                             CXTranslationUnitIterator Visitor) {
2468506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  const char *UseExternalASTs =
2478506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    getenv("CINDEXTEST_USE_EXTERNAL_AST_GENERATION");
248ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXIndex Idx;
249ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  CXTranslationUnit TU;
250ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  Idx = clang_createIndex(/* excludeDeclsFromPCH */
251ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          !strcmp(filter, "local") ? 1 : 0,
252ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar                          /* displayDiagnostics */ 1);
253ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
2548506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar  if (UseExternalASTs && strlen(UseExternalASTs))
2558506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar    clang_setUseExternalASTGeneration(Idx, 1);
2568506dde586459887b7e14e23a30af8ac5be5adb6Daniel Dunbar
257ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  TU = clang_createTranslationUnitFromSourceFile(Idx, 0, argc, argv);
258ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  if (!TU) {
259ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    fprintf(stderr, "Unable to load translation unit!\n");
260ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar    return 1;
261ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar  }
262ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
26398271567b6f10be85bcc75d0bbb67416c8cfb83aTed Kremenek  return perform_test_load(Idx, TU, filter, NULL, Visitor);
264ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar}
265ada487d498d82277bbc60312fc6f6479f0afda76Daniel Dunbar
2660d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
2671c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/* Logic for testing clang_getCursor().                                       */
2681c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
2691c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2701c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenekstatic void print_cursor_file_scan(CXCursor cursor,
2711c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                   unsigned start_line, unsigned start_col,
2721d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   unsigned end_line, unsigned end_col,
2731d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                                   const char *prefix) {
2749096a20fc0fd799911b738ce7a9134dbacaf64b7Ted Kremenek  printf("// %s: ", FileCheckPrefix);
2751d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  if (prefix)
2761d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    printf("-%s", prefix);
2771d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek  printf("{start_line=%d start_col=%d end_line=%d end_col=%d} ",
2781d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          start_line, start_col, end_line, end_col);
2791c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  PrintCursor(cursor);
2801c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printf("\n");
2811c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
2821c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2831d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenekstatic int perform_file_scan(const char *ast_file, const char *source_file,
2841d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             const char *prefix) {
2851c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXIndex Idx;
2861c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXTranslationUnit TU;
2871c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  FILE *fp;
2881c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned line;
2891c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  CXCursor prevCursor;
2901c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned printed;
2911c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  unsigned start_line, start_col, last_line, last_col;
2921c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  size_t i;
2931c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
2941c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!(Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1,
2951c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek                                /* displayDiagnostics */ 1))) {
2961c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not create Index\n");
2971c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
2981c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
2991c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3001c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!CreateTranslationUnit(Idx, ast_file, &TU))
3011c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
3021c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3031c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if ((fp = fopen(source_file, "r")) == NULL) {
3041c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    fprintf(stderr, "Could not open '%s'\n", source_file);
3051c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    return 1;
3061c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
3071c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3081c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  line = 0;
3091c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  prevCursor = clang_getNullCursor();
3101c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  printed = 0;
3111c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_line = last_line = 1;
3121c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  start_col = last_col = 1;
3131c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3141c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  while (!feof(fp)) {
315a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    size_t len = 0;
316a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    int c;
317a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
318a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    while ((c = fgetc(fp)) != EOF) {
319a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      len++;
320a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer      if (c == '\n')
321a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer        break;
322a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer    }
323a9933b98399f656653a0876fc39e5b9093efb732Benjamin Kramer
3241c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    ++line;
3251c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3261c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    for (i = 0; i < len ; ++i) {
3271c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      CXCursor cursor;
3281c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      cursor = clang_getCursor(TU, source_file, line, i+1);
3291c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3301c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      if (!clang_equalCursors(cursor, prevCursor) &&
3311c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek          prevCursor.kind != CXCursor_InvalidFile) {
3321c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        print_cursor_file_scan(prevCursor, start_line, start_col,
3331d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                               last_line, last_col, prefix);
3341c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 1;
3351c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_line = line;
3361c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        start_col = (unsigned) i+1;
3371c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
3381c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      else {
3391c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek        printed = 0;
3401c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      }
3411c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3421c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      prevCursor = cursor;
3431c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_line = line;
3441c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek      last_col = (unsigned) i+1;
3451c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    }
3461c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
3471c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3481c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  if (!printed && prevCursor.kind != CXCursor_InvalidFile) {
3491c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek    print_cursor_file_scan(prevCursor, start_line, start_col,
3501d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                           last_line, last_col, prefix);
3511c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  }
3521c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3531c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  fclose(fp);
3541c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek  return 0;
3551c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek}
3561c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek
3571c6da1735ddc5978a2c24394c5112b4868b347f0Ted Kremenek/******************************************************************************/
3580d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Logic for testing clang_codeComplete().                                    */
3590d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
3600d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek
3610c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor/* Parse file:line:column from the input string. Returns 0 on success, non-zero
3620c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   on failure. If successful, the pointer *filename will contain newly-allocated
3630c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor   memory (that will be owned by the caller) to store the file name. */
3640c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorint parse_file_line_column(const char *input, char **filename, unsigned *line,
3650c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor                           unsigned *column) {
36688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the second colon. */
36788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  const char *second_colon = strrchr(input, ':'), *first_colon;
3680c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *endptr = 0;
36988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (!second_colon || second_colon == input) {
3700c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse filename:line:column in '%s'\n", input);
3710c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3720c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3730c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
3740c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  /* Parse the column number. */
37588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *column = strtol(second_colon + 1, &endptr, 10);
3760c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  if (*endptr != 0) {
3770c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(stderr, "could not parse column in '%s'\n", input);
37888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
37988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
38088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
38188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Find the first colon. */
38288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  first_colon = second_colon - 1;
38388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  while (first_colon != input && *first_colon != ':')
38488d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    --first_colon;
38588d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (first_colon == input) {
38688d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
38788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    return 1;
38888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  }
38988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor
39088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Parse the line number. */
39188d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *line = strtol(first_colon + 1, &endptr, 10);
39288d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  if (*endptr != ':') {
39388d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor    fprintf(stderr, "could not parse line in '%s'\n", input);
3940c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    return 1;
3950c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
3960c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
39788d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  /* Copy the file name. */
39888d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  *filename = (char*)malloc(first_colon - input + 1);
39988d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  memcpy(*filename, input, first_colon - input);
40088d23952eadb0737e5bd839654d69a0a578e19bcDouglas Gregor  (*filename)[first_colon - input] = 0;
4010c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return 0;
4020c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
4030c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
4040c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorconst char *
4050c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregorclang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) {
4060c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  switch (Kind) {
4070c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Optional: return "Optional";
4080c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_TypedText: return "TypedText";
4090c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Text: return "Text";
4100c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Placeholder: return "Placeholder";
4110c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Informative: return "Informative";
4120c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_CurrentParameter: return "CurrentParameter";
4130c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftParen: return "LeftParen";
4140c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightParen: return "RightParen";
4150c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBracket: return "LeftBracket";
4160c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBracket: return "RightBracket";
4170c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftBrace: return "LeftBrace";
4180c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightBrace: return "RightBrace";
4190c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_LeftAngle: return "LeftAngle";
4200c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_RightAngle: return "RightAngle";
4210c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  case CXCompletionChunk_Comma: return "Comma";
422ff5ce6eefc7c253ef6edf4d4bfc996fdd82d09aaDouglas Gregor  case CXCompletionChunk_ResultType: return "ResultType";
42301dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Colon: return "Colon";
42401dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_SemiColon: return "SemiColon";
42501dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_Equal: return "Equal";
42601dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_HorizontalSpace: return "HorizontalSpace";
42701dfea02d1da297e8b53db8eea3d3cc652acda8dDouglas Gregor  case CXCompletionChunk_VerticalSpace: return "VerticalSpace";
4280c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
4290c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
4300c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  return "Unknown";
4310c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
4320c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
4333ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_string(CXCompletionString completion_string, FILE *file) {
434f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  int I, N;
4353ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
4363ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  N = clang_getNumCompletionChunks(completion_string);
4370c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  for (I = 0; I != N; ++I) {
438d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    const char *text = 0;
4390c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    enum CXCompletionChunkKind Kind
4403ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      = clang_getCompletionChunkKind(completion_string, I);
4413ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
4423ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    if (Kind == CXCompletionChunk_Optional) {
4433ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "{Optional ");
4443ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      print_completion_string(
4453ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                clang_getCompletionChunkCompletionString(completion_string, I),
4463ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                              file);
4473ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      fprintf(file, "}");
4483ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor      continue;
4493ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor    }
4503ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
451d5a2089663d81faee0de031deabc418fa53ecf3bDouglas Gregor    text = clang_getCompletionChunkText(completion_string, I);
4520c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor    fprintf(file, "{%s %s}",
4530c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            clang_getCompletionChunkKindSpelling(Kind),
4540c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor            text? text : "");
4550c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  }
4563ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor}
4573ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor
4583ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregorvoid print_completion_result(CXCompletionResult *completion_result,
4593ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor                             CXClientData client_data) {
4603ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  FILE *file = (FILE *)client_data;
4613ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  fprintf(file, "%s:",
4623ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor          clang_getCursorKindSpelling(completion_result->CursorKind));
4633ac738567fdf4df636b9e76c5a2d3dc3d6f80235Douglas Gregor  print_completion_string(completion_result->CompletionString, file);
4640c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  fprintf(file, "\n");
4650c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
4660c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
467735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorvoid free_remapped_files(struct CXUnsavedFile *unsaved_files,
468735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         int num_unsaved_files) {
469735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
470735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (i = 0; i != num_unsaved_files; ++i) {
471735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Filename);
472735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    free((char *)unsaved_files[i].Contents);
473735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
474735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
475735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
476735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregorint parse_remapped_files(int argc, const char **argv, int start_arg,
477735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                         struct CXUnsavedFile **unsaved_files,
478735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                          int *num_unsaved_files) {
479735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int i;
480735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int arg;
481735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int prefix_len = strlen("-remap-file=");
482735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files = 0;
483735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *num_unsaved_files = 0;
484735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
485735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  /* Count the number of remapped files. */
486735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg; arg < argc; ++arg) {
487735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (strncmp(argv[arg], "-remap-file=", prefix_len))
488735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      break;
489735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
490735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    ++*num_unsaved_files;
491735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
492735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
493735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (*num_unsaved_files == 0)
494735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return 0;
495735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
496735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  *unsaved_files
497735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    = (struct CXUnsavedFile *)malloc(sizeof(struct CXUnsavedFile) *
498735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor                                     *num_unsaved_files);
499735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  for (arg = start_arg, i = 0; i != *num_unsaved_files; ++i, ++arg) {
500735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    struct CXUnsavedFile *unsaved = *unsaved_files + i;
501735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *arg_string = argv[arg] + prefix_len;
502735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    int filename_len;
503735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *filename;
504735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    char *contents;
505735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    FILE *to_file;
506735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    const char *semi = strchr(arg_string, ';');
507735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!semi) {
508735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr,
509735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              "error: -remap-file=from;to argument is missing semicolon\n");
510735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
511735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
512735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
513735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
514735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
515735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
516735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Open the file that we're remapping to. */
517735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    to_file = fopen(semi + 1, "r");
518735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    if (!to_file) {
519735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      fprintf(stderr, "error: cannot open file %s that we are remapping to\n",
520735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor              semi + 1);
521735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      free_remapped_files(*unsaved_files, i);
522735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *unsaved_files = 0;
523735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      *num_unsaved_files = 0;
524735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor      return -1;
525735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    }
526735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
527735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Determine the length of the file we're remapping to. */
528735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_END);
529735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Length = ftell(to_file);
530735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fseek(to_file, 0, SEEK_SET);
531735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
532735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Read the contents of the file we're remapping to. */
533735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents = (char *)malloc(unsaved->Length + 1);
5344da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth    if (fread(contents, 1, unsaved->Length, to_file) != unsaved->Length) {
5354da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      fprintf(stderr, "error: unexpected %s reading 'to' file %s\n",
5364da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth              (feof(to_file) ? "EOF" : "error"), semi + 1);
5374da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      fclose(to_file);
5384da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      free_remapped_files(*unsaved_files, i);
5394da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      *unsaved_files = 0;
5404da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      *num_unsaved_files = 0;
5414da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth      return -1;
5424da689a0252275e865af846f0e75e733ba954ec2Chandler Carruth    }
543735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    contents[unsaved->Length] = 0;
544735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Contents = contents;
545735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
546735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Close the file. */
547735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    fclose(to_file);
548735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
549735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    /* Copy the file name that we're remapping from. */
550735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename_len = semi - arg_string;
551735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename = (char *)malloc(filename_len + 1);
552735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    memcpy(filename, arg_string, filename_len);
553735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    filename[filename_len] = 0;
554735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    unsaved->Filename = filename;
555735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  }
556735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
557735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  return 0;
558735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor}
559735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
560f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint perform_code_completion(int argc, const char **argv) {
5610c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  const char *input = argv[1];
5620c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  char *filename = 0;
5630c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned line;
5640c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  unsigned column;
565f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CXIndex CIdx;
566f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  int errorCode;
567735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
568735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  int num_unsaved_files = 0;
569ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  CXCodeCompleteResults *results = 0;
570f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar
5710c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  input += strlen("-code-completion-at=");
572f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if ((errorCode = parse_file_line_column(input, &filename, &line, &column)))
573f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return errorCode;
5740c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
575735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  if (parse_remapped_files(argc, argv, 2, &unsaved_files, &num_unsaved_files))
576735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor    return -1;
577735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
578f8297f1512d29c88f20bf2901f04cc04182a3eeeDaniel Dunbar  CIdx = clang_createIndex(0, 0);
579ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  results = clang_codeComplete(CIdx,
580ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv[argc - 1], argc - num_unsaved_files - 3,
581ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               argv + num_unsaved_files + 2,
582ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               num_unsaved_files, unsaved_files,
583ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor                               filename, line, column);
584ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  if (results) {
585ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    unsigned i, n = results->NumResults;
586ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    for (i = 0; i != n; ++i)
587ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor      print_completion_result(results->Results + i, stdout);
588ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor    clang_disposeCodeCompleteResults(results);
589ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor  }
590ec6762c709726bf2ee5f76c21df81e71a56e6f81Douglas Gregor
5910c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  clang_disposeIndex(CIdx);
5920c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor  free(filename);
593f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
594735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
595735df88a38e80c1ca70daa889aa516b8b9f54b50Douglas Gregor
596f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  return 0;
5970c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor}
5980c8296dfb495f41d6f0de6fe1d03014ffd063674Douglas Gregor
599f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregortypedef struct {
600f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  char *filename;
601f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned line;
602f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned column;
603f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor} CursorSourceLocation;
604f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
605f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregorint inspect_cursor_at(int argc, const char **argv) {
606f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXIndex CIdx;
607f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int errorCode;
608f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  struct CXUnsavedFile *unsaved_files = 0;
609f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  int num_unsaved_files = 0;
610f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXTranslationUnit TU;
611f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CXCursor Cursor;
612f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CursorSourceLocation *Locations = 0;
613f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  unsigned NumLocations = 0, Loc;
614f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
615f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Count the number of locations. */
616f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  while (strstr(argv[NumLocations+1], "-cursor-at=") == argv[NumLocations+1])
617f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    ++NumLocations;
618f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
619f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  /* Parse the locations. */
620f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  assert(NumLocations > 0 && "Unable to count locations?");
621f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  Locations = (CursorSourceLocation *)malloc(
622f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  NumLocations * sizeof(CursorSourceLocation));
623f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
624f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    const char *input = argv[Loc + 1] + strlen("-cursor-at=");
625f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    if ((errorCode = parse_file_line_column(input, &Locations[Loc].filename,
626f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                            &Locations[Loc].line,
627f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                            &Locations[Loc].column)))
628f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor      return errorCode;
629f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
630f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
631f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (parse_remapped_files(argc, argv, NumLocations + 1, &unsaved_files,
632f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                           &num_unsaved_files))
633f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
634f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
635f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (num_unsaved_files > 0) {
636f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    fprintf(stderr, "cannot remap files when looking for a cursor\n");
637f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
638f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
639f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
640f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  CIdx = clang_createIndex(0, 1);
641f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  TU = clang_createTranslationUnitFromSourceFile(CIdx, argv[argc - 1],
642f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                  argc - num_unsaved_files - 2 - NumLocations,
643f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                                   argv + num_unsaved_files + 1 + NumLocations);
644f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (!TU) {
645f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    fprintf(stderr, "unable to parse input\n");
646f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return -1;
647f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
648f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
649f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  for (Loc = 0; Loc < NumLocations; ++Loc) {
650f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    Cursor = clang_getCursor(TU, Locations[Loc].filename,
651f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor                             Locations[Loc].line, Locations[Loc].column);
652f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    PrintCursor(Cursor);
653f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    printf("\n");
654f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    free(Locations[Loc].filename);
655f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  }
656f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
657f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeTranslationUnit(TU);
658f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  clang_disposeIndex(CIdx);
659f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free(Locations);
660f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  free_remapped_files(unsaved_files, num_unsaved_files);
661f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  return 0;
662f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor}
663f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor
6640d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
6650d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/* Command line processing.                                                   */
6660d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek/******************************************************************************/
667f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
6687d40562f83552b7295411e10ee887d8d55470679Ted Kremenekstatic CXTranslationUnitIterator GetVisitor(const char *s) {
6697d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (s[0] == '\0')
6707d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    return TranslationUnitVisitor;
6717d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  if (strcmp(s, "-usrs") == 0)
6727d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    return USRVisitor;
6737d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  return NULL;
6747d40562f83552b7295411e10ee887d8d55470679Ted Kremenek}
6757d40562f83552b7295411e10ee887d8d55470679Ted Kremenek
676f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekstatic void print_usage(void) {
677f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  fprintf(stderr,
6780d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "usage: c-index-test -code-completion-at=<site> <compiler arguments>\n"
679f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    "       c-index-test -cursor-at=<site> <compiler arguments>\n"
6801d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    "       c-index-test -test-file-scan <AST file> <source file> "
6811d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek          "[FileCheck prefix]\n"
682fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek    "       c-index-test -test-load-tu <AST file> <symbol filter> "
683fe6fd3d41a7f48317d6856c9327b6cead32c3498Ted Kremenek          "[FileCheck prefix]\n"
6847d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-tu-usrs <AST file> <symbol filter> "
6857d40562f83552b7295411e10ee887d8d55470679Ted Kremenek           "[FileCheck prefix]\n"
6867d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    "       c-index-test -test-load-source <symbol filter> {<args>}*\n"
687f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    "       c-index-test -test-load-source-usrs <symbol filter> {<args>}*\n\n");
688f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  fprintf(stderr,
6897d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    " <symbol filter> values:\n%s",
6900d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   all - load all symbols, including those from PCH\n"
6910d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   local - load all symbols except those in PCH\n"
6920d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   category - only load ObjC categories (non-PCH)\n"
6930d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   interface - only load ObjC interfaces (non-PCH)\n"
6940d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   protocol - only load ObjC protocols (non-PCH)\n"
6950d435191fc8f78338c2ef26d566cfe4d2c52c706Ted Kremenek    "   function - only load functions (non-PCH)\n"
696625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   typedef - only load typdefs (non-PCH)\n"
697625e4efc2c64b638285c9f836cc00a3ad7d0bd5fDaniel Dunbar    "   scan-function - scan function bodies (non-PCH)\n\n");
698f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek}
699f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
700f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenekint main(int argc, const char **argv) {
701f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1])
702f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek    return perform_code_completion(argc, argv);
703f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor  if (argc > 2 && strstr(argv[1], "-cursor-at=") == argv[1])
704f2c87bd0368775927ead93e0dee3e4f3ca3f9a63Douglas Gregor    return inspect_cursor_at(argc, argv);
7057d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-tu", 13) == 0) {
7067d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    CXTranslationUnitIterator I = GetVisitor(argv[1] + 13);
7077d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
7087d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I);
7097d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
7107d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strncmp(argv[1], "-test-load-source", 17) == 0) {
7117d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    CXTranslationUnitIterator I = GetVisitor(argv[1] + 17);
7127d40562f83552b7295411e10ee887d8d55470679Ted Kremenek    if (I)
7137d40562f83552b7295411e10ee887d8d55470679Ted Kremenek      return perform_test_load_source(argc - 3, argv + 3, argv[2], I);
7147d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  }
7157d40562f83552b7295411e10ee887d8d55470679Ted Kremenek  else if (argc >= 4 && strcmp(argv[1], "-test-file-scan") == 0)
7161d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek    return perform_file_scan(argv[2], argv[3],
7171d5fdf3d3b5ea2640ebe8673814a0b6ab7cf5eb2Ted Kremenek                             argc >= 5 ? argv[4] : 0);
718f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek
719f5d9c9340b1a5ecd6ab62b916600b6e19e69539fTed Kremenek  print_usage();
72050398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff  return 1;
72150398199fb10e196a8d92fbf7a062dbe42ed88fdSteve Naroff}
722