blob: 4e41c5f1c7b5b95d3642516804483047d4d6b270 [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;
Daniel Dunbar35b84402010-01-30 23:31:40 +0000181
182 LangOptions LangOpts;
Ted Kremenekab188932010-01-05 19:32:54 +0000183};
184
185CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
186 const char *source_filename,
187 int num_command_line_args,
188 const char **command_line_args,
189 unsigned num_unsaved_files,
190 struct CXUnsavedFile *unsaved_files,
191 const char *complete_filename,
192 unsigned complete_line,
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000193 unsigned complete_column,
194 CXDiagnosticCallback diag_callback,
195 CXClientData diag_client_data) {
Ted Kremenekab188932010-01-05 19:32:54 +0000196 // The indexer, which is mainly used to determine where diagnostics go.
197 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
198
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000199 // Configure the diagnostics.
200 DiagnosticOptions DiagOpts;
201 llvm::OwningPtr<Diagnostic> Diags;
202 Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
203 CIndexDiagnosticClient DiagClient(diag_callback, diag_client_data);
204 Diags->setClient(&DiagClient);
205
Ted Kremenekab188932010-01-05 19:32:54 +0000206 // The set of temporary files that we've built.
207 std::vector<llvm::sys::Path> TemporaryFiles;
208
209 // Build up the arguments for invoking 'clang'.
210 std::vector<const char *> argv;
211
212 // First add the complete path to the 'clang' executable.
213 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
214 argv.push_back(ClangPath.c_str());
215
216 // Add the '-fsyntax-only' argument so that we only perform a basic
217 // syntax check of the code.
218 argv.push_back("-fsyntax-only");
219
220 // Add the appropriate '-code-completion-at=file:line:column' argument
221 // to perform code completion, with an "-Xclang" preceding it.
222 std::string code_complete_at;
223 code_complete_at += complete_filename;
224 code_complete_at += ":";
225 code_complete_at += llvm::utostr(complete_line);
226 code_complete_at += ":";
227 code_complete_at += llvm::utostr(complete_column);
228 argv.push_back("-Xclang");
229 argv.push_back("-code-completion-at");
230 argv.push_back("-Xclang");
231 argv.push_back(code_complete_at.c_str());
232 argv.push_back("-Xclang");
233 argv.push_back("-no-code-completion-debug-printer");
234 argv.push_back("-Xclang");
235 argv.push_back("-code-completion-macros");
Douglas Gregord93256e2010-01-28 06:00:51 +0000236 argv.push_back("-fdiagnostics-binary");
237
Douglas Gregor4db64a42010-01-23 00:14:00 +0000238 // Remap any unsaved files to temporary files.
Ted Kremenekab188932010-01-05 19:32:54 +0000239 std::vector<std::string> RemapArgs;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000240 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
241 return 0;
Ted Kremenekab188932010-01-05 19:32:54 +0000242
243 // The pointers into the elements of RemapArgs are stable because we
244 // won't be adding anything to RemapArgs after this point.
245 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
246 argv.push_back(RemapArgs[i].c_str());
247
248 // Add the source file name (FIXME: later, we'll want to build temporary
249 // file from the buffer, or just feed the source text via standard input).
250 if (source_filename)
251 argv.push_back(source_filename);
252
253 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
254 for (int i = 0; i < num_command_line_args; ++i)
255 if (const char *arg = command_line_args[i]) {
256 if (strcmp(arg, "-o") == 0) {
257 ++i; // Also skip the matching argument.
258 continue;
259 }
260 if (strcmp(arg, "-emit-ast") == 0 ||
261 strcmp(arg, "-c") == 0 ||
262 strcmp(arg, "-fsyntax-only") == 0) {
263 continue;
264 }
265
266 // Keep the argument.
267 argv.push_back(arg);
268 }
269
270 // Add the null terminator.
271 argv.push_back(NULL);
272
Douglas Gregord93256e2010-01-28 06:00:51 +0000273 // Generate a temporary name for the code-completion results file.
Ted Kremenekab188932010-01-05 19:32:54 +0000274 char tmpFile[L_tmpnam];
275 char *tmpFileName = tmpnam(tmpFile);
276 llvm::sys::Path ResultsFile(tmpFileName);
277 TemporaryFiles.push_back(ResultsFile);
278
Douglas Gregord93256e2010-01-28 06:00:51 +0000279 // Generate a temporary name for the diagnostics file.
280 char tmpFileResults[L_tmpnam];
281 char *tmpResultsFileName = tmpnam(tmpFileResults);
282 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
283 TemporaryFiles.push_back(DiagnosticsFile);
284
Ted Kremenekab188932010-01-05 19:32:54 +0000285 // Invoke 'clang'.
286 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
287 // on Unix or NUL (Windows).
288 std::string ErrMsg;
Douglas Gregord93256e2010-01-28 06:00:51 +0000289 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
290 &DiagnosticsFile, 0 };
Ted Kremenekab188932010-01-05 19:32:54 +0000291 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
292 /* redirects */ &Redirects[0],
293 /* secondsToWait */ 0,
294 /* memoryLimits */ 0, &ErrMsg);
295
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000296 if (!ErrMsg.empty()) {
297 std::string AllArgs;
Ted Kremenekab188932010-01-05 19:32:54 +0000298 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000299 I != E; ++I) {
300 AllArgs += ' ';
Ted Kremenekab188932010-01-05 19:32:54 +0000301 if (*I)
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000302 AllArgs += *I;
Ted Kremenekab188932010-01-05 19:32:54 +0000303 }
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000304
305 Diags->Report(diag::err_fe_clang) << AllArgs << ErrMsg;
Ted Kremenekab188932010-01-05 19:32:54 +0000306 }
307
308 // Parse the resulting source file to find code-completion results.
309 using llvm::MemoryBuffer;
310 using llvm::StringRef;
311 AllocatedCXCodeCompleteResults *Results = 0;
312 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
313 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
314 StringRef Buffer = F->getBuffer();
315 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
316 Str < StrEnd;) {
317 unsigned KindValue;
318 if (ReadUnsigned(Str, StrEnd, KindValue))
319 break;
320
321 CodeCompletionString *CCStr
322 = CodeCompletionString::Deserialize(Str, StrEnd);
323 if (!CCStr)
324 continue;
325
326 if (!CCStr->empty()) {
327 // Vend the code-completion result to the caller.
328 CXCompletionResult Result;
329 Result.CursorKind = (CXCursorKind)KindValue;
330 Result.CompletionString = CCStr;
331 CompletionResults.push_back(Result);
332 }
333 };
334
335 // Allocate the results.
336 Results = new AllocatedCXCodeCompleteResults;
337 Results->Results = new CXCompletionResult [CompletionResults.size()];
338 Results->NumResults = CompletionResults.size();
339 memcpy(Results->Results, CompletionResults.data(),
340 CompletionResults.size() * sizeof(CXCompletionResult));
341 Results->Buffer = F;
342 }
343
Daniel Dunbar35b84402010-01-30 23:31:40 +0000344 // FIXME: The LangOptions we are passing here are not at all correct. However,
345 // in the current design we must pass something in so the SourceLocations have
346 // a LangOptions object to refer to.
Douglas Gregord93256e2010-01-28 06:00:51 +0000347 ReportSerializedDiagnostics(DiagnosticsFile, *Diags,
Daniel Dunbar35b84402010-01-30 23:31:40 +0000348 num_unsaved_files, unsaved_files,
349 Results->LangOpts);
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000350
Ted Kremenekab188932010-01-05 19:32:54 +0000351 for (unsigned i = 0, e = TemporaryFiles.size(); i != e; ++i)
352 TemporaryFiles[i].eraseFromDisk();
353
354 return Results;
355}
356
357void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
358 if (!ResultsIn)
359 return;
360
361 AllocatedCXCodeCompleteResults *Results
362 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
363
364 for (unsigned I = 0, N = Results->NumResults; I != N; ++I)
365 delete (CXCompletionString *)Results->Results[I].CompletionString;
366 delete [] Results->Results;
367
368 Results->Results = 0;
369 Results->NumResults = 0;
370 delete Results->Buffer;
371 Results->Buffer = 0;
372 delete Results;
373}
374
375} // end extern "C"