CIndexCodeCompletion.cpp revision 3d398aa5c2be8919bbc0144bce611c48119bc861
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/CompilerInstance.h" 20#include "clang/Frontend/FrontendDiagnostic.h" 21#include "clang/Sema/CodeCompleteConsumer.h" 22#include "llvm/ADT/StringExtras.h" 23#include "llvm/Support/MemoryBuffer.h" 24#include "llvm/System/Program.h" 25#include <cstdlib> 26#include <cstdio> 27 28#ifdef UDP_CODE_COMPLETION_LOGGER 29#include "clang/Basic/Version.h" 30#include "llvm/ADT/SmallString.h" 31#include "llvm/Support/Timer.h" 32#include "llvm/Support/raw_ostream.h" 33#include <arpa/inet.h> 34#include <sys/socket.h> 35#include <sys/types.h> 36#include <unistd.h> 37#endif 38 39using namespace clang; 40using namespace clang::cxstring; 41 42namespace { 43 /// \brief Stored representation of a completion string. 44 /// 45 /// This is the representation behind a CXCompletionString. 46 class CXStoredCodeCompletionString : public CodeCompletionString { 47 unsigned Priority; 48 49 public: 50 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } 51 52 unsigned getPriority() const { return Priority; } 53 }; 54} 55 56extern "C" { 57 58enum CXCompletionChunkKind 59clang_getCompletionChunkKind(CXCompletionString completion_string, 60 unsigned chunk_number) { 61 CXStoredCodeCompletionString *CCStr 62 = (CXStoredCodeCompletionString *)completion_string; 63 if (!CCStr || chunk_number >= CCStr->size()) 64 return CXCompletionChunk_Text; 65 66 switch ((*CCStr)[chunk_number].Kind) { 67 case CodeCompletionString::CK_TypedText: 68 return CXCompletionChunk_TypedText; 69 case CodeCompletionString::CK_Text: 70 return CXCompletionChunk_Text; 71 case CodeCompletionString::CK_Optional: 72 return CXCompletionChunk_Optional; 73 case CodeCompletionString::CK_Placeholder: 74 return CXCompletionChunk_Placeholder; 75 case CodeCompletionString::CK_Informative: 76 return CXCompletionChunk_Informative; 77 case CodeCompletionString::CK_ResultType: 78 return CXCompletionChunk_ResultType; 79 case CodeCompletionString::CK_CurrentParameter: 80 return CXCompletionChunk_CurrentParameter; 81 case CodeCompletionString::CK_LeftParen: 82 return CXCompletionChunk_LeftParen; 83 case CodeCompletionString::CK_RightParen: 84 return CXCompletionChunk_RightParen; 85 case CodeCompletionString::CK_LeftBracket: 86 return CXCompletionChunk_LeftBracket; 87 case CodeCompletionString::CK_RightBracket: 88 return CXCompletionChunk_RightBracket; 89 case CodeCompletionString::CK_LeftBrace: 90 return CXCompletionChunk_LeftBrace; 91 case CodeCompletionString::CK_RightBrace: 92 return CXCompletionChunk_RightBrace; 93 case CodeCompletionString::CK_LeftAngle: 94 return CXCompletionChunk_LeftAngle; 95 case CodeCompletionString::CK_RightAngle: 96 return CXCompletionChunk_RightAngle; 97 case CodeCompletionString::CK_Comma: 98 return CXCompletionChunk_Comma; 99 case CodeCompletionString::CK_Colon: 100 return CXCompletionChunk_Colon; 101 case CodeCompletionString::CK_SemiColon: 102 return CXCompletionChunk_SemiColon; 103 case CodeCompletionString::CK_Equal: 104 return CXCompletionChunk_Equal; 105 case CodeCompletionString::CK_HorizontalSpace: 106 return CXCompletionChunk_HorizontalSpace; 107 case CodeCompletionString::CK_VerticalSpace: 108 return CXCompletionChunk_VerticalSpace; 109 } 110 111 // Should be unreachable, but let's be careful. 112 return CXCompletionChunk_Text; 113} 114 115CXString clang_getCompletionChunkText(CXCompletionString completion_string, 116 unsigned chunk_number) { 117 CXStoredCodeCompletionString *CCStr 118 = (CXStoredCodeCompletionString *)completion_string; 119 if (!CCStr || chunk_number >= CCStr->size()) 120 return createCXString(0); 121 122 switch ((*CCStr)[chunk_number].Kind) { 123 case CodeCompletionString::CK_TypedText: 124 case CodeCompletionString::CK_Text: 125 case CodeCompletionString::CK_Placeholder: 126 case CodeCompletionString::CK_CurrentParameter: 127 case CodeCompletionString::CK_Informative: 128 case CodeCompletionString::CK_LeftParen: 129 case CodeCompletionString::CK_RightParen: 130 case CodeCompletionString::CK_LeftBracket: 131 case CodeCompletionString::CK_RightBracket: 132 case CodeCompletionString::CK_LeftBrace: 133 case CodeCompletionString::CK_RightBrace: 134 case CodeCompletionString::CK_LeftAngle: 135 case CodeCompletionString::CK_RightAngle: 136 case CodeCompletionString::CK_Comma: 137 case CodeCompletionString::CK_ResultType: 138 case CodeCompletionString::CK_Colon: 139 case CodeCompletionString::CK_SemiColon: 140 case CodeCompletionString::CK_Equal: 141 case CodeCompletionString::CK_HorizontalSpace: 142 return createCXString((*CCStr)[chunk_number].Text, false); 143 144 case CodeCompletionString::CK_VerticalSpace: 145 // FIXME: Temporary hack until we figure out how to handle vertical space. 146 return createCXString(" "); 147 148 case CodeCompletionString::CK_Optional: 149 // Note: treated as an empty text block. 150 return createCXString(""); 151 } 152 153 // Should be unreachable, but let's be careful. 154 return createCXString(0); 155} 156 157 158CXCompletionString 159clang_getCompletionChunkCompletionString(CXCompletionString completion_string, 160 unsigned chunk_number) { 161 CXStoredCodeCompletionString *CCStr 162 = (CXStoredCodeCompletionString *)completion_string; 163 if (!CCStr || chunk_number >= CCStr->size()) 164 return 0; 165 166 switch ((*CCStr)[chunk_number].Kind) { 167 case CodeCompletionString::CK_TypedText: 168 case CodeCompletionString::CK_Text: 169 case CodeCompletionString::CK_Placeholder: 170 case CodeCompletionString::CK_CurrentParameter: 171 case CodeCompletionString::CK_Informative: 172 case CodeCompletionString::CK_LeftParen: 173 case CodeCompletionString::CK_RightParen: 174 case CodeCompletionString::CK_LeftBracket: 175 case CodeCompletionString::CK_RightBracket: 176 case CodeCompletionString::CK_LeftBrace: 177 case CodeCompletionString::CK_RightBrace: 178 case CodeCompletionString::CK_LeftAngle: 179 case CodeCompletionString::CK_RightAngle: 180 case CodeCompletionString::CK_Comma: 181 case CodeCompletionString::CK_ResultType: 182 case CodeCompletionString::CK_Colon: 183 case CodeCompletionString::CK_SemiColon: 184 case CodeCompletionString::CK_Equal: 185 case CodeCompletionString::CK_HorizontalSpace: 186 case CodeCompletionString::CK_VerticalSpace: 187 return 0; 188 189 case CodeCompletionString::CK_Optional: 190 // Note: treated as an empty text block. 191 return (*CCStr)[chunk_number].Optional; 192 } 193 194 // Should be unreachable, but let's be careful. 195 return 0; 196} 197 198unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { 199 CXStoredCodeCompletionString *CCStr 200 = (CXStoredCodeCompletionString *)completion_string; 201 return CCStr? CCStr->size() : 0; 202} 203 204unsigned clang_getCompletionPriority(CXCompletionString completion_string) { 205 CXStoredCodeCompletionString *CCStr 206 = (CXStoredCodeCompletionString *)completion_string; 207 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); 208} 209 210static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, 211 unsigned &Value) { 212 if (Memory + sizeof(unsigned) > MemoryEnd) 213 return true; 214 215 memmove(&Value, Memory, sizeof(unsigned)); 216 Memory += sizeof(unsigned); 217 return false; 218} 219 220/// \brief The CXCodeCompleteResults structure we allocate internally; 221/// the client only sees the initial CXCodeCompleteResults structure. 222struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { 223 AllocatedCXCodeCompleteResults(); 224 ~AllocatedCXCodeCompleteResults(); 225 226 /// \brief The memory buffer from which we parsed the results. We 227 /// retain this buffer because the completion strings point into it. 228 llvm::MemoryBuffer *Buffer; 229 230 /// \brief Diagnostics produced while performing code completion. 231 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; 232 233 /// \brief Diag object 234 Diagnostic Diag; 235 236 /// \brief Language options used to adjust source locations. 237 LangOptions LangOpts; 238 239 /// \brief Source manager, used for diagnostics. 240 SourceManager SourceMgr; 241 242 /// \brief File manager, used for diagnostics. 243 FileManager FileMgr; 244 245 /// \brief Temporary files that should be removed once we have finished 246 /// with the code-completion results. 247 std::vector<llvm::sys::Path> TemporaryFiles; 248}; 249 250AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 251 : CXCodeCompleteResults(), Buffer(0), 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 delete Buffer; 258 259 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 260 TemporaryFiles[I].eraseFromDisk(); 261} 262 263CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, 264 const char *source_filename, 265 int num_command_line_args, 266 const char **command_line_args, 267 unsigned num_unsaved_files, 268 struct CXUnsavedFile *unsaved_files, 269 const char *complete_filename, 270 unsigned complete_line, 271 unsigned complete_column) { 272#ifdef UDP_CODE_COMPLETION_LOGGER 273#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 274 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); 275#endif 276#endif 277 278 bool EnableLogging = getenv("LIBCLANG_CODE_COMPLETION_LOGGING") != 0; 279 280 // The indexer, which is mainly used to determine where diagnostics go. 281 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); 282 283 // Configure the diagnostics. 284 DiagnosticOptions DiagOpts; 285 llvm::IntrusiveRefCntPtr<Diagnostic> Diags; 286 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); 287 288 // The set of temporary files that we've built. 289 std::vector<llvm::sys::Path> TemporaryFiles; 290 291 // Build up the arguments for invoking 'clang'. 292 std::vector<const char *> argv; 293 294 // First add the complete path to the 'clang' executable. 295 llvm::sys::Path ClangPath = CXXIdx->getClangPath(); 296 argv.push_back(ClangPath.c_str()); 297 298 // Always use Clang C++ support. 299 argv.push_back("-ccc-clang-cxx"); 300 301 // Add the '-fsyntax-only' argument so that we only perform a basic 302 // syntax check of the code. 303 argv.push_back("-fsyntax-only"); 304 305 // Add the appropriate '-code-completion-at=file:line:column' argument 306 // to perform code completion, with an "-Xclang" preceding it. 307 std::string code_complete_at; 308 code_complete_at += complete_filename; 309 code_complete_at += ":"; 310 code_complete_at += llvm::utostr(complete_line); 311 code_complete_at += ":"; 312 code_complete_at += llvm::utostr(complete_column); 313 argv.push_back("-Xclang"); 314 argv.push_back("-code-completion-at"); 315 argv.push_back("-Xclang"); 316 argv.push_back(code_complete_at.c_str()); 317 argv.push_back("-Xclang"); 318 argv.push_back("-no-code-completion-debug-printer"); 319 argv.push_back("-Xclang"); 320 argv.push_back("-code-completion-macros"); 321 argv.push_back("-fdiagnostics-binary"); 322 323 // Remap any unsaved files to temporary files. 324 std::vector<std::string> RemapArgs; 325 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) 326 return 0; 327 328 // The pointers into the elements of RemapArgs are stable because we 329 // won't be adding anything to RemapArgs after this point. 330 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) 331 argv.push_back(RemapArgs[i].c_str()); 332 333 // Add the source file name (FIXME: later, we'll want to build temporary 334 // file from the buffer, or just feed the source text via standard input). 335 if (source_filename) 336 argv.push_back(source_filename); 337 338 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. 339 for (int i = 0; i < num_command_line_args; ++i) 340 if (const char *arg = command_line_args[i]) { 341 if (strcmp(arg, "-o") == 0) { 342 ++i; // Also skip the matching argument. 343 continue; 344 } 345 if (strcmp(arg, "-emit-ast") == 0 || 346 strcmp(arg, "-c") == 0 || 347 strcmp(arg, "-fsyntax-only") == 0) { 348 continue; 349 } 350 351 // Keep the argument. 352 argv.push_back(arg); 353 } 354 355 if (EnableLogging) { 356 std::string Log = ClangPath.str(); 357 for (unsigned I = 0, N = argv.size(); I != N; ++I) { 358 Log += ' '; 359 Log += argv[I]; 360 } 361 fprintf(stderr, "libclang (Code Completion): %s\n", Log.c_str()); 362 } 363 364 // Add the null terminator. 365 argv.push_back(NULL); 366 367 // Generate a temporary name for the code-completion results file. 368 char tmpFile[L_tmpnam]; 369 char *tmpFileName = tmpnam(tmpFile); 370 llvm::sys::Path ResultsFile(tmpFileName); 371 TemporaryFiles.push_back(ResultsFile); 372 373 // Generate a temporary name for the diagnostics file. 374 char tmpFileResults[L_tmpnam]; 375 char *tmpResultsFileName = tmpnam(tmpFileResults); 376 llvm::sys::Path DiagnosticsFile(tmpResultsFileName); 377 TemporaryFiles.push_back(DiagnosticsFile); 378 379 380 381 // Invoke 'clang'. 382 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null 383 // on Unix or NUL (Windows). 384 std::string ErrMsg; 385 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 386 &DiagnosticsFile, 0 }; 387 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, 388 /* redirects */ &Redirects[0], 389 /* secondsToWait */ 0, 390 /* memoryLimits */ 0, &ErrMsg); 391 392 if (!ErrMsg.empty()) { 393 std::string AllArgs; 394 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 395 I != E; ++I) { 396 AllArgs += ' '; 397 if (*I) 398 AllArgs += *I; 399 } 400 401 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; 402 } 403 404 // Parse the resulting source file to find code-completion results. 405 using llvm::MemoryBuffer; 406 using llvm::StringRef; 407 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; 408 Results->Results = 0; 409 Results->NumResults = 0; 410 Results->Buffer = 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->Buffer = 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 532void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { 533 if (!ResultsIn) 534 return; 535 536 AllocatedCXCodeCompleteResults *Results 537 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 538 delete Results; 539} 540 541unsigned 542clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { 543 AllocatedCXCodeCompleteResults *Results 544 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 545 if (!Results) 546 return 0; 547 548 return Results->Diagnostics.size(); 549} 550 551CXDiagnostic 552clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, 553 unsigned Index) { 554 AllocatedCXCodeCompleteResults *Results 555 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 556 if (!Results || Index >= Results->Diagnostics.size()) 557 return 0; 558 559 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); 560} 561 562 563} // end extern "C" 564