1 //===--- CodeComplete.cpp ---------------------------------------*- C++-*-===// 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 // AST-based completions are provided using the completion hooks in Sema. 11 // 12 // Signature help works in a similar way as code completion, but it is simpler 13 // as there are typically fewer candidates. 14 // 15 //===---------------------------------------------------------------------===// 16 17 #include "CodeComplete.h" 18 #include "CodeCompletionStrings.h" 19 #include "Compiler.h" 20 #include "Logger.h" 21 #include "index/Index.h" 22 #include "clang/Frontend/CompilerInstance.h" 23 #include "clang/Frontend/FrontendActions.h" 24 #include "clang/Sema/CodeCompleteConsumer.h" 25 #include "clang/Sema/Sema.h" 26 #include <queue> 27 28 namespace clang { 29 namespace clangd { 30 namespace { 31 32 CompletionItemKind toCompletionItemKind(CXCursorKind CursorKind) { 33 switch (CursorKind) { 34 case CXCursor_MacroInstantiation: 35 case CXCursor_MacroDefinition: 36 return CompletionItemKind::Text; 37 case CXCursor_CXXMethod: 38 case CXCursor_Destructor: 39 return CompletionItemKind::Method; 40 case CXCursor_FunctionDecl: 41 case CXCursor_FunctionTemplate: 42 return CompletionItemKind::Function; 43 case CXCursor_Constructor: 44 return CompletionItemKind::Constructor; 45 case CXCursor_FieldDecl: 46 return CompletionItemKind::Field; 47 case CXCursor_VarDecl: 48 case CXCursor_ParmDecl: 49 return CompletionItemKind::Variable; 50 // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the 51 // protocol. 52 case CXCursor_StructDecl: 53 case CXCursor_ClassDecl: 54 case CXCursor_UnionDecl: 55 case CXCursor_ClassTemplate: 56 case CXCursor_ClassTemplatePartialSpecialization: 57 return CompletionItemKind::Class; 58 case CXCursor_Namespace: 59 case CXCursor_NamespaceAlias: 60 case CXCursor_NamespaceRef: 61 return CompletionItemKind::Module; 62 case CXCursor_EnumConstantDecl: 63 return CompletionItemKind::Value; 64 case CXCursor_EnumDecl: 65 return CompletionItemKind::Enum; 66 // FIXME(ioeric): figure out whether reference is the right type for aliases. 67 case CXCursor_TypeAliasDecl: 68 case CXCursor_TypeAliasTemplateDecl: 69 case CXCursor_TypedefDecl: 70 case CXCursor_MemberRef: 71 case CXCursor_TypeRef: 72 return CompletionItemKind::Reference; 73 default: 74 return CompletionItemKind::Missing; 75 } 76 } 77 78 CompletionItemKind 79 toCompletionItemKind(CodeCompletionResult::ResultKind ResKind, 80 CXCursorKind CursorKind) { 81 switch (ResKind) { 82 case CodeCompletionResult::RK_Declaration: 83 return toCompletionItemKind(CursorKind); 84 case CodeCompletionResult::RK_Keyword: 85 return CompletionItemKind::Keyword; 86 case CodeCompletionResult::RK_Macro: 87 return CompletionItemKind::Text; // unfortunately, there's no 'Macro' 88 // completion items in LSP. 89 case CodeCompletionResult::RK_Pattern: 90 return CompletionItemKind::Snippet; 91 } 92 llvm_unreachable("Unhandled CodeCompletionResult::ResultKind."); 93 } 94 95 CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) { 96 using SK = index::SymbolKind; 97 switch (Kind) { 98 case SK::Unknown: 99 return CompletionItemKind::Missing; 100 case SK::Module: 101 case SK::Namespace: 102 case SK::NamespaceAlias: 103 return CompletionItemKind::Module; 104 case SK::Macro: 105 return CompletionItemKind::Text; 106 case SK::Enum: 107 return CompletionItemKind::Enum; 108 // FIXME(ioeric): use LSP struct instead of class when it is suppoted in the 109 // protocol. 110 case SK::Struct: 111 case SK::Class: 112 case SK::Protocol: 113 case SK::Extension: 114 case SK::Union: 115 return CompletionItemKind::Class; 116 // FIXME(ioeric): figure out whether reference is the right type for aliases. 117 case SK::TypeAlias: 118 case SK::Using: 119 return CompletionItemKind::Reference; 120 case SK::Function: 121 // FIXME(ioeric): this should probably be an operator. This should be fixed 122 // when `Operator` is support type in the protocol. 123 case SK::ConversionFunction: 124 return CompletionItemKind::Function; 125 case SK::Variable: 126 case SK::Parameter: 127 return CompletionItemKind::Variable; 128 case SK::Field: 129 return CompletionItemKind::Field; 130 // FIXME(ioeric): use LSP enum constant when it is supported in the protocol. 131 case SK::EnumConstant: 132 return CompletionItemKind::Value; 133 case SK::InstanceMethod: 134 case SK::ClassMethod: 135 case SK::StaticMethod: 136 case SK::Destructor: 137 return CompletionItemKind::Method; 138 case SK::InstanceProperty: 139 case SK::ClassProperty: 140 case SK::StaticProperty: 141 return CompletionItemKind::Property; 142 case SK::Constructor: 143 return CompletionItemKind::Constructor; 144 } 145 llvm_unreachable("Unhandled clang::index::SymbolKind."); 146 } 147 148 /// Get the optional chunk as a string. This function is possibly recursive. 149 /// 150 /// The parameter info for each parameter is appended to the Parameters. 151 std::string 152 getOptionalParameters(const CodeCompletionString &CCS, 153 std::vector<ParameterInformation> &Parameters) { 154 std::string Result; 155 for (const auto &Chunk : CCS) { 156 switch (Chunk.Kind) { 157 case CodeCompletionString::CK_Optional: 158 assert(Chunk.Optional && 159 "Expected the optional code completion string to be non-null."); 160 Result += getOptionalParameters(*Chunk.Optional, Parameters); 161 break; 162 case CodeCompletionString::CK_VerticalSpace: 163 break; 164 case CodeCompletionString::CK_Placeholder: 165 // A string that acts as a placeholder for, e.g., a function call 166 // argument. 167 // Intentional fallthrough here. 168 case CodeCompletionString::CK_CurrentParameter: { 169 // A piece of text that describes the parameter that corresponds to 170 // the code-completion location within a function call, message send, 171 // macro invocation, etc. 172 Result += Chunk.Text; 173 ParameterInformation Info; 174 Info.label = Chunk.Text; 175 Parameters.push_back(std::move(Info)); 176 break; 177 } 178 default: 179 Result += Chunk.Text; 180 break; 181 } 182 } 183 return Result; 184 } 185 186 /// A scored code completion result. 187 /// It may be promoted to a CompletionItem if it's among the top-ranked results. 188 struct CompletionCandidate { 189 CompletionCandidate(CodeCompletionResult &Result) 190 : Result(&Result), Score(score(Result)) {} 191 192 CodeCompletionResult *Result; 193 float Score; // 0 to 1, higher is better. 194 195 // Comparison reflects rank: better candidates are smaller. 196 bool operator<(const CompletionCandidate &C) const { 197 if (Score != C.Score) 198 return Score > C.Score; 199 return *Result < *C.Result; 200 } 201 202 // Returns a string that sorts in the same order as operator<, for LSP. 203 // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and 204 // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo" 205 std::string sortText() const { 206 std::string S, NameStorage; 207 llvm::raw_string_ostream OS(S); 208 write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower, 209 /*Width=*/2 * sizeof(Score)); 210 OS << Result->getOrderedName(NameStorage); 211 return OS.str(); 212 } 213 214 private: 215 static float score(const CodeCompletionResult &Result) { 216 // Priority 80 is a really bad score. 217 float Score = 1 - std::min<float>(80, Result.Priority) / 80; 218 219 switch (static_cast<CXAvailabilityKind>(Result.Availability)) { 220 case CXAvailability_Available: 221 // No penalty. 222 break; 223 case CXAvailability_Deprecated: 224 Score *= 0.1f; 225 break; 226 case CXAvailability_NotAccessible: 227 case CXAvailability_NotAvailable: 228 Score = 0; 229 break; 230 } 231 return Score; 232 } 233 234 // Produces an integer that sorts in the same order as F. 235 // That is: a < b <==> encodeFloat(a) < encodeFloat(b). 236 static uint32_t encodeFloat(float F) { 237 static_assert(std::numeric_limits<float>::is_iec559, ""); 238 static_assert(sizeof(float) == sizeof(uint32_t), ""); 239 constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1); 240 241 // Get the bits of the float. Endianness is the same as for integers. 242 uint32_t U; 243 memcpy(&U, &F, sizeof(float)); 244 // IEEE 754 floats compare like sign-magnitude integers. 245 if (U & TopBit) // Negative float. 246 return 0 - U; // Map onto the low half of integers, order reversed. 247 return U + TopBit; // Positive floats map onto the high half of integers. 248 } 249 }; 250 251 /// \brief Information about the scope specifier in the qualified-id code 252 /// completion (e.g. "ns::ab?"). 253 struct SpecifiedScope { 254 /// The scope specifier as written. For example, for completion "ns::ab?", the 255 /// written scope specifier is "ns". 256 std::string Written; 257 // If this scope specifier is recognized in Sema (e.g. as a namespace 258 // context), this will be set to the fully qualfied name of the corresponding 259 // context. 260 std::string Resolved; 261 }; 262 263 /// \brief Information from sema about (parital) symbol names to be completed. 264 /// For example, for completion "ns::ab^", this stores the scope specifier 265 /// "ns::" and the completion filter text "ab". 266 struct NameToComplete { 267 // The partial identifier being completed, without qualifier. 268 std::string Filter; 269 270 /// This is set if the completion is for qualified IDs, e.g. "abc::x^". 271 llvm::Optional<SpecifiedScope> SSInfo; 272 }; 273 274 SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS); 275 276 class CompletionItemsCollector : public CodeCompleteConsumer { 277 public: 278 CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts, 279 CompletionList &Items, NameToComplete &CompletedName) 280 : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(), 281 /*OutputIsBinary=*/false), 282 ClangdOpts(CodeCompleteOpts), Items(Items), 283 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()), 284 CCTUInfo(Allocator), CompletedName(CompletedName), 285 EnableSnippets(CodeCompleteOpts.EnableSnippets) {} 286 287 void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context, 288 CodeCompletionResult *Results, 289 unsigned NumResults) override final { 290 if (auto SS = Context.getCXXScopeSpecifier()) 291 CompletedName.SSInfo = extraCompletionScope(S, **SS); 292 293 CompletedName.Filter = S.getPreprocessor().getCodeCompletionFilter(); 294 std::priority_queue<CompletionCandidate> Candidates; 295 for (unsigned I = 0; I < NumResults; ++I) { 296 auto &Result = Results[I]; 297 if (!ClangdOpts.IncludeIneligibleResults && 298 (Result.Availability == CXAvailability_NotAvailable || 299 Result.Availability == CXAvailability_NotAccessible)) 300 continue; 301 if (!CompletedName.Filter.empty() && 302 !fuzzyMatch(S, Context, CompletedName.Filter, Result)) 303 continue; 304 Candidates.emplace(Result); 305 if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) { 306 Candidates.pop(); 307 Items.isIncomplete = true; 308 } 309 } 310 while (!Candidates.empty()) { 311 auto &Candidate = Candidates.top(); 312 const auto *CCS = Candidate.Result->CreateCodeCompletionString( 313 S, Context, *Allocator, CCTUInfo, 314 CodeCompleteOpts.IncludeBriefComments); 315 assert(CCS && "Expected the CodeCompletionString to be non-null"); 316 Items.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS)); 317 Candidates.pop(); 318 } 319 std::reverse(Items.items.begin(), Items.items.end()); 320 } 321 322 GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; } 323 324 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } 325 326 private: 327 bool fuzzyMatch(Sema &S, const CodeCompletionContext &CCCtx, StringRef Filter, 328 CodeCompletionResult Result) { 329 switch (Result.Kind) { 330 case CodeCompletionResult::RK_Declaration: 331 if (auto *ID = Result.Declaration->getIdentifier()) 332 return fuzzyMatch(Filter, ID->getName()); 333 break; 334 case CodeCompletionResult::RK_Keyword: 335 return fuzzyMatch(Filter, Result.Keyword); 336 case CodeCompletionResult::RK_Macro: 337 return fuzzyMatch(Filter, Result.Macro->getName()); 338 case CodeCompletionResult::RK_Pattern: 339 return fuzzyMatch(Filter, Result.Pattern->getTypedText()); 340 } 341 auto *CCS = Result.CreateCodeCompletionString( 342 S, CCCtx, *Allocator, CCTUInfo, /*IncludeBriefComments=*/false); 343 return fuzzyMatch(Filter, CCS->getTypedText()); 344 } 345 346 // Checks whether Target matches the Filter. 347 // Currently just requires a case-insensitive subsequence match. 348 // FIXME: make stricter and word-based: 'unique_ptr' should not match 'que'. 349 // FIXME: return a score to be incorporated into ranking. 350 static bool fuzzyMatch(StringRef Filter, StringRef Target) { 351 size_t TPos = 0; 352 for (char C : Filter) { 353 TPos = Target.find_lower(C, TPos); 354 if (TPos == StringRef::npos) 355 return false; 356 } 357 return true; 358 } 359 360 CompletionItem 361 ProcessCodeCompleteResult(const CompletionCandidate &Candidate, 362 const CodeCompletionString &CCS) const { 363 364 // Adjust this to InsertTextFormat::Snippet iff we encounter a 365 // CK_Placeholder chunk in SnippetCompletionItemsCollector. 366 CompletionItem Item; 367 368 Item.documentation = getDocumentation(CCS); 369 Item.sortText = Candidate.sortText(); 370 371 Item.detail = getDetail(CCS); 372 Item.filterText = getFilterText(CCS); 373 getLabelAndInsertText(CCS, &Item.label, &Item.insertText, EnableSnippets); 374 375 Item.insertTextFormat = EnableSnippets ? InsertTextFormat::Snippet 376 : InsertTextFormat::PlainText; 377 378 // Fill in the kind field of the CompletionItem. 379 Item.kind = toCompletionItemKind(Candidate.Result->Kind, 380 Candidate.Result->CursorKind); 381 382 return Item; 383 } 384 385 CodeCompleteOptions ClangdOpts; 386 CompletionList &Items; 387 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator; 388 CodeCompletionTUInfo CCTUInfo; 389 NameToComplete &CompletedName; 390 bool EnableSnippets; 391 }; // CompletionItemsCollector 392 393 class SignatureHelpCollector final : public CodeCompleteConsumer { 394 395 public: 396 SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts, 397 SignatureHelp &SigHelp) 398 : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false), 399 SigHelp(SigHelp), 400 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()), 401 CCTUInfo(Allocator) {} 402 403 void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, 404 OverloadCandidate *Candidates, 405 unsigned NumCandidates) override { 406 SigHelp.signatures.reserve(NumCandidates); 407 // FIXME(rwols): How can we determine the "active overload candidate"? 408 // Right now the overloaded candidates seem to be provided in a "best fit" 409 // order, so I'm not too worried about this. 410 SigHelp.activeSignature = 0; 411 assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() && 412 "too many arguments"); 413 SigHelp.activeParameter = static_cast<int>(CurrentArg); 414 for (unsigned I = 0; I < NumCandidates; ++I) { 415 const auto &Candidate = Candidates[I]; 416 const auto *CCS = Candidate.CreateSignatureString( 417 CurrentArg, S, *Allocator, CCTUInfo, true); 418 assert(CCS && "Expected the CodeCompletionString to be non-null"); 419 SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS)); 420 } 421 } 422 423 GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; } 424 425 CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; } 426 427 private: 428 // FIXME(ioeric): consider moving CodeCompletionString logic here to 429 // CompletionString.h. 430 SignatureInformation 431 ProcessOverloadCandidate(const OverloadCandidate &Candidate, 432 const CodeCompletionString &CCS) const { 433 SignatureInformation Result; 434 const char *ReturnType = nullptr; 435 436 Result.documentation = getDocumentation(CCS); 437 438 for (const auto &Chunk : CCS) { 439 switch (Chunk.Kind) { 440 case CodeCompletionString::CK_ResultType: 441 // A piece of text that describes the type of an entity or, 442 // for functions and methods, the return type. 443 assert(!ReturnType && "Unexpected CK_ResultType"); 444 ReturnType = Chunk.Text; 445 break; 446 case CodeCompletionString::CK_Placeholder: 447 // A string that acts as a placeholder for, e.g., a function call 448 // argument. 449 // Intentional fallthrough here. 450 case CodeCompletionString::CK_CurrentParameter: { 451 // A piece of text that describes the parameter that corresponds to 452 // the code-completion location within a function call, message send, 453 // macro invocation, etc. 454 Result.label += Chunk.Text; 455 ParameterInformation Info; 456 Info.label = Chunk.Text; 457 Result.parameters.push_back(std::move(Info)); 458 break; 459 } 460 case CodeCompletionString::CK_Optional: { 461 // The rest of the parameters are defaulted/optional. 462 assert(Chunk.Optional && 463 "Expected the optional code completion string to be non-null."); 464 Result.label += 465 getOptionalParameters(*Chunk.Optional, Result.parameters); 466 break; 467 } 468 case CodeCompletionString::CK_VerticalSpace: 469 break; 470 default: 471 Result.label += Chunk.Text; 472 break; 473 } 474 } 475 if (ReturnType) { 476 Result.label += " -> "; 477 Result.label += ReturnType; 478 } 479 return Result; 480 } 481 482 SignatureHelp &SigHelp; 483 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator; 484 CodeCompletionTUInfo CCTUInfo; 485 486 }; // SignatureHelpCollector 487 488 bool invokeCodeComplete(const Context &Ctx, 489 std::unique_ptr<CodeCompleteConsumer> Consumer, 490 const clang::CodeCompleteOptions &Options, 491 PathRef FileName, 492 const tooling::CompileCommand &Command, 493 PrecompiledPreamble const *Preamble, StringRef Contents, 494 Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS, 495 std::shared_ptr<PCHContainerOperations> PCHs) { 496 std::vector<const char *> ArgStrs; 497 for (const auto &S : Command.CommandLine) 498 ArgStrs.push_back(S.c_str()); 499 500 VFS->setCurrentWorkingDirectory(Command.Directory); 501 502 IgnoreDiagnostics DummyDiagsConsumer; 503 auto CI = createInvocationFromCommandLine( 504 ArgStrs, 505 CompilerInstance::createDiagnostics(new DiagnosticOptions, 506 &DummyDiagsConsumer, false), 507 VFS); 508 assert(CI && "Couldn't create CompilerInvocation"); 509 510 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer = 511 llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName); 512 513 // Attempt to reuse the PCH from precompiled preamble, if it was built. 514 if (Preamble) { 515 auto Bounds = 516 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0); 517 if (!Preamble->CanReuse(*CI, ContentsBuffer.get(), Bounds, VFS.get())) 518 Preamble = nullptr; 519 } 520 521 auto Clang = prepareCompilerInstance( 522 std::move(CI), Preamble, std::move(ContentsBuffer), std::move(PCHs), 523 std::move(VFS), DummyDiagsConsumer); 524 auto &DiagOpts = Clang->getDiagnosticOpts(); 525 DiagOpts.IgnoreWarnings = true; 526 527 auto &FrontendOpts = Clang->getFrontendOpts(); 528 FrontendOpts.SkipFunctionBodies = true; 529 FrontendOpts.CodeCompleteOpts = Options; 530 FrontendOpts.CodeCompletionAt.FileName = FileName; 531 FrontendOpts.CodeCompletionAt.Line = Pos.line + 1; 532 FrontendOpts.CodeCompletionAt.Column = Pos.character + 1; 533 534 Clang->setCodeCompletionConsumer(Consumer.release()); 535 536 SyntaxOnlyAction Action; 537 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) { 538 log(Ctx, 539 "BeginSourceFile() failed when running codeComplete for " + FileName); 540 return false; 541 } 542 if (!Action.Execute()) { 543 log(Ctx, "Execute() failed when running codeComplete for " + FileName); 544 return false; 545 } 546 547 Action.EndSourceFile(); 548 549 return true; 550 } 551 552 CompletionItem indexCompletionItem(const Symbol &Sym, llvm::StringRef Filter, 553 const SpecifiedScope &SSInfo) { 554 CompletionItem Item; 555 Item.kind = toCompletionItemKind(Sym.SymInfo.Kind); 556 Item.label = Sym.Name; 557 // FIXME(ioeric): support inserting/replacing scope qualifiers. 558 Item.insertText = Sym.Name; 559 // FIXME(ioeric): support snippets. 560 Item.insertTextFormat = InsertTextFormat::PlainText; 561 Item.filterText = Sym.Name; 562 563 // FIXME(ioeric): sort symbols appropriately. 564 Item.sortText = ""; 565 566 // FIXME(ioeric): use more symbol information (e.g. documentation, label) to 567 // populate the completion item. 568 569 return Item; 570 } 571 572 void completeWithIndex(const Context &Ctx, const SymbolIndex &Index, 573 llvm::StringRef Code, const SpecifiedScope &SSInfo, 574 llvm::StringRef Filter, CompletionList *Items) { 575 FuzzyFindRequest Req; 576 Req.Query = Filter; 577 // FIXME(ioeric): add more possible scopes based on using namespaces and 578 // containing namespaces. 579 StringRef Scope = SSInfo.Resolved.empty() ? SSInfo.Written : SSInfo.Resolved; 580 Req.Scopes = {Scope.trim(':').str()}; 581 582 Items->isIncomplete = !Index.fuzzyFind(Ctx, Req, [&](const Symbol &Sym) { 583 Items->items.push_back(indexCompletionItem(Sym, Filter, SSInfo)); 584 }); 585 } 586 587 SpecifiedScope extraCompletionScope(Sema &S, const CXXScopeSpec &SS) { 588 SpecifiedScope Info; 589 auto &SM = S.getSourceManager(); 590 auto SpecifierRange = SS.getRange(); 591 Info.Written = Lexer::getSourceText( 592 CharSourceRange::getCharRange(SpecifierRange), SM, clang::LangOptions()); 593 if (SS.isValid()) { 594 DeclContext *DC = S.computeDeclContext(SS); 595 if (auto *NS = llvm::dyn_cast<NamespaceDecl>(DC)) { 596 Info.Resolved = NS->getQualifiedNameAsString(); 597 } else if (llvm::dyn_cast<TranslationUnitDecl>(DC) != nullptr) { 598 Info.Resolved = "::"; 599 // Sema does not include the suffix "::" in the range of SS, so we add 600 // it back here. 601 Info.Written = "::"; 602 } 603 } 604 return Info; 605 } 606 607 } // namespace 608 609 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { 610 clang::CodeCompleteOptions Result; 611 Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns; 612 Result.IncludeMacros = IncludeMacros; 613 Result.IncludeGlobals = IncludeGlobals; 614 Result.IncludeBriefComments = IncludeBriefComments; 615 616 // Enable index-based code completion when Index is provided. 617 Result.IncludeNamespaceLevelDecls = !Index; 618 619 return Result; 620 } 621 622 CompletionList codeComplete(const Context &Ctx, PathRef FileName, 623 const tooling::CompileCommand &Command, 624 PrecompiledPreamble const *Preamble, 625 StringRef Contents, Position Pos, 626 IntrusiveRefCntPtr<vfs::FileSystem> VFS, 627 std::shared_ptr<PCHContainerOperations> PCHs, 628 CodeCompleteOptions Opts) { 629 CompletionList Results; 630 NameToComplete CompletedName; 631 auto Consumer = 632 llvm::make_unique<CompletionItemsCollector>(Opts, Results, CompletedName); 633 invokeCodeComplete(Ctx, std::move(Consumer), Opts.getClangCompleteOpts(), 634 FileName, Command, Preamble, Contents, Pos, std::move(VFS), 635 std::move(PCHs)); 636 if (Opts.Index && CompletedName.SSInfo) { 637 if (!Results.items.empty()) 638 log(Ctx, "WARNING: Got completion results from sema for completion on " 639 "qualified ID while symbol index is provided."); 640 Results.items.clear(); 641 completeWithIndex(Ctx, *Opts.Index, Contents, *CompletedName.SSInfo, 642 CompletedName.Filter, &Results); 643 } 644 return Results; 645 } 646 647 SignatureHelp signatureHelp(const Context &Ctx, PathRef FileName, 648 const tooling::CompileCommand &Command, 649 PrecompiledPreamble const *Preamble, 650 StringRef Contents, Position Pos, 651 IntrusiveRefCntPtr<vfs::FileSystem> VFS, 652 std::shared_ptr<PCHContainerOperations> PCHs) { 653 SignatureHelp Result; 654 clang::CodeCompleteOptions Options; 655 Options.IncludeGlobals = false; 656 Options.IncludeMacros = false; 657 Options.IncludeCodePatterns = false; 658 Options.IncludeBriefComments = true; 659 invokeCodeComplete(Ctx, 660 llvm::make_unique<SignatureHelpCollector>(Options, Result), 661 Options, FileName, Command, Preamble, Contents, Pos, 662 std::move(VFS), std::move(PCHs)); 663 return Result; 664 } 665 666 } // namespace clangd 667 } // namespace clang 668