CIndexCodeCompletion.cpp revision cee235cdf0b8047761ffac598c4c3a32ab7411a2
1//===- 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" 16#include "CIndexDiagnostic.h" 17#include "clang/Basic/SourceManager.h" 18#include "clang/Basic/FileManager.h" 19#include "clang/Frontend/ASTUnit.h" 20#include "clang/Frontend/CompilerInstance.h" 21#include "clang/Frontend/FrontendDiagnostic.h" 22#include "clang/Sema/CodeCompleteConsumer.h" 23#include "llvm/ADT/StringExtras.h" 24#include "llvm/Support/MemoryBuffer.h" 25#include "llvm/System/Program.h" 26#include <cstdlib> 27#include <cstdio> 28 29#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 40using namespace clang; 41using namespace clang::cxstring; 42 43namespace { 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 57extern "C" { 58 59enum CXCompletionChunkKind 60clang_getCompletionChunkKind(CXCompletionString completion_string, 61 unsigned chunk_number) { 62 CXStoredCodeCompletionString *CCStr 63 = (CXStoredCodeCompletionString *)completion_string; 64 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; 100 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; 110 } 111 112 // Should be unreachable, but let's be careful. 113 return CXCompletionChunk_Text; 114} 115 116CXString clang_getCompletionChunkText(CXCompletionString completion_string, 117 unsigned chunk_number) { 118 CXStoredCodeCompletionString *CCStr 119 = (CXStoredCodeCompletionString *)completion_string; 120 if (!CCStr || chunk_number >= CCStr->size()) 121 return createCXString(0); 122 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: 139 case CodeCompletionString::CK_Colon: 140 case CodeCompletionString::CK_SemiColon: 141 case CodeCompletionString::CK_Equal: 142 case CodeCompletionString::CK_HorizontalSpace: 143 return createCXString((*CCStr)[chunk_number].Text, false); 144 145 case CodeCompletionString::CK_VerticalSpace: 146 // FIXME: Temporary hack until we figure out how to handle vertical space. 147 return createCXString(" "); 148 149 case CodeCompletionString::CK_Optional: 150 // Note: treated as an empty text block. 151 return createCXString(""); 152 } 153 154 // Should be unreachable, but let's be careful. 155 return createCXString(0); 156} 157 158 159CXCompletionString 160clang_getCompletionChunkCompletionString(CXCompletionString completion_string, 161 unsigned chunk_number) { 162 CXStoredCodeCompletionString *CCStr 163 = (CXStoredCodeCompletionString *)completion_string; 164 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: 183 case CodeCompletionString::CK_Colon: 184 case CodeCompletionString::CK_SemiColon: 185 case CodeCompletionString::CK_Equal: 186 case CodeCompletionString::CK_HorizontalSpace: 187 case CodeCompletionString::CK_VerticalSpace: 188 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) { 200 CXStoredCodeCompletionString *CCStr 201 = (CXStoredCodeCompletionString *)completion_string; 202 return CCStr? CCStr->size() : 0; 203} 204 205unsigned clang_getCompletionPriority(CXCompletionString completion_string) { 206 CXStoredCodeCompletionString *CCStr 207 = (CXStoredCodeCompletionString *)completion_string; 208 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); 209} 210 211static 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 { 224 AllocatedCXCodeCompleteResults(); 225 ~AllocatedCXCodeCompleteResults(); 226 227 /// \brief Diagnostics produced while performing code completion. 228 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; 229 230 /// \brief Diag object 231 llvm::IntrusiveRefCntPtr<Diagnostic> Diag; 232 233 /// \brief Language options used to adjust source locations. 234 LangOptions LangOpts; 235 236 /// \brief Source manager, used for diagnostics. 237 SourceManager SourceMgr; 238 239 /// \brief File manager, used for diagnostics. 240 FileManager FileMgr; 241 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; 245 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; 248}; 249 250AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 251 : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { } 252 253AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { 254 for (unsigned I = 0, N = NumResults; I != N; ++I) 255 delete (CXStoredCodeCompletionString *)Results[I].CompletionString; 256 delete [] Results; 257 258 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 259 TemporaryFiles[I].eraseFromDisk(); 260 for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) 261 delete TemporaryBuffers[I]; 262} 263 264CXCodeCompleteResults *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, 272 unsigned complete_column) { 273#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 279 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; 280 281 // The indexer, which is mainly used to determine where diagnostics go. 282 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); 283 284 // Configure the diagnostics. 285 DiagnosticOptions DiagOpts; 286 llvm::IntrusiveRefCntPtr<Diagnostic> Diags; 287 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); 288 289 // 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 299 // Always use Clang C++ support. 300 argv.push_back("-ccc-clang-cxx"); 301 302 // 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"); 322 argv.push_back("-fdiagnostics-binary"); 323 324 // Remap any unsaved files to temporary files. 325 std::vector<std::string> RemapArgs; 326 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) 327 return 0; 328 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 356 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 365 // Add the null terminator. 366 argv.push_back(NULL); 367 368 // Generate a temporary name for the code-completion results file. 369 char tmpFile[L_tmpnam]; 370 char *tmpFileName = tmpnam(tmpFile); 371 llvm::sys::Path ResultsFile(tmpFileName); 372 TemporaryFiles.push_back(ResultsFile); 373 374 // Generate a temporary name for the diagnostics file. 375 char tmpFileResults[L_tmpnam]; 376 char *tmpResultsFileName = tmpnam(tmpFileResults); 377 llvm::sys::Path DiagnosticsFile(tmpResultsFileName); 378 TemporaryFiles.push_back(DiagnosticsFile); 379 380 381 382 // Invoke 'clang'. 383 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null 384 // on Unix or NUL (Windows). 385 std::string ErrMsg; 386 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 387 &DiagnosticsFile, 0 }; 388 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, 389 /* redirects */ &Redirects[0], 390 /* secondsToWait */ 0, 391 /* memoryLimits */ 0, &ErrMsg); 392 393 if (!ErrMsg.empty()) { 394 std::string AllArgs; 395 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 396 I != E; ++I) { 397 AllArgs += ' '; 398 if (*I) 399 AllArgs += *I; 400 } 401 402 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; 403 } 404 405 // Parse the resulting source file to find code-completion results. 406 using llvm::MemoryBuffer; 407 using llvm::StringRef; 408 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; 409 Results->Results = 0; 410 Results->NumResults = 0; 411 // FIXME: Set Results->LangOpts! 412 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 421 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; 429 continue; 430 } 431 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. 442 Results->Results = new CXCompletionResult [CompletionResults.size()]; 443 Results->NumResults = CompletionResults.size(); 444 memcpy(Results->Results, CompletionResults.data(), 445 CompletionResults.size() * sizeof(CXCompletionResult)); 446 Results->TemporaryBuffers.push_back(F); 447 } 448 449 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, 450 Results->FileMgr, Results->SourceMgr, 451 Results->Diagnostics); 452 453 // Make sure we delete temporary files when the code-completion results are 454 // destroyed. 455 Results->TemporaryFiles.swap(TemporaryFiles); 456 457#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 494 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>") << '"'; 500 const char *name = getlogin(); 501 os << ", \"user\": \"" << (name ? name : "unknown") << '"'; 502 os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; 503 os << " }"; 504 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 529 return Results; 530} 531 532} // 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, 572 unsigned num_unsaved_files, 573 unsigned options) { 574#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; 604 605 // Create a code-completion consumer to capture the results. 606 CaptureCompletionResults Capture(*Results); 607 608 // 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 613 // Perform completion. 614 AST->CodeComplete(complete_filename, complete_line, complete_column, 615 RemappedFiles.data(), RemappedFiles.size(), 616 (options & CXCodeComplete_IncludeMacros), 617 (options & CXCodeComplete_IncludeCodePatterns), 618 Capture, 619 *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 699unsigned clang_defaultCodeCompleteOptions(void) { 700 return CXCodeComplete_IncludeMacros; 701} 702 703void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { 704 if (!ResultsIn) 705 return; 706 707 AllocatedCXCodeCompleteResults *Results 708 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 709 delete Results; 710} 711 712unsigned 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 734} // end extern "C" 735