c-index-test.c revision f8297f1512d29c88f20bf2901f04cc04182a3eee
1/* c-index-test.c */ 2 3#include "clang-c/Index.h" 4#include <stdlib.h> 5#include <stdio.h> 6#include <string.h> 7 8#ifdef _MSC_VER 9char *basename(const char* path) 10{ 11 char* base1 = (char*)strrchr(path, '/'); 12 char* base2 = (char*)strrchr(path, '\\'); 13 if (base1 && base2) 14 return((base1 > base2) ? base1 + 1 : base2 + 1); 15 else if (base1) 16 return(base1 + 1); 17 else if (base2) 18 return(base2 + 1); 19 20 return((char*)path); 21} 22#else 23extern char *basename(const char *); 24#endif 25 26static void PrintCursor(CXCursor Cursor) { 27 if (clang_isInvalid(Cursor.kind)) 28 printf("Invalid Cursor => %s\n", clang_getCursorKindSpelling(Cursor.kind)); 29 else { 30 CXDecl DeclReferenced; 31 printf("%s=%s", clang_getCursorKindSpelling(Cursor.kind), 32 clang_getCursorSpelling(Cursor)); 33 DeclReferenced = clang_getCursorDecl(Cursor); 34 if (DeclReferenced) 35 printf(":%d:%d", clang_getDeclLine(DeclReferenced), 36 clang_getDeclColumn(DeclReferenced)); 37 } 38} 39 40static void DeclVisitor(CXDecl Dcl, CXCursor Cursor, CXClientData Filter) 41{ 42 if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { 43 printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)), 44 clang_getCursorLine(Cursor), 45 clang_getCursorColumn(Cursor)); 46 PrintCursor(Cursor); 47 printf(" [Context=%s]\n", clang_getDeclSpelling(Dcl)); 48 } 49} 50static void TranslationUnitVisitor(CXTranslationUnit Unit, CXCursor Cursor, 51 CXClientData Filter) 52{ 53 if (!Filter || (Cursor.kind == *(enum CXCursorKind *)Filter)) { 54 printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Cursor)), 55 clang_getCursorLine(Cursor), 56 clang_getCursorColumn(Cursor)); 57 PrintCursor(Cursor); 58 printf(" [Context=%s]\n", basename(clang_getTranslationUnitSpelling(Unit))); 59 60 clang_loadDeclaration(Cursor.decl, DeclVisitor, 0); 61 62 if (Cursor.kind == CXCursor_FunctionDefn) { 63 const char *startBuf, *endBuf; 64 unsigned startLine, startColumn, endLine, endColumn; 65 clang_getDefinitionSpellingAndExtent(Cursor, &startBuf, &endBuf, 66 &startLine, &startColumn, 67 &endLine, &endColumn); 68 { 69 /* Probe the entire body, looking for both decls and refs. */ 70 unsigned curLine = startLine, curColumn = startColumn; 71 CXCursor Ref; 72 73 while (startBuf < endBuf) { 74 if (*startBuf == '\n') { 75 startBuf++; 76 curLine++; 77 curColumn = 1; 78 } else if (*startBuf != '\t') 79 curColumn++; 80 81 Ref = clang_getCursor(Unit, clang_getCursorSource(Cursor), 82 curLine, curColumn); 83 if (Ref.kind == CXCursor_NoDeclFound) { 84 /* Nothing found here; that's fine. */ 85 } else if (Ref.kind != CXCursor_FunctionDecl) { 86 printf("// CHECK: %s:%d:%d: ", basename(clang_getCursorSource(Ref)), 87 curLine, curColumn); 88 PrintCursor(Ref); 89 printf(" [Context:%s]\n", clang_getDeclSpelling(Ref.decl)); 90 } 91 startBuf++; 92 } 93 } 94 } 95 } 96} 97 98/* Parse file:line:column from the input string. Returns 0 on success, non-zero 99 on failure. If successful, the pointer *filename will contain newly-allocated 100 memory (that will be owned by the caller) to store the file name. */ 101int parse_file_line_column(const char *input, char **filename, unsigned *line, 102 unsigned *column) { 103 const char *colon = strchr(input, ':'); 104 char *endptr = 0; 105 if (!colon) { 106 fprintf(stderr, "could not parse filename:line:column in '%s'\n", input); 107 return 1; 108 } 109 110 /* Copy the file name. */ 111 *filename = (char*)malloc(colon - input); 112 strncpy(*filename, input, colon - input); 113 (*filename)[colon - input] = 0; 114 input = colon + 1; 115 116 /* Parse the line number. */ 117 *line = strtol(input, &endptr, 10); 118 if (*endptr != ':') { 119 fprintf(stderr, "could not parse line:column in '%s'\n", input); 120 free(filename); 121 *filename = 0; 122 return 1; 123 } 124 input = endptr + 1; 125 126 /* Parse the column number. */ 127 *column = strtol(input, &endptr, 10); 128 if (*endptr != 0) { 129 fprintf(stderr, "could not parse column in '%s'\n", input); 130 free(filename); 131 *filename = 0; 132 return 1; 133 } 134 135 return 0; 136} 137 138const char * 139clang_getCompletionChunkKindSpelling(enum CXCompletionChunkKind Kind) { 140 switch (Kind) { 141 case CXCompletionChunk_Optional: return "Optional"; 142 case CXCompletionChunk_TypedText: return "TypedText"; 143 case CXCompletionChunk_Text: return "Text"; 144 case CXCompletionChunk_Placeholder: return "Placeholder"; 145 case CXCompletionChunk_Informative: return "Informative"; 146 case CXCompletionChunk_CurrentParameter: return "CurrentParameter"; 147 case CXCompletionChunk_LeftParen: return "LeftParen"; 148 case CXCompletionChunk_RightParen: return "RightParen"; 149 case CXCompletionChunk_LeftBracket: return "LeftBracket"; 150 case CXCompletionChunk_RightBracket: return "RightBracket"; 151 case CXCompletionChunk_LeftBrace: return "LeftBrace"; 152 case CXCompletionChunk_RightBrace: return "RightBrace"; 153 case CXCompletionChunk_LeftAngle: return "LeftAngle"; 154 case CXCompletionChunk_RightAngle: return "RightAngle"; 155 case CXCompletionChunk_Comma: return "Comma"; 156 } 157 158 return "Unknown"; 159} 160 161void print_completion_result(CXCompletionResult *completion_result, 162 CXClientData client_data) { 163 FILE *file = (FILE *)client_data; 164 int I, N; 165 166 fprintf(file, "%s:", 167 clang_getCursorKindSpelling(completion_result->CursorKind)); 168 N = clang_getNumCompletionChunks(completion_result->CompletionString); 169 for (I = 0; I != N; ++I) { 170 const char *text 171 = clang_getCompletionChunkText(completion_result->CompletionString, I); 172 173 enum CXCompletionChunkKind Kind 174 = clang_getCompletionChunkKind(completion_result->CompletionString, I); 175 fprintf(file, "{%s %s}", 176 clang_getCompletionChunkKindSpelling(Kind), 177 text? text : ""); 178 } 179 fprintf(file, "\n"); 180} 181 182void perform_code_completion(int argc, const char **argv) { 183 const char *input = argv[1]; 184 char *filename = 0; 185 unsigned line; 186 unsigned column; 187 CXIndex CIdx; 188 189 input += strlen("-code-completion-at="); 190 if (parse_file_line_column(input, &filename, &line, &column)) 191 return; 192 193 CIdx = clang_createIndex(0, 0); 194 clang_codeComplete(CIdx, argv[argc - 1], argc - 3, argv + 2, 195 filename, line, column, &print_completion_result, stdout); 196 clang_disposeIndex(CIdx); 197 free(filename); 198} 199 200/* 201 * First sign of life:-) 202 */ 203int main(int argc, char **argv) { 204 if (argc > 2 && strstr(argv[1], "-code-completion-at=") == argv[1]) { 205 perform_code_completion(argc, (const char **)argv); 206 return 0; 207 } 208 209 210 if (argc != 3) { 211 printf("Incorrect usage of c-index-test (requires 3 arguments)\n"); 212 return 0; 213 } 214 { 215 CXIndex Idx; 216 CXTranslationUnit TU; 217 enum CXCursorKind K = CXCursor_NotImplemented; 218 219 Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(argv[2], "local") ? 1 : 0, 220 /* displayDiagnostics */ 1); 221 222 TU = clang_createTranslationUnit(Idx, argv[1]); 223 224 if (!TU) { 225 fprintf(stderr, "Unable to load translation unit!\n"); 226 return 1; 227 } 228 229 if (!strcmp(argv[2], "all") || !strcmp(argv[2], "local")) { 230 clang_loadTranslationUnit(TU, TranslationUnitVisitor, 0); 231 clang_disposeTranslationUnit(TU); 232 return 1; 233 } 234 /* Perform some simple filtering. */ 235 if (!strcmp(argv[2], "category")) K = CXCursor_ObjCCategoryDecl; 236 else if (!strcmp(argv[2], "interface")) K = CXCursor_ObjCInterfaceDecl; 237 else if (!strcmp(argv[2], "protocol")) K = CXCursor_ObjCProtocolDecl; 238 else if (!strcmp(argv[2], "function")) K = CXCursor_FunctionDecl; 239 else if (!strcmp(argv[2], "typedef")) K = CXCursor_TypedefDecl; 240 241 clang_loadTranslationUnit(TU, TranslationUnitVisitor, &K); 242 clang_disposeTranslationUnit(TU); 243 return 1; 244 } 245} 246