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