blob: 264e5064ddb46c3e72e9910ce27d483fda7d7c68 [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;
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +000024using namespace clang::cxstring;
Ted Kremenekab188932010-01-05 19:32:54 +000025
26extern "C" {
27
28enum CXCompletionChunkKind
29clang_getCompletionChunkKind(CXCompletionString completion_string,
30 unsigned chunk_number) {
31 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
32 if (!CCStr || chunk_number >= CCStr->size())
33 return CXCompletionChunk_Text;
34
35 switch ((*CCStr)[chunk_number].Kind) {
36 case CodeCompletionString::CK_TypedText:
37 return CXCompletionChunk_TypedText;
38 case CodeCompletionString::CK_Text:
39 return CXCompletionChunk_Text;
40 case CodeCompletionString::CK_Optional:
41 return CXCompletionChunk_Optional;
42 case CodeCompletionString::CK_Placeholder:
43 return CXCompletionChunk_Placeholder;
44 case CodeCompletionString::CK_Informative:
45 return CXCompletionChunk_Informative;
46 case CodeCompletionString::CK_ResultType:
47 return CXCompletionChunk_ResultType;
48 case CodeCompletionString::CK_CurrentParameter:
49 return CXCompletionChunk_CurrentParameter;
50 case CodeCompletionString::CK_LeftParen:
51 return CXCompletionChunk_LeftParen;
52 case CodeCompletionString::CK_RightParen:
53 return CXCompletionChunk_RightParen;
54 case CodeCompletionString::CK_LeftBracket:
55 return CXCompletionChunk_LeftBracket;
56 case CodeCompletionString::CK_RightBracket:
57 return CXCompletionChunk_RightBracket;
58 case CodeCompletionString::CK_LeftBrace:
59 return CXCompletionChunk_LeftBrace;
60 case CodeCompletionString::CK_RightBrace:
61 return CXCompletionChunk_RightBrace;
62 case CodeCompletionString::CK_LeftAngle:
63 return CXCompletionChunk_LeftAngle;
64 case CodeCompletionString::CK_RightAngle:
65 return CXCompletionChunk_RightAngle;
66 case CodeCompletionString::CK_Comma:
67 return CXCompletionChunk_Comma;
Douglas Gregor01dfea02010-01-10 23:08:15 +000068 case CodeCompletionString::CK_Colon:
69 return CXCompletionChunk_Colon;
70 case CodeCompletionString::CK_SemiColon:
71 return CXCompletionChunk_SemiColon;
72 case CodeCompletionString::CK_Equal:
73 return CXCompletionChunk_Equal;
74 case CodeCompletionString::CK_HorizontalSpace:
75 return CXCompletionChunk_HorizontalSpace;
76 case CodeCompletionString::CK_VerticalSpace:
77 return CXCompletionChunk_VerticalSpace;
Ted Kremenekab188932010-01-05 19:32:54 +000078 }
79
80 // Should be unreachable, but let's be careful.
81 return CXCompletionChunk_Text;
82}
83
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +000084CXString clang_getCompletionChunkText(CXCompletionString completion_string,
85 unsigned chunk_number) {
Ted Kremenekab188932010-01-05 19:32:54 +000086 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
87 if (!CCStr || chunk_number >= CCStr->size())
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +000088 return createCXString(0);
Ted Kremenekab188932010-01-05 19:32:54 +000089
90 switch ((*CCStr)[chunk_number].Kind) {
91 case CodeCompletionString::CK_TypedText:
92 case CodeCompletionString::CK_Text:
93 case CodeCompletionString::CK_Placeholder:
94 case CodeCompletionString::CK_CurrentParameter:
95 case CodeCompletionString::CK_Informative:
96 case CodeCompletionString::CK_LeftParen:
97 case CodeCompletionString::CK_RightParen:
98 case CodeCompletionString::CK_LeftBracket:
99 case CodeCompletionString::CK_RightBracket:
100 case CodeCompletionString::CK_LeftBrace:
101 case CodeCompletionString::CK_RightBrace:
102 case CodeCompletionString::CK_LeftAngle:
103 case CodeCompletionString::CK_RightAngle:
104 case CodeCompletionString::CK_Comma:
105 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000106 case CodeCompletionString::CK_Colon:
107 case CodeCompletionString::CK_SemiColon:
108 case CodeCompletionString::CK_Equal:
109 case CodeCompletionString::CK_HorizontalSpace:
110 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000111 return createCXString((*CCStr)[chunk_number].Text, false);
Ted Kremenekab188932010-01-05 19:32:54 +0000112
113 case CodeCompletionString::CK_Optional:
114 // Note: treated as an empty text block.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000115 return createCXString("");
Ted Kremenekab188932010-01-05 19:32:54 +0000116 }
117
118 // Should be unreachable, but let's be careful.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000119 return createCXString(0);
Ted Kremenekab188932010-01-05 19:32:54 +0000120}
121
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000122
Ted Kremenekab188932010-01-05 19:32:54 +0000123CXCompletionString
124clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
125 unsigned chunk_number) {
126 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
127 if (!CCStr || chunk_number >= CCStr->size())
128 return 0;
129
130 switch ((*CCStr)[chunk_number].Kind) {
131 case CodeCompletionString::CK_TypedText:
132 case CodeCompletionString::CK_Text:
133 case CodeCompletionString::CK_Placeholder:
134 case CodeCompletionString::CK_CurrentParameter:
135 case CodeCompletionString::CK_Informative:
136 case CodeCompletionString::CK_LeftParen:
137 case CodeCompletionString::CK_RightParen:
138 case CodeCompletionString::CK_LeftBracket:
139 case CodeCompletionString::CK_RightBracket:
140 case CodeCompletionString::CK_LeftBrace:
141 case CodeCompletionString::CK_RightBrace:
142 case CodeCompletionString::CK_LeftAngle:
143 case CodeCompletionString::CK_RightAngle:
144 case CodeCompletionString::CK_Comma:
145 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000146 case CodeCompletionString::CK_Colon:
147 case CodeCompletionString::CK_SemiColon:
148 case CodeCompletionString::CK_Equal:
149 case CodeCompletionString::CK_HorizontalSpace:
150 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenekab188932010-01-05 19:32:54 +0000151 return 0;
152
153 case CodeCompletionString::CK_Optional:
154 // Note: treated as an empty text block.
155 return (*CCStr)[chunk_number].Optional;
156 }
157
158 // Should be unreachable, but let's be careful.
159 return 0;
160}
161
162unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
163 CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
164 return CCStr? CCStr->size() : 0;
165}
166
167static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
168 unsigned &Value) {
169 if (Memory + sizeof(unsigned) > MemoryEnd)
170 return true;
171
172 memmove(&Value, Memory, sizeof(unsigned));
173 Memory += sizeof(unsigned);
174 return false;
175}
176
177/// \brief The CXCodeCompleteResults structure we allocate internally;
178/// the client only sees the initial CXCodeCompleteResults structure.
179struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000180 AllocatedCXCodeCompleteResults();
181 ~AllocatedCXCodeCompleteResults();
182
Ted Kremenekab188932010-01-05 19:32:54 +0000183 /// \brief The memory buffer from which we parsed the results. We
184 /// retain this buffer because the completion strings point into it.
185 llvm::MemoryBuffer *Buffer;
Daniel Dunbar35b84402010-01-30 23:31:40 +0000186
Douglas Gregora88084b2010-02-18 18:08:43 +0000187 /// \brief Diagnostics produced while performing code completion.
188 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
189
Douglas Gregorf715ca12010-03-16 00:06:06 +0000190 /// \brief Diag object
191 Diagnostic Diag;
192
Douglas Gregora88084b2010-02-18 18:08:43 +0000193 /// \brief Language options used to adjust source locations.
Daniel Dunbar35b84402010-01-30 23:31:40 +0000194 LangOptions LangOpts;
Douglas Gregora88084b2010-02-18 18:08:43 +0000195
196 /// \brief Source manager, used for diagnostics.
197 SourceManager SourceMgr;
198
199 /// \brief File manager, used for diagnostics.
200 FileManager FileMgr;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000201
202 /// \brief Temporary files that should be removed once we have finished
203 /// with the code-completion results.
204 std::vector<llvm::sys::Path> TemporaryFiles;
Ted Kremenekab188932010-01-05 19:32:54 +0000205};
206
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000207AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
Douglas Gregorf715ca12010-03-16 00:06:06 +0000208 : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000209
210AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
211 for (unsigned I = 0, N = NumResults; I != N; ++I)
212 delete (CodeCompletionString *)Results[I].CompletionString;
213 delete [] Results;
214 delete Buffer;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000215
216 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
217 TemporaryFiles[I].eraseFromDisk();
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000218}
219
Ted Kremenekab188932010-01-05 19:32:54 +0000220CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
221 const char *source_filename,
222 int num_command_line_args,
223 const char **command_line_args,
224 unsigned num_unsaved_files,
225 struct CXUnsavedFile *unsaved_files,
226 const char *complete_filename,
227 unsigned complete_line,
Douglas Gregora88084b2010-02-18 18:08:43 +0000228 unsigned complete_column) {
Ted Kremenekab188932010-01-05 19:32:54 +0000229 // The indexer, which is mainly used to determine where diagnostics go.
230 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
231
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000232 // Configure the diagnostics.
233 DiagnosticOptions DiagOpts;
234 llvm::OwningPtr<Diagnostic> Diags;
235 Diags.reset(CompilerInstance::createDiagnostics(DiagOpts, 0, 0));
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000236
Ted Kremenekab188932010-01-05 19:32:54 +0000237 // The set of temporary files that we've built.
238 std::vector<llvm::sys::Path> TemporaryFiles;
239
240 // Build up the arguments for invoking 'clang'.
241 std::vector<const char *> argv;
242
243 // First add the complete path to the 'clang' executable.
244 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
245 argv.push_back(ClangPath.c_str());
246
247 // Add the '-fsyntax-only' argument so that we only perform a basic
248 // syntax check of the code.
249 argv.push_back("-fsyntax-only");
250
251 // Add the appropriate '-code-completion-at=file:line:column' argument
252 // to perform code completion, with an "-Xclang" preceding it.
253 std::string code_complete_at;
254 code_complete_at += complete_filename;
255 code_complete_at += ":";
256 code_complete_at += llvm::utostr(complete_line);
257 code_complete_at += ":";
258 code_complete_at += llvm::utostr(complete_column);
259 argv.push_back("-Xclang");
260 argv.push_back("-code-completion-at");
261 argv.push_back("-Xclang");
262 argv.push_back(code_complete_at.c_str());
263 argv.push_back("-Xclang");
264 argv.push_back("-no-code-completion-debug-printer");
265 argv.push_back("-Xclang");
266 argv.push_back("-code-completion-macros");
Douglas Gregord93256e2010-01-28 06:00:51 +0000267 argv.push_back("-fdiagnostics-binary");
268
Douglas Gregor4db64a42010-01-23 00:14:00 +0000269 // Remap any unsaved files to temporary files.
Ted Kremenekab188932010-01-05 19:32:54 +0000270 std::vector<std::string> RemapArgs;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000271 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
272 return 0;
Ted Kremenekab188932010-01-05 19:32:54 +0000273
274 // The pointers into the elements of RemapArgs are stable because we
275 // won't be adding anything to RemapArgs after this point.
276 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
277 argv.push_back(RemapArgs[i].c_str());
278
279 // Add the source file name (FIXME: later, we'll want to build temporary
280 // file from the buffer, or just feed the source text via standard input).
281 if (source_filename)
282 argv.push_back(source_filename);
283
284 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
285 for (int i = 0; i < num_command_line_args; ++i)
286 if (const char *arg = command_line_args[i]) {
287 if (strcmp(arg, "-o") == 0) {
288 ++i; // Also skip the matching argument.
289 continue;
290 }
291 if (strcmp(arg, "-emit-ast") == 0 ||
292 strcmp(arg, "-c") == 0 ||
293 strcmp(arg, "-fsyntax-only") == 0) {
294 continue;
295 }
296
297 // Keep the argument.
298 argv.push_back(arg);
299 }
300
301 // Add the null terminator.
302 argv.push_back(NULL);
303
Douglas Gregord93256e2010-01-28 06:00:51 +0000304 // Generate a temporary name for the code-completion results file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000305 char tmpFile[L_tmpnam];
306 char *tmpFileName = tmpnam(tmpFile);
307 llvm::sys::Path ResultsFile(tmpFileName);
Ted Kremenekab188932010-01-05 19:32:54 +0000308 TemporaryFiles.push_back(ResultsFile);
309
Douglas Gregord93256e2010-01-28 06:00:51 +0000310 // Generate a temporary name for the diagnostics file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000311 char tmpFileResults[L_tmpnam];
312 char *tmpResultsFileName = tmpnam(tmpFileResults);
313 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
Douglas Gregord93256e2010-01-28 06:00:51 +0000314 TemporaryFiles.push_back(DiagnosticsFile);
315
Ted Kremenekab188932010-01-05 19:32:54 +0000316 // Invoke 'clang'.
317 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
318 // on Unix or NUL (Windows).
319 std::string ErrMsg;
Douglas Gregord93256e2010-01-28 06:00:51 +0000320 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
321 &DiagnosticsFile, 0 };
Ted Kremenekab188932010-01-05 19:32:54 +0000322 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
323 /* redirects */ &Redirects[0],
324 /* secondsToWait */ 0,
325 /* memoryLimits */ 0, &ErrMsg);
326
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000327 if (!ErrMsg.empty()) {
328 std::string AllArgs;
Ted Kremenekab188932010-01-05 19:32:54 +0000329 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000330 I != E; ++I) {
331 AllArgs += ' ';
Ted Kremenekab188932010-01-05 19:32:54 +0000332 if (*I)
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000333 AllArgs += *I;
Ted Kremenekab188932010-01-05 19:32:54 +0000334 }
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000335
Daniel Dunbar32141c82010-02-23 20:23:45 +0000336 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
Ted Kremenekab188932010-01-05 19:32:54 +0000337 }
338
339 // Parse the resulting source file to find code-completion results.
340 using llvm::MemoryBuffer;
341 using llvm::StringRef;
Douglas Gregora88084b2010-02-18 18:08:43 +0000342 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
343 Results->Results = 0;
344 Results->NumResults = 0;
345 Results->Buffer = 0;
346 // FIXME: Set Results->LangOpts!
Ted Kremenekab188932010-01-05 19:32:54 +0000347 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
348 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
349 StringRef Buffer = F->getBuffer();
350 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
351 Str < StrEnd;) {
352 unsigned KindValue;
353 if (ReadUnsigned(Str, StrEnd, KindValue))
354 break;
355
356 CodeCompletionString *CCStr
357 = CodeCompletionString::Deserialize(Str, StrEnd);
358 if (!CCStr)
359 continue;
360
361 if (!CCStr->empty()) {
362 // Vend the code-completion result to the caller.
363 CXCompletionResult Result;
364 Result.CursorKind = (CXCursorKind)KindValue;
365 Result.CompletionString = CCStr;
366 CompletionResults.push_back(Result);
367 }
368 };
369
370 // Allocate the results.
Ted Kremenekab188932010-01-05 19:32:54 +0000371 Results->Results = new CXCompletionResult [CompletionResults.size()];
372 Results->NumResults = CompletionResults.size();
373 memcpy(Results->Results, CompletionResults.data(),
374 CompletionResults.size() * sizeof(CXCompletionResult));
375 Results->Buffer = F;
376 }
377
Douglas Gregora88084b2010-02-18 18:08:43 +0000378 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
379 Results->FileMgr, Results->SourceMgr,
380 Results->Diagnostics);
381
Douglas Gregor313e26c2010-02-18 23:35:40 +0000382 // Make sure we delete temporary files when the code-completion results are
383 // destroyed.
384 Results->TemporaryFiles.swap(TemporaryFiles);
Ted Kremenekab188932010-01-05 19:32:54 +0000385
386 return Results;
387}
388
389void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
390 if (!ResultsIn)
391 return;
392
393 AllocatedCXCodeCompleteResults *Results
394 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
Ted Kremenekab188932010-01-05 19:32:54 +0000395 delete Results;
396}
397
Douglas Gregora88084b2010-02-18 18:08:43 +0000398unsigned
399clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
400 AllocatedCXCodeCompleteResults *Results
401 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
402 if (!Results)
403 return 0;
404
405 return Results->Diagnostics.size();
406}
407
408CXDiagnostic
409clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
410 unsigned Index) {
411 AllocatedCXCodeCompleteResults *Results
412 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
413 if (!Results || Index >= Results->Diagnostics.size())
414 return 0;
415
416 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
417}
418
419
Ted Kremenekab188932010-01-05 19:32:54 +0000420} // end extern "C"