blob: 277fadf683bc7168a3e5712fcee8c6145d04b012 [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"
19#include "clang/Frontend/CompilerInstance.h"
Douglas Gregor936ea3b2010-01-28 00:56:43 +000020#include "clang/Frontend/FrontendDiagnostic.h"
Ted Kremenekab188932010-01-05 19:32:54 +000021#include "clang/Sema/CodeCompleteConsumer.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/System/Program.h"
25
Ted Kremenekda7af322010-04-15 01:02:28 +000026#ifdef UDP_CODE_COMPLETION_LOGGER
27#include "clang/Basic/Version.h"
28#include "llvm/ADT/SmallString.h"
29#include "llvm/Support/Timer.h"
30#include "llvm/Support/raw_ostream.h"
31#include <arpa/inet.h>
32#include <sys/socket.h>
33#include <sys/types.h>
34#include <unistd.h>
35#endif
36
Ted Kremenekab188932010-01-05 19:32:54 +000037using namespace clang;
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +000038using namespace clang::cxstring;
Ted Kremenekab188932010-01-05 19:32:54 +000039
Douglas Gregor12e13132010-05-26 22:00:08 +000040namespace {
41 /// \brief Stored representation of a completion string.
42 ///
43 /// This is the representation behind a CXCompletionString.
44 class CXStoredCodeCompletionString : public CodeCompletionString {
45 unsigned Priority;
46
47 public:
48 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { }
49
50 unsigned getPriority() const { return Priority; }
51 };
52}
53
Ted Kremenekab188932010-01-05 19:32:54 +000054extern "C" {
55
56enum CXCompletionChunkKind
57clang_getCompletionChunkKind(CXCompletionString completion_string,
58 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +000059 CXStoredCodeCompletionString *CCStr
60 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +000061 if (!CCStr || chunk_number >= CCStr->size())
62 return CXCompletionChunk_Text;
63
64 switch ((*CCStr)[chunk_number].Kind) {
65 case CodeCompletionString::CK_TypedText:
66 return CXCompletionChunk_TypedText;
67 case CodeCompletionString::CK_Text:
68 return CXCompletionChunk_Text;
69 case CodeCompletionString::CK_Optional:
70 return CXCompletionChunk_Optional;
71 case CodeCompletionString::CK_Placeholder:
72 return CXCompletionChunk_Placeholder;
73 case CodeCompletionString::CK_Informative:
74 return CXCompletionChunk_Informative;
75 case CodeCompletionString::CK_ResultType:
76 return CXCompletionChunk_ResultType;
77 case CodeCompletionString::CK_CurrentParameter:
78 return CXCompletionChunk_CurrentParameter;
79 case CodeCompletionString::CK_LeftParen:
80 return CXCompletionChunk_LeftParen;
81 case CodeCompletionString::CK_RightParen:
82 return CXCompletionChunk_RightParen;
83 case CodeCompletionString::CK_LeftBracket:
84 return CXCompletionChunk_LeftBracket;
85 case CodeCompletionString::CK_RightBracket:
86 return CXCompletionChunk_RightBracket;
87 case CodeCompletionString::CK_LeftBrace:
88 return CXCompletionChunk_LeftBrace;
89 case CodeCompletionString::CK_RightBrace:
90 return CXCompletionChunk_RightBrace;
91 case CodeCompletionString::CK_LeftAngle:
92 return CXCompletionChunk_LeftAngle;
93 case CodeCompletionString::CK_RightAngle:
94 return CXCompletionChunk_RightAngle;
95 case CodeCompletionString::CK_Comma:
96 return CXCompletionChunk_Comma;
Douglas Gregor01dfea02010-01-10 23:08:15 +000097 case CodeCompletionString::CK_Colon:
98 return CXCompletionChunk_Colon;
99 case CodeCompletionString::CK_SemiColon:
100 return CXCompletionChunk_SemiColon;
101 case CodeCompletionString::CK_Equal:
102 return CXCompletionChunk_Equal;
103 case CodeCompletionString::CK_HorizontalSpace:
104 return CXCompletionChunk_HorizontalSpace;
105 case CodeCompletionString::CK_VerticalSpace:
106 return CXCompletionChunk_VerticalSpace;
Ted Kremenekab188932010-01-05 19:32:54 +0000107 }
108
109 // Should be unreachable, but let's be careful.
110 return CXCompletionChunk_Text;
111}
112
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000113CXString clang_getCompletionChunkText(CXCompletionString completion_string,
114 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +0000115 CXStoredCodeCompletionString *CCStr
116 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +0000117 if (!CCStr || chunk_number >= CCStr->size())
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000118 return createCXString(0);
Ted Kremenekab188932010-01-05 19:32:54 +0000119
120 switch ((*CCStr)[chunk_number].Kind) {
121 case CodeCompletionString::CK_TypedText:
122 case CodeCompletionString::CK_Text:
123 case CodeCompletionString::CK_Placeholder:
124 case CodeCompletionString::CK_CurrentParameter:
125 case CodeCompletionString::CK_Informative:
126 case CodeCompletionString::CK_LeftParen:
127 case CodeCompletionString::CK_RightParen:
128 case CodeCompletionString::CK_LeftBracket:
129 case CodeCompletionString::CK_RightBracket:
130 case CodeCompletionString::CK_LeftBrace:
131 case CodeCompletionString::CK_RightBrace:
132 case CodeCompletionString::CK_LeftAngle:
133 case CodeCompletionString::CK_RightAngle:
134 case CodeCompletionString::CK_Comma:
135 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000136 case CodeCompletionString::CK_Colon:
137 case CodeCompletionString::CK_SemiColon:
138 case CodeCompletionString::CK_Equal:
139 case CodeCompletionString::CK_HorizontalSpace:
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000140 return createCXString((*CCStr)[chunk_number].Text, false);
Ted Kremenekab188932010-01-05 19:32:54 +0000141
Douglas Gregor21c241f2010-05-25 06:14:46 +0000142 case CodeCompletionString::CK_VerticalSpace:
143 // FIXME: Temporary hack until we figure out how to handle vertical space.
144 return createCXString(" ");
145
Ted Kremenekab188932010-01-05 19:32:54 +0000146 case CodeCompletionString::CK_Optional:
147 // Note: treated as an empty text block.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000148 return createCXString("");
Ted Kremenekab188932010-01-05 19:32:54 +0000149 }
150
151 // Should be unreachable, but let's be careful.
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000152 return createCXString(0);
Ted Kremenekab188932010-01-05 19:32:54 +0000153}
154
Ted Kremenek2ef6f8f2010-02-17 01:42:24 +0000155
Ted Kremenekab188932010-01-05 19:32:54 +0000156CXCompletionString
157clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
158 unsigned chunk_number) {
Douglas Gregor12e13132010-05-26 22:00:08 +0000159 CXStoredCodeCompletionString *CCStr
160 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +0000161 if (!CCStr || chunk_number >= CCStr->size())
162 return 0;
163
164 switch ((*CCStr)[chunk_number].Kind) {
165 case CodeCompletionString::CK_TypedText:
166 case CodeCompletionString::CK_Text:
167 case CodeCompletionString::CK_Placeholder:
168 case CodeCompletionString::CK_CurrentParameter:
169 case CodeCompletionString::CK_Informative:
170 case CodeCompletionString::CK_LeftParen:
171 case CodeCompletionString::CK_RightParen:
172 case CodeCompletionString::CK_LeftBracket:
173 case CodeCompletionString::CK_RightBracket:
174 case CodeCompletionString::CK_LeftBrace:
175 case CodeCompletionString::CK_RightBrace:
176 case CodeCompletionString::CK_LeftAngle:
177 case CodeCompletionString::CK_RightAngle:
178 case CodeCompletionString::CK_Comma:
179 case CodeCompletionString::CK_ResultType:
Douglas Gregor01dfea02010-01-10 23:08:15 +0000180 case CodeCompletionString::CK_Colon:
181 case CodeCompletionString::CK_SemiColon:
182 case CodeCompletionString::CK_Equal:
183 case CodeCompletionString::CK_HorizontalSpace:
184 case CodeCompletionString::CK_VerticalSpace:
Ted Kremenekab188932010-01-05 19:32:54 +0000185 return 0;
186
187 case CodeCompletionString::CK_Optional:
188 // Note: treated as an empty text block.
189 return (*CCStr)[chunk_number].Optional;
190 }
191
192 // Should be unreachable, but let's be careful.
193 return 0;
194}
195
196unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) {
Douglas Gregor12e13132010-05-26 22:00:08 +0000197 CXStoredCodeCompletionString *CCStr
198 = (CXStoredCodeCompletionString *)completion_string;
Ted Kremenekab188932010-01-05 19:32:54 +0000199 return CCStr? CCStr->size() : 0;
200}
201
Douglas Gregor12e13132010-05-26 22:00:08 +0000202unsigned clang_getCompletionPriority(CXCompletionString completion_string) {
203 CXStoredCodeCompletionString *CCStr
204 = (CXStoredCodeCompletionString *)completion_string;
Bill Wendlinga2ace582010-05-27 18:35:05 +0000205 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely);
Douglas Gregor12e13132010-05-26 22:00:08 +0000206}
207
Ted Kremenekab188932010-01-05 19:32:54 +0000208static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd,
209 unsigned &Value) {
210 if (Memory + sizeof(unsigned) > MemoryEnd)
211 return true;
212
213 memmove(&Value, Memory, sizeof(unsigned));
214 Memory += sizeof(unsigned);
215 return false;
216}
217
218/// \brief The CXCodeCompleteResults structure we allocate internally;
219/// the client only sees the initial CXCodeCompleteResults structure.
220struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000221 AllocatedCXCodeCompleteResults();
222 ~AllocatedCXCodeCompleteResults();
223
Ted Kremenekab188932010-01-05 19:32:54 +0000224 /// \brief The memory buffer from which we parsed the results. We
225 /// retain this buffer because the completion strings point into it.
226 llvm::MemoryBuffer *Buffer;
Daniel Dunbar35b84402010-01-30 23:31:40 +0000227
Douglas Gregora88084b2010-02-18 18:08:43 +0000228 /// \brief Diagnostics produced while performing code completion.
229 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics;
230
Douglas Gregorf715ca12010-03-16 00:06:06 +0000231 /// \brief Diag object
232 Diagnostic Diag;
233
Douglas Gregora88084b2010-02-18 18:08:43 +0000234 /// \brief Language options used to adjust source locations.
Daniel Dunbar35b84402010-01-30 23:31:40 +0000235 LangOptions LangOpts;
Douglas Gregora88084b2010-02-18 18:08:43 +0000236
237 /// \brief Source manager, used for diagnostics.
238 SourceManager SourceMgr;
239
240 /// \brief File manager, used for diagnostics.
241 FileManager FileMgr;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000242
243 /// \brief Temporary files that should be removed once we have finished
244 /// with the code-completion results.
245 std::vector<llvm::sys::Path> TemporaryFiles;
Ted Kremenekab188932010-01-05 19:32:54 +0000246};
247
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000248AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults()
Douglas Gregorf715ca12010-03-16 00:06:06 +0000249 : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { }
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000250
251AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
252 for (unsigned I = 0, N = NumResults; I != N; ++I)
Douglas Gregor12e13132010-05-26 22:00:08 +0000253 delete (CXStoredCodeCompletionString *)Results[I].CompletionString;
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000254 delete [] Results;
255 delete Buffer;
Douglas Gregor313e26c2010-02-18 23:35:40 +0000256
257 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
258 TemporaryFiles[I].eraseFromDisk();
Douglas Gregor0a812cf2010-02-18 23:07:20 +0000259}
260
Ted Kremenekab188932010-01-05 19:32:54 +0000261CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx,
262 const char *source_filename,
263 int num_command_line_args,
264 const char **command_line_args,
265 unsigned num_unsaved_files,
266 struct CXUnsavedFile *unsaved_files,
267 const char *complete_filename,
268 unsigned complete_line,
Douglas Gregora88084b2010-02-18 18:08:43 +0000269 unsigned complete_column) {
Ted Kremenekda7af322010-04-15 01:02:28 +0000270#ifdef UDP_CODE_COMPLETION_LOGGER
271#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
272 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime();
273#endif
274#endif
275
Ted Kremenekab188932010-01-05 19:32:54 +0000276 // The indexer, which is mainly used to determine where diagnostics go.
277 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx);
278
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000279 // Configure the diagnostics.
280 DiagnosticOptions DiagOpts;
Douglas Gregor28019772010-04-05 23:52:57 +0000281 llvm::IntrusiveRefCntPtr<Diagnostic> Diags;
282 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0);
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000283
Ted Kremenekab188932010-01-05 19:32:54 +0000284 // The set of temporary files that we've built.
285 std::vector<llvm::sys::Path> TemporaryFiles;
286
287 // Build up the arguments for invoking 'clang'.
288 std::vector<const char *> argv;
289
290 // First add the complete path to the 'clang' executable.
291 llvm::sys::Path ClangPath = CXXIdx->getClangPath();
292 argv.push_back(ClangPath.c_str());
293
Daniel Dunbar3d9c6e12010-06-30 21:40:01 +0000294 // Always use Clang C++ support.
295 argv.push_back("-ccc-clang-cxx");
296
Ted Kremenekab188932010-01-05 19:32:54 +0000297 // Add the '-fsyntax-only' argument so that we only perform a basic
298 // syntax check of the code.
299 argv.push_back("-fsyntax-only");
300
301 // Add the appropriate '-code-completion-at=file:line:column' argument
302 // to perform code completion, with an "-Xclang" preceding it.
303 std::string code_complete_at;
304 code_complete_at += complete_filename;
305 code_complete_at += ":";
306 code_complete_at += llvm::utostr(complete_line);
307 code_complete_at += ":";
308 code_complete_at += llvm::utostr(complete_column);
309 argv.push_back("-Xclang");
310 argv.push_back("-code-completion-at");
311 argv.push_back("-Xclang");
312 argv.push_back(code_complete_at.c_str());
313 argv.push_back("-Xclang");
314 argv.push_back("-no-code-completion-debug-printer");
315 argv.push_back("-Xclang");
316 argv.push_back("-code-completion-macros");
Douglas Gregord93256e2010-01-28 06:00:51 +0000317 argv.push_back("-fdiagnostics-binary");
318
Douglas Gregor4db64a42010-01-23 00:14:00 +0000319 // Remap any unsaved files to temporary files.
Ted Kremenekab188932010-01-05 19:32:54 +0000320 std::vector<std::string> RemapArgs;
Douglas Gregor4db64a42010-01-23 00:14:00 +0000321 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles))
322 return 0;
Ted Kremenekab188932010-01-05 19:32:54 +0000323
324 // The pointers into the elements of RemapArgs are stable because we
325 // won't be adding anything to RemapArgs after this point.
326 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i)
327 argv.push_back(RemapArgs[i].c_str());
328
329 // Add the source file name (FIXME: later, we'll want to build temporary
330 // file from the buffer, or just feed the source text via standard input).
331 if (source_filename)
332 argv.push_back(source_filename);
333
334 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'.
335 for (int i = 0; i < num_command_line_args; ++i)
336 if (const char *arg = command_line_args[i]) {
337 if (strcmp(arg, "-o") == 0) {
338 ++i; // Also skip the matching argument.
339 continue;
340 }
341 if (strcmp(arg, "-emit-ast") == 0 ||
342 strcmp(arg, "-c") == 0 ||
343 strcmp(arg, "-fsyntax-only") == 0) {
344 continue;
345 }
346
347 // Keep the argument.
348 argv.push_back(arg);
349 }
350
351 // Add the null terminator.
352 argv.push_back(NULL);
353
Douglas Gregord93256e2010-01-28 06:00:51 +0000354 // Generate a temporary name for the code-completion results file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000355 char tmpFile[L_tmpnam];
356 char *tmpFileName = tmpnam(tmpFile);
357 llvm::sys::Path ResultsFile(tmpFileName);
Ted Kremenekab188932010-01-05 19:32:54 +0000358 TemporaryFiles.push_back(ResultsFile);
359
Douglas Gregord93256e2010-01-28 06:00:51 +0000360 // Generate a temporary name for the diagnostics file.
Benjamin Kramerc2a98162010-03-13 21:22:49 +0000361 char tmpFileResults[L_tmpnam];
362 char *tmpResultsFileName = tmpnam(tmpFileResults);
363 llvm::sys::Path DiagnosticsFile(tmpResultsFileName);
Douglas Gregord93256e2010-01-28 06:00:51 +0000364 TemporaryFiles.push_back(DiagnosticsFile);
365
Ted Kremenekab188932010-01-05 19:32:54 +0000366 // Invoke 'clang'.
367 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null
368 // on Unix or NUL (Windows).
369 std::string ErrMsg;
Douglas Gregord93256e2010-01-28 06:00:51 +0000370 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile,
371 &DiagnosticsFile, 0 };
Ted Kremenekab188932010-01-05 19:32:54 +0000372 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL,
373 /* redirects */ &Redirects[0],
374 /* secondsToWait */ 0,
375 /* memoryLimits */ 0, &ErrMsg);
376
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000377 if (!ErrMsg.empty()) {
378 std::string AllArgs;
Ted Kremenekab188932010-01-05 19:32:54 +0000379 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000380 I != E; ++I) {
381 AllArgs += ' ';
Ted Kremenekab188932010-01-05 19:32:54 +0000382 if (*I)
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000383 AllArgs += *I;
Ted Kremenekab188932010-01-05 19:32:54 +0000384 }
Douglas Gregor936ea3b2010-01-28 00:56:43 +0000385
Daniel Dunbar32141c82010-02-23 20:23:45 +0000386 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg;
Ted Kremenekab188932010-01-05 19:32:54 +0000387 }
388
389 // Parse the resulting source file to find code-completion results.
390 using llvm::MemoryBuffer;
391 using llvm::StringRef;
Douglas Gregora88084b2010-02-18 18:08:43 +0000392 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults;
393 Results->Results = 0;
394 Results->NumResults = 0;
395 Results->Buffer = 0;
396 // FIXME: Set Results->LangOpts!
Ted Kremenekab188932010-01-05 19:32:54 +0000397 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) {
398 llvm::SmallVector<CXCompletionResult, 4> CompletionResults;
399 StringRef Buffer = F->getBuffer();
400 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size();
401 Str < StrEnd;) {
402 unsigned KindValue;
403 if (ReadUnsigned(Str, StrEnd, KindValue))
404 break;
405
Douglas Gregor12e13132010-05-26 22:00:08 +0000406 unsigned Priority;
407 if (ReadUnsigned(Str, StrEnd, Priority))
408 break;
409
410 CXStoredCodeCompletionString *CCStr
411 = new CXStoredCodeCompletionString(Priority);
412 if (!CCStr->Deserialize(Str, StrEnd)) {
413 delete CCStr;
Ted Kremenekab188932010-01-05 19:32:54 +0000414 continue;
Douglas Gregor12e13132010-05-26 22:00:08 +0000415 }
Ted Kremenekab188932010-01-05 19:32:54 +0000416
417 if (!CCStr->empty()) {
418 // Vend the code-completion result to the caller.
419 CXCompletionResult Result;
420 Result.CursorKind = (CXCursorKind)KindValue;
421 Result.CompletionString = CCStr;
422 CompletionResults.push_back(Result);
423 }
424 };
425
426 // Allocate the results.
Ted Kremenekab188932010-01-05 19:32:54 +0000427 Results->Results = new CXCompletionResult [CompletionResults.size()];
428 Results->NumResults = CompletionResults.size();
429 memcpy(Results->Results, CompletionResults.data(),
430 CompletionResults.size() * sizeof(CXCompletionResult));
431 Results->Buffer = F;
432 }
433
Douglas Gregora88084b2010-02-18 18:08:43 +0000434 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files,
435 Results->FileMgr, Results->SourceMgr,
436 Results->Diagnostics);
437
Douglas Gregor313e26c2010-02-18 23:35:40 +0000438 // Make sure we delete temporary files when the code-completion results are
439 // destroyed.
440 Results->TemporaryFiles.swap(TemporaryFiles);
Ted Kremenekab188932010-01-05 19:32:54 +0000441
Ted Kremenekda7af322010-04-15 01:02:28 +0000442#ifdef UDP_CODE_COMPLETION_LOGGER
443#ifdef UDP_CODE_COMPLETION_LOGGER_PORT
444 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime();
445 llvm::SmallString<256> LogResult;
446 llvm::raw_svector_ostream os(LogResult);
447
448 // Figure out the language and whether or not it uses PCH.
449 const char *lang = 0;
450 bool usesPCH = false;
451
452 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end();
453 I != E; ++I) {
454 if (*I == 0)
455 continue;
456 if (strcmp(*I, "-x") == 0) {
457 if (I + 1 != E) {
458 lang = *(++I);
459 continue;
460 }
461 }
462 else if (strcmp(*I, "-include") == 0) {
463 if (I+1 != E) {
464 const char *arg = *(++I);
465 llvm::SmallString<512> pchName;
466 {
467 llvm::raw_svector_ostream os(pchName);
468 os << arg << ".pth";
469 }
470 pchName.push_back('\0');
471 struct stat stat_results;
472 if (stat(pchName.data(), &stat_results) == 0)
473 usesPCH = true;
474 continue;
475 }
476 }
477 }
478
Ted Kremenek2ee297f2010-04-17 00:21:42 +0000479 os << "{ ";
480 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime());
481 os << ", \"numRes\": " << Results->NumResults;
482 os << ", \"diags\": " << Results->Diagnostics.size();
483 os << ", \"pch\": " << (usesPCH ? "true" : "false");
484 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"';
Ted Kremenekda7af322010-04-15 01:02:28 +0000485 const char *name = getlogin();
Ted Kremenek2ee297f2010-04-17 00:21:42 +0000486 os << ", \"user\": \"" << (name ? name : "unknown") << '"';
487 os << ", \"clangVer\": \"" << getClangFullVersion() << '"';
488 os << " }";
Ted Kremenekda7af322010-04-15 01:02:28 +0000489
490 llvm::StringRef res = os.str();
491 if (res.size() > 0) {
492 do {
493 // Setup the UDP socket.
494 struct sockaddr_in servaddr;
495 bzero(&servaddr, sizeof(servaddr));
496 servaddr.sin_family = AF_INET;
497 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT);
498 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER,
499 &servaddr.sin_addr) <= 0)
500 break;
501
502 int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
503 if (sockfd < 0)
504 break;
505
506 sendto(sockfd, res.data(), res.size(), 0,
507 (struct sockaddr *)&servaddr, sizeof(servaddr));
508 close(sockfd);
509 }
510 while (false);
511 }
512#endif
513#endif
Ted Kremenekab188932010-01-05 19:32:54 +0000514 return Results;
515}
516
517void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) {
518 if (!ResultsIn)
519 return;
520
521 AllocatedCXCodeCompleteResults *Results
522 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
Ted Kremenekab188932010-01-05 19:32:54 +0000523 delete Results;
524}
525
Douglas Gregora88084b2010-02-18 18:08:43 +0000526unsigned
527clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) {
528 AllocatedCXCodeCompleteResults *Results
529 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
530 if (!Results)
531 return 0;
532
533 return Results->Diagnostics.size();
534}
535
536CXDiagnostic
537clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn,
538 unsigned Index) {
539 AllocatedCXCodeCompleteResults *Results
540 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn);
541 if (!Results || Index >= Results->Diagnostics.size())
542 return 0;
543
544 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts);
545}
546
547
Ted Kremenekab188932010-01-05 19:32:54 +0000548} // end extern "C"