CIndexCodeCompletion.cpp revision e6b1bb6e7fe906d164637ca33503b8fafdbc99e5
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/SmallString.h" 24#include "llvm/ADT/StringExtras.h" 25#include "llvm/Support/MemoryBuffer.h" 26#include "llvm/Support/Timer.h" 27#include "llvm/Support/raw_ostream.h" 28#include "llvm/System/Program.h" 29#include <cstdlib> 30#include <cstdio> 31 32 33#ifdef UDP_CODE_COMPLETION_LOGGER 34#include "clang/Basic/Version.h" 35#include <arpa/inet.h> 36#include <sys/socket.h> 37#include <sys/types.h> 38#include <unistd.h> 39#endif 40 41using namespace clang; 42using namespace clang::cxstring; 43 44namespace { 45 /// \brief Stored representation of a completion string. 46 /// 47 /// This is the representation behind a CXCompletionString. 48 class CXStoredCodeCompletionString : public CodeCompletionString { 49 unsigned Priority; 50 51 public: 52 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } 53 54 unsigned getPriority() const { return Priority; } 55 }; 56} 57 58extern "C" { 59 60enum CXCompletionChunkKind 61clang_getCompletionChunkKind(CXCompletionString completion_string, 62 unsigned chunk_number) { 63 CXStoredCodeCompletionString *CCStr 64 = (CXStoredCodeCompletionString *)completion_string; 65 if (!CCStr || chunk_number >= CCStr->size()) 66 return CXCompletionChunk_Text; 67 68 switch ((*CCStr)[chunk_number].Kind) { 69 case CodeCompletionString::CK_TypedText: 70 return CXCompletionChunk_TypedText; 71 case CodeCompletionString::CK_Text: 72 return CXCompletionChunk_Text; 73 case CodeCompletionString::CK_Optional: 74 return CXCompletionChunk_Optional; 75 case CodeCompletionString::CK_Placeholder: 76 return CXCompletionChunk_Placeholder; 77 case CodeCompletionString::CK_Informative: 78 return CXCompletionChunk_Informative; 79 case CodeCompletionString::CK_ResultType: 80 return CXCompletionChunk_ResultType; 81 case CodeCompletionString::CK_CurrentParameter: 82 return CXCompletionChunk_CurrentParameter; 83 case CodeCompletionString::CK_LeftParen: 84 return CXCompletionChunk_LeftParen; 85 case CodeCompletionString::CK_RightParen: 86 return CXCompletionChunk_RightParen; 87 case CodeCompletionString::CK_LeftBracket: 88 return CXCompletionChunk_LeftBracket; 89 case CodeCompletionString::CK_RightBracket: 90 return CXCompletionChunk_RightBracket; 91 case CodeCompletionString::CK_LeftBrace: 92 return CXCompletionChunk_LeftBrace; 93 case CodeCompletionString::CK_RightBrace: 94 return CXCompletionChunk_RightBrace; 95 case CodeCompletionString::CK_LeftAngle: 96 return CXCompletionChunk_LeftAngle; 97 case CodeCompletionString::CK_RightAngle: 98 return CXCompletionChunk_RightAngle; 99 case CodeCompletionString::CK_Comma: 100 return CXCompletionChunk_Comma; 101 case CodeCompletionString::CK_Colon: 102 return CXCompletionChunk_Colon; 103 case CodeCompletionString::CK_SemiColon: 104 return CXCompletionChunk_SemiColon; 105 case CodeCompletionString::CK_Equal: 106 return CXCompletionChunk_Equal; 107 case CodeCompletionString::CK_HorizontalSpace: 108 return CXCompletionChunk_HorizontalSpace; 109 case CodeCompletionString::CK_VerticalSpace: 110 return CXCompletionChunk_VerticalSpace; 111 } 112 113 // Should be unreachable, but let's be careful. 114 return CXCompletionChunk_Text; 115} 116 117CXString clang_getCompletionChunkText(CXCompletionString completion_string, 118 unsigned chunk_number) { 119 CXStoredCodeCompletionString *CCStr 120 = (CXStoredCodeCompletionString *)completion_string; 121 if (!CCStr || chunk_number >= CCStr->size()) 122 return createCXString(0); 123 124 switch ((*CCStr)[chunk_number].Kind) { 125 case CodeCompletionString::CK_TypedText: 126 case CodeCompletionString::CK_Text: 127 case CodeCompletionString::CK_Placeholder: 128 case CodeCompletionString::CK_CurrentParameter: 129 case CodeCompletionString::CK_Informative: 130 case CodeCompletionString::CK_LeftParen: 131 case CodeCompletionString::CK_RightParen: 132 case CodeCompletionString::CK_LeftBracket: 133 case CodeCompletionString::CK_RightBracket: 134 case CodeCompletionString::CK_LeftBrace: 135 case CodeCompletionString::CK_RightBrace: 136 case CodeCompletionString::CK_LeftAngle: 137 case CodeCompletionString::CK_RightAngle: 138 case CodeCompletionString::CK_Comma: 139 case CodeCompletionString::CK_ResultType: 140 case CodeCompletionString::CK_Colon: 141 case CodeCompletionString::CK_SemiColon: 142 case CodeCompletionString::CK_Equal: 143 case CodeCompletionString::CK_HorizontalSpace: 144 return createCXString((*CCStr)[chunk_number].Text, false); 145 146 case CodeCompletionString::CK_VerticalSpace: 147 // FIXME: Temporary hack until we figure out how to handle vertical space. 148 return createCXString(" "); 149 150 case CodeCompletionString::CK_Optional: 151 // Note: treated as an empty text block. 152 return createCXString(""); 153 } 154 155 // Should be unreachable, but let's be careful. 156 return createCXString(0); 157} 158 159 160CXCompletionString 161clang_getCompletionChunkCompletionString(CXCompletionString completion_string, 162 unsigned chunk_number) { 163 CXStoredCodeCompletionString *CCStr 164 = (CXStoredCodeCompletionString *)completion_string; 165 if (!CCStr || chunk_number >= CCStr->size()) 166 return 0; 167 168 switch ((*CCStr)[chunk_number].Kind) { 169 case CodeCompletionString::CK_TypedText: 170 case CodeCompletionString::CK_Text: 171 case CodeCompletionString::CK_Placeholder: 172 case CodeCompletionString::CK_CurrentParameter: 173 case CodeCompletionString::CK_Informative: 174 case CodeCompletionString::CK_LeftParen: 175 case CodeCompletionString::CK_RightParen: 176 case CodeCompletionString::CK_LeftBracket: 177 case CodeCompletionString::CK_RightBracket: 178 case CodeCompletionString::CK_LeftBrace: 179 case CodeCompletionString::CK_RightBrace: 180 case CodeCompletionString::CK_LeftAngle: 181 case CodeCompletionString::CK_RightAngle: 182 case CodeCompletionString::CK_Comma: 183 case CodeCompletionString::CK_ResultType: 184 case CodeCompletionString::CK_Colon: 185 case CodeCompletionString::CK_SemiColon: 186 case CodeCompletionString::CK_Equal: 187 case CodeCompletionString::CK_HorizontalSpace: 188 case CodeCompletionString::CK_VerticalSpace: 189 return 0; 190 191 case CodeCompletionString::CK_Optional: 192 // Note: treated as an empty text block. 193 return (*CCStr)[chunk_number].Optional; 194 } 195 196 // Should be unreachable, but let's be careful. 197 return 0; 198} 199 200unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { 201 CXStoredCodeCompletionString *CCStr 202 = (CXStoredCodeCompletionString *)completion_string; 203 return CCStr? CCStr->size() : 0; 204} 205 206unsigned clang_getCompletionPriority(CXCompletionString completion_string) { 207 CXStoredCodeCompletionString *CCStr 208 = (CXStoredCodeCompletionString *)completion_string; 209 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); 210} 211 212static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, 213 unsigned &Value) { 214 if (Memory + sizeof(unsigned) > MemoryEnd) 215 return true; 216 217 memmove(&Value, Memory, sizeof(unsigned)); 218 Memory += sizeof(unsigned); 219 return false; 220} 221 222/// \brief The CXCodeCompleteResults structure we allocate internally; 223/// the client only sees the initial CXCodeCompleteResults structure. 224struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { 225 AllocatedCXCodeCompleteResults(); 226 ~AllocatedCXCodeCompleteResults(); 227 228 /// \brief Diagnostics produced while performing code completion. 229 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; 230 231 /// \brief Diag object 232 llvm::IntrusiveRefCntPtr<Diagnostic> Diag; 233 234 /// \brief Language options used to adjust source locations. 235 LangOptions LangOpts; 236 237 /// \brief Source manager, used for diagnostics. 238 SourceManager SourceMgr; 239 240 /// \brief File manager, used for diagnostics. 241 FileManager FileMgr; 242 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; 246 247 /// \brief Temporary buffers that will be deleted once we have finished with the code-completion results. 248 llvm::SmallVector<const llvm::MemoryBuffer *, 1> TemporaryBuffers; 249}; 250 251AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 252 : CXCodeCompleteResults(), Diag(new Diagnostic), SourceMgr(*Diag) { } 253 254AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { 255 for (unsigned I = 0, N = NumResults; I != N; ++I) 256 delete (CXStoredCodeCompletionString *)Results[I].CompletionString; 257 delete [] Results; 258 259 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 260 TemporaryFiles[I].eraseFromDisk(); 261 for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I) 262 delete TemporaryBuffers[I]; 263} 264 265CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, 266 const char *source_filename, 267 int num_command_line_args, 268 const char **command_line_args, 269 unsigned num_unsaved_files, 270 struct CXUnsavedFile *unsaved_files, 271 const char *complete_filename, 272 unsigned complete_line, 273 unsigned complete_column) { 274#ifdef UDP_CODE_COMPLETION_LOGGER 275#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 276 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); 277#endif 278#endif 279 280 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; 281 282 llvm::OwningPtr<llvm::NamedRegionTimer> CCTimer; 283 if (getenv("LIBCLANG_TIMING")) { 284 llvm::SmallString<128> TimerName; 285 llvm::raw_svector_ostream TimerNameOut(TimerName); 286 TimerNameOut << "Code completion (out-of-process) @ " << complete_filename 287 << ":" << complete_line << ":" << complete_column; 288 CCTimer.reset(new llvm::NamedRegionTimer(TimerNameOut.str())); 289 } 290 291 // The indexer, which is mainly used to determine where diagnostics go. 292 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); 293 294 // Configure the diagnostics. 295 DiagnosticOptions DiagOpts; 296 llvm::IntrusiveRefCntPtr<Diagnostic> Diags; 297 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); 298 299 // The set of temporary files that we've built. 300 std::vector<llvm::sys::Path> TemporaryFiles; 301 302 // Build up the arguments for invoking 'clang'. 303 std::vector<const char *> argv; 304 305 // First add the complete path to the 'clang' executable. 306 llvm::sys::Path ClangPath = CXXIdx->getClangPath(); 307 argv.push_back(ClangPath.c_str()); 308 309 // Always use Clang C++ support. 310 argv.push_back("-ccc-clang-cxx"); 311 312 // Add the '-fsyntax-only' argument so that we only perform a basic 313 // syntax check of the code. 314 argv.push_back("-fsyntax-only"); 315 316 // Add the appropriate '-code-completion-at=file:line:column' argument 317 // to perform code completion, with an "-Xclang" preceding it. 318 std::string code_complete_at; 319 code_complete_at += complete_filename; 320 code_complete_at += ":"; 321 code_complete_at += llvm::utostr(complete_line); 322 code_complete_at += ":"; 323 code_complete_at += llvm::utostr(complete_column); 324 argv.push_back("-Xclang"); 325 argv.push_back("-code-completion-at"); 326 argv.push_back("-Xclang"); 327 argv.push_back(code_complete_at.c_str()); 328 argv.push_back("-Xclang"); 329 argv.push_back("-no-code-completion-debug-printer"); 330 argv.push_back("-Xclang"); 331 argv.push_back("-code-completion-macros"); 332 argv.push_back("-fdiagnostics-binary"); 333 334 // Remap any unsaved files to temporary files. 335 std::vector<std::string> RemapArgs; 336 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) 337 return 0; 338 339 // The pointers into the elements of RemapArgs are stable because we 340 // won't be adding anything to RemapArgs after this point. 341 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) 342 argv.push_back(RemapArgs[i].c_str()); 343 344 // Add the source file name (FIXME: later, we'll want to build temporary 345 // file from the buffer, or just feed the source text via standard input). 346 if (source_filename) 347 argv.push_back(source_filename); 348 349 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. 350 for (int i = 0; i < num_command_line_args; ++i) 351 if (const char *arg = command_line_args[i]) { 352 if (strcmp(arg, "-o") == 0) { 353 ++i; // Also skip the matching argument. 354 continue; 355 } 356 if (strcmp(arg, "-emit-ast") == 0 || 357 strcmp(arg, "-c") == 0 || 358 strcmp(arg, "-fsyntax-only") == 0) { 359 continue; 360 } 361 362 // Keep the argument. 363 argv.push_back(arg); 364 } 365 366 if (EnableLogging) { 367 std::string Log = ClangPath.str(); 368 for (unsigned I = 0, N = argv.size(); I != N; ++I) { 369 Log += ' '; 370 Log += argv[I]; 371 } 372 fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str()); 373 } 374 375 // Add the null terminator. 376 argv.push_back(NULL); 377 378 // Generate a temporary name for the code-completion results file. 379 char tmpFile[L_tmpnam]; 380 char *tmpFileName = tmpnam(tmpFile); 381 llvm::sys::Path ResultsFile(tmpFileName); 382 TemporaryFiles.push_back(ResultsFile); 383 384 // Generate a temporary name for the diagnostics file. 385 char tmpFileResults[L_tmpnam]; 386 char *tmpResultsFileName = tmpnam(tmpFileResults); 387 llvm::sys::Path DiagnosticsFile(tmpResultsFileName); 388 TemporaryFiles.push_back(DiagnosticsFile); 389 390 391 392 // Invoke 'clang'. 393 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null 394 // on Unix or NUL (Windows). 395 std::string ErrMsg; 396 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 397 &DiagnosticsFile, 0 }; 398 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, 399 /* redirects */ &Redirects[0], 400 /* secondsToWait */ 0, 401 /* memoryLimits */ 0, &ErrMsg); 402 403 if (!ErrMsg.empty()) { 404 std::string AllArgs; 405 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 406 I != E; ++I) { 407 AllArgs += ' '; 408 if (*I) 409 AllArgs += *I; 410 } 411 412 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; 413 } 414 415 // Parse the resulting source file to find code-completion results. 416 using llvm::MemoryBuffer; 417 using llvm::StringRef; 418 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; 419 Results->Results = 0; 420 Results->NumResults = 0; 421 // FIXME: Set Results->LangOpts! 422 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { 423 llvm::SmallVector<CXCompletionResult, 4> CompletionResults; 424 StringRef Buffer = F->getBuffer(); 425 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size(); 426 Str < StrEnd;) { 427 unsigned KindValue; 428 if (ReadUnsigned(Str, StrEnd, KindValue)) 429 break; 430 431 unsigned Priority; 432 if (ReadUnsigned(Str, StrEnd, Priority)) 433 break; 434 435 CXStoredCodeCompletionString *CCStr 436 = new CXStoredCodeCompletionString(Priority); 437 if (!CCStr->Deserialize(Str, StrEnd)) { 438 delete CCStr; 439 continue; 440 } 441 442 if (!CCStr->empty()) { 443 // Vend the code-completion result to the caller. 444 CXCompletionResult Result; 445 Result.CursorKind = (CXCursorKind)KindValue; 446 Result.CompletionString = CCStr; 447 CompletionResults.push_back(Result); 448 } 449 }; 450 451 // Allocate the results. 452 Results->Results = new CXCompletionResult [CompletionResults.size()]; 453 Results->NumResults = CompletionResults.size(); 454 memcpy(Results->Results, CompletionResults.data(), 455 CompletionResults.size() * sizeof(CXCompletionResult)); 456 Results->TemporaryBuffers.push_back(F); 457 } 458 459 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, 460 Results->FileMgr, Results->SourceMgr, 461 Results->Diagnostics); 462 463 // Make sure we delete temporary files when the code-completion results are 464 // destroyed. 465 Results->TemporaryFiles.swap(TemporaryFiles); 466 467#ifdef UDP_CODE_COMPLETION_LOGGER 468#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 469 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); 470 llvm::SmallString<256> LogResult; 471 llvm::raw_svector_ostream os(LogResult); 472 473 // Figure out the language and whether or not it uses PCH. 474 const char *lang = 0; 475 bool usesPCH = false; 476 477 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 478 I != E; ++I) { 479 if (*I == 0) 480 continue; 481 if (strcmp(*I, "-x") == 0) { 482 if (I + 1 != E) { 483 lang = *(++I); 484 continue; 485 } 486 } 487 else if (strcmp(*I, "-include") == 0) { 488 if (I+1 != E) { 489 const char *arg = *(++I); 490 llvm::SmallString<512> pchName; 491 { 492 llvm::raw_svector_ostream os(pchName); 493 os << arg << ".pth"; 494 } 495 pchName.push_back('\0'); 496 struct stat stat_results; 497 if (stat(pchName.data(), &stat_results) == 0) 498 usesPCH = true; 499 continue; 500 } 501 } 502 } 503 504 os << "{ "; 505 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); 506 os << ", \"numRes\": " << Results->NumResults; 507 os << ", \"diags\": " << Results->Diagnostics.size(); 508 os << ", \"pch\": " << (usesPCH ? "true" : "false"); 509 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; 510 const char *name = getlogin(); 511 os << ", \"user\": \"" << (name ? name : "unknown") << '"'; 512 os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; 513 os << " }"; 514 515 llvm::StringRef res = os.str(); 516 if (res.size() > 0) { 517 do { 518 // Setup the UDP socket. 519 struct sockaddr_in servaddr; 520 bzero(&servaddr, sizeof(servaddr)); 521 servaddr.sin_family = AF_INET; 522 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); 523 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, 524 &servaddr.sin_addr) <= 0) 525 break; 526 527 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 528 if (sockfd < 0) 529 break; 530 531 sendto(sockfd, res.data(), res.size(), 0, 532 (struct sockaddr *)&servaddr, sizeof(servaddr)); 533 close(sockfd); 534 } 535 while (false); 536 } 537#endif 538#endif 539 return Results; 540} 541 542} // end extern "C" 543 544namespace clang { 545 // FIXME: defined in CodeCompleteConsumer.cpp, but should be a 546 // static function here. 547 CXCursorKind 548 getCursorKindForCompletionResult(const CodeCompleteConsumer::Result &R); 549} 550 551 552namespace { 553 class CaptureCompletionResults : public CodeCompleteConsumer { 554 AllocatedCXCodeCompleteResults &AllocatedResults; 555 556 public: 557 explicit CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results) 558 : CodeCompleteConsumer(true, false, false), AllocatedResults(Results) { } 559 560 virtual void ProcessCodeCompleteResults(Sema &S, 561 CodeCompletionContext Context, 562 Result *Results, 563 unsigned NumResults) { 564 AllocatedResults.Results = new CXCompletionResult [NumResults]; 565 AllocatedResults.NumResults = NumResults; 566 for (unsigned I = 0; I != NumResults; ++I) { 567 CXStoredCodeCompletionString *StoredCompletion 568 = new CXStoredCodeCompletionString(Results[I].Priority); 569 (void)Results[I].CreateCodeCompletionString(S, StoredCompletion); 570 AllocatedResults.Results[I].CursorKind 571 = getCursorKindForCompletionResult(Results[I]); 572 AllocatedResults.Results[I].CompletionString = StoredCompletion; 573 } 574 } 575 }; 576} 577 578extern "C" { 579CXCodeCompleteResults *clang_codeCompleteAt(CXTranslationUnit TU, 580 const char *complete_filename, 581 unsigned complete_line, 582 unsigned complete_column, 583 struct CXUnsavedFile *unsaved_files, 584 unsigned num_unsaved_files, 585 unsigned options) { 586#ifdef UDP_CODE_COMPLETION_LOGGER 587#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 588 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); 589#endif 590#endif 591 592 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; 593 594 ASTUnit *AST = static_cast<ASTUnit *>(TU); 595 if (!AST) 596 return 0; 597 598 // Perform the remapping of source files. 599 llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles; 600 for (unsigned I = 0; I != num_unsaved_files; ++I) { 601 llvm::StringRef Data(unsaved_files[I].Contents, unsaved_files[I].Length); 602 const llvm::MemoryBuffer *Buffer 603 = llvm::MemoryBuffer::getMemBufferCopy(Data, unsaved_files[I].Filename); 604 RemappedFiles.push_back(std::make_pair(unsaved_files[I].Filename, 605 Buffer)); 606 } 607 608 if (EnableLogging) { 609 // FIXME: Add logging. 610 } 611 612 // Parse the resulting source file to find code-completion results. 613 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; 614 Results->Results = 0; 615 Results->NumResults = 0; 616 617 // Create a code-completion consumer to capture the results. 618 CaptureCompletionResults Capture(*Results); 619 620 // Make sure that we free the temporary buffers when the 621 // code-completion constructor is freed. 622 for (unsigned I = 0, N = RemappedFiles.size(); I != N; ++I) 623 Results->TemporaryBuffers.push_back(RemappedFiles[I].second); 624 625 // Perform completion. 626 AST->CodeComplete(complete_filename, complete_line, complete_column, 627 RemappedFiles.data(), RemappedFiles.size(), 628 (options & CXCodeComplete_IncludeMacros), 629 (options & CXCodeComplete_IncludeCodePatterns), 630 Capture, 631 *Results->Diag, Results->LangOpts, Results->SourceMgr, 632 Results->FileMgr, Results->Diagnostics); 633 634 635 636#ifdef UDP_CODE_COMPLETION_LOGGER 637#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 638 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); 639 llvm::SmallString<256> LogResult; 640 llvm::raw_svector_ostream os(LogResult); 641 642 // Figure out the language and whether or not it uses PCH. 643 const char *lang = 0; 644 bool usesPCH = false; 645 646 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 647 I != E; ++I) { 648 if (*I == 0) 649 continue; 650 if (strcmp(*I, "-x") == 0) { 651 if (I + 1 != E) { 652 lang = *(++I); 653 continue; 654 } 655 } 656 else if (strcmp(*I, "-include") == 0) { 657 if (I+1 != E) { 658 const char *arg = *(++I); 659 llvm::SmallString<512> pchName; 660 { 661 llvm::raw_svector_ostream os(pchName); 662 os << arg << ".pth"; 663 } 664 pchName.push_back('\0'); 665 struct stat stat_results; 666 if (stat(pchName.data(), &stat_results) == 0) 667 usesPCH = true; 668 continue; 669 } 670 } 671 } 672 673 os << "{ "; 674 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); 675 os << ", \"numRes\": " << Results->NumResults; 676 os << ", \"diags\": " << Results->Diagnostics.size(); 677 os << ", \"pch\": " << (usesPCH ? "true" : "false"); 678 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; 679 const char *name = getlogin(); 680 os << ", \"user\": \"" << (name ? name : "unknown") << '"'; 681 os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; 682 os << " }"; 683 684 llvm::StringRef res = os.str(); 685 if (res.size() > 0) { 686 do { 687 // Setup the UDP socket. 688 struct sockaddr_in servaddr; 689 bzero(&servaddr, sizeof(servaddr)); 690 servaddr.sin_family = AF_INET; 691 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); 692 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, 693 &servaddr.sin_addr) <= 0) 694 break; 695 696 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 697 if (sockfd < 0) 698 break; 699 700 sendto(sockfd, res.data(), res.size(), 0, 701 (struct sockaddr *)&servaddr, sizeof(servaddr)); 702 close(sockfd); 703 } 704 while (false); 705 } 706#endif 707#endif 708 return Results; 709} 710 711unsigned clang_defaultCodeCompleteOptions(void) { 712 return CXCodeComplete_IncludeMacros; 713} 714 715void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { 716 if (!ResultsIn) 717 return; 718 719 AllocatedCXCodeCompleteResults *Results 720 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 721 delete Results; 722} 723 724unsigned 725clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { 726 AllocatedCXCodeCompleteResults *Results 727 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 728 if (!Results) 729 return 0; 730 731 return Results->Diagnostics.size(); 732} 733 734CXDiagnostic 735clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, 736 unsigned Index) { 737 AllocatedCXCodeCompleteResults *Results 738 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 739 if (!Results || Index >= Results->Diagnostics.size()) 740 return 0; 741 742 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); 743} 744 745 746} // end extern "C" 747