blob: c2febf9b722d6f0a8f3cfd71aac58e9309a411a7 [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"
Douglas Gregor028d3e42010-08-09 20:45:32 +000023#include "llvm/ADT/SmallString.h"
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000024#include "llvm/ADT/StringExtras.h"
Daniel Dunbar77af1c52010-08-19 23:44:10 +000025#include "llvm/Support/CrashRecoveryContext.h"
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000026#include "llvm/Support/MemoryBuffer.h"
Douglas Gregor028d3e42010-08-09 20:45:32 +000027#include "llvm/Support/Timer.h"
28#include "llvm/Support/raw_ostream.h"
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000029#include "llvm/System/Program.h"
Douglas Gregord6009ff2010-07-26 16:29:14 +000030#include <cstdlib>
31#include <cstdio>
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000032
Douglas Gregor028d3e42010-08-09 20:45:32 +000033
Ted Kremenek9e0cf092010-04-15 01:02:28 +000034#ifdef UDP_CODE_COMPLETION_LOGGER
35#include "clang/Basic/Version.h"
Ted Kremenek9e0cf092010-04-15 01:02:28 +000036#include <arpa/inet.h>
37#include <sys/socket.h>
38#include <sys/types.h>
39#include <unistd.h>
40#endif
41
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000042using namespace clang;
Ted Kremenekf602f962010-02-17 01:42:24 +000043using namespace clang::cxstring;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000044
Douglas Gregora2db7932010-05-26 22:00:08 +000045namespace {
46 /// \brief Stored representation of a completion string.
47 ///
48 /// This is the representation behind a CXCompletionString.
49 class CXStoredCodeCompletionString : public CodeCompletionString {
50 unsigned Priority;
51
52 public:
53 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
54
55 unsigned getPriority() const { return Priority; }
56 };
57}
58
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000059extern "C" {
60
61enum CXCompletionChunkKind
62clang_getCompletionChunkKind(CXCompletionString completion_string,
63 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +000064 CXStoredCodeCompletionString *CCStr
65 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +000066 if (!CCStr || chunk_number >= CCStr->size())
67 return CXCompletionChunk_Text;
68
69 switch ((*CCStr)[chunk_number].Kind) {
70 case CodeCompletionString::CK_TypedText:
71 return CXCompletionChunk_TypedText;
72 case CodeCompletionString::CK_Text:
73 return CXCompletionChunk_Text;
74 case CodeCompletionString::CK_Optional:
75 return CXCompletionChunk_Optional;
76 case CodeCompletionString::CK_Placeholder:
77 return CXCompletionChunk_Placeholder;
78 case CodeCompletionString::CK_Informative:
79 return CXCompletionChunk_Informative;
80 case CodeCompletionString::CK_ResultType:
81 return CXCompletionChunk_ResultType;
82 case CodeCompletionString::CK_CurrentParameter:
83 return CXCompletionChunk_CurrentParameter;
84 case CodeCompletionString::CK_LeftParen:
85 return CXCompletionChunk_LeftParen;
86 case CodeCompletionString::CK_RightParen:
87 return CXCompletionChunk_RightParen;
88 case CodeCompletionString::CK_LeftBracket:
89 return CXCompletionChunk_LeftBracket;
90 case CodeCompletionString::CK_RightBracket:
91 return CXCompletionChunk_RightBracket;
92 case CodeCompletionString::CK_LeftBrace:
93 return CXCompletionChunk_LeftBrace;
94 case CodeCompletionString::CK_RightBrace:
95 return CXCompletionChunk_RightBrace;
96 case CodeCompletionString::CK_LeftAngle:
97 return CXCompletionChunk_LeftAngle;
98 case CodeCompletionString::CK_RightAngle:
99 return CXCompletionChunk_RightAngle;
100 case CodeCompletionString::CK_Comma:
101 return CXCompletionChunk_Comma;
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000102 case CodeCompletionString::CK_Colon:
103 return CXCompletionChunk_Colon;
104 case CodeCompletionString::CK_SemiColon:
105 return CXCompletionChunk_SemiColon;
106 case CodeCompletionString::CK_Equal:
107 return CXCompletionChunk_Equal;
108 case CodeCompletionString::CK_HorizontalSpace:
109 return CXCompletionChunk_HorizontalSpace;
110 case CodeCompletionString::CK_VerticalSpace:
111 return CXCompletionChunk_VerticalSpace;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000112 }
113
114 // Should be unreachable, but let's be careful.
115 return CXCompletionChunk_Text;
116}
117
Ted Kremenekf602f962010-02-17 01:42:24 +0000118CXString clang_getCompletionChunkText(CXCompletionString completion_string,
119 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000120 CXStoredCodeCompletionString *CCStr
121 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000122 if (!CCStr || chunk_number >= CCStr->size())
Ted Kremenekf602f962010-02-17 01:42:24 +0000123 return createCXString(0);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000124
125 switch ((*CCStr)[chunk_number].Kind) {
126 case CodeCompletionString::CK_TypedText:
127 case CodeCompletionString::CK_Text:
128 case CodeCompletionString::CK_Placeholder:
129 case CodeCompletionString::CK_CurrentParameter:
130 case CodeCompletionString::CK_Informative:
131 case CodeCompletionString::CK_LeftParen:
132 case CodeCompletionString::CK_RightParen:
133 case CodeCompletionString::CK_LeftBracket:
134 case CodeCompletionString::CK_RightBracket:
135 case CodeCompletionString::CK_LeftBrace:
136 case CodeCompletionString::CK_RightBrace:
137 case CodeCompletionString::CK_LeftAngle:
138 case CodeCompletionString::CK_RightAngle:
139 case CodeCompletionString::CK_Comma:
140 case CodeCompletionString::CK_ResultType:
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000141 case CodeCompletionString::CK_Colon:
142 case CodeCompletionString::CK_SemiColon:
143 case CodeCompletionString::CK_Equal:
144 case CodeCompletionString::CK_HorizontalSpace:
Ted Kremenekf602f962010-02-17 01:42:24 +0000145 return createCXString((*CCStr)[chunk_number].Text, false);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000146
Douglas Gregor09737ee2010-05-25 06:14:46 +0000147 case CodeCompletionString::CK_VerticalSpace:
148 // FIXME: Temporary hack until we figure out how to handle vertical space.
149 return createCXString(" ");
150
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000151 case CodeCompletionString::CK_Optional:
152 // Note: treated as an empty text block.
Ted Kremenekf602f962010-02-17 01:42:24 +0000153 return createCXString("");
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000154 }
155
156 // Should be unreachable, but let's be careful.
Ted Kremenekf602f962010-02-17 01:42:24 +0000157 return createCXString(0);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000158}
159
Ted Kremenekf602f962010-02-17 01:42:24 +0000160
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000161CXCompletionString
162clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
163 unsigned chunk_number) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000164 CXStoredCodeCompletionString *CCStr
165 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000166 if (!CCStr || chunk_number >= CCStr->size())
167 return 0;
168
169 switch ((*CCStr)[chunk_number].Kind) {
170 case CodeCompletionString::CK_TypedText:
171 case CodeCompletionString::CK_Text:
172 case CodeCompletionString::CK_Placeholder:
173 case CodeCompletionString::CK_CurrentParameter:
174 case CodeCompletionString::CK_Informative:
175 case CodeCompletionString::CK_LeftParen:
176 case CodeCompletionString::CK_RightParen:
177 case CodeCompletionString::CK_LeftBracket:
178 case CodeCompletionString::CK_RightBracket:
179 case CodeCompletionString::CK_LeftBrace:
180 case CodeCompletionString::CK_RightBrace:
181 case CodeCompletionString::CK_LeftAngle:
182 case CodeCompletionString::CK_RightAngle:
183 case CodeCompletionString::CK_Comma:
184 case CodeCompletionString::CK_ResultType:
Douglas Gregor504a6ae2010-01-10 23:08:15 +0000185 case CodeCompletionString::CK_Colon:
186 case CodeCompletionString::CK_SemiColon:
187 case CodeCompletionString::CK_Equal:
188 case CodeCompletionString::CK_HorizontalSpace:
189 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000190 return 0;
191
192 case CodeCompletionString::CK_Optional:
193 // Note: treated as an empty text block.
194 return (*CCStr)[chunk_number].Optional;
195 }
196
197 // Should be unreachable, but let's be careful.
198 return 0;
199}
200
201unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
Douglas Gregora2db7932010-05-26 22:00:08 +0000202 CXStoredCodeCompletionString *CCStr
203 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000204 return CCStr? CCStr->size() : 0;
205}
206
Douglas Gregora2db7932010-05-26 22:00:08 +0000207unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
208 CXStoredCodeCompletionString *CCStr
209 = (CXStoredCodeCompletionString *)completion_string;
Bill Wendling47bb3e22010-05-27 18:35:05 +0000210 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely);
Douglas Gregora2db7932010-05-26 22:00:08 +0000211}
212
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000213static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
214 unsigned &Value) {
215 if (Memory + sizeof(unsigned) > MemoryEnd)
216 return true;
217
218 memmove(&Value, Memory, sizeof(unsigned));
219 Memory += sizeof(unsigned);
220 return false;
221}
222
223/// \brief The CXCodeCompleteResults structure we allocate internally;
224/// the client only sees the initial CXCodeCompleteResults structure.
225struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000226 AllocatedCXCodeCompleteResults();
227 ~AllocatedCXCodeCompleteResults();
228
Douglas Gregor33cdd812010-02-18 18:08:43 +0000229 /// \brief Diagnostics produced while performing code completion.
230 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
231
Douglas Gregore0fbb832010-03-16 00:06:06 +0000232 /// \brief Diag object
Douglas Gregor8e984da2010-08-04 16:47:14 +0000233 llvm::IntrusiveRefCntPtr<Diagnostic> Diag;
Douglas Gregore0fbb832010-03-16 00:06:06 +0000234
Douglas Gregor33cdd812010-02-18 18:08:43 +0000235 /// \brief Language options used to adjust source locations.
Daniel Dunbar854d36b2010-01-30 23:31:40 +0000236 LangOptions LangOpts;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000237
238 /// \brief Source manager, used for diagnostics.
239 SourceManager SourceMgr;
240
241 /// \brief File manager, used for diagnostics.
242 FileManager FileMgr;
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000243
244 /// \brief Temporary files that should be removed once we have finished
245 /// with the code-completion results.
246 std::vector<llvm::sys::Path> TemporaryFiles;
Douglas Gregord8a5dba2010-08-04 17:07:00 +0000247
248 /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results.
249 llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000250};
251
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000252AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
Douglas Gregord8a5dba2010-08-04 17:07:00 +0000253 : CXCodeCompleteResults(), Diag(new Diagnostic), 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;
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000259
260 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
261 TemporaryFiles[I].eraseFromDisk();
Douglas Gregord8a5dba2010-08-04 17:07:00 +0000262 for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
263 delete TemporaryBuffers[I];
Douglas Gregor1e21cc72010-02-18 23:07:20 +0000264}
265
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000266CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
267 const char *source_filename,
268 int num_command_line_args,
269 const char **command_line_args,
270 unsigned num_unsaved_files,
271 struct CXUnsavedFile *unsaved_files,
272 const char *complete_filename,
273 unsigned complete_line,
Douglas Gregor33cdd812010-02-18 18:08:43 +0000274 unsigned complete_column) {
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000275#ifdef UDP_CODE_COMPLETION_LOGGER
276#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
277 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
278#endif
279#endif
280
Douglas Gregord6009ff2010-07-26 16:29:14 +0000281 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
Douglas Gregor028d3e42010-08-09 20:45:32 +0000282
283 llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer;
284 if (getenv("LIBCLANG_TIMING")) {
285 llvm::SmallString<128> TimerName;
286 llvm::raw_svector_ostream TimerNameOut(TimerName);
Douglas Gregor8ef4c802010-08-09 21:00:09 +0000287 TimerNameOut << "Code completion (out-of-process) @ " << complete_filename
288 << ":" << complete_line << ":" << complete_column;
Douglas Gregor028d3e42010-08-09 20:45:32 +0000289 CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str()));
290 }
291
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000292 // The indexer, which is mainly used to determine where diagnostics go.
293 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
294
Douglas Gregorba965fb2010-01-28 00:56:43 +0000295 // Configure the diagnostics.
296 DiagnosticOptions DiagOpts;
Douglas Gregor7f95d262010-04-05 23:52:57 +0000297 llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
298 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregorba965fb2010-01-28 00:56:43 +0000299
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000300 // The set of temporary files that we've built.
301 std::vector<llvm::sys::Path> TemporaryFiles;
302
303 // Build up the arguments for invoking 'clang'.
304 std::vector<const char *> argv;
305
306 // First add the complete path to the 'clang' executable.
307 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
308 argv.push_back(ClangPath.c_str());
309
Daniel Dunbardf000da2010-06-30 21:40:01 +0000310 // Always use Clang C++ support.
311 argv.push_back("-ccc-clang-cxx");
312
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000313 // Add the '-fsyntax-only' argument so that we only perform a basic
314 // syntax check of the code.
315 argv.push_back("-fsyntax-only");
316
317 // Add the appropriate '-code-completion-at=file:line:column' argument
318 // to perform code completion, with an "-Xclang" preceding it.
319 std::string code_complete_at;
320 code_complete_at += complete_filename;
321 code_complete_at += ":";
322 code_complete_at += llvm::utostr(complete_line);
323 code_complete_at += ":";
324 code_complete_at += llvm::utostr(complete_column);
325 argv.push_back("-Xclang");
326 argv.push_back("-code-completion-at");
327 argv.push_back("-Xclang");
328 argv.push_back(code_complete_at.c_str());
329 argv.push_back("-Xclang");
330 argv.push_back("-no-code-completion-debug-printer");
331 argv.push_back("-Xclang");
332 argv.push_back("-code-completion-macros");
Douglas Gregorac0605e2010-01-28 06:00:51 +0000333 argv.push_back("-fdiagnostics-binary");
334
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000335 // Remap any unsaved files to temporary files.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000336 std::vector<std::string> RemapArgs;
Douglas Gregoraa98ed92010-01-23 00:14:00 +0000337 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
338 return 0;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000339
340 // The pointers into the elements of RemapArgs are stable because we
341 // won't be adding anything to RemapArgs after this point.
342 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
343 argv.push_back(RemapArgs[i].c_str());
344
345 // Add the source file name (FIXME: later, we'll want to build temporary
346 // file from the buffer, or just feed the source text via standard input).
347 if (source_filename)
348 argv.push_back(source_filename);
349
350 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
351 for (int i = 0; i < num_command_line_args; ++i)
352 if (const char *arg = command_line_args[i]) {
353 if (strcmp(arg, "-o") == 0) {
354 ++i; // Also skip the matching argument.
355 continue;
356 }
357 if (strcmp(arg, "-emit-ast") == 0 ||
358 strcmp(arg, "-c") == 0 ||
359 strcmp(arg, "-fsyntax-only") == 0) {
360 continue;
361 }
362
363 // Keep the argument.
364 argv.push_back(arg);
365 }
366
Douglas Gregord6009ff2010-07-26 16:29:14 +0000367 if (EnableLogging) {
368 std::string Log = ClangPath.str();
369 for (unsigned I = 0, N = argv.size(); I != N; ++I) {
370 Log += ' ';
371 Log += argv[I];
372 }
373 fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str());
374 }
375
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000376 // Add the null terminator.
377 argv.push_back(NULL);
378
Douglas Gregorac0605e2010-01-28 06:00:51 +0000379 // Generate a temporary name for the code-completion results file.
Benjamin Kramerf156b9d2010-03-13 21:22:49 +0000380 char tmpFile[L_tmpnam];
381 char *tmpFileName = tmpnam(tmpFile);
382 llvm::sys::Path ResultsFile(tmpFileName);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000383 TemporaryFiles.push_back(ResultsFile);
384
Douglas Gregorac0605e2010-01-28 06:00:51 +0000385 // Generate a temporary name for the diagnostics file.
Benjamin Kramerf156b9d2010-03-13 21:22:49 +0000386 char tmpFileResults[L_tmpnam];
387 char *tmpResultsFileName = tmpnam(tmpFileResults);
388 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
Douglas Gregorac0605e2010-01-28 06:00:51 +0000389 TemporaryFiles.push_back(DiagnosticsFile);
390
Douglas Gregord6009ff2010-07-26 16:29:14 +0000391
392
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000393 // Invoke 'clang'.
394 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
395 // on Unix or NUL (Windows).
396 std::string ErrMsg;
Douglas Gregorac0605e2010-01-28 06:00:51 +0000397 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
398 &DiagnosticsFile, 0 };
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000399 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
400 /* redirects */ &Redirects[0],
401 /* secondsToWait */ 0,
402 /* memoryLimits */ 0, &ErrMsg);
403
Douglas Gregorba965fb2010-01-28 00:56:43 +0000404 if (!ErrMsg.empty()) {
405 std::string AllArgs;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000406 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregorba965fb2010-01-28 00:56:43 +0000407 I != E; ++I) {
408 AllArgs += ' ';
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000409 if (*I)
Douglas Gregorba965fb2010-01-28 00:56:43 +0000410 AllArgs += *I;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000411 }
Douglas Gregorba965fb2010-01-28 00:56:43 +0000412
Daniel Dunbar253dbad2010-02-23 20:23:45 +0000413 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000414 }
415
416 // Parse the resulting source file to find code-completion results.
417 using llvm::MemoryBuffer;
418 using llvm::StringRef;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000419 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
420 Results->Results = 0;
421 Results->NumResults = 0;
Douglas Gregor33cdd812010-02-18 18:08:43 +0000422 // FIXME: Set Results->LangOpts!
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000423 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
424 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
425 StringRef Buffer = F->getBuffer();
426 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
427 Str < StrEnd;) {
428 unsigned KindValue;
429 if (ReadUnsigned(Str, StrEnd, KindValue))
430 break;
431
Douglas Gregora2db7932010-05-26 22:00:08 +0000432 unsigned Priority;
433 if (ReadUnsigned(Str, StrEnd, Priority))
434 break;
435
436 CXStoredCodeCompletionString *CCStr
437 = new CXStoredCodeCompletionString(Priority);
438 if (!CCStr->Deserialize(Str, StrEnd)) {
439 delete CCStr;
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000440 continue;
Douglas Gregora2db7932010-05-26 22:00:08 +0000441 }
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000442
443 if (!CCStr->empty()) {
444 // Vend the code-completion result to the caller.
445 CXCompletionResult Result;
446 Result.CursorKind = (CXCursorKind)KindValue;
447 Result.CompletionString = CCStr;
448 CompletionResults.push_back(Result);
449 }
450 };
451
452 // Allocate the results.
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000453 Results->Results = new CXCompletionResult [CompletionResults.size()];
454 Results->NumResults = CompletionResults.size();
455 memcpy(Results->Results, CompletionResults.data(),
456 CompletionResults.size() * sizeof(CXCompletionResult));
Douglas Gregord8a5dba2010-08-04 17:07:00 +0000457 Results->TemporaryBuffers.push_back(F);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000458 }
459
Douglas Gregor33cdd812010-02-18 18:08:43 +0000460 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
461 Results->FileMgr, Results->SourceMgr,
462 Results->Diagnostics);
463
Douglas Gregor6cb5ba42010-02-18 23:35:40 +0000464 // Make sure we delete temporary files when the code-completion results are
465 // destroyed.
466 Results->TemporaryFiles.swap(TemporaryFiles);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000467
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000468#ifdef UDP_CODE_COMPLETION_LOGGER
469#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
470 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
471 llvm::SmallString<256> LogResult;
472 llvm::raw_svector_ostream os(LogResult);
473
474 // Figure out the language and whether or not it uses PCH.
475 const char *lang = 0;
476 bool usesPCH = false;
477
478 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
479 I != E; ++I) {
480 if (*I == 0)
481 continue;
482 if (strcmp(*I, "-x") == 0) {
483 if (I + 1 != E) {
484 lang = *(++I);
485 continue;
486 }
487 }
488 else if (strcmp(*I, "-include") == 0) {
489 if (I+1 != E) {
490 const char *arg = *(++I);
491 llvm::SmallString<512> pchName;
492 {
493 llvm::raw_svector_ostream os(pchName);
494 os << arg << ".pth";
495 }
496 pchName.push_back('\0');
497 struct stat stat_results;
498 if (stat(pchName.data(), &stat_results) == 0)
499 usesPCH = true;
500 continue;
501 }
502 }
503 }
504
Ted Kremenekcab334c2010-04-17 00:21:42 +0000505 os << "{ ";
506 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
507 os << ", \"numRes\": " << Results->NumResults;
508 os << ", \"diags\": " << Results->Diagnostics.size();
509 os << ", \"pch\": " << (usesPCH ? "true" : "false");
510 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000511 const char *name = getlogin();
Ted Kremenekcab334c2010-04-17 00:21:42 +0000512 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
513 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
514 os << " }";
Ted Kremenek9e0cf092010-04-15 01:02:28 +0000515
516 llvm::StringRef res = os.str();
517 if (res.size() > 0) {
518 do {
519 // Setup the UDP socket.
520 struct sockaddr_in servaddr;
521 bzero(&servaddr, sizeof(servaddr));
522 servaddr.sin_family = AF_INET;
523 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
524 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
525 &servaddr.sin_addr) <= 0)
526 break;
527
528 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
529 if (sockfd < 0)
530 break;
531
532 sendto(sockfd, res.data(), res.size(), 0,
533 (struct sockaddr *)&servaddr, sizeof(servaddr));
534 close(sockfd);
535 }
536 while (false);
537 }
538#endif
539#endif
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000540 return Results;
541}
542
Douglas Gregor8e984da2010-08-04 16:47:14 +0000543} // end extern "C"
544
Douglas Gregor8e984da2010-08-04 16:47:14 +0000545namespace {
546 class CaptureCompletionResults : public CodeCompleteConsumer {
547 AllocatedCXCodeCompleteResults &AllocatedResults;
548
549 public:
550 explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results)
Douglas Gregor39982192010-08-15 06:18:01 +0000551 : CodeCompleteConsumer(true, false, true, false),
552 AllocatedResults(Results) { }
Douglas Gregor8e984da2010-08-04 16:47:14 +0000553
Douglas Gregor00c37ef2010-08-11 21:23:17 +0000554 virtual void ProcessCodeCompleteResults(Sema &S,
555 CodeCompletionContext Context,
556 Result *Results,
Douglas Gregor8e984da2010-08-04 16:47:14 +0000557 unsigned NumResults) {
558 AllocatedResults.Results = new CXCompletionResult [NumResults];
559 AllocatedResults.NumResults = NumResults;
560 for (unsigned I = 0; I != NumResults; ++I) {
561 CXStoredCodeCompletionString *StoredCompletion
562 = new CXStoredCodeCompletionString(Results[I].Priority);
563 (void)Results[I].CreateCodeCompletionString(S, StoredCompletion);
Douglas Gregorb14904c2010-08-13 22:48:40 +0000564 AllocatedResults.Results[I].CursorKind = Results[I].CursorKind;
Douglas Gregor8e984da2010-08-04 16:47:14 +0000565 AllocatedResults.Results[I].CompletionString = StoredCompletion;
566 }
567 }
568 };
569}
570
571extern "C" {
Daniel Dunbar77af1c52010-08-19 23:44:10 +0000572struct CodeCompleteAtInfo {
573 CXTranslationUnit TU;
574 const char *complete_filename;
575 unsigned complete_line;
576 unsigned complete_column;
577 struct CXUnsavedFile *unsaved_files;
578 unsigned num_unsaved_files;
579 unsigned options;
580 CXCodeCompleteResults *result;
581};
582void clang_codeCompleteAt_Impl(void *UserData) {
583 CodeCompleteAtInfo *CCAI = static_cast<CodeCompleteAtInfo*>(UserData);
584 CXTranslationUnit TU = CCAI->TU;
585 const char *complete_filename = CCAI->complete_filename;
586 unsigned complete_line = CCAI->complete_line;
587 unsigned complete_column = CCAI->complete_column;
588 struct CXUnsavedFile *unsaved_files = CCAI->unsaved_files;
589 unsigned num_unsaved_files = CCAI->num_unsaved_files;
590 unsigned options = CCAI->options;
591 CCAI->result = 0;
592
Douglas Gregor8e984da2010-08-04 16:47:14 +0000593#ifdef UDP_CODE_COMPLETION_LOGGER
594#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
595 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
596#endif
597#endif
598
599 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
600
601 ASTUnit *AST = static_cast<ASTUnit *>(TU);
602 if (!AST)
Daniel Dunbar77af1c52010-08-19 23:44:10 +0000603 return;
Douglas Gregor8e984da2010-08-04 16:47:14 +0000604
605 // Perform the remapping of source files.
606 llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
607 for (unsigned I = 0; I != num_unsaved_files; ++I) {
608 llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
609 const llvm::MemoryBuffer *Buffer
610 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
611 RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
612 Buffer));
613 }
614
615 if (EnableLogging) {
616 // FIXME: Add logging.
617 }
618
619 // Parse the resulting source file to find code-completion results.
620 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
621 Results->Results = 0;
622 Results->NumResults = 0;
Douglas Gregor8e984da2010-08-04 16:47:14 +0000623
624 // Create a code-completion consumer to capture the results.
625 CaptureCompletionResults Capture(*Results);
626
627 // Perform completion.
628 AST->CodeComplete(complete_filename, complete_line, complete_column,
Douglas Gregorb68bc592010-08-05 09:09:23 +0000629 RemappedFiles.data(), RemappedFiles.size(),
630 (options & CXCodeComplete_IncludeMacros),
631 (options & CXCodeComplete_IncludeCodePatterns),
632 Capture,
Douglas Gregor8e984da2010-08-04 16:47:14 +0000633 *Results->Diag, Results->LangOpts, Results->SourceMgr,
Douglas Gregorb97b6662010-08-20 00:59:43 +0000634 Results->FileMgr, Results->Diagnostics,
635 Results->TemporaryBuffers);
Douglas Gregor8e984da2010-08-04 16:47:14 +0000636
637
638
639#ifdef UDP_CODE_COMPLETION_LOGGER
640#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
641 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
642 llvm::SmallString<256> LogResult;
643 llvm::raw_svector_ostream os(LogResult);
644
645 // Figure out the language and whether or not it uses PCH.
646 const char *lang = 0;
647 bool usesPCH = false;
648
649 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
650 I != E; ++I) {
651 if (*I == 0)
652 continue;
653 if (strcmp(*I, "-x") == 0) {
654 if (I + 1 != E) {
655 lang = *(++I);
656 continue;
657 }
658 }
659 else if (strcmp(*I, "-include") == 0) {
660 if (I+1 != E) {
661 const char *arg = *(++I);
662 llvm::SmallString<512> pchName;
663 {
664 llvm::raw_svector_ostream os(pchName);
665 os << arg << ".pth";
666 }
667 pchName.push_back('\0');
668 struct stat stat_results;
669 if (stat(pchName.data(), &stat_results) == 0)
670 usesPCH = true;
671 continue;
672 }
673 }
674 }
675
676 os << "{ ";
677 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
678 os << ", \"numRes\": " << Results->NumResults;
679 os << ", \"diags\": " << Results->Diagnostics.size();
680 os << ", \"pch\": " << (usesPCH ? "true" : "false");
681 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
682 const char *name = getlogin();
683 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
684 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
685 os << " }";
686
687 llvm::StringRef res = os.str();
688 if (res.size() > 0) {
689 do {
690 // Setup the UDP socket.
691 struct sockaddr_in servaddr;
692 bzero(&servaddr, sizeof(servaddr));
693 servaddr.sin_family = AF_INET;
694 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
695 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
696 &servaddr.sin_addr) <= 0)
697 break;
698
699 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
700 if (sockfd < 0)
701 break;
702
703 sendto(sockfd, res.data(), res.size(), 0,
704 (struct sockaddr *)&servaddr, sizeof(servaddr));
705 close(sockfd);
706 }
707 while (false);
708 }
709#endif
710#endif
Daniel Dunbar77af1c52010-08-19 23:44:10 +0000711 CCAI->result = Results;
712}
713CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
714 const char *complete_filename,
715 unsigned complete_line,
716 unsigned complete_column,
717 struct CXUnsavedFile *unsaved_files,
718 unsigned num_unsaved_files,
719 unsigned options) {
720 CodeCompleteAtInfo CCAI = { TU, complete_filename, complete_line,
721 complete_column, unsaved_files, num_unsaved_files,
722 options, 0 };
723 llvm::CrashRecoveryContext CRC;
724
725 if (!CRC.RunSafely(clang_codeCompleteAt_Impl, &CCAI)) {
726 fprintf(stderr, "libclang: crash detected in code completion\n");
727 static_cast<ASTUnit *>(TU)->setUnsafeToFree(true);
728 return 0;
729 }
730
731 return CCAI.result;
Douglas Gregor8e984da2010-08-04 16:47:14 +0000732}
733
Douglas Gregorb68bc592010-08-05 09:09:23 +0000734unsigned clang_defaultCodeCompleteOptions(void) {
735 return CXCodeComplete_IncludeMacros;
736}
737
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000738void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
739 if (!ResultsIn)
740 return;
741
742 AllocatedCXCodeCompleteResults *Results
743 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000744 delete Results;
745}
746
Douglas Gregor33cdd812010-02-18 18:08:43 +0000747unsigned
748clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
749 AllocatedCXCodeCompleteResults *Results
750 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
751 if (!Results)
752 return 0;
753
754 return Results->Diagnostics.size();
755}
756
757CXDiagnostic
758clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
759 unsigned Index) {
760 AllocatedCXCodeCompleteResults *Results
761 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
762 if (!Results || Index >= Results->Diagnostics.size())
763 return 0;
764
765 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
766}
767
768
Ted Kremenek0ec2cca2010-01-05 19:32:54 +0000769} // end extern "C"