44#include "clang/AST/Decl.h"
45#include "clang/AST/DeclBase.h"
46#include "clang/Basic/CharInfo.h"
47#include "clang/Basic/LangOptions.h"
48#include "clang/Basic/SourceLocation.h"
49#include "clang/Basic/TokenKinds.h"
50#include "clang/Format/Format.h"
51#include "clang/Frontend/CompilerInstance.h"
52#include "clang/Frontend/FrontendActions.h"
53#include "clang/Lex/ExternalPreprocessorSource.h"
54#include "clang/Lex/Lexer.h"
55#include "clang/Lex/Preprocessor.h"
56#include "clang/Lex/PreprocessorOptions.h"
57#include "clang/Sema/CodeCompleteConsumer.h"
58#include "clang/Sema/DeclSpec.h"
59#include "clang/Sema/Sema.h"
60#include "llvm/ADT/ArrayRef.h"
61#include "llvm/ADT/SmallVector.h"
62#include "llvm/ADT/StringExtras.h"
63#include "llvm/ADT/StringRef.h"
64#include "llvm/Support/Casting.h"
65#include "llvm/Support/Compiler.h"
66#include "llvm/Support/Debug.h"
67#include "llvm/Support/Error.h"
68#include "llvm/Support/FormatVariadic.h"
69#include "llvm/Support/ScopedPrinter.h"
77#define DEBUG_TYPE "CodeComplete"
82#if CLANGD_DECISION_FOREST
96toCompletionItemKind(index::SymbolKind
Kind,
97 const llvm::StringRef *
Signature =
nullptr) {
98 using SK = index::SymbolKind;
104 case SK::NamespaceAlias:
131 case SK::ConversionFunction:
135 case SK::NonTypeTemplateParm:
139 case SK::EnumConstant:
141 case SK::InstanceMethod:
142 case SK::ClassMethod:
143 case SK::StaticMethod:
146 case SK::InstanceProperty:
147 case SK::ClassProperty:
148 case SK::StaticProperty:
150 case SK::Constructor:
152 case SK::TemplateTypeParm:
153 case SK::TemplateTemplateParm:
158 llvm_unreachable(
"Unhandled clang::index::SymbolKind.");
164 CodeCompletionContext::Kind CtxKind) {
166 return toCompletionItemKind(index::getSymbolInfo(Res.Declaration).Kind);
167 if (CtxKind == CodeCompletionContext::CCC_IncludedFile)
170 case CodeCompletionResult::RK_Declaration:
171 llvm_unreachable(
"RK_Declaration without Decl");
172 case CodeCompletionResult::RK_Keyword:
174 case CodeCompletionResult::RK_Macro:
178 return Res.MacroDefInfo && Res.MacroDefInfo->isFunctionLike()
181 case CodeCompletionResult::RK_Pattern:
184 llvm_unreachable(
"Unhandled CodeCompletionResult::ResultKind.");
188MarkupContent renderDoc(
const markup::Document &Doc,
MarkupKind Kind) {
189 MarkupContent Result;
193 Result.value.append(Doc.asPlainText());
196 Result.value.append(Doc.asMarkdown());
209struct RawIdentifier {
216struct CompletionCandidate {
217 llvm::StringRef
Name;
226 size_t overloadSet(
const CodeCompleteOptions &Opts, llvm::StringRef
FileName,
227 IncludeInserter *Inserter,
228 CodeCompletionContext::Kind CCContextKind)
const {
229 if (!Opts.BundleOverloads.value_or(
false))
235 std::string HeaderForHash;
237 if (
auto Header = headerToInsertIfAllowed(Opts, CCContextKind)) {
240 Inserter->calculateIncludePath(*HeaderFile,
FileName))
243 vlog(
"Code completion header path manipulation failed {0}",
244 HeaderFile.takeError());
249 llvm::SmallString<256> Scratch;
252 case index::SymbolKind::ClassMethod:
253 case index::SymbolKind::InstanceMethod:
254 case index::SymbolKind::StaticMethod:
256 llvm_unreachable(
"Don't expect members from index in code completion");
260 case index::SymbolKind::Function:
263 return llvm::hash_combine(
273 if (!D || !D->isFunctionOrFunctionTemplate())
276 llvm::raw_svector_ostream
OS(Scratch);
277 D->printQualifiedName(
OS);
279 return llvm::hash_combine(Scratch, HeaderForHash);
285 bool contextAllowsHeaderInsertion(CodeCompletionContext::Kind
Kind)
const {
288 if (
Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
294 std::optional<llvm::StringRef>
295 headerToInsertIfAllowed(
const CodeCompleteOptions &Opts,
296 CodeCompletionContext::Kind ContextKind)
const {
299 !contextAllowsHeaderInsertion(ContextKind))
304 auto &SM =
SemaResult->Declaration->getASTContext().getSourceManager();
306 if (SM.isInMainFile(SM.getExpansionLoc(RD->getBeginLoc())))
310 for (
const auto &Inc : RankedIncludeHeaders)
316 using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
319 std::pair<CompletionCandidate::Bundle, CodeCompletion::Scores>;
320struct ScoredBundleGreater {
321 bool operator()(
const ScoredBundle &L,
const ScoredBundle &R) {
322 if (L.second.Total != R.second.Total)
323 return L.second.Total > R.second.Total;
324 return L.first.front().Name <
325 R.first.front().Name;
331std::string removeFirstTemplateArg(llvm::StringRef
Signature) {
335 return (
"<" + Rest.ltrim()).str();
345struct CodeCompletionBuilder {
346 CodeCompletionBuilder(ASTContext *ASTCtx,
const CompletionCandidate &
C,
347 CodeCompletionString *SemaCCS,
349 const IncludeInserter &Includes,
351 CodeCompletionContext::Kind ContextKind,
352 const CodeCompleteOptions &Opts,
353 bool IsUsingDeclaration, tok::TokenKind NextTokenKind)
354 : ASTCtx(ASTCtx), ArgumentLists(Opts.ArgumentLists),
355 IsUsingDeclaration(IsUsingDeclaration), NextTokenKind(NextTokenKind) {
356 Completion.Deprecated =
true;
357 add(
C, SemaCCS, ContextKind);
361 Completion.Name = std::string(llvm::StringRef(SemaCCS->getTypedText()));
362 Completion.FilterText = SemaCCS->getAllTypedText();
363 if (Completion.Scope.empty()) {
364 if ((
C.SemaResult->Kind == CodeCompletionResult::RK_Declaration) ||
365 (
C.SemaResult->Kind == CodeCompletionResult::RK_Pattern))
366 if (
const auto *D =
C.SemaResult->getDeclaration())
367 if (
const auto *ND = dyn_cast<NamedDecl>(D))
368 Completion.Scope = std::string(
371 Completion.Kind = toCompletionItemKind(*
C.SemaResult, ContextKind);
375 Completion.Name.back() ==
'/')
377 for (
const auto &
FixIt :
C.SemaResult->FixIts) {
379 FixIt, ASTCtx->getSourceManager(), ASTCtx->getLangOpts()));
381 llvm::sort(Completion.FixIts, [](
const TextEdit &
X,
const TextEdit &Y) {
382 return std::tie(X.range.start.line, X.range.start.character) <
383 std::tie(Y.range.start.line, Y.range.start.character);
387 Completion.Origin |=
C.IndexResult->Origin;
388 if (Completion.Scope.empty())
389 Completion.Scope = std::string(
C.IndexResult->Scope);
391 Completion.Kind = toCompletionItemKind(
C.IndexResult->SymInfo.Kind,
392 &
C.IndexResult->Signature);
393 if (Completion.Name.empty())
394 Completion.Name = std::string(
C.IndexResult->Name);
395 if (Completion.FilterText.empty())
396 Completion.FilterText = Completion.Name;
399 if (Completion.RequiredQualifier.empty() && !
C.SemaResult) {
400 llvm::StringRef ShortestQualifier =
C.IndexResult->Scope;
402 llvm::StringRef Qualifier =
C.IndexResult->Scope;
403 if (Qualifier.consume_front(Scope) &&
404 Qualifier.size() < ShortestQualifier.size())
405 ShortestQualifier = Qualifier;
407 Completion.RequiredQualifier = std::string(ShortestQualifier);
410 if (
C.IdentifierResult) {
413 Completion.Name = std::string(
C.IdentifierResult->Name);
414 Completion.FilterText = Completion.Name;
418 auto Inserted = [&](llvm::StringRef Header)
419 -> llvm::Expected<std::pair<std::string, bool>> {
420 auto ResolvedDeclaring =
422 if (!ResolvedDeclaring)
423 return ResolvedDeclaring.takeError();
425 if (!ResolvedInserted)
426 return ResolvedInserted.takeError();
427 auto Spelled = Includes.calculateIncludePath(*ResolvedInserted,
FileName);
429 return error(
"Header not on include path");
430 return std::make_pair(
432 Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
435 C.headerToInsertIfAllowed(Opts, ContextKind).has_value();
438 for (
const auto &Inc :
C.RankedIncludeHeaders) {
442 if (
auto ToInclude = Inserted(Inc.Header)) {
443 CodeCompletion::IncludeCandidate Include;
444 Include.Header = ToInclude->first;
445 if (ToInclude->second && ShouldInsert)
446 Include.Insertion = Includes.insert(
448 ? tooling::IncludeDirective::Import
449 : tooling::IncludeDirective::Include);
450 Completion.Includes.push_back(std::move(Include));
452 log(
"Failed to generate include insertion edits for adding header "
453 "(FileURI='{0}', IncludeHeader='{1}') into {2}: {3}",
454 C.IndexResult->CanonicalDeclaration.FileURI, Inc.Header,
FileName,
455 ToInclude.takeError());
458 std::stable_partition(Completion.Includes.begin(),
459 Completion.Includes.end(),
460 [](
const CodeCompletion::IncludeCandidate &I) {
461 return !I.Insertion.has_value();
465 void add(
const CompletionCandidate &
C, CodeCompletionString *SemaCCS,
466 CodeCompletionContext::Kind ContextKind) {
467 assert(
bool(
C.SemaResult) ==
bool(SemaCCS));
468 Bundled.emplace_back();
469 BundledEntry &S = Bundled.back();
470 bool IsConcept =
false;
472 getSignature(*SemaCCS, &S.Signature, &S.SnippetSuffix,
C.SemaResult->Kind,
473 C.SemaResult->CursorKind,
474 C.SemaResult->FunctionCanBeCall,
475 &Completion.RequiredQualifier);
477 if (
C.SemaResult->Kind == CodeCompletionResult::RK_Declaration)
478 if (
const auto *D =
C.SemaResult->getDeclaration())
479 if (isa<ConceptDecl>(D))
481 }
else if (
C.IndexResult) {
482 S.Signature = std::string(
C.IndexResult->Signature);
483 S.SnippetSuffix = std::string(
C.IndexResult->CompletionSnippetSuffix);
484 S.ReturnType = std::string(
C.IndexResult->ReturnType);
485 if (
C.IndexResult->SymInfo.Kind == index::SymbolKind::Concept)
492 if (IsConcept && ContextKind == CodeCompletionContext::CCC_TopLevel) {
493 S.Signature = removeFirstTemplateArg(S.Signature);
496 S.SnippetSuffix = removeFirstTemplateArg(S.SnippetSuffix);
499 if (!Completion.Documentation) {
500 auto SetDoc = [&](llvm::StringRef Doc) {
502 Completion.Documentation.emplace();
507 SetDoc(
C.IndexResult->Documentation);
508 }
else if (
C.SemaResult) {
514 if (Completion.Deprecated) {
516 Completion.Deprecated &=
517 C.SemaResult->Availability == CXAvailability_Deprecated;
519 Completion.Deprecated &=
524 CodeCompletion build() {
525 Completion.ReturnType = summarizeReturnType();
526 Completion.Signature = summarizeSignature();
527 Completion.SnippetSuffix = summarizeSnippet();
528 Completion.BundleSize = Bundled.size();
529 return std::move(Completion);
533 struct BundledEntry {
540 template <std::
string BundledEntry::*Member>
541 const std::string *onlyValue()
const {
542 auto B = Bundled.begin(),
E = Bundled.end();
543 for (
auto *I =
B + 1; I !=
E; ++I)
544 if (I->*Member !=
B->*Member)
546 return &(
B->*Member);
549 template <
bool BundledEntry::*Member>
const bool *onlyValue()
const {
550 auto B = Bundled.begin(),
E = Bundled.end();
551 for (
auto *I = B + 1; I !=
E; ++I)
552 if (I->*Member !=
B->*Member)
554 return &(
B->*Member);
557 std::string summarizeReturnType()
const {
558 if (
auto *RT = onlyValue<&BundledEntry::ReturnType>())
563 std::string summarizeSnippet()
const {
573 if (IsUsingDeclaration)
575 auto *
Snippet = onlyValue<&BundledEntry::SnippetSuffix>();
580 return None ?
"" : (
Open ?
"(" :
"($0)");
593 if (MayHaveArgList) {
597 if (NextTokenKind == tok::less &&
Snippet->front() ==
'<')
600 if (NextTokenKind == tok::l_paren) {
610 else if (
Snippet->at(I) ==
'<')
613 }
while (Balance > 0);
623 if (MayHaveArgList) {
632 bool EmptyArgs = llvm::StringRef(*Snippet).ends_with(
"()");
634 return None ?
"" : (
Open ?
"<" : (EmptyArgs ?
"<$1>()$0" :
"<$1>($0)"));
636 return None ?
"" : (
Open ?
"(" : (EmptyArgs ?
"()" :
"($0)"));
648 if (llvm::StringRef(*Snippet).ends_with(
"<>"))
650 return None ?
"" : (
Open ?
"<" :
"<$0>");
655 std::string summarizeSignature()
const {
656 if (
auto *
Signature = onlyValue<&BundledEntry::Signature>())
664 CodeCompletion Completion;
665 llvm::SmallVector<BundledEntry, 1> Bundled;
670 bool IsUsingDeclaration;
671 tok::TokenKind NextTokenKind;
677 case CodeCompletionResult::RK_Declaration:
678 case CodeCompletionResult::RK_Pattern: {
684 case CodeCompletionResult::RK_Macro:
686 case CodeCompletionResult::RK_Keyword:
689 llvm_unreachable(
"unknown CodeCompletionResult kind");
694struct SpecifiedScope {
731 std::vector<std::string> scopesForQualification() {
741 std::vector<std::string> scopesForIndexQuery() {
743 std::vector<std::string> EnclosingAtFront;
745 EnclosingAtFront.push_back(*EnclosingNamespace);
746 std::set<std::string> Deduplicated;
747 for (llvm::StringRef S : QueryScopes)
748 if (S != EnclosingNamespace)
751 EnclosingAtFront.reserve(EnclosingAtFront.size() + Deduplicated.size());
752 llvm::copy(Deduplicated, std::back_inserter(EnclosingAtFront));
754 return EnclosingAtFront;
761SpecifiedScope getQueryScopes(CodeCompletionContext &
CCContext,
763 const CompletionPrefix &HeuristicPrefix,
764 const CodeCompleteOptions &Opts) {
765 SpecifiedScope Scopes;
766 for (
auto *Context :
CCContext.getVisitedContexts()) {
767 if (isa<TranslationUnitDecl>(Context)) {
768 Scopes.QueryScopes.push_back(
"");
769 Scopes.AccessibleScopes.push_back(
"");
770 }
else if (
const auto *ND = dyn_cast<NamespaceDecl>(Context)) {
776 const CXXScopeSpec *SemaSpecifier =
777 CCContext.getCXXScopeSpecifier().value_or(
nullptr);
779 if (!SemaSpecifier) {
782 if (!HeuristicPrefix.
Qualifier.empty()) {
783 vlog(
"Sema said no scope specifier, but we saw {0} in the source code",
785 StringRef SpelledSpecifier = HeuristicPrefix.
Qualifier;
786 if (SpelledSpecifier.consume_front(
"::")) {
787 Scopes.AccessibleScopes = {
""};
788 Scopes.QueryScopes = {
""};
790 Scopes.UnresolvedQualifier = std::string(SpelledSpecifier);
802 if (SemaSpecifier && SemaSpecifier->isValid())
806 Scopes.QueryScopes.push_back(
"");
807 llvm::StringRef SpelledSpecifier = Lexer::getSourceText(
808 CharSourceRange::getCharRange(SemaSpecifier->getRange()),
809 CCSema.SourceMgr, clang::LangOptions());
810 if (SpelledSpecifier.consume_front(
"::"))
811 Scopes.QueryScopes = {
""};
812 Scopes.UnresolvedQualifier = std::string(SpelledSpecifier);
814 if (!Scopes.UnresolvedQualifier->empty())
815 *Scopes.UnresolvedQualifier +=
"::";
817 Scopes.AccessibleScopes = Scopes.QueryScopes;
824bool contextAllowsIndex(
enum CodeCompletionContext::Kind
K) {
826 case CodeCompletionContext::CCC_TopLevel:
827 case CodeCompletionContext::CCC_ObjCInterface:
828 case CodeCompletionContext::CCC_ObjCImplementation:
829 case CodeCompletionContext::CCC_ObjCIvarList:
830 case CodeCompletionContext::CCC_ClassStructUnion:
831 case CodeCompletionContext::CCC_Statement:
832 case CodeCompletionContext::CCC_Expression:
833 case CodeCompletionContext::CCC_ObjCMessageReceiver:
834 case CodeCompletionContext::CCC_EnumTag:
835 case CodeCompletionContext::CCC_UnionTag:
836 case CodeCompletionContext::CCC_ClassOrStructTag:
837 case CodeCompletionContext::CCC_ObjCProtocolName:
838 case CodeCompletionContext::CCC_Namespace:
839 case CodeCompletionContext::CCC_Type:
840 case CodeCompletionContext::CCC_ParenthesizedExpression:
841 case CodeCompletionContext::CCC_ObjCInterfaceName:
842 case CodeCompletionContext::CCC_Symbol:
843 case CodeCompletionContext::CCC_SymbolOrNewName:
844 case CodeCompletionContext::CCC_ObjCClassForwardDecl:
845 case CodeCompletionContext::CCC_TopLevelOrExpression:
847 case CodeCompletionContext::CCC_OtherWithMacros:
848 case CodeCompletionContext::CCC_DotMemberAccess:
849 case CodeCompletionContext::CCC_ArrowMemberAccess:
850 case CodeCompletionContext::CCC_ObjCCategoryName:
851 case CodeCompletionContext::CCC_ObjCPropertyAccess:
852 case CodeCompletionContext::CCC_MacroName:
853 case CodeCompletionContext::CCC_MacroNameUse:
854 case CodeCompletionContext::CCC_PreprocessorExpression:
855 case CodeCompletionContext::CCC_PreprocessorDirective:
856 case CodeCompletionContext::CCC_SelectorName:
857 case CodeCompletionContext::CCC_TypeQualifiers:
858 case CodeCompletionContext::CCC_ObjCInstanceMessage:
859 case CodeCompletionContext::CCC_ObjCClassMessage:
860 case CodeCompletionContext::CCC_IncludedFile:
861 case CodeCompletionContext::CCC_Attribute:
863 case CodeCompletionContext::CCC_Other:
864 case CodeCompletionContext::CCC_NaturalLanguage:
865 case CodeCompletionContext::CCC_Recovery:
866 case CodeCompletionContext::CCC_NewName:
869 llvm_unreachable(
"unknown code completion context");
872static bool isInjectedClass(
const NamedDecl &D) {
873 if (
auto *R = dyn_cast_or_null<RecordDecl>(&D))
874 if (R->isInjectedClassName())
880static bool isExcludedMember(
const NamedDecl &D) {
883 if (D.getKind() == Decl::CXXDestructor)
886 if (isInjectedClass(D))
889 auto NameKind = D.getDeclName().getNameKind();
890 if (NameKind == DeclarationName::CXXOperatorName ||
891 NameKind == DeclarationName::CXXLiteralOperatorName ||
892 NameKind == DeclarationName::CXXConversionFunctionName)
903struct CompletionRecorder :
public CodeCompleteConsumer {
904 CompletionRecorder(
const CodeCompleteOptions &Opts,
905 llvm::unique_function<
void()> ResultsCallback)
906 : CodeCompleteConsumer(Opts.getClangCompleteOpts()),
907 CCContext(CodeCompletionContext::CCC_Other), Opts(Opts),
908 CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
909 CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) {
910 assert(this->ResultsCallback);
918 void ProcessCodeCompleteResults(
class Sema &S, CodeCompletionContext Context,
919 CodeCompletionResult *InResults,
920 unsigned NumResults)
final {
929 if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
930 log(
"Code complete: Ignoring sema code complete callback with Recovery "
937 if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
940 log(
"Multiple code complete callbacks (parser backtracked?). "
941 "Dropping results from context {0}, keeping results from {1}.",
942 getCompletionKindString(Context.getKind()),
943 getCompletionKindString(this->CCContext.getKind()));
951 for (
unsigned I = 0; I < NumResults; ++I) {
952 auto &Result = InResults[I];
954 if (Result.Hidden && Result.Declaration &&
955 Result.Declaration->isCXXClassMember())
957 if (!Opts.IncludeIneligibleResults &&
958 (Result.Availability == CXAvailability_NotAvailable ||
959 Result.Availability == CXAvailability_NotAccessible))
961 if (Result.Declaration &&
962 !Context.getBaseType().isNull()
963 && isExcludedMember(*Result.Declaration))
967 if (Result.Declaration && !Context.getCXXScopeSpecifier() &&
968 isInjectedClass(*Result.Declaration))
971 Result.StartsNestedNameSpecifier =
false;
977 CodeCompletionAllocator &getAllocator()
override {
return *CCAllocator; }
978 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
982 llvm::StringRef getName(
const CodeCompletionResult &Result) {
983 switch (Result.Kind) {
984 case CodeCompletionResult::RK_Declaration:
985 if (
auto *
ID = Result.Declaration->getIdentifier())
986 return ID->getName();
988 case CodeCompletionResult::RK_Keyword:
989 return Result.Keyword;
990 case CodeCompletionResult::RK_Macro:
991 return Result.Macro->getName();
992 case CodeCompletionResult::RK_Pattern:
995 auto *CCS = codeCompletionString(Result);
996 const CodeCompletionString::Chunk *OnlyText =
nullptr;
997 for (
auto &
C : *CCS) {
998 if (
C.Kind != CodeCompletionString::CK_TypedText)
1001 return CCAllocator->CopyString(CCS->getAllTypedText());
1004 return OnlyText ? OnlyText->Text : llvm::StringRef();
1009 CodeCompletionString *codeCompletionString(
const CodeCompletionResult &R) {
1011 return const_cast<CodeCompletionResult &
>(R).CreateCodeCompletionString(
1012 *CCSema, CCContext, *CCAllocator, CCTUInfo,
1017 CodeCompleteOptions Opts;
1018 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
1019 CodeCompletionTUInfo CCTUInfo;
1020 llvm::unique_function<void()> ResultsCallback;
1023struct ScoredSignature {
1036int paramIndexForArg(
const CodeCompleteConsumer::OverloadCandidate &
Candidate,
1038 int NumParams =
Candidate.getNumParams();
1040 if (
auto *Proto =
T->getAs<FunctionProtoType>()) {
1041 if (Proto->isVariadic())
1045 return std::min(Arg, std::max(NumParams - 1, 0));
1048class SignatureHelpCollector final :
public CodeCompleteConsumer {
1050 SignatureHelpCollector(
const clang::CodeCompleteOptions &CodeCompleteOpts,
1052 const SymbolIndex *Index, SignatureHelp &SigHelp)
1053 : CodeCompleteConsumer(CodeCompleteOpts), SigHelp(SigHelp),
1054 Allocator(std::make_shared<
clang::GlobalCodeCompletionAllocator>()),
1055 CCTUInfo(Allocator), Index(Index),
1056 DocumentationFormat(DocumentationFormat) {}
1058 void ProcessOverloadCandidates(Sema &S,
unsigned CurrentArg,
1059 OverloadCandidate *Candidates,
1060 unsigned NumCandidates,
1061 SourceLocation OpenParLoc,
1062 bool Braced)
override {
1063 assert(!OpenParLoc.isInvalid());
1064 SourceManager &SrcMgr = S.getSourceManager();
1065 OpenParLoc = SrcMgr.getFileLoc(OpenParLoc);
1066 if (SrcMgr.isInMainFile(OpenParLoc))
1069 elog(
"Location oustide main file in signature help: {0}",
1070 OpenParLoc.printToString(SrcMgr));
1072 std::vector<ScoredSignature> ScoredSignatures;
1073 SigHelp.signatures.reserve(NumCandidates);
1074 ScoredSignatures.reserve(NumCandidates);
1078 SigHelp.activeSignature = 0;
1079 assert(CurrentArg <= (
unsigned)std::numeric_limits<int>::max() &&
1080 "too many arguments");
1082 SigHelp.activeParameter =
static_cast<int>(CurrentArg);
1084 for (
unsigned I = 0; I < NumCandidates; ++I) {
1085 OverloadCandidate
Candidate = Candidates[I];
1089 if (
auto *Func =
Candidate.getFunction()) {
1090 if (
auto *Pattern = Func->getTemplateInstantiationPattern())
1093 if (
static_cast<int>(I) == SigHelp.activeSignature) {
1098 SigHelp.activeParameter =
1099 paramIndexForArg(
Candidate, SigHelp.activeParameter);
1102 const auto *CCS =
Candidate.CreateSignatureString(
1103 CurrentArg, S, *Allocator, CCTUInfo,
1105 assert(CCS &&
"Expected the CodeCompletionString to be non-null");
1106 ScoredSignatures.push_back(processOverloadCandidate(
1115 llvm::DenseMap<SymbolID, std::string> FetchedDocs;
1117 LookupRequest IndexRequest;
1118 for (
const auto &S : ScoredSignatures) {
1121 IndexRequest.IDs.insert(S.IDForDoc);
1123 Index->lookup(IndexRequest, [&](
const Symbol &S) {
1124 if (!S.Documentation.empty())
1125 FetchedDocs[S.ID] = std::string(S.Documentation);
1127 vlog(
"SigHelp: requested docs for {0} symbols from the index, got {1} "
1128 "symbols with non-empty docs in the response",
1129 IndexRequest.IDs.size(), FetchedDocs.size());
1132 llvm::sort(ScoredSignatures, [](
const ScoredSignature &L,
1133 const ScoredSignature &R) {
1140 if (L.Quality.NumberOfParameters != R.Quality.NumberOfParameters)
1141 return L.Quality.NumberOfParameters < R.Quality.NumberOfParameters;
1142 if (L.Quality.NumberOfOptionalParameters !=
1143 R.Quality.NumberOfOptionalParameters)
1144 return L.Quality.NumberOfOptionalParameters <
1145 R.Quality.NumberOfOptionalParameters;
1146 if (L.Quality.Kind != R.Quality.Kind) {
1147 using OC = CodeCompleteConsumer::OverloadCandidate;
1148 auto KindPriority = [&](OC::CandidateKind K) {
1150 case OC::CK_Aggregate:
1152 case OC::CK_Function:
1154 case OC::CK_FunctionType:
1156 case OC::CK_FunctionProtoTypeLoc:
1158 case OC::CK_FunctionTemplate:
1160 case OC::CK_Template:
1163 llvm_unreachable(
"Unknown overload candidate type.");
1165 return KindPriority(L.Quality.Kind) < KindPriority(R.Quality.Kind);
1167 if (L.Signature.label.size() != R.Signature.label.size())
1168 return L.Signature.label.size() < R.Signature.label.size();
1169 return L.Signature.label < R.Signature.label;
1172 for (
auto &SS : ScoredSignatures) {
1174 SS.IDForDoc ? FetchedDocs.find(SS.IDForDoc) : FetchedDocs.end();
1175 if (IndexDocIt != FetchedDocs.end()) {
1176 markup::Document SignatureComment;
1178 SS.Signature.documentation =
1179 renderDoc(SignatureComment, DocumentationFormat);
1182 SigHelp.signatures.push_back(std::move(SS.Signature));
1186 GlobalCodeCompletionAllocator &getAllocator()
override {
return *Allocator; }
1188 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
1191 void processParameterChunk(llvm::StringRef ChunkText,
1192 SignatureInformation &
Signature)
const {
1195 unsigned ParamEndOffset = ParamStartOffset +
lspLength(ChunkText);
1200 ParameterInformation
Info;
1201 Info.labelOffsets.emplace(ParamStartOffset, ParamEndOffset);
1203 Info.labelString = std::string(ChunkText);
1208 void processOptionalChunk(
const CodeCompletionString &CCS,
1210 SignatureQualitySignals &Signal)
const {
1211 for (
const auto &Chunk : CCS) {
1212 switch (Chunk.Kind) {
1213 case CodeCompletionString::CK_Optional:
1214 assert(Chunk.Optional &&
1215 "Expected the optional code completion string to be non-null.");
1216 processOptionalChunk(*Chunk.Optional,
Signature, Signal);
1218 case CodeCompletionString::CK_VerticalSpace:
1220 case CodeCompletionString::CK_CurrentParameter:
1221 case CodeCompletionString::CK_Placeholder:
1222 processParameterChunk(Chunk.Text,
Signature);
1223 Signal.NumberOfOptionalParameters++;
1234 ScoredSignature processOverloadCandidate(
const OverloadCandidate &
Candidate,
1235 const CodeCompletionString &CCS,
1236 llvm::StringRef DocComment)
const {
1238 SignatureQualitySignals Signal;
1241 markup::Document OverloadComment;
1243 Signature.documentation = renderDoc(OverloadComment, DocumentationFormat);
1246 for (
const auto &Chunk : CCS) {
1247 switch (Chunk.Kind) {
1248 case CodeCompletionString::CK_ResultType:
1251 assert(!
ReturnType &&
"Unexpected CK_ResultType");
1254 case CodeCompletionString::CK_CurrentParameter:
1255 case CodeCompletionString::CK_Placeholder:
1256 processParameterChunk(Chunk.Text,
Signature);
1257 Signal.NumberOfParameters++;
1259 case CodeCompletionString::CK_Optional: {
1261 assert(Chunk.Optional &&
1262 "Expected the optional code completion string to be non-null.");
1263 processOptionalChunk(*Chunk.Optional,
Signature, Signal);
1266 case CodeCompletionString::CK_VerticalSpace:
1278 ScoredSignature Result;
1279 Result.Signature = std::move(
Signature);
1280 Result.Quality = Signal;
1281 const FunctionDecl *Func =
Candidate.getFunction();
1282 if (Func && Result.Signature.documentation.value.empty()) {
1290 SignatureHelp &SigHelp;
1291 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
1292 CodeCompletionTUInfo CCTUInfo;
1293 const SymbolIndex *Index;
1299class ParamNameCollector final :
public CodeCompleteConsumer {
1301 ParamNameCollector(
const clang::CodeCompleteOptions &CodeCompleteOpts,
1302 std::set<std::string> &ParamNames)
1303 : CodeCompleteConsumer(CodeCompleteOpts),
1304 Allocator(std::make_shared<
clang::GlobalCodeCompletionAllocator>()),
1305 CCTUInfo(Allocator), ParamNames(ParamNames) {}
1307 void ProcessOverloadCandidates(Sema &S,
unsigned CurrentArg,
1308 OverloadCandidate *Candidates,
1309 unsigned NumCandidates,
1310 SourceLocation OpenParLoc,
1311 bool Braced)
override {
1312 assert(CurrentArg <= (
unsigned)std::numeric_limits<int>::max() &&
1313 "too many arguments");
1315 for (
unsigned I = 0; I < NumCandidates; ++I) {
1316 if (
const NamedDecl *ND = Candidates[I].getParamDecl(CurrentArg))
1317 if (
const auto *II = ND->getIdentifier())
1318 ParamNames.emplace(II->getName());
1323 GlobalCodeCompletionAllocator &getAllocator()
override {
return *Allocator; }
1325 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
1327 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
1328 CodeCompletionTUInfo CCTUInfo;
1329 std::set<std::string> &ParamNames;
1332struct SemaCompleteInput {
1336 const std::optional<PreamblePatch>
Patch;
1340void loadMainFilePreambleMacros(
const Preprocessor &PP,
1345 ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource();
1348 const auto &ITable = PP.getIdentifierTable();
1349 IdentifierInfoLookup *PreambleIdentifiers =
1350 ITable.getExternalIdentifierLookup();
1352 if (!PreambleIdentifiers || !PreambleMacros)
1355 if (ITable.find(
MacroName.getKey()) != ITable.end())
1357 if (
auto *II = PreambleIdentifiers->get(
MacroName.getKey()))
1358 if (II->isOutOfDate())
1359 PreambleMacros->updateOutOfDateIdentifier(*II);
1365bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
1366 const clang::CodeCompleteOptions &Options,
1367 const SemaCompleteInput &Input,
1368 IncludeStructure *Includes =
nullptr) {
1369 trace::Span Tracer(
"Sema completion");
1374 elog(
"Couldn't create CompilerInvocation");
1377 auto &FrontendOpts =
CI->getFrontendOpts();
1378 FrontendOpts.SkipFunctionBodies =
true;
1380 CI->getLangOpts().SpellChecking =
false;
1384 CI->getLangOpts().DelayedTemplateParsing =
false;
1386 FrontendOpts.CodeCompleteOpts = Options;
1387 FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName);
1388 std::tie(FrontendOpts.CodeCompletionAt.Line,
1389 FrontendOpts.CodeCompletionAt.Column) =
1392 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
1393 llvm::MemoryBuffer::getMemBuffer(Input.ParseInput.Contents,
1396 CI->getDiagnosticOpts().IgnoreWarnings =
true;
1403 PreambleBounds PreambleRegion =
1404 ComputePreambleBounds(
CI->getLangOpts(), *ContentsBuffer, 0);
1405 bool CompletingInPreamble = Input.Offset < PreambleRegion.Size ||
1406 (!PreambleRegion.PreambleEndsAtStartOfLine &&
1407 Input.Offset == PreambleRegion.Size);
1409 Input.Patch->apply(*
CI);
1412 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
1413 Input.ParseInput.TFS->view(Input.ParseInput.CompileCommand.Directory);
1414 if (Input.Preamble.StatCache)
1415 VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS));
1417 std::move(
CI), !CompletingInPreamble ? &Input.Preamble.Preamble :
nullptr,
1418 std::move(ContentsBuffer), std::move(VFS),
IgnoreDiags);
1419 Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble;
1420 Clang->setCodeCompletionConsumer(Consumer.release());
1422 if (Input.Preamble.RequiredModules)
1423 Input.Preamble.RequiredModules->adjustHeaderSearchOptions(
Clang->getHeaderSearchOpts());
1427 log(
"BeginSourceFile() failed when running codeComplete for {0}",
1437 loadMainFilePreambleMacros(
Clang->getPreprocessor(), Input.Preamble);
1440 if (llvm::Error Err =
Action.Execute()) {
1441 log(
"Execute() failed when running codeComplete for {0}: {1}",
1442 Input.FileName,
toString(std::move(Err)));
1451bool allowIndex(CodeCompletionContext &
CC) {
1452 if (!contextAllowsIndex(
CC.getKind()))
1455 auto Scope =
CC.getCXXScopeSpecifier();
1458 NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
1463 switch (NameSpec->getKind()) {
1464 case NestedNameSpecifier::Global:
1465 case NestedNameSpecifier::Namespace:
1466 case NestedNameSpecifier::NamespaceAlias:
1468 case NestedNameSpecifier::Super:
1469 case NestedNameSpecifier::TypeSpec:
1470 case NestedNameSpecifier::TypeSpecWithTemplate:
1472 case NestedNameSpecifier::Identifier:
1475 llvm_unreachable(
"invalid NestedNameSpecifier kind");
1480bool includeSymbolFromIndex(CodeCompletionContext::Kind
Kind,
1481 const Symbol &Sym) {
1485 if (Sym.SymInfo.Kind == index::SymbolKind::Protocol &&
1486 Sym.SymInfo.Lang == index::SymbolLanguage::ObjC)
1487 return Kind == CodeCompletionContext::CCC_ObjCProtocolName;
1488 else if (
Kind == CodeCompletionContext::CCC_ObjCProtocolName)
1492 if (
Kind == CodeCompletionContext::CCC_ObjCClassForwardDecl)
1493 return Sym.SymInfo.Kind == index::SymbolKind::Class &&
1494 Sym.SymInfo.Lang == index::SymbolLanguage::ObjC;
1498std::future<std::pair<bool, SymbolSlab>>
1499startAsyncFuzzyFind(
const SymbolIndex &Index,
const FuzzyFindRequest &Req) {
1500 return runAsync<std::pair<bool, SymbolSlab>>([&Index, Req]() {
1501 trace::Span Tracer(
"Async fuzzyFind");
1502 SymbolSlab::Builder Syms;
1504 Index.fuzzyFind(Req, [&Syms](
const Symbol &Sym) { Syms.insert(Sym); });
1505 return std::make_pair(Incomplete, std::move(Syms).build());
1512FuzzyFindRequest speculativeFuzzyFindRequestForCompletion(
1513 FuzzyFindRequest CachedReq,
const CompletionPrefix &HeuristicPrefix) {
1514 CachedReq.Query = std::string(HeuristicPrefix.
Name);
1522findTokenAfterCompletionPoint(SourceLocation CompletionPoint,
1523 const SourceManager &SM,
1524 const LangOptions &LangOpts) {
1525 SourceLocation
Loc = CompletionPoint;
1526 if (
Loc.isMacroID()) {
1527 if (!Lexer::isAtEndOfMacroExpansion(
Loc, SM, LangOpts, &
Loc))
1528 return std::nullopt;
1536 Loc =
Loc.getLocWithOffset(1);
1539 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(
Loc);
1542 bool InvalidTemp =
false;
1543 StringRef
File = SM.getBufferData(LocInfo.first, &InvalidTemp);
1545 return std::nullopt;
1547 const char *TokenBegin =
File.data() + LocInfo.second;
1550 Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), LangOpts,
File.begin(),
1551 TokenBegin,
File.end());
1554 TheLexer.LexFromRawLexer(Tok);
1587class CodeCompleteFlow {
1589 IncludeStructure Includes;
1590 SpeculativeFuzzyFind *SpecFuzzyFind;
1591 const CodeCompleteOptions &Opts;
1594 CompletionRecorder *Recorder =
nullptr;
1595 CodeCompletionContext::Kind CCContextKind = CodeCompletionContext::CCC_Other;
1596 bool IsUsingDeclaration =
false;
1600 tok::TokenKind NextTokenKind = tok::eof;
1602 int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0;
1603 bool Incomplete =
false;
1604 CompletionPrefix HeuristicPrefix;
1605 std::optional<FuzzyMatcher> Filter;
1606 Range ReplacedRange;
1610 std::optional<ScopeDistance> ScopeProximity;
1611 std::optional<OpaqueType> PreferredType;
1613 bool AllScopes =
false;
1614 llvm::StringSet<> ContextWords;
1617 std::optional<IncludeInserter> Inserter;
1618 std::optional<URIDistance> FileProximity;
1623 std::optional<FuzzyFindRequest> SpecReq;
1627 CodeCompleteFlow(
PathRef FileName,
const IncludeStructure &Includes,
1628 SpeculativeFuzzyFind *SpecFuzzyFind,
1629 const CodeCompleteOptions &Opts)
1633 CodeCompleteResult
run(
const SemaCompleteInput &SemaCCInput) && {
1634 trace::Span Tracer(
"CodeCompleteFlow");
1636 SemaCCInput.Offset);
1637 populateContextWords(SemaCCInput.ParseInput.Contents);
1638 if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq) {
1639 assert(!SpecFuzzyFind->Result.valid());
1640 SpecReq = speculativeFuzzyFindRequestForCompletion(
1641 *SpecFuzzyFind->CachedReq, HeuristicPrefix);
1642 SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq);
1648 CodeCompleteResult
Output;
1649 auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() {
1650 assert(Recorder &&
"Recorder is not set");
1651 CCContextKind = Recorder->CCContext.getKind();
1652 IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration();
1654 SemaCCInput.ParseInput.Contents,
1655 *SemaCCInput.ParseInput.TFS,
false);
1656 const auto NextToken = findTokenAfterCompletionPoint(
1657 Recorder->CCSema->getPreprocessor().getCodeCompletionLoc(),
1658 Recorder->CCSema->getSourceManager(), Recorder->CCSema->LangOpts);
1660 NextTokenKind = NextToken->getKind();
1664 SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style,
1665 SemaCCInput.ParseInput.CompileCommand.Directory,
1666 &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
1667 for (
const auto &Inc : Includes.MainFileIncludes)
1668 Inserter->addExisting(Inc);
1674 FileDistanceOptions ProxOpts{};
1675 const auto &SM = Recorder->CCSema->getSourceManager();
1676 llvm::StringMap<SourceParams> ProxSources;
1678 Includes.getID(SM.getFileEntryForID(SM.getMainFileID()));
1680 for (
auto &HeaderIDAndDepth : Includes.includeDepth(*MainFileID)) {
1682 ProxSources[Includes.getRealPath(HeaderIDAndDepth.getFirst())];
1683 Source.Cost = HeaderIDAndDepth.getSecond() * ProxOpts.IncludeCost;
1687 if (HeaderIDAndDepth.getSecond() > 0)
1688 Source.MaxUpTraversals = 1;
1690 FileProximity.emplace(ProxSources, ProxOpts);
1695 getCompletionKindString(CCContextKind));
1696 log(
"Code complete: sema context {0}, query scopes [{1}] (AnyScope={2}), "
1697 "expected type {3}{4}",
1698 getCompletionKindString(CCContextKind),
1700 PreferredType ? Recorder->CCContext.getPreferredType().getAsString()
1702 IsUsingDeclaration ?
", inside using declaration" :
"");
1705 Recorder = RecorderOwner.get();
1707 semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(),
1708 SemaCCInput, &Includes);
1709 logResults(
Output, Tracer);
1713 void logResults(
const CodeCompleteResult &
Output,
const trace::Span &Tracer) {
1716 SPAN_ATTACH(Tracer,
"merged_results", NSemaAndIndex);
1717 SPAN_ATTACH(Tracer,
"identifier_results", NIdent);
1720 log(
"Code complete: {0} results from Sema, {1} from Index, "
1721 "{2} matched, {3} from identifiers, {4} returned{5}.",
1722 NSema, NIndex, NSemaAndIndex, NIdent,
Output.Completions.size(),
1723 Output.HasMore ?
" (incomplete)" :
"");
1724 assert(!Opts.Limit ||
Output.Completions.size() <= Opts.Limit);
1729 CodeCompleteResult runWithoutSema(llvm::StringRef Content,
size_t Offset,
1730 const ThreadsafeFS &TFS) && {
1731 trace::Span Tracer(
"CodeCompleteWithoutSema");
1734 populateContextWords(Content);
1735 CCContextKind = CodeCompletionContext::CCC_Recovery;
1736 IsUsingDeclaration =
false;
1737 Filter = FuzzyMatcher(HeuristicPrefix.Name);
1739 ReplacedRange.start = ReplacedRange.end =
Pos;
1740 ReplacedRange.start.character -= HeuristicPrefix.Name.size();
1742 llvm::StringMap<SourceParams> ProxSources;
1744 FileProximity.emplace(ProxSources);
1748 Inserter.emplace(FileName, Content, Style,
1752 std::vector<RawIdentifier> IdentifierResults;
1753 for (
const auto &IDAndCount : Identifiers) {
1755 ID.Name = IDAndCount.first();
1756 ID.References = IDAndCount.second;
1758 if (
ID.Name == HeuristicPrefix.Name)
1760 if (
ID.References > 0)
1761 IdentifierResults.push_back(std::move(
ID));
1767 SpecifiedScope Scopes;
1769 Content.take_front(
Offset), format::getFormattingLangOpts(Style));
1770 for (std::string &S : Scopes.QueryScopes)
1773 if (HeuristicPrefix.Qualifier.empty())
1774 AllScopes = Opts.AllScopes;
1775 else if (HeuristicPrefix.Qualifier.starts_with(
"::")) {
1776 Scopes.QueryScopes = {
""};
1777 Scopes.UnresolvedQualifier =
1778 std::string(HeuristicPrefix.Qualifier.drop_front(2));
1780 Scopes.UnresolvedQualifier = std::string(HeuristicPrefix.Qualifier);
1784 ScopeProximity.emplace(QueryScopes);
1786 SymbolSlab IndexResults = Opts.Index ? queryIndex() : SymbolSlab();
1788 CodeCompleteResult
Output = toCodeCompleteResult(mergeResults(
1789 {}, IndexResults, IdentifierResults));
1790 Output.RanParser =
false;
1791 logResults(
Output, Tracer);
1796 void populateContextWords(llvm::StringRef Content) {
1798 unsigned RangeEnd = HeuristicPrefix.Qualifier.begin() - Content.data(),
1799 RangeBegin = RangeEnd;
1800 for (
size_t I = 0; I < 3 && RangeBegin > 0; ++I) {
1801 auto PrevNL = Content.rfind(
'\n', RangeBegin);
1802 if (PrevNL == StringRef::npos) {
1806 RangeBegin = PrevNL;
1809 ContextWords =
collectWords(Content.slice(RangeBegin, RangeEnd));
1810 dlog(
"Completion context words: {0}",
1811 llvm::join(ContextWords.keys(),
", "));
1816 CodeCompleteResult runWithSema() {
1817 const auto &CodeCompletionRange = CharSourceRange::getCharRange(
1818 Recorder->CCSema->getPreprocessor().getCodeCompletionTokenRange());
1824 if (CodeCompletionRange.isValid()) {
1826 CodeCompletionRange);
1829 Recorder->CCSema->getSourceManager(),
1830 Recorder->CCSema->getPreprocessor().getCodeCompletionLoc());
1831 ReplacedRange.start = ReplacedRange.end =
Pos;
1833 Filter = FuzzyMatcher(
1834 Recorder->CCSema->getPreprocessor().getCodeCompletionFilter());
1835 auto SpecifiedScopes = getQueryScopes(
1836 Recorder->CCContext, *Recorder->CCSema, HeuristicPrefix, Opts);
1838 QueryScopes = SpecifiedScopes.scopesForIndexQuery();
1840 AllScopes = SpecifiedScopes.AllowAllScopes;
1842 ScopeProximity.emplace(QueryScopes);
1845 Recorder->CCContext.getPreferredType());
1851 auto IndexResults = (Opts.Index && allowIndex(Recorder->CCContext))
1854 trace::Span Tracer(
"Populate CodeCompleteResult");
1857 mergeResults(Recorder->Results, IndexResults, {});
1858 return toCodeCompleteResult(Top);
1862 toCodeCompleteResult(
const std::vector<ScoredBundle> &Scored) {
1863 CodeCompleteResult
Output;
1866 for (
auto &
C : Scored) {
1867 Output.Completions.push_back(toCodeCompletion(
C.first));
1868 Output.Completions.back().Score =
C.second;
1869 Output.Completions.back().CompletionTokenRange = ReplacedRange;
1871 Output.HasMore = Incomplete;
1872 Output.Context = CCContextKind;
1873 Output.CompletionRange = ReplacedRange;
1877 SymbolSlab queryIndex() {
1878 trace::Span Tracer(
"Query index");
1879 SPAN_ATTACH(Tracer,
"limit", int64_t(Opts.Limit));
1882 FuzzyFindRequest Req;
1884 Req.Limit = Opts.Limit;
1885 Req.Query = std::string(Filter->pattern());
1886 Req.RestrictForCodeCompletion =
true;
1888 Req.AnyScope = AllScopes;
1890 Req.ProximityPaths.push_back(std::string(FileName));
1892 Req.PreferredTypes.push_back(std::string(PreferredType->raw()));
1893 vlog(
"Code complete: fuzzyFind({0:2})",
toJSON(Req));
1896 SpecFuzzyFind->NewReq = Req;
1897 if (SpecFuzzyFind && SpecFuzzyFind->Result.valid() && (*SpecReq == Req)) {
1898 vlog(
"Code complete: speculative fuzzy request matches the actual index "
1899 "request. Waiting for the speculative index results.");
1902 trace::Span WaitSpec(
"Wait speculative results");
1903 auto SpecRes = SpecFuzzyFind->Result.get();
1904 Incomplete |= SpecRes.first;
1905 return std::move(SpecRes.second);
1908 SPAN_ATTACH(Tracer,
"Speculative results",
false);
1911 SymbolSlab::Builder ResultsBuilder;
1912 Incomplete |= Opts.Index->fuzzyFind(
1913 Req, [&](
const Symbol &Sym) { ResultsBuilder.insert(Sym); });
1914 return std::move(ResultsBuilder).build();
1922 std::vector<ScoredBundle>
1923 mergeResults(
const std::vector<CodeCompletionResult> &SemaResults,
1924 const SymbolSlab &IndexResults,
1925 const std::vector<RawIdentifier> &IdentifierResults) {
1926 trace::Span Tracer(
"Merge and score results");
1927 std::vector<CompletionCandidate::Bundle> Bundles;
1928 llvm::DenseMap<size_t, size_t> BundleLookup;
1929 auto AddToBundles = [&](
const CodeCompletionResult *
SemaResult,
1932 CompletionCandidate
C;
1936 if (
C.IndexResult) {
1939 }
else if (
C.SemaResult) {
1945 if (
auto OverloadSet =
C.overloadSet(
1946 Opts, FileName, Inserter ? &*Inserter :
nullptr, CCContextKind)) {
1947 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
1949 Bundles.emplace_back();
1950 Bundles[Ret.first->second].push_back(std::move(
C));
1952 Bundles.emplace_back();
1953 Bundles.back().push_back(std::move(
C));
1956 llvm::DenseSet<const Symbol *> UsedIndexResults;
1957 auto CorrespondingIndexResult =
1958 [&](
const CodeCompletionResult &
SemaResult) ->
const Symbol * {
1961 auto I = IndexResults.find(SymID);
1962 if (I != IndexResults.end()) {
1963 UsedIndexResults.insert(&*I);
1976 if (!includeSymbolFromIndex(CCContextKind,
IndexResult))
1981 for (
const auto &Ident : IdentifierResults)
1982 AddToBundles(
nullptr,
nullptr, &Ident);
1984 TopN<ScoredBundle, ScoredBundleGreater> Top(
1985 Opts.Limit == 0 ? std::numeric_limits<size_t>::max() : Opts.Limit);
1986 for (
auto &Bundle : Bundles)
1987 addCandidate(Top, std::move(Bundle));
1988 return std::move(Top).items();
1991 std::optional<float> fuzzyScore(
const CompletionCandidate &
C) {
1993 if (((
C.SemaResult &&
1994 C.SemaResult->Kind == CodeCompletionResult::RK_Macro) ||
1996 C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)) &&
1997 !
C.Name.starts_with_insensitive(Filter->pattern()))
1998 return std::nullopt;
1999 return Filter->match(
C.Name);
2002 CodeCompletion::Scores
2003 evaluateCompletion(
const SymbolQualitySignals &
Quality,
2004 const SymbolRelevanceSignals &Relevance) {
2006 CodeCompletion::Scores Scores;
2007 switch (Opts.RankingModel) {
2008 case RM::Heuristics:
2009 Scores.Quality =
Quality.evaluateHeuristics();
2010 Scores.Relevance = Relevance.evaluateHeuristics();
2015 Scores.ExcludingName =
2016 Relevance.NameMatch > std::numeric_limits<float>::epsilon()
2017 ? Scores.Total / Relevance.NameMatch
2021 case RM::DecisionForest:
2022 DecisionForestScores DFScores = Opts.DecisionForestScorer(
2023 Quality, Relevance, Opts.DecisionForestBase);
2024 Scores.ExcludingName = DFScores.ExcludingName;
2025 Scores.Total = DFScores.Total;
2028 llvm_unreachable(
"Unhandled CodeCompletion ranking model.");
2032 void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates,
2033 CompletionCandidate::Bundle Bundle) {
2035 SymbolRelevanceSignals Relevance;
2036 Relevance.Context = CCContextKind;
2037 Relevance.Name = Bundle.front().Name;
2038 Relevance.FilterLength = HeuristicPrefix.Name.size();
2040 Relevance.FileProximityMatch = &*FileProximity;
2042 Relevance.ScopeProximityMatch = &*ScopeProximity;
2044 Relevance.HadContextType =
true;
2045 Relevance.ContextWords = &ContextWords;
2046 Relevance.MainFileSignals = Opts.MainFileSignals;
2048 auto &First = Bundle.front();
2049 if (
auto FuzzyScore = fuzzyScore(First))
2050 Relevance.NameMatch = *FuzzyScore;
2054 bool FromIndex =
false;
2058 Relevance.merge(*
Candidate.IndexResult);
2059 Origin |=
Candidate.IndexResult->Origin;
2061 if (!
Candidate.IndexResult->Type.empty())
2062 Relevance.HadSymbolType |=
true;
2063 if (PreferredType &&
2064 PreferredType->raw() ==
Candidate.IndexResult->Type) {
2065 Relevance.TypeMatchesPreferred =
true;
2071 if (PreferredType) {
2073 Recorder->CCSema->getASTContext(), *
Candidate.SemaResult)) {
2074 Relevance.HadSymbolType |=
true;
2075 if (PreferredType == CompletionType)
2076 Relevance.TypeMatchesPreferred =
true;
2088 CodeCompletion::Scores Scores = evaluateCompletion(
Quality, Relevance);
2089 if (Opts.RecordCCResult)
2090 Opts.RecordCCResult(toCodeCompletion(Bundle),
Quality, Relevance,
2093 dlog(
"CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
2094 llvm::to_string(Origin), Scores.Total, llvm::to_string(
Quality),
2095 llvm::to_string(Relevance));
2098 NIndex += FromIndex;
2101 if (Candidates.push({std::move(Bundle), Scores}))
2105 CodeCompletion toCodeCompletion(
const CompletionCandidate::Bundle &Bundle) {
2106 std::optional<CodeCompletionBuilder>
Builder;
2107 for (
const auto &Item : Bundle) {
2108 CodeCompletionString *SemaCCS =
2109 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult)
2112 Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() :
nullptr,
2113 Item, SemaCCS, AccessibleScopes, *Inserter, FileName,
2114 CCContextKind, Opts, IsUsingDeclaration, NextTokenKind);
2116 Builder->add(Item, SemaCCS, CCContextKind);
2124clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts()
const {
2125 clang::CodeCompleteOptions Result;
2126 Result.IncludeCodePatterns = EnableSnippets;
2127 Result.IncludeMacros =
true;
2128 Result.IncludeGlobals =
true;
2133 Result.IncludeBriefComments =
false;
2138 Result.LoadExternal = ForceLoadPreamble || !Index;
2139 Result.IncludeFixIts = IncludeFixIts;
2146 assert(
Offset <= Content.size());
2147 StringRef Rest = Content.take_front(
Offset);
2152 while (!Rest.empty() && isAsciiIdentifierContinue(Rest.back()))
2153 Rest = Rest.drop_back();
2154 Result.Name = Content.slice(Rest.size(),
Offset);
2157 while (Rest.consume_back(
"::") && !Rest.ends_with(
":"))
2158 while (!Rest.empty() && isAsciiIdentifierContinue(Rest.back()))
2159 Rest = Rest.drop_back();
2161 Content.slice(Rest.size(), Result.Name.begin() - Content.begin());
2170 llvm::StringRef Prefix,
2176 clang::CodeCompleteOptions Options;
2177 Options.IncludeGlobals =
false;
2178 Options.IncludeMacros =
false;
2179 Options.IncludeCodePatterns =
false;
2180 Options.IncludeBriefComments =
false;
2181 std::set<std::string> ParamNames;
2185 std::make_unique<ParamNameCollector>(Options, ParamNames), Options,
2189 if (ParamNames.empty())
2193 Range CompletionRange;
2197 CompletionRange.
end =
2199 Result.CompletionRange = CompletionRange;
2200 Result.Context = CodeCompletionContext::CCC_NaturalLanguage;
2201 for (llvm::StringRef
Name : ParamNames) {
2202 if (!
Name.starts_with(Prefix))
2207 Item.
Kind = CompletionItemKind::Text;
2209 Item.
Origin = SymbolOrigin::AST;
2210 Result.Completions.push_back(Item);
2219std::optional<unsigned>
2221 while (!Content.empty() && isAsciiIdentifierContinue(Content.back()))
2222 Content = Content.drop_back();
2223 Content = Content.rtrim();
2224 if (Content.ends_with(
"/*"))
2225 return Content.size() - 2;
2226 return std::nullopt;
2236 elog(
"Code completion position was invalid {0}",
Offset.takeError());
2247 auto CommentPrefix = Content.substr(*OffsetBeforeComment + 2).trim();
2252 auto Flow = CodeCompleteFlow(
2254 SpecFuzzyFind, Opts);
2255 return (!
Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse)
2260 PreamblePatch::createMacroPatch(
2271 elog(
"Signature help position was invalid {0}",
Offset.takeError());
2275 clang::CodeCompleteOptions Options;
2276 Options.IncludeGlobals =
false;
2277 Options.IncludeMacros =
false;
2278 Options.IncludeCodePatterns =
false;
2279 Options.IncludeBriefComments =
false;
2281 std::make_unique<SignatureHelpCollector>(Options, DocumentationFormat,
2284 {FileName, *Offset, Preamble,
2285 PreamblePatch::createFullPatch(FileName, ParseInput, Preamble),
2291 auto InTopLevelScope = [](
const NamedDecl &ND) {
2292 switch (ND.getDeclContext()->getDeclKind()) {
2293 case Decl::TranslationUnit:
2294 case Decl::Namespace:
2295 case Decl::LinkageSpec:
2302 auto InClassScope = [](
const NamedDecl &ND) {
2303 return ND.getDeclContext()->getDeclKind() == Decl::CXXRecord;
2314 if (llvm::isa<ObjCCategoryDecl>(&ND) || llvm::isa<ObjCCategoryImplDecl>(&ND))
2317 if (InTopLevelScope(ND))
2323 if (
const auto *EnumDecl = dyn_cast<clang::EnumDecl>(ND.getDeclContext()))
2324 return (InTopLevelScope(*EnumDecl) || InClassScope(*EnumDecl));
2331 const auto *InsertInclude = Includes.empty() ? nullptr : &Includes[0];
2334 LSP.
label = ((InsertInclude && InsertInclude->Insertion)
2335 ? Opts.IncludeIndicator.Insert
2336 : Opts.IncludeIndicator.NoInsert) +
2337 (Opts.ShowOrigins ?
"[" + llvm::to_string(Origin) +
"]" :
"") +
2338 RequiredQualifier +
Name;
2343 LSP.
detail = BundleSize > 1
2344 ? std::string(llvm::formatv(
"[{0} overloads]", BundleSize))
2349 if (InsertInclude || Documentation) {
2354 Doc.
append(*Documentation);
2355 LSP.
documentation = renderDoc(Doc, Opts.DocumentationFormat);
2359 LSP.
textEdit = {CompletionTokenRange, RequiredQualifier +
Name,
""};
2367 for (
const auto &
FixIt : FixIts) {
2375 if (Opts.EnableSnippets)
2385 ? InsertTextFormat::Snippet
2386 : InsertTextFormat::PlainText;
2387 if (InsertInclude && InsertInclude->Insertion)
2403 <<
" (" << getCompletionKindString(R.
Context) <<
")"
2413 if (!
Line.consume_front(
"#"))
2416 if (!(
Line.consume_front(
"include_next") ||
Line.consume_front(
"include") ||
2417 Line.consume_front(
"import")))
2420 if (
Line.consume_front(
"<"))
2421 return Line.count(
'>') == 0;
2422 if (
Line.consume_front(
"\""))
2423 return Line.count(
'"') == 0;
2429 Content = Content.take_front(
Offset);
2430 auto Pos = Content.rfind(
'\n');
2431 if (
Pos != llvm::StringRef::npos)
2432 Content = Content.substr(
Pos + 1);
2435 if (Content.ends_with(
".") || Content.ends_with(
"->") ||
2436 Content.ends_with(
"::") || Content.ends_with(
"/*"))
2439 if ((Content.ends_with(
"<") || Content.ends_with(
"\"") ||
2440 Content.ends_with(
"/")) &&
2445 return !Content.empty() && (isAsciiIdentifierContinue(Content.back()) ||
2446 !llvm::isASCII(Content.back()));
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
const ParseInputs & ParseInput
std::vector< std::string > AccessibleScopes
std::optional< std::string > UnresolvedQualifier
CodeCompletionContext CCContext
llvm::SmallVector< SymbolInclude, 1 > RankedIncludeHeaders
const RawIdentifier * IdentifierResult
const Symbol * IndexResult
std::vector< std::string > QueryScopes
std::vector< CodeCompletionResult > Results
std::optional< std::string > EnclosingNamespace
const std::optional< PreamblePatch > Patch
std::string SnippetSuffix
SignatureQualitySignals Quality
const PreambleData & Preamble
const CodeCompletionResult * SemaResult
CodeCompletionBuilder Builder
std::optional< float > Score
CharSourceRange Range
SourceRange for the file name.
const MacroDirective * Directive
std::unique_ptr< CompilerInvocation > CI
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
std::optional< FixItHint > FixIt
void collect(const CompilerInstance &CI)
static std::optional< OpaqueType > fromCompletionResult(ASTContext &Ctx, const CodeCompletionResult &R)
Create a type from a code completion result.
static std::optional< OpaqueType > fromType(ASTContext &Ctx, QualType Type)
Construct an instance from a clang::QualType.
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
A format-agnostic representation for structured text.
Paragraph & addParagraph()
Adds a semantical block that will be separate from others.
void append(Document Other)
Paragraph & appendText(llvm::StringRef Text)
Append plain text to the end of the string.
Paragraph & appendCode(llvm::StringRef Code, bool Preserve=false)
Append inline code, this translates to the ` block in markdown.
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
@ Info
An information message.
SymbolID getSymbolID(const Decl *D)
Gets the symbol ID for a declaration. Returned SymbolID might be null.
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
bool isIncludeFile(llvm::StringRef Line)
TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M, const LangOptions &L)
Position offsetToPosition(llvm::StringRef Code, size_t Offset)
Turn an offset in Code into a [line, column] pair.
size_t lspLength(llvm::StringRef Code)
CompletionPrefix guessCompletionPrefix(llvm::StringRef Content, unsigned Offset)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D, std::vector< std::string > *CC1Args)
Builds compiler invocation that could be used to build AST or preamble.
bool isExplicitTemplateSpecialization(const NamedDecl *D)
Indicates if D is an explicit template specialization, e.g.
CompletionItemKind
The kind of a completion entry.
bool allowImplicitCompletion(llvm::StringRef Content, unsigned Offset)
void vlog(const char *Fmt, Ts &&... Vals)
static const char * toString(OffsetEncoding OE)
CodeCompleteResult codeCompleteComment(PathRef FileName, unsigned Offset, llvm::StringRef Prefix, const PreambleData *Preamble, const ParseInputs &ParseInput)
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&... Vals)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
llvm::StringMap< unsigned > collectIdentifiers(llvm::StringRef Content, const format::FormatStyle &Style)
Collects identifiers with counts in the source code.
bool hasUnstableLinkage(const Decl *D)
Whether we must avoid computing linkage for D during code completion.
llvm::json::Value toJSON(const FuzzyFindRequest &Request)
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const LangOptions &LangOpts)
Heuristically determine namespaces visible at a point, without parsing Code.
llvm::Expected< HeaderFile > toHeaderFile(llvm::StringRef Header, llvm::StringRef HintPath)
Creates a HeaderFile from Header which can be either a URI or a literal include.
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
void log(const char *Fmt, Ts &&... Vals)
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
std::optional< unsigned > maybeFunctionArgumentCommentStart(llvm::StringRef Content)
llvm::StringSet collectWords(llvm::StringRef Content)
Collects words from the source code.
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, CodeCompletionResult::ResultKind ResultKind, CXCursorKind CursorKind, bool IncludeFunctionArguments, std::string *RequiredQualifiers)
Formats the signature for an item, as a display string and snippet.
llvm::SmallVector< SymbolInclude, 1 > getRankedIncludes(const Symbol &Sym)
std::pair< size_t, size_t > offsetToClangLineColumn(llvm::StringRef Code, size_t Offset)
@ Deprecated
Deprecated or obsolete code.
@ Full
Documents are synced by always sending the full content of the document.
void parseDocumentation(llvm::StringRef Input, markup::Document &Output)
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
CodeCompleteResult codeComplete(PathRef FileName, Position Pos, const PreambleData *Preamble, const ParseInputs &ParseInput, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
Gets code completions at a specified Pos in FileName.
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
SignatureHelp signatureHelp(PathRef FileName, Position Pos, const PreambleData &Preamble, const ParseInputs &ParseInput, MarkupKind DocumentationFormat)
Get signature help at a specified Pos in FileName.
void elog(const char *Fmt, Ts &&... Vals)
std::string getDocComment(const ASTContext &Ctx, const CodeCompletionResult &Result, bool CommentsFromHeaders)
Gets a minimally formatted documentation comment of Result, with comment markers stripped.
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx)
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, const ThreadsafeFS &TFS, bool FormatFile)
Choose the clang-format style we should apply to a certain file.
std::array< uint8_t, 20 > SymbolID
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Symbol::IncludeDirective InsertionDirective
Preferred preprocessor directive to use for inclusions by the file.
static const CodeCompletionRankingModel DefaultRankingModel
CodeCompletionRankingModel
Model to use for ranking code completion candidates.
const ASTSignals * MainFileSignals
bool ImportInsertions
Whether include insertions for Objective-C code should use #import instead of #include.
bool AllScopes
Whether to include index symbols that are not defined in the scopes visible from the code completion ...
std::vector< CodeCompletion > Completions
CodeCompletionContext::Kind Context
Range CompletionTokenRange
Holds the range of the token we are going to replace with this completion.
std::string sortText
A string that should be used when comparing this item with other items.
std::optional< TextEdit > textEdit
An edit which is applied to a document when selecting this completion.
std::string filterText
A string that should be used when filtering a set of completion items.
std::string detail
A human-readable string with additional information about this item, like type or symbol information.
InsertTextFormat insertTextFormat
The format of the insert text.
CompletionItemKind kind
The kind of this completion item.
std::vector< TextEdit > additionalTextEdits
An optional array of additional text edits that are applied when selecting this completion.
std::optional< MarkupContent > documentation
A human-readable string that represents a doc-comment.
std::string insertText
A string that should be inserted to a document when selecting this completion.
bool deprecated
Indicates if this item is deprecated.
std::optional< CompletionItemLabelDetails > labelDetails
Additional details for the label.
float score
The score that clangd calculates to rank the returned completions.
std::string label
The label of this completion item.
llvm::StringRef Qualifier
ArgumentListsPolicy
controls the completion options for argument lists.
@ None
nothing, no argument list and also NO Delimiters "()" or "<>".
@ Delimiters
empty pair of delimiters "()" or "<>".
@ OpenDelimiter
open, only opening delimiter "(" or "<".
@ FullPlaceholders
full name of both type and variable.
The parsed preamble and associated data.
Position start
The range's start position.
Position end
The range's end position.
Represents the signature of a callable.
A speculative and asynchronous fuzzy find index request (based on cached request) that can be sent be...
@ Deprecated
Indicates if the symbol is deprecated.
@ Include
#include "header.h"
@ Import
#import "header.h"