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