blob: f4ed6cafb0da0d4308d5fecd926c3299fe99c4f1 [file] [log] [blame]
Ted Kremenekab188932010-01-05 19:32:54 +00001//===- CIndexCodeCompletion.cpp - Code Completion API hooks ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Clang-C Source Indexing library hooks for
11// code completion.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CIndexer.h"
16#include "clang/Sema/CodeCompleteConsumer.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include "llvm/System/Program.h"
20
21using namespace clang;
22
23extern "C" {
24
25enum CXCompletionChunkKind
26clang_getCompletionChunkKind(CXCompletionString completion_string,
27 unsigned chunk_number) {
28 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
29 if (!CCStr || chunk_number >= CCStr->size())
30 return CXCompletionChunk_Text;
31
32 switch ((*CCStr)[chunk_number].Kind) {
33 case CodeCompletionString::CK_TypedText:
34 return CXCompletionChunk_TypedText;
35 case CodeCompletionString::CK_Text:
36 return CXCompletionChunk_Text;
37 case CodeCompletionString::CK_Optional:
38 return CXCompletionChunk_Optional;
39 case CodeCompletionString::CK_Placeholder:
40 return CXCompletionChunk_Placeholder;
41 case CodeCompletionString::CK_Informative:
42 return CXCompletionChunk_Informative;
43 case CodeCompletionString::CK_ResultType:
44 return CXCompletionChunk_ResultType;
45 case CodeCompletionString::CK_CurrentParameter:
46 return CXCompletionChunk_CurrentParameter;
47 case CodeCompletionString::CK_LeftParen:
48 return CXCompletionChunk_LeftParen;
49 case CodeCompletionString::CK_RightParen:
50 return CXCompletionChunk_RightParen;
51 case CodeCompletionString::CK_LeftBracket:
52 return CXCompletionChunk_LeftBracket;
53 case CodeCompletionString::CK_RightBracket:
54 return CXCompletionChunk_RightBracket;
55 case CodeCompletionString::CK_LeftBrace:
56 return CXCompletionChunk_LeftBrace;
57 case CodeCompletionString::CK_RightBrace:
58 return CXCompletionChunk_RightBrace;
59 case CodeCompletionString::CK_LeftAngle:
60 return CXCompletionChunk_LeftAngle;
61 case CodeCompletionString::CK_RightAngle:
62 return CXCompletionChunk_RightAngle;
63 case CodeCompletionString::CK_Comma:
64 return CXCompletionChunk_Comma;
65 }
66
67 // Should be unreachable, but let's be careful.
68 return CXCompletionChunk_Text;
69}
70
71const char *clang_getCompletionChunkText(CXCompletionString completion_string,
72 unsigned chunk_number) {
73 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
74 if (!CCStr || chunk_number >= CCStr->size())
75 return 0;
76
77 switch ((*CCStr)[chunk_number].Kind) {
78 case CodeCompletionString::CK_TypedText:
79 case CodeCompletionString::CK_Text:
80 case CodeCompletionString::CK_Placeholder:
81 case CodeCompletionString::CK_CurrentParameter:
82 case CodeCompletionString::CK_Informative:
83 case CodeCompletionString::CK_LeftParen:
84 case CodeCompletionString::CK_RightParen:
85 case CodeCompletionString::CK_LeftBracket:
86 case CodeCompletionString::CK_RightBracket:
87 case CodeCompletionString::CK_LeftBrace:
88 case CodeCompletionString::CK_RightBrace:
89 case CodeCompletionString::CK_LeftAngle:
90 case CodeCompletionString::CK_RightAngle:
91 case CodeCompletionString::CK_Comma:
92 case CodeCompletionString::CK_ResultType:
93 return (*CCStr)[chunk_number].Text;
94
95 case CodeCompletionString::CK_Optional:
96 // Note: treated as an empty text block.
97 return "";
98 }
99
100 // Should be unreachable, but let's be careful.
101 return 0;
102}
103
104CXCompletionString
105clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
106 unsigned chunk_number) {
107 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
108 if (!CCStr || chunk_number >= CCStr->size())
109 return 0;
110
111 switch ((*CCStr)[chunk_number].Kind) {
112 case CodeCompletionString::CK_TypedText:
113 case CodeCompletionString::CK_Text:
114 case CodeCompletionString::CK_Placeholder:
115 case CodeCompletionString::CK_CurrentParameter:
116 case CodeCompletionString::CK_Informative:
117 case CodeCompletionString::CK_LeftParen:
118 case CodeCompletionString::CK_RightParen:
119 case CodeCompletionString::CK_LeftBracket:
120 case CodeCompletionString::CK_RightBracket:
121 case CodeCompletionString::CK_LeftBrace:
122 case CodeCompletionString::CK_RightBrace:
123 case CodeCompletionString::CK_LeftAngle:
124 case CodeCompletionString::CK_RightAngle:
125 case CodeCompletionString::CK_Comma:
126 case CodeCompletionString::CK_ResultType:
127 return 0;
128
129 case CodeCompletionString::CK_Optional:
130 // Note: treated as an empty text block.
131 return (*CCStr)[chunk_number].Optional;
132 }
133
134 // Should be unreachable, but let's be careful.
135 return 0;
136}
137
138unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
139 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
140 return CCStr? CCStr->size() : 0;
141}
142
143static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
144 unsigned &Value) {
145 if (Memory + sizeof(unsigned) > MemoryEnd)
146 return true;
147
148 memmove(&Value, Memory, sizeof(unsigned));
149 Memory += sizeof(unsigned);
150 return false;
151}
152
153/// \brief The CXCodeCompleteResults structure we allocate internally;
154/// the client only sees the initial CXCodeCompleteResults structure.
155struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
156 /// \brief The memory buffer from which we parsed the results. We
157 /// retain this buffer because the completion strings point into it.
158 llvm::MemoryBuffer *Buffer;
159};
160
161CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
162 const char *source_filename,
163 int num_command_line_args,
164 const char **command_line_args,
165 unsigned num_unsaved_files,
166 struct CXUnsavedFile *unsaved_files,
167 const char *complete_filename,
168 unsigned complete_line,
169 unsigned complete_column) {
170 // The indexer, which is mainly used to determine where diagnostics go.
171 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
172
173 // The set of temporary files that we've built.
174 std::vector<llvm::sys::Path> TemporaryFiles;
175
176 // Build up the arguments for invoking 'clang'.
177 std::vector<const char *> argv;
178
179 // First add the complete path to the 'clang' executable.
180 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
181 argv.push_back(ClangPath.c_str());
182
183 // Add the '-fsyntax-only' argument so that we only perform a basic
184 // syntax check of the code.
185 argv.push_back("-fsyntax-only");
186
187 // Add the appropriate '-code-completion-at=file:line:column' argument
188 // to perform code completion, with an "-Xclang" preceding it.
189 std::string code_complete_at;
190 code_complete_at += complete_filename;
191 code_complete_at += ":";
192 code_complete_at += llvm::utostr(complete_line);
193 code_complete_at += ":";
194 code_complete_at += llvm::utostr(complete_column);
195 argv.push_back("-Xclang");
196 argv.push_back("-code-completion-at");
197 argv.push_back("-Xclang");
198 argv.push_back(code_complete_at.c_str());
199 argv.push_back("-Xclang");
200 argv.push_back("-no-code-completion-debug-printer");
201 argv.push_back("-Xclang");
202 argv.push_back("-code-completion-macros");
203
204 std::vector<std::string> RemapArgs;
205 for (unsigned i = 0; i != num_unsaved_files; ++i) {
206 char tmpFile[L_tmpnam];
207 char *tmpFileName = tmpnam(tmpFile);
208
209 // Write the contents of this unsaved file into the temporary file.
210 llvm::sys::Path SavedFile(tmpFileName);
211 std::string ErrorInfo;
212 llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
213 if (!ErrorInfo.empty())
214 continue;
215
216 OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
217 OS.close();
218 if (OS.has_error()) {
219 SavedFile.eraseFromDisk();
220 continue;
221 }
222
223 // Remap the file.
224 std::string RemapArg = unsaved_files[i].Filename;
225 RemapArg += ';';
226 RemapArg += tmpFileName;
227 RemapArgs.push_back("-Xclang");
228 RemapArgs.push_back("-remap-file");
229 RemapArgs.push_back("-Xclang");
230 RemapArgs.push_back(RemapArg);
231 TemporaryFiles.push_back(SavedFile);
232 }
233
234 // The pointers into the elements of RemapArgs are stable because we
235 // won't be adding anything to RemapArgs after this point.
236 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
237 argv.push_back(RemapArgs[i].c_str());
238
239 // Add the source file name (FIXME: later, we'll want to build temporary
240 // file from the buffer, or just feed the source text via standard input).
241 if (source_filename)
242 argv.push_back(source_filename);
243
244 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
245 for (int i = 0; i < num_command_line_args; ++i)
246 if (const char *arg = command_line_args[i]) {
247 if (strcmp(arg, "-o") == 0) {
248 ++i; // Also skip the matching argument.
249 continue;
250 }
251 if (strcmp(arg, "-emit-ast") == 0 ||
252 strcmp(arg, "-c") == 0 ||
253 strcmp(arg, "-fsyntax-only") == 0) {
254 continue;
255 }
256
257 // Keep the argument.
258 argv.push_back(arg);
259 }
260
261 // Add the null terminator.
262 argv.push_back(NULL);
263
264 // Generate a temporary name for the AST file.
265 char tmpFile[L_tmpnam];
266 char *tmpFileName = tmpnam(tmpFile);
267 llvm::sys::Path ResultsFile(tmpFileName);
268 TemporaryFiles.push_back(ResultsFile);
269
270 // Invoke 'clang'.
271 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
272 // on Unix or NUL (Windows).
273 std::string ErrMsg;
274 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
275 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
276 /* redirects */ &Redirects[0],
277 /* secondsToWait */ 0,
278 /* memoryLimits */ 0, &ErrMsg);
279
280 if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
281 llvm::errs() << "clang_codeComplete: " << ErrMsg
282 << '\n' << "Arguments: \n";
283 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
284 I!=E; ++I) {
285 if (*I)
286 llvm::errs() << ' ' << *I << '\n';
287 }
288 llvm::errs() << '\n';
289 }
290
291 // Parse the resulting source file to find code-completion results.
292 using llvm::MemoryBuffer;
293 using llvm::StringRef;
294 AllocatedCXCodeCompleteResults *Results = 0;
295 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
296 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
297 StringRef Buffer = F->getBuffer();
298 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
299 Str < StrEnd;) {
300 unsigned KindValue;
301 if (ReadUnsigned(Str, StrEnd, KindValue))
302 break;
303
304 CodeCompletionString *CCStr
305 = CodeCompletionString::Deserialize(Str, StrEnd);
306 if (!CCStr)
307 continue;
308
309 if (!CCStr->empty()) {
310 // Vend the code-completion result to the caller.
311 CXCompletionResult Result;
312 Result.CursorKind = (CXCursorKind)KindValue;
313 Result.CompletionString = CCStr;
314 CompletionResults.push_back(Result);
315 }
316 };
317
318 // Allocate the results.
319 Results = new AllocatedCXCodeCompleteResults;
320 Results->Results = new CXCompletionResult [CompletionResults.size()];
321 Results->NumResults = CompletionResults.size();
322 memcpy(Results->Results, CompletionResults.data(),
323 CompletionResults.size() * sizeof(CXCompletionResult));
324 Results->Buffer = F;
325 }
326
327 for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
328 TemporaryFiles[i].eraseFromDisk();
329
330 return Results;
331}
332
333void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
334 if (!ResultsIn)
335 return;
336
337 AllocatedCXCodeCompleteResults *Results
338 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
339
340 for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
341 delete (CXCompletionString *)Results->Results[I].CompletionString;
342 delete [] Results->Results;
343
344 Results->Results = 0;
345 Results->NumResults = 0;
346 delete Results->Buffer;
347 Results->Buffer = 0;
348 delete Results;
349}
350
351} // end extern "C"