blob: fe4eb8af1165ee8ad4f2b29b7694a88f47ae469e [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"
Douglas Gregorba965fb2010-01-28 00:56:43 +000016#include "CIndexDiagnostic.h"
17#include "clang/Frontend/FrontendDiagnostic.h"
Ted Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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 Gregor504a6ae2010-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 Kremenek0ec2cca2010-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 Gregorba965fb2010-01-28 00:56:43 +0000191 unsigned complete_column,
192 CXDiagnosticCallback diag_callback,
193 CXClientData diag_client_data) {
Ted Kremenek0ec2cca2010-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 Gregorba965fb2010-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 Kremenek0ec2cca2010-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");
Douglas Gregorac0605e2010-01-28 06:00:51 +0000234 argv.push_back("-fdiagnostics-binary");
235
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000236 // Remap any unsaved files to temporary files.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000237 std::vector<std::string> RemapArgs;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000238 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
239 return 0;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000240
241 // The pointers into the elements of RemapArgs are stable because we
242 // won't be adding anything to RemapArgs after this point.
243 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
244 argv.push_back(RemapArgs[i].c_str());
245
246 // Add the source file name (FIXME: later, we'll want to build temporary
247 // file from the buffer, or just feed the source text via standard input).
248 if (source_filename)
249 argv.push_back(source_filename);
250
251 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
252 for (int i = 0; i < num_command_line_args; ++i)
253 if (const char *arg = command_line_args[i]) {
254 if (strcmp(arg, "-o") == 0) {
255 ++i; // Also skip the matching argument.
256 continue;
257 }
258 if (strcmp(arg, "-emit-ast") == 0 ||
259 strcmp(arg, "-c") == 0 ||
260 strcmp(arg, "-fsyntax-only") == 0) {
261 continue;
262 }
263
264 // Keep the argument.
265 argv.push_back(arg);
266 }
267
268 // Add the null terminator.
269 argv.push_back(NULL);
270
Douglas Gregorac0605e2010-01-28 06:00:51 +0000271 // Generate a temporary name for the code-completion results file.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000272 char tmpFile[L_tmpnam];
273 char *tmpFileName = tmpnam(tmpFile);
274 llvm::sys::Path ResultsFile(tmpFileName);
275 TemporaryFiles.push_back(ResultsFile);
276
Douglas Gregorac0605e2010-01-28 06:00:51 +0000277 // Generate a temporary name for the diagnostics file.
278 char tmpFileResults[L_tmpnam];
279 char *tmpResultsFileName = tmpnam(tmpFileResults);
280 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
281 TemporaryFiles.push_back(DiagnosticsFile);
282
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000283 // Invoke 'clang'.
284 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
285 // on Unix or NUL (Windows).
286 std::string ErrMsg;
Douglas Gregorac0605e2010-01-28 06:00:51 +0000287 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
288 &DiagnosticsFile, 0 };
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000289 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
290 /* redirects */ &Redirects[0],
291 /* secondsToWait */ 0,
292 /* memoryLimits */ 0, &ErrMsg);
293
Douglas Gregorba965fb2010-01-28 00:56:43 +0000294 if (!ErrMsg.empty()) {
295 std::string AllArgs;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000296 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregorba965fb2010-01-28 00:56:43 +0000297 I != E; ++I) {
298 AllArgs += ' ';
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000299 if (*I)
Douglas Gregorba965fb2010-01-28 00:56:43 +0000300 AllArgs += *I;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000301 }
Douglas Gregorba965fb2010-01-28 00:56:43 +0000302
303 Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000304 }
305
306 // Parse the resulting source file to find code-completion results.
307 using llvm::MemoryBuffer;
308 using llvm::StringRef;
309 AllocatedCXCodeCompleteResults *Results = 0;
310 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
311 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
312 StringRef Buffer = F->getBuffer();
313 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
314 Str < StrEnd;) {
315 unsigned KindValue;
316 if (ReadUnsigned(Str, StrEnd, KindValue))
317 break;
318
319 CodeCompletionString *CCStr
320 = CodeCompletionString::Deserialize(Str, StrEnd);
321 if (!CCStr)
322 continue;
323
324 if (!CCStr->empty()) {
325 // Vend the code-completion result to the caller.
326 CXCompletionResult Result;
327 Result.CursorKind = (CXCursorKind)KindValue;
328 Result.CompletionString = CCStr;
329 CompletionResults.push_back(Result);
330 }
331 };
332
333 // Allocate the results.
334 Results = new AllocatedCXCodeCompleteResults;
335 Results->Results = new CXCompletionResult [CompletionResults.size()];
336 Results->NumResults = CompletionResults.size();
337 memcpy(Results->Results, CompletionResults.data(),
338 CompletionResults.size() * sizeof(CXCompletionResult));
339 Results->Buffer = F;
340 }
341
Douglas Gregorac0605e2010-01-28 06:00:51 +0000342 ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
343 num_unsaved_files, unsaved_files);
Douglas Gregorba965fb2010-01-28 00:56:43 +0000344
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000345 for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
346 TemporaryFiles[i].eraseFromDisk();
347
348 return Results;
349}
350
351void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
352 if (!ResultsIn)
353 return;
354
355 AllocatedCXCodeCompleteResults *Results
356 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
357
358 for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
359 delete (CXCompletionString *)Results->Results[I].CompletionString;
360 delete [] Results->Results;
361
362 Results->Results = 0;
363 Results->NumResults = 0;
364 delete Results->Buffer;
365 Results->Buffer = 0;
366 delete Results;
367}
368
369} // end extern "C"