CIndexCodeCompletion.cpp revision 3d9c6e1c97bdae6a9daedc6969bc839e93074b0f
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 26#ifdef UDP_CODE_COMPLETION_LOGGER 27#include "clang/Basic/Version.h" 28#include "llvm/ADT/SmallString.h" 29#include "llvm/Support/Timer.h" 30#include "llvm/Support/raw_ostream.h" 31#include <arpa/inet.h> 32#include <sys/socket.h> 33#include <sys/types.h> 34#include <unistd.h> 35#endif 36 37using namespace clang; 38using namespace clang::cxstring; 39 40namespace { 41 /// \brief Stored representation of a completion string. 42 /// 43 /// This is the representation behind a CXCompletionString. 44 class CXStoredCodeCompletionString : public CodeCompletionString { 45 unsigned Priority; 46 47 public: 48 CXStoredCodeCompletionString(unsigned Priority) : Priority(Priority) { } 49 50 unsigned getPriority() const { return Priority; } 51 }; 52} 53 54extern "C" { 55 56enum CXCompletionChunkKind 57clang_getCompletionChunkKind(CXCompletionString completion_string, 58 unsigned chunk_number) { 59 CXStoredCodeCompletionString *CCStr 60 = (CXStoredCodeCompletionString *)completion_string; 61 if (!CCStr || chunk_number >= CCStr->size()) 62 return CXCompletionChunk_Text; 63 64 switch ((*CCStr)[chunk_number].Kind) { 65 case CodeCompletionString::CK_TypedText: 66 return CXCompletionChunk_TypedText; 67 case CodeCompletionString::CK_Text: 68 return CXCompletionChunk_Text; 69 case CodeCompletionString::CK_Optional: 70 return CXCompletionChunk_Optional; 71 case CodeCompletionString::CK_Placeholder: 72 return CXCompletionChunk_Placeholder; 73 case CodeCompletionString::CK_Informative: 74 return CXCompletionChunk_Informative; 75 case CodeCompletionString::CK_ResultType: 76 return CXCompletionChunk_ResultType; 77 case CodeCompletionString::CK_CurrentParameter: 78 return CXCompletionChunk_CurrentParameter; 79 case CodeCompletionString::CK_LeftParen: 80 return CXCompletionChunk_LeftParen; 81 case CodeCompletionString::CK_RightParen: 82 return CXCompletionChunk_RightParen; 83 case CodeCompletionString::CK_LeftBracket: 84 return CXCompletionChunk_LeftBracket; 85 case CodeCompletionString::CK_RightBracket: 86 return CXCompletionChunk_RightBracket; 87 case CodeCompletionString::CK_LeftBrace: 88 return CXCompletionChunk_LeftBrace; 89 case CodeCompletionString::CK_RightBrace: 90 return CXCompletionChunk_RightBrace; 91 case CodeCompletionString::CK_LeftAngle: 92 return CXCompletionChunk_LeftAngle; 93 case CodeCompletionString::CK_RightAngle: 94 return CXCompletionChunk_RightAngle; 95 case CodeCompletionString::CK_Comma: 96 return CXCompletionChunk_Comma; 97 case CodeCompletionString::CK_Colon: 98 return CXCompletionChunk_Colon; 99 case CodeCompletionString::CK_SemiColon: 100 return CXCompletionChunk_SemiColon; 101 case CodeCompletionString::CK_Equal: 102 return CXCompletionChunk_Equal; 103 case CodeCompletionString::CK_HorizontalSpace: 104 return CXCompletionChunk_HorizontalSpace; 105 case CodeCompletionString::CK_VerticalSpace: 106 return CXCompletionChunk_VerticalSpace; 107 } 108 109 // Should be unreachable, but let's be careful. 110 return CXCompletionChunk_Text; 111} 112 113CXString clang_getCompletionChunkText(CXCompletionString completion_string, 114 unsigned chunk_number) { 115 CXStoredCodeCompletionString *CCStr 116 = (CXStoredCodeCompletionString *)completion_string; 117 if (!CCStr || chunk_number >= CCStr->size()) 118 return createCXString(0); 119 120 switch ((*CCStr)[chunk_number].Kind) { 121 case CodeCompletionString::CK_TypedText: 122 case CodeCompletionString::CK_Text: 123 case CodeCompletionString::CK_Placeholder: 124 case CodeCompletionString::CK_CurrentParameter: 125 case CodeCompletionString::CK_Informative: 126 case CodeCompletionString::CK_LeftParen: 127 case CodeCompletionString::CK_RightParen: 128 case CodeCompletionString::CK_LeftBracket: 129 case CodeCompletionString::CK_RightBracket: 130 case CodeCompletionString::CK_LeftBrace: 131 case CodeCompletionString::CK_RightBrace: 132 case CodeCompletionString::CK_LeftAngle: 133 case CodeCompletionString::CK_RightAngle: 134 case CodeCompletionString::CK_Comma: 135 case CodeCompletionString::CK_ResultType: 136 case CodeCompletionString::CK_Colon: 137 case CodeCompletionString::CK_SemiColon: 138 case CodeCompletionString::CK_Equal: 139 case CodeCompletionString::CK_HorizontalSpace: 140 return createCXString((*CCStr)[chunk_number].Text, false); 141 142 case CodeCompletionString::CK_VerticalSpace: 143 // FIXME: Temporary hack until we figure out how to handle vertical space. 144 return createCXString(" "); 145 146 case CodeCompletionString::CK_Optional: 147 // Note: treated as an empty text block. 148 return createCXString(""); 149 } 150 151 // Should be unreachable, but let's be careful. 152 return createCXString(0); 153} 154 155 156CXCompletionString 157clang_getCompletionChunkCompletionString(CXCompletionString completion_string, 158 unsigned chunk_number) { 159 CXStoredCodeCompletionString *CCStr 160 = (CXStoredCodeCompletionString *)completion_string; 161 if (!CCStr || chunk_number >= CCStr->size()) 162 return 0; 163 164 switch ((*CCStr)[chunk_number].Kind) { 165 case CodeCompletionString::CK_TypedText: 166 case CodeCompletionString::CK_Text: 167 case CodeCompletionString::CK_Placeholder: 168 case CodeCompletionString::CK_CurrentParameter: 169 case CodeCompletionString::CK_Informative: 170 case CodeCompletionString::CK_LeftParen: 171 case CodeCompletionString::CK_RightParen: 172 case CodeCompletionString::CK_LeftBracket: 173 case CodeCompletionString::CK_RightBracket: 174 case CodeCompletionString::CK_LeftBrace: 175 case CodeCompletionString::CK_RightBrace: 176 case CodeCompletionString::CK_LeftAngle: 177 case CodeCompletionString::CK_RightAngle: 178 case CodeCompletionString::CK_Comma: 179 case CodeCompletionString::CK_ResultType: 180 case CodeCompletionString::CK_Colon: 181 case CodeCompletionString::CK_SemiColon: 182 case CodeCompletionString::CK_Equal: 183 case CodeCompletionString::CK_HorizontalSpace: 184 case CodeCompletionString::CK_VerticalSpace: 185 return 0; 186 187 case CodeCompletionString::CK_Optional: 188 // Note: treated as an empty text block. 189 return (*CCStr)[chunk_number].Optional; 190 } 191 192 // Should be unreachable, but let's be careful. 193 return 0; 194} 195 196unsigned clang_getNumCompletionChunks(CXCompletionString completion_string) { 197 CXStoredCodeCompletionString *CCStr 198 = (CXStoredCodeCompletionString *)completion_string; 199 return CCStr? CCStr->size() : 0; 200} 201 202unsigned clang_getCompletionPriority(CXCompletionString completion_string) { 203 CXStoredCodeCompletionString *CCStr 204 = (CXStoredCodeCompletionString *)completion_string; 205 return CCStr? CCStr->getPriority() : unsigned(CCP_Unlikely); 206} 207 208static bool ReadUnsigned(const char *&Memory, const char *MemoryEnd, 209 unsigned &Value) { 210 if (Memory + sizeof(unsigned) > MemoryEnd) 211 return true; 212 213 memmove(&Value, Memory, sizeof(unsigned)); 214 Memory += sizeof(unsigned); 215 return false; 216} 217 218/// \brief The CXCodeCompleteResults structure we allocate internally; 219/// the client only sees the initial CXCodeCompleteResults structure. 220struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { 221 AllocatedCXCodeCompleteResults(); 222 ~AllocatedCXCodeCompleteResults(); 223 224 /// \brief The memory buffer from which we parsed the results. We 225 /// retain this buffer because the completion strings point into it. 226 llvm::MemoryBuffer *Buffer; 227 228 /// \brief Diagnostics produced while performing code completion. 229 llvm::SmallVector<StoredDiagnostic, 8> Diagnostics; 230 231 /// \brief Diag object 232 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 248AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults() 249 : CXCodeCompleteResults(), Buffer(0), SourceMgr(Diag) { } 250 251AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() { 252 for (unsigned I = 0, N = NumResults; I != N; ++I) 253 delete (CXStoredCodeCompletionString *)Results[I].CompletionString; 254 delete [] Results; 255 delete Buffer; 256 257 for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I) 258 TemporaryFiles[I].eraseFromDisk(); 259} 260 261CXCodeCompleteResults *clang_codeComplete(CXIndex CIdx, 262 const char *source_filename, 263 int num_command_line_args, 264 const char **command_line_args, 265 unsigned num_unsaved_files, 266 struct CXUnsavedFile *unsaved_files, 267 const char *complete_filename, 268 unsigned complete_line, 269 unsigned complete_column) { 270#ifdef UDP_CODE_COMPLETION_LOGGER 271#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 272 const llvm::TimeRecord &StartTime = llvm::TimeRecord::getCurrentTime(); 273#endif 274#endif 275 276 // The indexer, which is mainly used to determine where diagnostics go. 277 CIndexer *CXXIdx = static_cast<CIndexer *>(CIdx); 278 279 // Configure the diagnostics. 280 DiagnosticOptions DiagOpts; 281 llvm::IntrusiveRefCntPtr<Diagnostic> Diags; 282 Diags = CompilerInstance::createDiagnostics(DiagOpts, 0, 0); 283 284 // The set of temporary files that we've built. 285 std::vector<llvm::sys::Path> TemporaryFiles; 286 287 // Build up the arguments for invoking 'clang'. 288 std::vector<const char *> argv; 289 290 // First add the complete path to the 'clang' executable. 291 llvm::sys::Path ClangPath = CXXIdx->getClangPath(); 292 argv.push_back(ClangPath.c_str()); 293 294 // Always use Clang C++ support. 295 argv.push_back("-ccc-clang-cxx"); 296 297 // Add the '-fsyntax-only' argument so that we only perform a basic 298 // syntax check of the code. 299 argv.push_back("-fsyntax-only"); 300 301 // Add the appropriate '-code-completion-at=file:line:column' argument 302 // to perform code completion, with an "-Xclang" preceding it. 303 std::string code_complete_at; 304 code_complete_at += complete_filename; 305 code_complete_at += ":"; 306 code_complete_at += llvm::utostr(complete_line); 307 code_complete_at += ":"; 308 code_complete_at += llvm::utostr(complete_column); 309 argv.push_back("-Xclang"); 310 argv.push_back("-code-completion-at"); 311 argv.push_back("-Xclang"); 312 argv.push_back(code_complete_at.c_str()); 313 argv.push_back("-Xclang"); 314 argv.push_back("-no-code-completion-debug-printer"); 315 argv.push_back("-Xclang"); 316 argv.push_back("-code-completion-macros"); 317 argv.push_back("-fdiagnostics-binary"); 318 319 // Remap any unsaved files to temporary files. 320 std::vector<std::string> RemapArgs; 321 if (RemapFiles(num_unsaved_files, unsaved_files, RemapArgs, TemporaryFiles)) 322 return 0; 323 324 // The pointers into the elements of RemapArgs are stable because we 325 // won't be adding anything to RemapArgs after this point. 326 for (unsigned i = 0, e = RemapArgs.size(); i != e; ++i) 327 argv.push_back(RemapArgs[i].c_str()); 328 329 // Add the source file name (FIXME: later, we'll want to build temporary 330 // file from the buffer, or just feed the source text via standard input). 331 if (source_filename) 332 argv.push_back(source_filename); 333 334 // Process the compiler options, stripping off '-o', '-c', '-fsyntax-only'. 335 for (int i = 0; i < num_command_line_args; ++i) 336 if (const char *arg = command_line_args[i]) { 337 if (strcmp(arg, "-o") == 0) { 338 ++i; // Also skip the matching argument. 339 continue; 340 } 341 if (strcmp(arg, "-emit-ast") == 0 || 342 strcmp(arg, "-c") == 0 || 343 strcmp(arg, "-fsyntax-only") == 0) { 344 continue; 345 } 346 347 // Keep the argument. 348 argv.push_back(arg); 349 } 350 351 // Add the null terminator. 352 argv.push_back(NULL); 353 354 // Generate a temporary name for the code-completion results file. 355 char tmpFile[L_tmpnam]; 356 char *tmpFileName = tmpnam(tmpFile); 357 llvm::sys::Path ResultsFile(tmpFileName); 358 TemporaryFiles.push_back(ResultsFile); 359 360 // Generate a temporary name for the diagnostics file. 361 char tmpFileResults[L_tmpnam]; 362 char *tmpResultsFileName = tmpnam(tmpFileResults); 363 llvm::sys::Path DiagnosticsFile(tmpResultsFileName); 364 TemporaryFiles.push_back(DiagnosticsFile); 365 366 // Invoke 'clang'. 367 llvm::sys::Path DevNull; // leave empty, causes redirection to /dev/null 368 // on Unix or NUL (Windows). 369 std::string ErrMsg; 370 const llvm::sys::Path *Redirects[] = { &DevNull, &ResultsFile, 371 &DiagnosticsFile, 0 }; 372 llvm::sys::Program::ExecuteAndWait(ClangPath, &argv[0], /* env */ NULL, 373 /* redirects */ &Redirects[0], 374 /* secondsToWait */ 0, 375 /* memoryLimits */ 0, &ErrMsg); 376 377 if (!ErrMsg.empty()) { 378 std::string AllArgs; 379 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 380 I != E; ++I) { 381 AllArgs += ' '; 382 if (*I) 383 AllArgs += *I; 384 } 385 386 Diags->Report(diag::err_fe_invoking) << AllArgs << ErrMsg; 387 } 388 389 // Parse the resulting source file to find code-completion results. 390 using llvm::MemoryBuffer; 391 using llvm::StringRef; 392 AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults; 393 Results->Results = 0; 394 Results->NumResults = 0; 395 Results->Buffer = 0; 396 // FIXME: Set Results->LangOpts! 397 if (MemoryBuffer *F = MemoryBuffer::getFile(ResultsFile.c_str())) { 398 llvm::SmallVector<CXCompletionResult, 4> CompletionResults; 399 StringRef Buffer = F->getBuffer(); 400 for (const char *Str = Buffer.data(), *StrEnd = Str + Buffer.size(); 401 Str < StrEnd;) { 402 unsigned KindValue; 403 if (ReadUnsigned(Str, StrEnd, KindValue)) 404 break; 405 406 unsigned Priority; 407 if (ReadUnsigned(Str, StrEnd, Priority)) 408 break; 409 410 CXStoredCodeCompletionString *CCStr 411 = new CXStoredCodeCompletionString(Priority); 412 if (!CCStr->Deserialize(Str, StrEnd)) { 413 delete CCStr; 414 continue; 415 } 416 417 if (!CCStr->empty()) { 418 // Vend the code-completion result to the caller. 419 CXCompletionResult Result; 420 Result.CursorKind = (CXCursorKind)KindValue; 421 Result.CompletionString = CCStr; 422 CompletionResults.push_back(Result); 423 } 424 }; 425 426 // Allocate the results. 427 Results->Results = new CXCompletionResult [CompletionResults.size()]; 428 Results->NumResults = CompletionResults.size(); 429 memcpy(Results->Results, CompletionResults.data(), 430 CompletionResults.size() * sizeof(CXCompletionResult)); 431 Results->Buffer = F; 432 } 433 434 LoadSerializedDiagnostics(DiagnosticsFile, num_unsaved_files, unsaved_files, 435 Results->FileMgr, Results->SourceMgr, 436 Results->Diagnostics); 437 438 // Make sure we delete temporary files when the code-completion results are 439 // destroyed. 440 Results->TemporaryFiles.swap(TemporaryFiles); 441 442#ifdef UDP_CODE_COMPLETION_LOGGER 443#ifdef UDP_CODE_COMPLETION_LOGGER_PORT 444 const llvm::TimeRecord &EndTime = llvm::TimeRecord::getCurrentTime(); 445 llvm::SmallString<256> LogResult; 446 llvm::raw_svector_ostream os(LogResult); 447 448 // Figure out the language and whether or not it uses PCH. 449 const char *lang = 0; 450 bool usesPCH = false; 451 452 for (std::vector<const char*>::iterator I = argv.begin(), E = argv.end(); 453 I != E; ++I) { 454 if (*I == 0) 455 continue; 456 if (strcmp(*I, "-x") == 0) { 457 if (I + 1 != E) { 458 lang = *(++I); 459 continue; 460 } 461 } 462 else if (strcmp(*I, "-include") == 0) { 463 if (I+1 != E) { 464 const char *arg = *(++I); 465 llvm::SmallString<512> pchName; 466 { 467 llvm::raw_svector_ostream os(pchName); 468 os << arg << ".pth"; 469 } 470 pchName.push_back('\0'); 471 struct stat stat_results; 472 if (stat(pchName.data(), &stat_results) == 0) 473 usesPCH = true; 474 continue; 475 } 476 } 477 } 478 479 os << "{ "; 480 os << "\"wall\": " << (EndTime.getWallTime() - StartTime.getWallTime()); 481 os << ", \"numRes\": " << Results->NumResults; 482 os << ", \"diags\": " << Results->Diagnostics.size(); 483 os << ", \"pch\": " << (usesPCH ? "true" : "false"); 484 os << ", \"lang\": \"" << (lang ? lang : "<unknown>") << '"'; 485 const char *name = getlogin(); 486 os << ", \"user\": \"" << (name ? name : "unknown") << '"'; 487 os << ", \"clangVer\": \"" << getClangFullVersion() << '"'; 488 os << " }"; 489 490 llvm::StringRef res = os.str(); 491 if (res.size() > 0) { 492 do { 493 // Setup the UDP socket. 494 struct sockaddr_in servaddr; 495 bzero(&servaddr, sizeof(servaddr)); 496 servaddr.sin_family = AF_INET; 497 servaddr.sin_port = htons(UDP_CODE_COMPLETION_LOGGER_PORT); 498 if (inet_pton(AF_INET, UDP_CODE_COMPLETION_LOGGER, 499 &servaddr.sin_addr) <= 0) 500 break; 501 502 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); 503 if (sockfd < 0) 504 break; 505 506 sendto(sockfd, res.data(), res.size(), 0, 507 (struct sockaddr *)&servaddr, sizeof(servaddr)); 508 close(sockfd); 509 } 510 while (false); 511 } 512#endif 513#endif 514 return Results; 515} 516 517void clang_disposeCodeCompleteResults(CXCodeCompleteResults *ResultsIn) { 518 if (!ResultsIn) 519 return; 520 521 AllocatedCXCodeCompleteResults *Results 522 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 523 delete Results; 524} 525 526unsigned 527clang_codeCompleteGetNumDiagnostics(CXCodeCompleteResults *ResultsIn) { 528 AllocatedCXCodeCompleteResults *Results 529 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 530 if (!Results) 531 return 0; 532 533 return Results->Diagnostics.size(); 534} 535 536CXDiagnostic 537clang_codeCompleteGetDiagnostic(CXCodeCompleteResults *ResultsIn, 538 unsigned Index) { 539 AllocatedCXCodeCompleteResults *Results 540 = static_cast<AllocatedCXCodeCompleteResults*>(ResultsIn); 541 if (!Results || Index >= Results->Diagnostics.size()) 542 return 0; 543 544 return new CXStoredDiagnostic(Results->Diagnostics[Index], Results->LangOpts); 545} 546 547 548} // end extern "C" 549