blob: f3b60dc8b01a095388f422146bbc4e493be6ec84 [file] [log] [blame]
Ted Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000224 // Remap any unsaved files to temporary files.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000225 std::vector<std::string> RemapArgs;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000226 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
227 return 0;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000228
229 // The pointers into the elements of RemapArgs are stable because we
230 // won't be adding anything to RemapArgs after this point.
231 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
232 argv.push_back(RemapArgs[i].c_str());
233
234 // Add the source file name (FIXME: later, we'll want to build temporary
235 // file from the buffer, or just feed the source text via standard input).
236 if (source_filename)
237 argv.push_back(source_filename);
238
239 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
240 for (int i = 0; i < num_command_line_args; ++i)
241 if (const char *arg = command_line_args[i]) {
242 if (strcmp(arg, "-o") == 0) {
243 ++i; // Also skip the matching argument.
244 continue;
245 }
246 if (strcmp(arg, "-emit-ast") == 0 ||
247 strcmp(arg, "-c") == 0 ||
248 strcmp(arg, "-fsyntax-only") == 0) {
249 continue;
250 }
251
252 // Keep the argument.
253 argv.push_back(arg);
254 }
255
256 // Add the null terminator.
257 argv.push_back(NULL);
258
259 // Generate a temporary name for the AST file.
260 char tmpFile[L_tmpnam];
261 char *tmpFileName = tmpnam(tmpFile);
262 llvm::sys::Path ResultsFile(tmpFileName);
263 TemporaryFiles.push_back(ResultsFile);
264
265 // Invoke 'clang'.
266 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
267 // on Unix or NUL (Windows).
268 std::string ErrMsg;
269 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, &DevNull, 0 };
270 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
271 /* redirects */ &Redirects[0],
272 /* secondsToWait */ 0,
273 /* memoryLimits */ 0, &ErrMsg);
274
275 if (CXXIdx->getDisplayDiagnostics() && !ErrMsg.empty()) {
276 llvm::errs() << "clang_codeComplete: " << ErrMsg
277 << '\n' << "Arguments: \n";
278 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
279 I!=E; ++I) {
280 if (*I)
281 llvm::errs() << ' ' << *I << '\n';
282 }
283 llvm::errs() << '\n';
284 }
285
286 // Parse the resulting source file to find code-completion results.
287 using llvm::MemoryBuffer;
288 using llvm::StringRef;
289 AllocatedCXCodeCompleteResults *Results = 0;
290 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
291 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
292 StringRef Buffer = F->getBuffer();
293 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
294 Str < StrEnd;) {
295 unsigned KindValue;
296 if (ReadUnsigned(Str, StrEnd, KindValue))
297 break;
298
299 CodeCompletionString *CCStr
300 = CodeCompletionString::Deserialize(Str, StrEnd);
301 if (!CCStr)
302 continue;
303
304 if (!CCStr->empty()) {
305 // Vend the code-completion result to the caller.
306 CXCompletionResult Result;
307 Result.CursorKind = (CXCursorKind)KindValue;
308 Result.CompletionString = CCStr;
309 CompletionResults.push_back(Result);
310 }
311 };
312
313 // Allocate the results.
314 Results = new AllocatedCXCodeCompleteResults;
315 Results->Results = new CXCompletionResult [CompletionResults.size()];
316 Results->NumResults = CompletionResults.size();
317 memcpy(Results->Results, CompletionResults.data(),
318 CompletionResults.size() * sizeof(CXCompletionResult));
319 Results->Buffer = F;
320 }
321
322 for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
323 TemporaryFiles[i].eraseFromDisk();
324
325 return Results;
326}
327
328void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
329 if (!ResultsIn)
330 return;
331
332 AllocatedCXCodeCompleteResults *Results
333 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
334
335 for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
336 delete (CXCompletionString *)Results->Results[I].CompletionString;
337 delete [] Results->Results;
338
339 Results->Results = 0;
340 Results->NumResults = 0;
341 delete Results->Buffer;
342 Results->Buffer = 0;
343 delete Results;
344}
345
346} // end extern "C"