blob: 4ab6b9bd91e3e6ee3a8f1b05e63abbae1ac08abe [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"
Benjamin Kramerb846deb2010-04-12 19:45:50 +000017#include "clang/Basic/SourceManager.h"
18#include "clang/Basic/FileManager.h"
Douglas Gregor1abc6bc2010-08-04 16:47:14 +000019#include "clang/Frontend/ASTUnit.h"
Benjamin Kramerb846deb2010-04-12 19:45:50 +000020#include "clang/Frontend/CompilerInstance.h"
Douglas Gregor936ea3b2010-01-28 00:56:43 +000021#include "clang/Frontend/FrontendDiagnostic.h"
Ted Kremenekab188932010-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 Gregor3d398aa2010-07-26 16:29:14 +000026#include <cstdlib>
27#include <cstdio>
Ted Kremenekab188932010-01-05 19:32:54 +000028
Ted Kremenekda7af322010-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 Kremenekab188932010-01-05 19:32:54 +000040using namespace clang;
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +000041using namespace clang::cxstring;
Ted Kremenekab188932010-01-05 19:32:54 +000042
Douglas Gregor12e13132010-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 Kremenekab188932010-01-05 19:32:54 +000057extern "C" {
58
59enum CXCompletionChunkKind
60clang_getCompletionChunkKind(CXCompletionString completion_string,
61 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +000062 CXStoredCodeCompletionString *CCStr
63 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-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 Gregor01dfea02010-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 Kremenekab188932010-01-05 19:32:54 +0000110 }
111
112 // Should be unreachable, but let's be careful.
113 return CXCompletionChunk_Text;
114}
115
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000116CXString clang_getCompletionChunkText(CXCompletionString completion_string,
117 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +0000118 CXStoredCodeCompletionString *CCStr
119 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +0000120 if (!CCStr || chunk_number >= CCStr->size())
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000121 return createCXString(0);
Ted Kremenekab188932010-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 Gregor01dfea02010-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 Kremenek2ef6f8f2010-02-17 01:42:24 +0000143 return createCXString((*CCStr)[chunk_number].Text, false);
Ted Kremenekab188932010-01-05 19:32:54 +0000144
Douglas Gregor21c241f2010-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 Kremenekab188932010-01-05 19:32:54 +0000149 case CodeCompletionString::CK_Optional:
150 // Note: treated as an empty text block.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000151 return createCXString("");
Ted Kremenekab188932010-01-05 19:32:54 +0000152 }
153
154 // Should be unreachable, but let's be careful.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000155 return createCXString(0);
Ted Kremenekab188932010-01-05 19:32:54 +0000156}
157
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000158
Ted Kremenekab188932010-01-05 19:32:54 +0000159CXCompletionString
160clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
161 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +0000162 CXStoredCodeCompletionString *CCStr
163 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-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 Gregor01dfea02010-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 Kremenekab188932010-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 Gregor12e13132010-05-26 22:00:08 +0000200 CXStoredCodeCompletionString *CCStr
201 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +0000202 return CCStr? CCStr->size() : 0;
203}
204
Douglas Gregor12e13132010-05-26 22:00:08 +0000205unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
206 CXStoredCodeCompletionString *CCStr
207 = (CXStoredCodeCompletionString *)completion_string;
Bill Wendlinga2ace582010-05-27 18:35:05 +0000208 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely);
Douglas Gregor12e13132010-05-26 22:00:08 +0000209}
210
Ted Kremenekab188932010-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 Gregor0a812cf2010-02-18 23:07:20 +0000224 AllocatedCXCodeCompleteResults();
225 ~AllocatedCXCodeCompleteResults();
226
Douglas Gregora88084b2010-02-18 18:08:43 +0000227 /// \brief Diagnostics produced while performing code completion.
228 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
229
Douglas Gregorf715ca12010-03-16 00:06:06 +0000230 /// \brief Diag object
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000231 llvm::IntrusiveRefCntPtr<Diagnostic> Diag;
Douglas Gregorf715ca12010-03-16 00:06:06 +0000232
Douglas Gregora88084b2010-02-18 18:08:43 +0000233 /// \brief Language options used to adjust source locations.
Daniel Dunbar35b84402010-01-30 23:31:40 +0000234 LangOptions LangOpts;
Douglas Gregora88084b2010-02-18 18:08:43 +0000235
236 /// \brief Source manager, used for diagnostics.
237 SourceManager SourceMgr;
238
239 /// \brief File manager, used for diagnostics.
240 FileManager FileMgr;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000241
242 /// \brief Temporary files that should be removed once we have finished
243 /// with the code-completion results.
244 std::vector<llvm::sys::Path> TemporaryFiles;
Douglas Gregorb75d3df2010-08-04 17:07:00 +0000245
246 /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results.
247 llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers;
Ted Kremenekab188932010-01-05 19:32:54 +0000248};
249
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000250AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
Douglas Gregorb75d3df2010-08-04 17:07:00 +0000251 : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000252
253AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
254 for (unsigned I = 0, N = NumResults; I != N; ++I)
Douglas Gregor12e13132010-05-26 22:00:08 +0000255 delete (CXStoredCodeCompletionString *)Results[I].CompletionString;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000256 delete [] Results;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000257
258 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
259 TemporaryFiles[I].eraseFromDisk();
Douglas Gregorb75d3df2010-08-04 17:07:00 +0000260 for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
261 delete TemporaryBuffers[I];
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000262}
263
Ted Kremenekab188932010-01-05 19:32:54 +0000264CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
265 const char *source_filename,
266 int num_command_line_args,
267 const char **command_line_args,
268 unsigned num_unsaved_files,
269 struct CXUnsavedFile *unsaved_files,
270 const char *complete_filename,
271 unsigned complete_line,
Douglas Gregora88084b2010-02-18 18:08:43 +0000272 unsigned complete_column) {
Ted Kremenekda7af322010-04-15 01:02:28 +0000273#ifdef UDP_CODE_COMPLETION_LOGGER
274#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
275 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
276#endif
277#endif
278
Douglas Gregor3d398aa2010-07-26 16:29:14 +0000279 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
280
Ted Kremenekab188932010-01-05 19:32:54 +0000281 // The indexer, which is mainly used to determine where diagnostics go.
282 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
283
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000284 // Configure the diagnostics.
285 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000286 llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
287 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000288
Ted Kremenekab188932010-01-05 19:32:54 +0000289 // The set of temporary files that we've built.
290 std::vector<llvm::sys::Path> TemporaryFiles;
291
292 // Build up the arguments for invoking 'clang'.
293 std::vector<const char *> argv;
294
295 // First add the complete path to the 'clang' executable.
296 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
297 argv.push_back(ClangPath.c_str());
298
Daniel Dunbar3d9c6e12010-06-30 21:40:01 +0000299 // Always use Clang C++ support.
300 argv.push_back("-ccc-clang-cxx");
301
Ted Kremenekab188932010-01-05 19:32:54 +0000302 // Add the '-fsyntax-only' argument so that we only perform a basic
303 // syntax check of the code.
304 argv.push_back("-fsyntax-only");
305
306 // Add the appropriate '-code-completion-at=file:line:column' argument
307 // to perform code completion, with an "-Xclang" preceding it.
308 std::string code_complete_at;
309 code_complete_at += complete_filename;
310 code_complete_at += ":";
311 code_complete_at += llvm::utostr(complete_line);
312 code_complete_at += ":";
313 code_complete_at += llvm::utostr(complete_column);
314 argv.push_back("-Xclang");
315 argv.push_back("-code-completion-at");
316 argv.push_back("-Xclang");
317 argv.push_back(code_complete_at.c_str());
318 argv.push_back("-Xclang");
319 argv.push_back("-no-code-completion-debug-printer");
320 argv.push_back("-Xclang");
321 argv.push_back("-code-completion-macros");
Douglas Gregord93256e2010-01-28 06:00:51 +0000322 argv.push_back("-fdiagnostics-binary");
323
Douglas Gregor4db64a42010-01-23 00:14:00 +0000324 // Remap any unsaved files to temporary files.
Ted Kremenekab188932010-01-05 19:32:54 +0000325 std::vector<std::string> RemapArgs;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000326 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
327 return 0;
Ted Kremenekab188932010-01-05 19:32:54 +0000328
329 // The pointers into the elements of RemapArgs are stable because we
330 // won't be adding anything to RemapArgs after this point.
331 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
332 argv.push_back(RemapArgs[i].c_str());
333
334 // Add the source file name (FIXME: later, we'll want to build temporary
335 // file from the buffer, or just feed the source text via standard input).
336 if (source_filename)
337 argv.push_back(source_filename);
338
339 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
340 for (int i = 0; i < num_command_line_args; ++i)
341 if (const char *arg = command_line_args[i]) {
342 if (strcmp(arg, "-o") == 0) {
343 ++i; // Also skip the matching argument.
344 continue;
345 }
346 if (strcmp(arg, "-emit-ast") == 0 ||
347 strcmp(arg, "-c") == 0 ||
348 strcmp(arg, "-fsyntax-only") == 0) {
349 continue;
350 }
351
352 // Keep the argument.
353 argv.push_back(arg);
354 }
355
Douglas Gregor3d398aa2010-07-26 16:29:14 +0000356 if (EnableLogging) {
357 std::string Log = ClangPath.str();
358 for (unsigned I = 0, N = argv.size(); I != N; ++I) {
359 Log += ' ';
360 Log += argv[I];
361 }
362 fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str());
363 }
364
Ted Kremenekab188932010-01-05 19:32:54 +0000365 // Add the null terminator.
366 argv.push_back(NULL);
367
Douglas Gregord93256e2010-01-28 06:00:51 +0000368 // Generate a temporary name for the code-completion results file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000369 char tmpFile[L_tmpnam];
370 char *tmpFileName = tmpnam(tmpFile);
371 llvm::sys::Path ResultsFile(tmpFileName);
Ted Kremenekab188932010-01-05 19:32:54 +0000372 TemporaryFiles.push_back(ResultsFile);
373
Douglas Gregord93256e2010-01-28 06:00:51 +0000374 // Generate a temporary name for the diagnostics file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000375 char tmpFileResults[L_tmpnam];
376 char *tmpResultsFileName = tmpnam(tmpFileResults);
377 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
Douglas Gregord93256e2010-01-28 06:00:51 +0000378 TemporaryFiles.push_back(DiagnosticsFile);
379
Douglas Gregor3d398aa2010-07-26 16:29:14 +0000380
381
Ted Kremenekab188932010-01-05 19:32:54 +0000382 // Invoke 'clang'.
383 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
384 // on Unix or NUL (Windows).
385 std::string ErrMsg;
Douglas Gregord93256e2010-01-28 06:00:51 +0000386 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
387 &DiagnosticsFile, 0 };
Ted Kremenekab188932010-01-05 19:32:54 +0000388 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
389 /* redirects */ &Redirects[0],
390 /* secondsToWait */ 0,
391 /* memoryLimits */ 0, &ErrMsg);
392
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000393 if (!ErrMsg.empty()) {
394 std::string AllArgs;
Ted Kremenekab188932010-01-05 19:32:54 +0000395 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000396 I != E; ++I) {
397 AllArgs += ' ';
Ted Kremenekab188932010-01-05 19:32:54 +0000398 if (*I)
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000399 AllArgs += *I;
Ted Kremenekab188932010-01-05 19:32:54 +0000400 }
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000401
Daniel Dunbar32141c82010-02-23 20:23:45 +0000402 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
Ted Kremenekab188932010-01-05 19:32:54 +0000403 }
404
405 // Parse the resulting source file to find code-completion results.
406 using llvm::MemoryBuffer;
407 using llvm::StringRef;
Douglas Gregora88084b2010-02-18 18:08:43 +0000408 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
409 Results->Results = 0;
410 Results->NumResults = 0;
Douglas Gregora88084b2010-02-18 18:08:43 +0000411 // FIXME: Set Results->LangOpts!
Ted Kremenekab188932010-01-05 19:32:54 +0000412 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
413 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
414 StringRef Buffer = F->getBuffer();
415 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
416 Str < StrEnd;) {
417 unsigned KindValue;
418 if (ReadUnsigned(Str, StrEnd, KindValue))
419 break;
420
Douglas Gregor12e13132010-05-26 22:00:08 +0000421 unsigned Priority;
422 if (ReadUnsigned(Str, StrEnd, Priority))
423 break;
424
425 CXStoredCodeCompletionString *CCStr
426 = new CXStoredCodeCompletionString(Priority);
427 if (!CCStr->Deserialize(Str, StrEnd)) {
428 delete CCStr;
Ted Kremenekab188932010-01-05 19:32:54 +0000429 continue;
Douglas Gregor12e13132010-05-26 22:00:08 +0000430 }
Ted Kremenekab188932010-01-05 19:32:54 +0000431
432 if (!CCStr->empty()) {
433 // Vend the code-completion result to the caller.
434 CXCompletionResult Result;
435 Result.CursorKind = (CXCursorKind)KindValue;
436 Result.CompletionString = CCStr;
437 CompletionResults.push_back(Result);
438 }
439 };
440
441 // Allocate the results.
Ted Kremenekab188932010-01-05 19:32:54 +0000442 Results->Results = new CXCompletionResult [CompletionResults.size()];
443 Results->NumResults = CompletionResults.size();
444 memcpy(Results->Results, CompletionResults.data(),
445 CompletionResults.size() * sizeof(CXCompletionResult));
Douglas Gregorb75d3df2010-08-04 17:07:00 +0000446 Results->TemporaryBuffers.push_back(F);
Ted Kremenekab188932010-01-05 19:32:54 +0000447 }
448
Douglas Gregora88084b2010-02-18 18:08:43 +0000449 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
450 Results->FileMgr, Results->SourceMgr,
451 Results->Diagnostics);
452
Douglas Gregor313e26c2010-02-18 23:35:40 +0000453 // Make sure we delete temporary files when the code-completion results are
454 // destroyed.
455 Results->TemporaryFiles.swap(TemporaryFiles);
Ted Kremenekab188932010-01-05 19:32:54 +0000456
Ted Kremenekda7af322010-04-15 01:02:28 +0000457#ifdef UDP_CODE_COMPLETION_LOGGER
458#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
459 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
460 llvm::SmallString<256> LogResult;
461 llvm::raw_svector_ostream os(LogResult);
462
463 // Figure out the language and whether or not it uses PCH.
464 const char *lang = 0;
465 bool usesPCH = false;
466
467 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
468 I != E; ++I) {
469 if (*I == 0)
470 continue;
471 if (strcmp(*I, "-x") == 0) {
472 if (I + 1 != E) {
473 lang = *(++I);
474 continue;
475 }
476 }
477 else if (strcmp(*I, "-include") == 0) {
478 if (I+1 != E) {
479 const char *arg = *(++I);
480 llvm::SmallString<512> pchName;
481 {
482 llvm::raw_svector_ostream os(pchName);
483 os << arg << ".pth";
484 }
485 pchName.push_back('\0');
486 struct stat stat_results;
487 if (stat(pchName.data(), &stat_results) == 0)
488 usesPCH = true;
489 continue;
490 }
491 }
492 }
493
Ted Kremenek2ee297f2010-04-17 00:21:42 +0000494 os << "{ ";
495 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
496 os << ", \"numRes\": " << Results->NumResults;
497 os << ", \"diags\": " << Results->Diagnostics.size();
498 os << ", \"pch\": " << (usesPCH ? "true" : "false");
499 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
Ted Kremenekda7af322010-04-15 01:02:28 +0000500 const char *name = getlogin();
Ted Kremenek2ee297f2010-04-17 00:21:42 +0000501 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
502 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
503 os << " }";
Ted Kremenekda7af322010-04-15 01:02:28 +0000504
505 llvm::StringRef res = os.str();
506 if (res.size() > 0) {
507 do {
508 // Setup the UDP socket.
509 struct sockaddr_in servaddr;
510 bzero(&servaddr, sizeof(servaddr));
511 servaddr.sin_family = AF_INET;
512 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
513 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
514 &servaddr.sin_addr) <= 0)
515 break;
516
517 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
518 if (sockfd < 0)
519 break;
520
521 sendto(sockfd, res.data(), res.size(), 0,
522 (struct sockaddr *)&servaddr, sizeof(servaddr));
523 close(sockfd);
524 }
525 while (false);
526 }
527#endif
528#endif
Ted Kremenekab188932010-01-05 19:32:54 +0000529 return Results;
530}
531
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000532} // end extern "C"
533
534namespace clang {
535 // FIXME: defined in CodeCompleteConsumer.cpp, but should be a
536 // static function here.
537 CXCursorKind
538 getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R);
539}
540
541
542namespace {
543 class CaptureCompletionResults : public CodeCompleteConsumer {
544 AllocatedCXCodeCompleteResults &AllocatedResults;
545
546 public:
547 explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results)
548 : CodeCompleteConsumer(true, false, false), AllocatedResults(Results) { }
549
550 virtual void ProcessCodeCompleteResults(Sema &S, Result *Results,
551 unsigned NumResults) {
552 AllocatedResults.Results = new CXCompletionResult [NumResults];
553 AllocatedResults.NumResults = NumResults;
554 for (unsigned I = 0; I != NumResults; ++I) {
555 CXStoredCodeCompletionString *StoredCompletion
556 = new CXStoredCodeCompletionString(Results[I].Priority);
557 (void)Results[I].CreateCodeCompletionString(S, StoredCompletion);
558 AllocatedResults.Results[I].CursorKind
559 = getCursorKindForCompletionResult(Results[I]);
560 AllocatedResults.Results[I].CompletionString = StoredCompletion;
561 }
562 }
563 };
564}
565
566extern "C" {
567CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU,
568 const char *complete_filename,
569 unsigned complete_line,
570 unsigned complete_column,
571 struct CXUnsavedFile *unsaved_files,
Douglas Gregorcee235c2010-08-05 09:09:23 +0000572 unsigned num_unsaved_files,
573 unsigned options) {
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000574#ifdef UDP_CODE_COMPLETION_LOGGER
575#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
576 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
577#endif
578#endif
579
580 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0;
581
582 ASTUnit *AST = static_cast<ASTUnit *>(TU);
583 if (!AST)
584 return 0;
585
586 // Perform the remapping of source files.
587 llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
588 for (unsigned I = 0; I != num_unsaved_files; ++I) {
589 llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length);
590 const llvm::MemoryBuffer *Buffer
591 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename);
592 RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename,
593 Buffer));
594 }
595
596 if (EnableLogging) {
597 // FIXME: Add logging.
598 }
599
600 // Parse the resulting source file to find code-completion results.
601 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
602 Results->Results = 0;
603 Results->NumResults = 0;
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000604
605 // Create a code-completion consumer to capture the results.
606 CaptureCompletionResults Capture(*Results);
607
Douglas Gregorb75d3df2010-08-04 17:07:00 +0000608 // Make sure that we free the temporary buffers when the
609 // code-completion constructor is freed.
610 for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I)
611 Results->TemporaryBuffers.push_back(RemappedFiles[I].second);
612
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000613 // Perform completion.
614 AST->CodeComplete(complete_filename, complete_line, complete_column,
Douglas Gregorcee235c2010-08-05 09:09:23 +0000615 RemappedFiles.data(), RemappedFiles.size(),
616 (options & CXCodeComplete_IncludeMacros),
617 (options & CXCodeComplete_IncludeCodePatterns),
618 Capture,
Douglas Gregor1abc6bc2010-08-04 16:47:14 +0000619 *Results->Diag, Results->LangOpts, Results->SourceMgr,
620 Results->FileMgr, Results->Diagnostics);
621
622
623
624#ifdef UDP_CODE_COMPLETION_LOGGER
625#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
626 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
627 llvm::SmallString<256> LogResult;
628 llvm::raw_svector_ostream os(LogResult);
629
630 // Figure out the language and whether or not it uses PCH.
631 const char *lang = 0;
632 bool usesPCH = false;
633
634 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
635 I != E; ++I) {
636 if (*I == 0)
637 continue;
638 if (strcmp(*I, "-x") == 0) {
639 if (I + 1 != E) {
640 lang = *(++I);
641 continue;
642 }
643 }
644 else if (strcmp(*I, "-include") == 0) {
645 if (I+1 != E) {
646 const char *arg = *(++I);
647 llvm::SmallString<512> pchName;
648 {
649 llvm::raw_svector_ostream os(pchName);
650 os << arg << ".pth";
651 }
652 pchName.push_back('\0');
653 struct stat stat_results;
654 if (stat(pchName.data(), &stat_results) == 0)
655 usesPCH = true;
656 continue;
657 }
658 }
659 }
660
661 os << "{ ";
662 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
663 os << ", \"numRes\": " << Results->NumResults;
664 os << ", \"diags\": " << Results->Diagnostics.size();
665 os << ", \"pch\": " << (usesPCH ? "true" : "false");
666 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
667 const char *name = getlogin();
668 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
669 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
670 os << " }";
671
672 llvm::StringRef res = os.str();
673 if (res.size() > 0) {
674 do {
675 // Setup the UDP socket.
676 struct sockaddr_in servaddr;
677 bzero(&servaddr, sizeof(servaddr));
678 servaddr.sin_family = AF_INET;
679 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
680 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
681 &servaddr.sin_addr) <= 0)
682 break;
683
684 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
685 if (sockfd < 0)
686 break;
687
688 sendto(sockfd, res.data(), res.size(), 0,
689 (struct sockaddr *)&servaddr, sizeof(servaddr));
690 close(sockfd);
691 }
692 while (false);
693 }
694#endif
695#endif
696 return Results;
697}
698
Douglas Gregorcee235c2010-08-05 09:09:23 +0000699unsigned clang_defaultCodeCompleteOptions(void) {
700 return CXCodeComplete_IncludeMacros;
701}
702
Ted Kremenekab188932010-01-05 19:32:54 +0000703void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
704 if (!ResultsIn)
705 return;
706
707 AllocatedCXCodeCompleteResults *Results
708 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
Ted Kremenekab188932010-01-05 19:32:54 +0000709 delete Results;
710}
711
Douglas Gregora88084b2010-02-18 18:08:43 +0000712unsigned
713clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
714 AllocatedCXCodeCompleteResults *Results
715 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
716 if (!Results)
717 return 0;
718
719 return Results->Diagnostics.size();
720}
721
722CXDiagnostic
723clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
724 unsigned Index) {
725 AllocatedCXCodeCompleteResults *Results
726 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
727 if (!Results || Index >= Results->Diagnostics.size())
728 return 0;
729
730 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
731}
732
733
Ted Kremenekab188932010-01-05 19:32:54 +0000734} // end extern "C"