blob: f70479b5e8d39f42c976d29aab2e1e0dcc25eaba [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;
Douglas Gregor01dfea02010-01-10 23:08:15 +000065 case CodeCompletionString::CK_Colon:
66 return CXCompletionChunk_Colon;
67 case CodeCompletionString::CK_SemiColon:
68 return CXCompletionChunk_SemiColon;
69 case CodeCompletionString::CK_Equal:
70 return CXCompletionChunk_Equal;
71 case CodeCompletionString::CK_HorizontalSpace:
72 return CXCompletionChunk_HorizontalSpace;
73 case CodeCompletionString::CK_VerticalSpace:
74 return CXCompletionChunk_VerticalSpace;
Ted Kremenekab188932010-01-05 19:32:54 +000075 }
76
77 // Should be unreachable, but let's be careful.
78 return CXCompletionChunk_Text;
79}
80
81const char *clang_getCompletionChunkText(CXCompletionString completion_string,
82 unsigned chunk_number) {
83 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
84 if (!CCStr || chunk_number >= CCStr->size())
85 return 0;
86
87 switch ((*CCStr)[chunk_number].Kind) {
88 case CodeCompletionString::CK_TypedText:
89 case CodeCompletionString::CK_Text:
90 case CodeCompletionString::CK_Placeholder:
91 case CodeCompletionString::CK_CurrentParameter:
92 case CodeCompletionString::CK_Informative:
93 case CodeCompletionString::CK_LeftParen:
94 case CodeCompletionString::CK_RightParen:
95 case CodeCompletionString::CK_LeftBracket:
96 case CodeCompletionString::CK_RightBracket:
97 case CodeCompletionString::CK_LeftBrace:
98 case CodeCompletionString::CK_RightBrace:
99 case CodeCompletionString::CK_LeftAngle:
100 case CodeCompletionString::CK_RightAngle:
101 case CodeCompletionString::CK_Comma:
102 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000103 case CodeCompletionString::CK_Colon:
104 case CodeCompletionString::CK_SemiColon:
105 case CodeCompletionString::CK_Equal:
106 case CodeCompletionString::CK_HorizontalSpace:
107 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenekab188932010-01-05 19:32:54 +0000108 return (*CCStr)[chunk_number].Text;
109
110 case CodeCompletionString::CK_Optional:
111 // Note: treated as an empty text block.
112 return "";
113 }
114
115 // Should be unreachable, but let's be careful.
116 return 0;
117}
118
119CXCompletionString
120clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
121 unsigned chunk_number) {
122 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
123 if (!CCStr || chunk_number >= CCStr->size())
124 return 0;
125
126 switch ((*CCStr)[chunk_number].Kind) {
127 case CodeCompletionString::CK_TypedText:
128 case CodeCompletionString::CK_Text:
129 case CodeCompletionString::CK_Placeholder:
130 case CodeCompletionString::CK_CurrentParameter:
131 case CodeCompletionString::CK_Informative:
132 case CodeCompletionString::CK_LeftParen:
133 case CodeCompletionString::CK_RightParen:
134 case CodeCompletionString::CK_LeftBracket:
135 case CodeCompletionString::CK_RightBracket:
136 case CodeCompletionString::CK_LeftBrace:
137 case CodeCompletionString::CK_RightBrace:
138 case CodeCompletionString::CK_LeftAngle:
139 case CodeCompletionString::CK_RightAngle:
140 case CodeCompletionString::CK_Comma:
141 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000142 case CodeCompletionString::CK_Colon:
143 case CodeCompletionString::CK_SemiColon:
144 case CodeCompletionString::CK_Equal:
145 case CodeCompletionString::CK_HorizontalSpace:
146 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenekab188932010-01-05 19:32:54 +0000147 return 0;
148
149 case CodeCompletionString::CK_Optional:
150 // Note: treated as an empty text block.
151 return (*CCStr)[chunk_number].Optional;
152 }
153
154 // Should be unreachable, but let's be careful.
155 return 0;
156}
157
158unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
159 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
160 return CCStr? CCStr->size() : 0;
161}
162
163static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
164 unsigned &Value) {
165 if (Memory + sizeof(unsigned) > MemoryEnd)
166 return true;
167
168 memmove(&Value, Memory, sizeof(unsigned));
169 Memory += sizeof(unsigned);
170 return false;
171}
172
173/// \brief The CXCodeCompleteResults structure we allocate internally;
174/// the client only sees the initial CXCodeCompleteResults structure.
175struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
176 /// \brief The memory buffer from which we parsed the results. We
177 /// retain this buffer because the completion strings point into it.
178 llvm::MemoryBuffer *Buffer;
179};
180
181CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
182 const char *source_filename,
183 int num_command_line_args,
184 const char **command_line_args,
185 unsigned num_unsaved_files,
186 struct CXUnsavedFile *unsaved_files,
187 const char *complete_filename,
188 unsigned complete_line,
189 unsigned complete_column) {
190 // The indexer, which is mainly used to determine where diagnostics go.
191 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
192
193 // The set of temporary files that we've built.
194 std::vector<llvm::sys::Path> TemporaryFiles;
195
196 // Build up the arguments for invoking 'clang'.
197 std::vector<const char *> argv;
198
199 // First add the complete path to the 'clang' executable.
200 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
201 argv.push_back(ClangPath.c_str());
202
203 // Add the '-fsyntax-only' argument so that we only perform a basic
204 // syntax check of the code.
205 argv.push_back("-fsyntax-only");
206
207 // Add the appropriate '-code-completion-at=file:line:column' argument
208 // to perform code completion, with an "-Xclang" preceding it.
209 std::string code_complete_at;
210 code_complete_at += complete_filename;
211 code_complete_at += ":";
212 code_complete_at += llvm::utostr(complete_line);
213 code_complete_at += ":";
214 code_complete_at += llvm::utostr(complete_column);
215 argv.push_back("-Xclang");
216 argv.push_back("-code-completion-at");
217 argv.push_back("-Xclang");
218 argv.push_back(code_complete_at.c_str());
219 argv.push_back("-Xclang");
220 argv.push_back("-no-code-completion-debug-printer");
221 argv.push_back("-Xclang");
222 argv.push_back("-code-completion-macros");
223
224 std::vector<std::string> RemapArgs;
225 for (unsigned i = 0; i != num_unsaved_files; ++i) {
226 char tmpFile[L_tmpnam];
227 char *tmpFileName = tmpnam(tmpFile);
228
229 // Write the contents of this unsaved file into the temporary file.
230 llvm::sys::Path SavedFile(tmpFileName);
231 std::string ErrorInfo;
232 llvm::raw_fd_ostream OS(SavedFile.c_str(), ErrorInfo);
233 if (!ErrorInfo.empty())
234 continue;
235
236 OS.write(unsaved_files[i].Contents, unsaved_files[i].Length);
237 OS.close();
238 if (OS.has_error()) {
239 SavedFile.eraseFromDisk();
240 continue;
241 }
242
243 // Remap the file.
244 std::string RemapArg = unsaved_files[i].Filename;
245 RemapArg += ';';
246 RemapArg += tmpFileName;
247 RemapArgs.push_back("-Xclang");
248 RemapArgs.push_back("-remap-file");
249 RemapArgs.push_back("-Xclang");
250 RemapArgs.push_back(RemapArg);
251 TemporaryFiles.push_back(SavedFile);
252 }
253
254 // The pointers into the elements of RemapArgs are stable because we
255 // won't be adding anything to RemapArgs after this point.
256 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
257 argv.push_back(RemapArgs[i].c_str());
258
259 // Add the source file name (FIXME: later, we'll want to build temporary
260 // file from the buffer, or just feed the source text via standard input).
261 if (source_filename)
262 argv.push_back(source_filename);
263
264 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
265 for (int i = 0; i < num_command_line_args; ++i)
266 if (const char *arg = command_line_args[i]) {
267 if (strcmp(arg, "-o") == 0) {
268 ++i; // Also skip the matching argument.
269 continue;
270 }
271 if (strcmp(arg, "-emit-ast") == 0 ||
272 strcmp(arg, "-c") == 0 ||
273 strcmp(arg, "-fsyntax-only") == 0) {
274 continue;
275 }
276
277 // Keep the argument.
278 argv.push_back(arg);
279 }
280
281 // Add the null terminator.
282 argv.push_back(NULL);
283
284 // Generate a temporary name for the AST file.
285 char tmpFile[L_tmpnam];
286 char *tmpFileName = tmpnam(tmpFile);
287 llvm::sys::Path ResultsFile(tmpFileName);
288 TemporaryFiles.push_back(ResultsFile);
289
290 // Invoke 'clang'.
291 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
292 // on Unix or NUL (Windows).
293 std::string ErrMsg;
294 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
295 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
296 /* redirects */ &Redirects[0],
297 /* secondsToWait */ 0,
298 /* memoryLimits */ 0, &ErrMsg);
299
300 if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
301 llvm::errs() << "clang_codeComplete: " << ErrMsg
302 << '\n' << "Arguments: \n";
303 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
304 I!=E; ++I) {
305 if (*I)
306 llvm::errs() << ' ' << *I << '\n';
307 }
308 llvm::errs() << '\n';
309 }
310
311 // Parse the resulting source file to find code-completion results.
312 using llvm::MemoryBuffer;
313 using llvm::StringRef;
314 AllocatedCXCodeCompleteResults *Results = 0;
315 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
316 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
317 StringRef Buffer = F->getBuffer();
318 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
319 Str < StrEnd;) {
320 unsigned KindValue;
321 if (ReadUnsigned(Str, StrEnd, KindValue))
322 break;
323
324 CodeCompletionString *CCStr
325 = CodeCompletionString::Deserialize(Str, StrEnd);
326 if (!CCStr)
327 continue;
328
329 if (!CCStr->empty()) {
330 // Vend the code-completion result to the caller.
331 CXCompletionResult Result;
332 Result.CursorKind = (CXCursorKind)KindValue;
333 Result.CompletionString = CCStr;
334 CompletionResults.push_back(Result);
335 }
336 };
337
338 // Allocate the results.
339 Results = new AllocatedCXCodeCompleteResults;
340 Results->Results = new CXCompletionResult [CompletionResults.size()];
341 Results->NumResults = CompletionResults.size();
342 memcpy(Results->Results, CompletionResults.data(),
343 CompletionResults.size() * sizeof(CXCompletionResult));
344 Results->Buffer = F;
345 }
346
347 for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
348 TemporaryFiles[i].eraseFromDisk();
349
350 return Results;
351}
352
353void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
354 if (!ResultsIn)
355 return;
356
357 AllocatedCXCodeCompleteResults *Results
358 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
359
360 for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
361 delete (CXCompletionString *)Results->Results[I].CompletionString;
362 delete [] Results->Results;
363
364 Results->Results = 0;
365 Results->NumResults = 0;
366 delete Results->Buffer;
367 Results->Buffer = 0;
368 delete Results;
369}
370
371} // end extern "C"