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