blob: f8fd470a1d8a8272deb76b43d95e30521f1525c2 [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"
Benjamin Kramer064414532010-04-12 19:45:50 +000017#include "clang/Basic/SourceManager.h"
18#include "clang/Basic/FileManager.h"
Douglas Gregor8e984da2010-08-04 16:47:14 +000019#include "clang/Frontend/ASTUnit.h"
Benjamin Kramer064414532010-04-12 19:45:50 +000020#include "clang/Frontend/CompilerInstance.h"
Douglas Gregorba965fb2010-01-28 00:56:43 +000021#include "clang/Frontend/FrontendDiagnostic.h"
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000022#include "clang/Sema/CodeCompleteConsumer.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/System/Program.h"
Douglas Gregord6009ff2010-07-26 16:29:14 +000026#include <cstdlib>
27#include <cstdio>
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000028
Ted Kremenek9e0cf092010-04-15 01:02:28 +000029#ifdef UDP_CODE_COMPLETION_LOGGER
30#include "clang/Basic/Version.h"
31#include "llvm/ADT/SmallString.h"
32#include "llvm/Support/Timer.h"
33#include "llvm/Support/raw_ostream.h"
34#include <arpa/inet.h>
35#include <sys/socket.h>
36#include <sys/types.h>
37#include <unistd.h>
38#endif
39
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000040using namespace clang;
Ted Kremenekf602f962010-02-17 01:42:24 +000041using namespace clang::cxstring;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000042
Douglas Gregora2db7932010-05-26 22:00:08 +000043namespace {
44 /// \brief Stored representation of a completion string.
45 ///
46 /// This is the representation behind a CXCompletionString.
47 class CXStoredCodeCompletionString : public CodeCompletionString {
48 unsigned Priority;
49
50 public:
51 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
52
53 unsigned getPriority() const { return Priority; }
54 };
55}
56
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000057extern "C" {
58
59enum CXCompletionChunkKind
60clang_getCompletionChunkKind(CXCompletionString completion_string,
61 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +000062 CXStoredCodeCompletionString *CCStr
63 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000064 if (!CCStr || chunk_number >= CCStr->size())
65 return CXCompletionChunk_Text;
66
67 switch ((*CCStr)[chunk_number].Kind) {
68 case CodeCompletionString::CK_TypedText:
69 return CXCompletionChunk_TypedText;
70 case CodeCompletionString::CK_Text:
71 return CXCompletionChunk_Text;
72 case CodeCompletionString::CK_Optional:
73 return CXCompletionChunk_Optional;
74 case CodeCompletionString::CK_Placeholder:
75 return CXCompletionChunk_Placeholder;
76 case CodeCompletionString::CK_Informative:
77 return CXCompletionChunk_Informative;
78 case CodeCompletionString::CK_ResultType:
79 return CXCompletionChunk_ResultType;
80 case CodeCompletionString::CK_CurrentParameter:
81 return CXCompletionChunk_CurrentParameter;
82 case CodeCompletionString::CK_LeftParen:
83 return CXCompletionChunk_LeftParen;
84 case CodeCompletionString::CK_RightParen:
85 return CXCompletionChunk_RightParen;
86 case CodeCompletionString::CK_LeftBracket:
87 return CXCompletionChunk_LeftBracket;
88 case CodeCompletionString::CK_RightBracket:
89 return CXCompletionChunk_RightBracket;
90 case CodeCompletionString::CK_LeftBrace:
91 return CXCompletionChunk_LeftBrace;
92 case CodeCompletionString::CK_RightBrace:
93 return CXCompletionChunk_RightBrace;
94 case CodeCompletionString::CK_LeftAngle:
95 return CXCompletionChunk_LeftAngle;
96 case CodeCompletionString::CK_RightAngle:
97 return CXCompletionChunk_RightAngle;
98 case CodeCompletionString::CK_Comma:
99 return CXCompletionChunk_Comma;
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000100 case CodeCompletionString::CK_Colon:
101 return CXCompletionChunk_Colon;
102 case CodeCompletionString::CK_SemiColon:
103 return CXCompletionChunk_SemiColon;
104 case CodeCompletionString::CK_Equal:
105 return CXCompletionChunk_Equal;
106 case CodeCompletionString::CK_HorizontalSpace:
107 return CXCompletionChunk_HorizontalSpace;
108 case CodeCompletionString::CK_VerticalSpace:
109 return CXCompletionChunk_VerticalSpace;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000110 }
111
112 // Should be unreachable, but let's be careful.
113 return CXCompletionChunk_Text;
114}
115
Ted Kremenekf602f962010-02-17 01:42:24 +0000116CXString clang_getCompletionChunkText(CXCompletionString completion_string,
117 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000118 CXStoredCodeCompletionString *CCStr
119 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000120 if (!CCStr || chunk_number >= CCStr->size())
Ted Kremenekf602f962010-02-17 01:42:24 +0000121 return createCXString(0);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000122
123 switch ((*CCStr)[chunk_number].Kind) {
124 case CodeCompletionString::CK_TypedText:
125 case CodeCompletionString::CK_Text:
126 case CodeCompletionString::CK_Placeholder:
127 case CodeCompletionString::CK_CurrentParameter:
128 case CodeCompletionString::CK_Informative:
129 case CodeCompletionString::CK_LeftParen:
130 case CodeCompletionString::CK_RightParen:
131 case CodeCompletionString::CK_LeftBracket:
132 case CodeCompletionString::CK_RightBracket:
133 case CodeCompletionString::CK_LeftBrace:
134 case CodeCompletionString::CK_RightBrace:
135 case CodeCompletionString::CK_LeftAngle:
136 case CodeCompletionString::CK_RightAngle:
137 case CodeCompletionString::CK_Comma:
138 case CodeCompletionString::CK_ResultType:
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000139 case CodeCompletionString::CK_Colon:
140 case CodeCompletionString::CK_SemiColon:
141 case CodeCompletionString::CK_Equal:
142 case CodeCompletionString::CK_HorizontalSpace:
Ted Kremenekf602f962010-02-17 01:42:24 +0000143 return createCXString((*CCStr)[chunk_number].Text, false);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000144
Douglas Gregor09737ee2010-05-25 06:14:46 +0000145 case CodeCompletionString::CK_VerticalSpace:
146 // FIXME: Temporary hack until we figure out how to handle vertical space.
147 return createCXString(" ");
148
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000149 case CodeCompletionString::CK_Optional:
150 // Note: treated as an empty text block.
Ted Kremenekf602f962010-02-17 01:42:24 +0000151 return createCXString("");
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000152 }
153
154 // Should be unreachable, but let's be careful.
Ted Kremenekf602f962010-02-17 01:42:24 +0000155 return createCXString(0);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000156}
157
Ted Kremenekf602f962010-02-17 01:42:24 +0000158
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000159CXCompletionString
160clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
161 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000162 CXStoredCodeCompletionString *CCStr
163 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000164 if (!CCStr || chunk_number >= CCStr->size())
165 return 0;
166
167 switch ((*CCStr)[chunk_number].Kind) {
168 case CodeCompletionString::CK_TypedText:
169 case CodeCompletionString::CK_Text:
170 case CodeCompletionString::CK_Placeholder:
171 case CodeCompletionString::CK_CurrentParameter:
172 case CodeCompletionString::CK_Informative:
173 case CodeCompletionString::CK_LeftParen:
174 case CodeCompletionString::CK_RightParen:
175 case CodeCompletionString::CK_LeftBracket:
176 case CodeCompletionString::CK_RightBracket:
177 case CodeCompletionString::CK_LeftBrace:
178 case CodeCompletionString::CK_RightBrace:
179 case CodeCompletionString::CK_LeftAngle:
180 case CodeCompletionString::CK_RightAngle:
181 case CodeCompletionString::CK_Comma:
182 case CodeCompletionString::CK_ResultType:
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000183 case CodeCompletionString::CK_Colon:
184 case CodeCompletionString::CK_SemiColon:
185 case CodeCompletionString::CK_Equal:
186 case CodeCompletionString::CK_HorizontalSpace:
187 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000188 return 0;
189
190 case CodeCompletionString::CK_Optional:
191 // Note: treated as an empty text block.
192 return (*CCStr)[chunk_number].Optional;
193 }
194
195 // Should be unreachable, but let's be careful.
196 return 0;
197}
198
199unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000200 CXStoredCodeCompletionString *CCStr
201 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000202 return CCStr? CCStr->size() : 0;
203}
204
Douglas Gregora2db7932010-05-26 22:00:08 +0000205unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
206 CXStoredCodeCompletionString *CCStr
207 = (CXStoredCodeCompletionString *)completion_string;
Bill Wendling47bb3e22010-05-27 18:35:05 +0000208 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely);
Douglas Gregora2db7932010-05-26 22:00:08 +0000209}
210
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000211static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
212 unsigned &Value) {
213 if (Memory + sizeof(unsigned) > MemoryEnd)
214 return true;
215
216 memmove(&Value, Memory, sizeof(unsigned));
217 Memory += sizeof(unsigned);
218 return false;
219}
220
221/// \brief The CXCodeCompleteResults structure we allocate internally;
222/// the client only sees the initial CXCodeCompleteResults structure.
223struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000224 AllocatedCXCodeCompleteResults();
225 ~AllocatedCXCodeCompleteResults();
226
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000227 /// \brief The memory buffer from which we parsed the results. We
228 /// retain this buffer because the completion strings point into it.
229 llvm::MemoryBuffer *Buffer;
Daniel Dunbar854d36b2010-01-30 23:31:40 +0000230
Douglas Gregor33cdd812010-02-18 18:08:43 +0000231 /// \brief Diagnostics produced while performing code completion.
232 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
233
Douglas Gregore0fbb832010-03-16 00:06:06 +0000234 /// \brief Diag object
Douglas Gregor8e984da2010-08-04 16:47:14 +0000235 llvm::IntrusiveRefCntPtr<Diagnostic> Diag;
Douglas Gregore0fbb832010-03-16 00:06:06 +0000236
Douglas Gregor33cdd812010-02-18 18:08:43 +0000237 /// \brief Language options used to adjust source locations.
Daniel Dunbar854d36b2010-01-30 23:31:40 +0000238 LangOptions LangOpts;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000239
240 /// \brief Source manager, used for diagnostics.
241 SourceManager SourceMgr;
242
243 /// \brief File manager, used for diagnostics.
244 FileManager FileMgr;
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000245
246 /// \brief Temporary files that should be removed once we have finished
247 /// with the code-completion results.
248 std::vector<llvm::sys::Path> TemporaryFiles;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000249};
250
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000251AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
Douglas Gregor8e984da2010-08-04 16:47:14 +0000252 : CXCodeCompleteResults(), Buffer(0), Diag(new Diagnostic),
253 SourceMgr(*Diag) { }
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000254
255AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
256 for (unsigned I = 0, N = NumResults; I != N; ++I)
Douglas Gregora2db7932010-05-26 22:00:08 +0000257 delete (CXStoredCodeCompletionString *)Results[I].CompletionString;
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000258 delete [] Results;
259 delete Buffer;
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000260
261 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
262 TemporaryFiles[I].eraseFromDisk();
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000263}
264
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000265CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
266 const char *source_filename,
267 int num_command_line_args,
268 const char **command_line_args,
269 unsigned num_unsaved_files,
270 struct CXUnsavedFile *unsaved_files,
271 const char *complete_filename,
272 unsigned complete_line,
Douglas Gregor33cdd812010-02-18 18:08:43 +0000273 unsigned complete_column) {
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000274#ifdef UDP_CODE_COMPLETION_LOGGER
275#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
276 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
277#endif
278#endif
279
Douglas Gregord6009ff2010-07-26 16:29:14 +0000280 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
281
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000282 // The indexer, which is mainly used to determine where diagnostics go.
283 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
284
Douglas Gregorba965fb2010-01-28 00:56:43 +0000285 // Configure the diagnostics.
286 DiagnosticOptions DiagOpts;
Douglas Gregor7f95d262010-04-05 23:52:57 +0000287 llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
288 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregorba965fb2010-01-28 00:56:43 +0000289
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000290 // The set of temporary files that we've built.
291 std::vector<llvm::sys::Path> TemporaryFiles;
292
293 // Build up the arguments for invoking 'clang'.
294 std::vector<const char *> argv;
295
296 // First add the complete path to the 'clang' executable.
297 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
298 argv.push_back(ClangPath.c_str());
299
Daniel Dunbardf000da2010-06-30 21:40:01 +0000300 // Always use Clang C++ support.
301 argv.push_back("-ccc-clang-cxx");
302
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000303 // Add the '-fsyntax-only' argument so that we only perform a basic
304 // syntax check of the code.
305 argv.push_back("-fsyntax-only");
306
307 // Add the appropriate '-code-completion-at=file:line:column' argument
308 // to perform code completion, with an "-Xclang" preceding it.
309 std::string code_complete_at;
310 code_complete_at += complete_filename;
311 code_complete_at += ":";
312 code_complete_at += llvm::utostr(complete_line);
313 code_complete_at += ":";
314 code_complete_at += llvm::utostr(complete_column);
315 argv.push_back("-Xclang");
316 argv.push_back("-code-completion-at");
317 argv.push_back("-Xclang");
318 argv.push_back(code_complete_at.c_str());
319 argv.push_back("-Xclang");
320 argv.push_back("-no-code-completion-debug-printer");
321 argv.push_back("-Xclang");
322 argv.push_back("-code-completion-macros");
Douglas Gregorac0605e2010-01-28 06:00:51 +0000323 argv.push_back("-fdiagnostics-binary");
324
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000325 // Remap any unsaved files to temporary files.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000326 std::vector<std::string> RemapArgs;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000327 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
328 return 0;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000329
330 // The pointers into the elements of RemapArgs are stable because we
331 // won't be adding anything to RemapArgs after this point.
332 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
333 argv.push_back(RemapArgs[i].c_str());
334
335 // Add the source file name (FIXME: later, we'll want to build temporary
336 // file from the buffer, or just feed the source text via standard input).
337 if (source_filename)
338 argv.push_back(source_filename);
339
340 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
341 for (int i = 0; i < num_command_line_args; ++i)
342 if (const char *arg = command_line_args[i]) {
343 if (strcmp(arg, "-o") == 0) {
344 ++i; // Also skip the matching argument.
345 continue;
346 }
347 if (strcmp(arg, "-emit-ast") == 0 ||
348 strcmp(arg, "-c") == 0 ||
349 strcmp(arg, "-fsyntax-only") == 0) {
350 continue;
351 }
352
353 // Keep the argument.
354 argv.push_back(arg);
355 }
356
Douglas Gregord6009ff2010-07-26 16:29:14 +0000357 if (EnableLogging) {
358 std::string Log = ClangPath.str();
359 for (unsigned I = 0, N = argv.size(); I != N; ++I) {
360 Log += ' ';
361 Log += argv[I];
362 }
363 fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str());
364 }
365
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000366 // Add the null terminator.
367 argv.push_back(NULL);
368
Douglas Gregorac0605e2010-01-28 06:00:51 +0000369 // Generate a temporary name for the code-completion results file.
Benjamin Kramerf156b9d2010-03-13 21:22:49 +0000370 char tmpFile[L_tmpnam];
371 char *tmpFileName = tmpnam(tmpFile);
372 llvm::sys::Path ResultsFile(tmpFileName);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000373 TemporaryFiles.push_back(ResultsFile);
374
Douglas Gregorac0605e2010-01-28 06:00:51 +0000375 // Generate a temporary name for the diagnostics file.
Benjamin Kramerf156b9d2010-03-13 21:22:49 +0000376 char tmpFileResults[L_tmpnam];
377 char *tmpResultsFileName = tmpnam(tmpFileResults);
378 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
Douglas Gregorac0605e2010-01-28 06:00:51 +0000379 TemporaryFiles.push_back(DiagnosticsFile);
380
Douglas Gregord6009ff2010-07-26 16:29:14 +0000381
382
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000383 // Invoke 'clang'.
384 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
385 // on Unix or NUL (Windows).
386 std::string ErrMsg;
Douglas Gregorac0605e2010-01-28 06:00:51 +0000387 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
388 &DiagnosticsFile, 0 };
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000389 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
390 /* redirects */ &Redirects[0],
391 /* secondsToWait */ 0,
392 /* memoryLimits */ 0, &ErrMsg);
393
Douglas Gregorba965fb2010-01-28 00:56:43 +0000394 if (!ErrMsg.empty()) {
395 std::string AllArgs;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000396 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregorba965fb2010-01-28 00:56:43 +0000397 I != E; ++I) {
398 AllArgs += ' ';
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000399 if (*I)
Douglas Gregorba965fb2010-01-28 00:56:43 +0000400 AllArgs += *I;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000401 }
Douglas Gregorba965fb2010-01-28 00:56:43 +0000402
Daniel Dunbar253dbad2010-02-23 20:23:45 +0000403 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000404 }
405
406 // Parse the resulting source file to find code-completion results.
407 using llvm::MemoryBuffer;
408 using llvm::StringRef;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000409 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
410 Results->Results = 0;
411 Results->NumResults = 0;
412 Results->Buffer = 0;
413 // FIXME: Set Results->LangOpts!
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000414 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
415 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
416 StringRef Buffer = F->getBuffer();
417 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
418 Str < StrEnd;) {
419 unsigned KindValue;
420 if (ReadUnsigned(Str, StrEnd, KindValue))
421 break;
422
Douglas Gregora2db7932010-05-26 22:00:08 +0000423 unsigned Priority;
424 if (ReadUnsigned(Str, StrEnd, Priority))
425 break;
426
427 CXStoredCodeCompletionString *CCStr
428 = new CXStoredCodeCompletionString(Priority);
429 if (!CCStr->Deserialize(Str, StrEnd)) {
430 delete CCStr;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000431 continue;
Douglas Gregora2db7932010-05-26 22:00:08 +0000432 }
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000433
434 if (!CCStr->empty()) {
435 // Vend the code-completion result to the caller.
436 CXCompletionResult Result;
437 Result.CursorKind = (CXCursorKind)KindValue;
438 Result.CompletionString = CCStr;
439 CompletionResults.push_back(Result);
440 }
441 };
442
443 // Allocate the results.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000444 Results->Results = new CXCompletionResult [CompletionResults.size()];
445 Results->NumResults = CompletionResults.size();
446 memcpy(Results->Results, CompletionResults.data(),
447 CompletionResults.size() * sizeof(CXCompletionResult));
448 Results->Buffer = F;
449 }
450
Douglas Gregor33cdd812010-02-18 18:08:43 +0000451 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
452 Results->FileMgr, Results->SourceMgr,
453 Results->Diagnostics);
454
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000455 // Make sure we delete temporary files when the code-completion results are
456 // destroyed.
457 Results->TemporaryFiles.swap(TemporaryFiles);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000458
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000459#ifdef UDP_CODE_COMPLETION_LOGGER
460#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
461 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
462 llvm::SmallString<256> LogResult;
463 llvm::raw_svector_ostream os(LogResult);
464
465 // Figure out the language and whether or not it uses PCH.
466 const char *lang = 0;
467 bool usesPCH = false;
468
469 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
470 I != E; ++I) {
471 if (*I == 0)
472 continue;
473 if (strcmp(*I, "-x") == 0) {
474 if (I + 1 != E) {
475 lang = *(++I);
476 continue;
477 }
478 }
479 else if (strcmp(*I, "-include") == 0) {
480 if (I+1 != E) {
481 const char *arg = *(++I);
482 llvm::SmallString<512> pchName;
483 {
484 llvm::raw_svector_ostream os(pchName);
485 os << arg << ".pth";
486 }
487 pchName.push_back('\0');
488 struct stat stat_results;
489 if (stat(pchName.data(), &stat_results) == 0)
490 usesPCH = true;
491 continue;
492 }
493 }
494 }
495
Ted Kremenekcab334c2010-04-17 00:21:42 +0000496 os << "{ ";
497 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
498 os << ", \"numRes\": " << Results->NumResults;
499 os << ", \"diags\": " << Results->Diagnostics.size();
500 os << ", \"pch\": " << (usesPCH ? "true" : "false");
501 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000502 const char *name = getlogin();
Ted Kremenekcab334c2010-04-17 00:21:42 +0000503 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
504 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
505 os << " }";
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000506
507 llvm::StringRef res = os.str();
508 if (res.size() > 0) {
509 do {
510 // Setup the UDP socket.
511 struct sockaddr_in servaddr;
512 bzero(&servaddr, sizeof(servaddr));
513 servaddr.sin_family = AF_INET;
514 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
515 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
516 &servaddr.sin_addr) <= 0)
517 break;
518
519 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
520 if (sockfd < 0)
521 break;
522
523 sendto(sockfd, res.data(), res.size(), 0,
524 (struct sockaddr *)&servaddr, sizeof(servaddr));
525 close(sockfd);
526 }
527 while (false);
528 }
529#endif
530#endif
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000531 return Results;
532}
533
Douglas Gregor8e984da2010-08-04 16:47:14 +0000534} // end extern "C"
535
536namespace clang {
537 // FIXME: defined in CodeCompleteConsumer.cpp, but should be a
538 // static function here.
539 CXCursorKind
540 getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R);
541}
542
543
544namespace {
545 class CaptureCompletionResults : public CodeCompleteConsumer {
546 AllocatedCXCodeCompleteResults &AllocatedResults;
547
548 public:
549 explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results)
550 : CodeCompleteConsumer(true, false, false), AllocatedResults(Results) { }
551
552 virtual void ProcessCodeCompleteResults(Sema &S, Result *Results,
553 unsigned NumResults) {
554 AllocatedResults.Results = new CXCompletionResult [NumResults];
555 AllocatedResults.NumResults = NumResults;
556 for (unsigned I = 0; I != NumResults; ++I) {
557 CXStoredCodeCompletionString *StoredCompletion
558 = new CXStoredCodeCompletionString(Results[I].Priority);
559 (void)Results[I].CreateCodeCompletionString(S, StoredCompletion);
560 AllocatedResults.Results[I].CursorKind
561 = getCursorKindForCompletionResult(Results[I]);
562 AllocatedResults.Results[I].CompletionString = StoredCompletion;
563 }
564 }
565 };
566}
567
568extern "C" {
569CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
570 const char *complete_filename,
571 unsigned complete_line,
572 unsigned complete_column,
573 struct CXUnsavedFile *unsaved_files,
574 unsigned num_unsaved_files) {
575#ifdef UDP_CODE_COMPLETION_LOGGER
576#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
577 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
578#endif
579#endif
580
581 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
582
583 ASTUnit *AST = static_cast<ASTUnit *>(TU);
584 if (!AST)
585 return 0;
586
587 // Perform the remapping of source files.
588 llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
589 for (unsigned I = 0; I != num_unsaved_files; ++I) {
590 llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
591 const llvm::MemoryBuffer *Buffer
592 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
593 RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
594 Buffer));
595 }
596
597 if (EnableLogging) {
598 // FIXME: Add logging.
599 }
600
601 // Parse the resulting source file to find code-completion results.
602 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
603 Results->Results = 0;
604 Results->NumResults = 0;
605 Results->Buffer = 0;
606
607 // Create a code-completion consumer to capture the results.
608 CaptureCompletionResults Capture(*Results);
609
610 // Perform completion.
611 AST->CodeComplete(complete_filename, complete_line, complete_column,
612 RemappedFiles.data(), RemappedFiles.size(), Capture,
613 *Results->Diag, Results->LangOpts, Results->SourceMgr,
614 Results->FileMgr, Results->Diagnostics);
615
616
617
618#ifdef UDP_CODE_COMPLETION_LOGGER
619#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
620 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
621 llvm::SmallString<256> LogResult;
622 llvm::raw_svector_ostream os(LogResult);
623
624 // Figure out the language and whether or not it uses PCH.
625 const char *lang = 0;
626 bool usesPCH = false;
627
628 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
629 I != E; ++I) {
630 if (*I == 0)
631 continue;
632 if (strcmp(*I, "-x") == 0) {
633 if (I + 1 != E) {
634 lang = *(++I);
635 continue;
636 }
637 }
638 else if (strcmp(*I, "-include") == 0) {
639 if (I+1 != E) {
640 const char *arg = *(++I);
641 llvm::SmallString<512> pchName;
642 {
643 llvm::raw_svector_ostream os(pchName);
644 os << arg << ".pth";
645 }
646 pchName.push_back('\0');
647 struct stat stat_results;
648 if (stat(pchName.data(), &stat_results) == 0)
649 usesPCH = true;
650 continue;
651 }
652 }
653 }
654
655 os << "{ ";
656 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
657 os << ", \"numRes\": " << Results->NumResults;
658 os << ", \"diags\": " << Results->Diagnostics.size();
659 os << ", \"pch\": " << (usesPCH ? "true" : "false");
660 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
661 const char *name = getlogin();
662 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
663 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
664 os << " }";
665
666 llvm::StringRef res = os.str();
667 if (res.size() > 0) {
668 do {
669 // Setup the UDP socket.
670 struct sockaddr_in servaddr;
671 bzero(&servaddr, sizeof(servaddr));
672 servaddr.sin_family = AF_INET;
673 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
674 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
675 &servaddr.sin_addr) <= 0)
676 break;
677
678 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
679 if (sockfd < 0)
680 break;
681
682 sendto(sockfd, res.data(), res.size(), 0,
683 (struct sockaddr *)&servaddr, sizeof(servaddr));
684 close(sockfd);
685 }
686 while (false);
687 }
688#endif
689#endif
690 return Results;
691}
692
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000693void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
694 if (!ResultsIn)
695 return;
696
697 AllocatedCXCodeCompleteResults *Results
698 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000699 delete Results;
700}
701
Douglas Gregor33cdd812010-02-18 18:08:43 +0000702unsigned
703clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
704 AllocatedCXCodeCompleteResults *Results
705 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
706 if (!Results)
707 return 0;
708
709 return Results->Diagnostics.size();
710}
711
712CXDiagnostic
713clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
714 unsigned Index) {
715 AllocatedCXCodeCompleteResults *Results
716 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
717 if (!Results || Index >= Results->Diagnostics.size())
718 return 0;
719
720 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
721}
722
723
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000724} // end extern "C"