41 #include "clang/AST/Decl.h" 42 #include "clang/AST/DeclBase.h" 43 #include "clang/Basic/CharInfo.h" 44 #include "clang/Basic/LangOptions.h" 45 #include "clang/Basic/SourceLocation.h" 46 #include "clang/Format/Format.h" 47 #include "clang/Frontend/CompilerInstance.h" 48 #include "clang/Frontend/FrontendActions.h" 49 #include "clang/Lex/ExternalPreprocessorSource.h" 50 #include "clang/Lex/Preprocessor.h" 51 #include "clang/Lex/PreprocessorOptions.h" 52 #include "clang/Sema/CodeCompleteConsumer.h" 53 #include "clang/Sema/DeclSpec.h" 54 #include "clang/Sema/Sema.h" 55 #include "llvm/ADT/ArrayRef.h" 56 #include "llvm/ADT/None.h" 57 #include "llvm/ADT/Optional.h" 58 #include "llvm/ADT/SmallVector.h" 59 #include "llvm/ADT/StringExtras.h" 60 #include "llvm/ADT/StringRef.h" 61 #include "llvm/Support/Compiler.h" 62 #include "llvm/Support/Debug.h" 63 #include "llvm/Support/Error.h" 64 #include "llvm/Support/Format.h" 65 #include "llvm/Support/FormatVariadic.h" 66 #include "llvm/Support/ScopedPrinter.h" 71 #define DEBUG_TYPE "CodeComplete" 84 case SK::NamespaceAlias:
107 case SK::ConversionFunction:
117 case SK::InstanceMethod:
118 case SK::ClassMethod:
122 case SK::InstanceProperty:
123 case SK::ClassProperty:
124 case SK::StaticProperty:
129 llvm_unreachable(
"Unhandled clang::index::SymbolKind.");
133 toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
134 const NamedDecl *
Decl,
138 if (CtxKind == CodeCompletionContext::CCC_IncludedFile)
141 case CodeCompletionResult::RK_Declaration:
142 llvm_unreachable(
"RK_Declaration without Decl");
143 case CodeCompletionResult::RK_Keyword:
145 case CodeCompletionResult::RK_Macro:
148 case CodeCompletionResult::RK_Pattern:
151 llvm_unreachable(
"Unhandled CodeCompletionResult::ResultKind.");
155 struct RawIdentifier {
162 struct CompletionCandidate {
163 llvm::StringRef
Name;
172 size_t overloadSet(
const CodeCompleteOptions &Opts)
const {
173 if (!Opts.BundleOverloads.getValueOr(
false))
175 llvm::SmallString<256> Scratch;
177 switch (IndexResult->SymInfo.Kind) {
178 case index::SymbolKind::ClassMethod:
179 case index::SymbolKind::InstanceMethod:
180 case index::SymbolKind::StaticMethod:
182 llvm_unreachable(
"Don't expect members from index in code completion");
186 case index::SymbolKind::Function:
189 return llvm::hash_combine(
190 (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch),
191 headerToInsertIfAllowed(Opts).getValueOr(
""));
198 const NamedDecl *D = SemaResult->Declaration;
199 if (!D || !D->isFunctionOrFunctionTemplate())
202 llvm::raw_svector_ostream OS(Scratch);
203 D->printQualifiedName(OS);
205 return llvm::hash_combine(Scratch,
206 headerToInsertIfAllowed(Opts).getValueOr(
""));
208 assert(IdentifierResult);
213 llvm::Optional<llvm::StringRef>
214 headerToInsertIfAllowed(
const CodeCompleteOptions &Opts)
const {
216 RankedIncludeHeaders.empty())
218 if (SemaResult && SemaResult->Declaration) {
221 auto &SM = SemaResult->Declaration->getASTContext().getSourceManager();
222 for (
const Decl *RD : SemaResult->Declaration->redecls())
223 if (SM.isInMainFile(SM.getExpansionLoc(RD->getBeginLoc())))
226 return RankedIncludeHeaders[0];
229 using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
232 std::pair<CompletionCandidate::Bundle, CodeCompletion::Scores>;
233 struct ScoredBundleGreater {
234 bool operator()(
const ScoredBundle &L,
const ScoredBundle &R) {
235 if (L.second.Total != R.second.Total)
236 return L.second.Total > R.second.Total;
237 return L.first.front().Name <
238 R.first.front().Name;
249 struct CodeCompletionBuilder {
250 CodeCompletionBuilder(ASTContext *ASTCtx,
const CompletionCandidate &C,
251 CodeCompletionString *SemaCCS,
252 llvm::ArrayRef<std::string> QueryScopes,
253 const IncludeInserter &Includes,
256 const CodeCompleteOptions &Opts,
bool GenerateSnippets)
257 : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments),
258 EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets),
259 GenerateSnippets(GenerateSnippets) {
264 Completion.Name = llvm::StringRef(SemaCCS->getTypedText());
265 if (Completion.Scope.empty()) {
266 if ((C.SemaResult->Kind == CodeCompletionResult::RK_Declaration) ||
267 (C.SemaResult->Kind == CodeCompletionResult::RK_Pattern))
268 if (
const auto *D = C.SemaResult->getDeclaration())
269 if (
const auto *ND = dyn_cast<NamedDecl>(D))
273 Completion.Kind = toCompletionItemKind(
274 C.SemaResult->Kind, C.SemaResult->Declaration, ContextKind);
278 Completion.Name.back() ==
'/')
280 for (
const auto &
FixIt : C.SemaResult->FixIts) {
282 FixIt, ASTCtx->getSourceManager(), ASTCtx->getLangOpts()));
284 llvm::sort(Completion.FixIts, [](
const TextEdit &
X,
const TextEdit &Y) {
285 return std::tie(X.range.start.line, X.range.start.character) <
286 std::tie(Y.range.start.line, Y.range.start.character);
288 Completion.Deprecated |=
289 (C.SemaResult->Availability == CXAvailability_Deprecated);
292 Completion.Origin |= C.IndexResult->Origin;
293 if (Completion.Scope.empty())
294 Completion.Scope = C.IndexResult->Scope;
296 Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
297 if (Completion.Name.empty())
298 Completion.Name = C.IndexResult->Name;
301 if (Completion.RequiredQualifier.empty() && !C.SemaResult) {
302 llvm::StringRef ShortestQualifier = C.IndexResult->Scope;
303 for (llvm::StringRef Scope : QueryScopes) {
304 llvm::StringRef Qualifier = C.IndexResult->Scope;
305 if (Qualifier.consume_front(Scope) &&
306 Qualifier.size() < ShortestQualifier.size())
307 ShortestQualifier = Qualifier;
309 Completion.RequiredQualifier = ShortestQualifier;
313 if (C.IdentifierResult) {
316 Completion.Name = C.IdentifierResult->Name;
320 auto Inserted = [&](llvm::StringRef Header)
322 auto ResolvedDeclaring =
323 URI::resolve(C.IndexResult->CanonicalDeclaration.FileURI, FileName);
324 if (!ResolvedDeclaring)
325 return ResolvedDeclaring.takeError();
327 if (!ResolvedInserted)
328 return ResolvedInserted.takeError();
329 auto Spelled = Includes.calculateIncludePath(*ResolvedInserted, FileName);
331 return llvm::createStringError(llvm::inconvertibleErrorCode(),
332 "Header not on include path");
333 return std::make_pair(
335 Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
337 bool ShouldInsert = C.headerToInsertIfAllowed(Opts).hasValue();
339 for (
const auto &Inc : C.RankedIncludeHeaders) {
340 if (
auto ToInclude = Inserted(Inc)) {
341 CodeCompletion::IncludeCandidate Include;
342 Include.Header = ToInclude->first;
343 if (ToInclude->second && ShouldInsert)
344 Include.Insertion = Includes.insert(ToInclude->first);
345 Completion.Includes.push_back(std::move(Include));
347 log(
"Failed to generate include insertion edits for adding header " 348 "(FileURI='{0}', IncludeHeader='{1}') into {2}: {3}",
349 C.IndexResult->CanonicalDeclaration.FileURI, Inc, FileName,
350 ToInclude.takeError());
353 std::stable_partition(Completion.Includes.begin(),
354 Completion.Includes.end(),
355 [](
const CodeCompletion::IncludeCandidate &I) {
356 return !I.Insertion.hasValue();
360 void add(
const CompletionCandidate &C, CodeCompletionString *SemaCCS) {
361 assert(
bool(C.SemaResult) ==
bool(SemaCCS));
362 Bundled.emplace_back();
363 BundledEntry &S = Bundled.back();
365 bool IsPattern = C.SemaResult->Kind == CodeCompletionResult::RK_Pattern;
367 &Completion.RequiredQualifier, IsPattern);
369 }
else if (C.IndexResult) {
370 S.Signature = C.IndexResult->Signature;
371 S.SnippetSuffix = C.IndexResult->CompletionSnippetSuffix;
372 S.ReturnType = C.IndexResult->ReturnType;
374 if (ExtractDocumentation && Completion.Documentation.empty()) {
376 Completion.Documentation = C.IndexResult->Documentation;
377 else if (C.SemaResult)
378 Completion.Documentation =
getDocComment(*ASTCtx, *C.SemaResult,
383 CodeCompletion build() {
384 Completion.ReturnType = summarizeReturnType();
385 Completion.Signature = summarizeSignature();
386 Completion.SnippetSuffix = summarizeSnippet();
387 Completion.BundleSize = Bundled.size();
388 return std::move(Completion);
392 struct BundledEntry {
399 template <std::
string BundledEntry::*Member>
400 const std::string *onlyValue()
const {
401 auto B = Bundled.begin(),
E = Bundled.end();
402 for (
auto I = B + 1; I !=
E; ++I)
403 if (I->*Member != B->*Member)
405 return &(B->*Member);
408 template <
bool BundledEntry::*Member>
const bool *onlyValue()
const {
409 auto B = Bundled.begin(),
E = Bundled.end();
410 for (
auto I = B + 1; I !=
E; ++I)
411 if (I->*Member != B->*Member)
413 return &(B->*Member);
416 std::string summarizeReturnType()
const {
417 if (
auto *RT = onlyValue<&BundledEntry::ReturnType>())
422 std::string summarizeSnippet()
const {
423 if (!GenerateSnippets)
425 auto *
Snippet = onlyValue<&BundledEntry::SnippetSuffix>();
431 if (EnableFunctionArgSnippets)
447 bool EmptyArgs = llvm::StringRef(*Snippet).endswith(
"()");
449 return EmptyArgs ?
"<$1>()$0" :
"<$1>($0)";
451 return EmptyArgs ?
"()" :
"($0)";
462 if (llvm::StringRef(*Snippet).endswith(
"<>"))
469 std::string summarizeSignature()
const {
470 if (
auto *
Signature = onlyValue<&BundledEntry::Signature>())
478 CodeCompletion Completion;
479 llvm::SmallVector<BundledEntry, 1> Bundled;
480 bool ExtractDocumentation;
481 bool EnableFunctionArgSnippets;
483 bool GenerateSnippets;
487 llvm::Optional<SymbolID>
getSymbolID(
const CodeCompletionResult &R,
488 const SourceManager &SM) {
490 case CodeCompletionResult::RK_Declaration:
491 case CodeCompletionResult::RK_Pattern: {
494 case CodeCompletionResult::RK_Macro:
496 case CodeCompletionResult::RK_Keyword:
499 llvm_unreachable(
"unknown CodeCompletionResult kind");
504 struct SpecifiedScope {
532 std::vector<std::string> scopesForIndexQuery() {
534 for (llvm::StringRef AS : AccessibleScopes)
536 (AS + (UnresolvedQualifier ? *UnresolvedQualifier :
"")).str());
537 return {Results.begin(), Results.end()};
544 std::pair<std::vector<std::string>,
bool>
546 const CompletionPrefix &HeuristicPrefix,
547 const CodeCompleteOptions &Opts) {
548 SpecifiedScope Scopes;
549 for (
auto *Context : CCContext.getVisitedContexts()) {
550 if (isa<TranslationUnitDecl>(Context))
551 Scopes.AccessibleScopes.push_back(
"");
552 else if (isa<NamespaceDecl>(Context))
556 const CXXScopeSpec *SemaSpecifier =
557 CCContext.getCXXScopeSpecifier().getValueOr(
nullptr);
559 if (!SemaSpecifier) {
562 if (!HeuristicPrefix.Qualifier.empty()) {
563 vlog(
"Sema said no scope specifier, but we saw {0} in the source code",
564 HeuristicPrefix.Qualifier);
565 StringRef SpelledSpecifier = HeuristicPrefix.Qualifier;
566 if (SpelledSpecifier.consume_front(
"::"))
567 Scopes.AccessibleScopes = {
""};
568 Scopes.UnresolvedQualifier = SpelledSpecifier;
569 return {Scopes.scopesForIndexQuery(),
false};
572 std::vector<std::string> EnclosingAtFront;
574 EnclosingAtFront.push_back(EnclosingScope);
575 for (
auto &S : Scopes.scopesForIndexQuery()) {
576 if (EnclosingScope != S)
577 EnclosingAtFront.push_back(std::move(S));
580 return {EnclosingAtFront, Opts.AllScopes};
583 if (SemaSpecifier && SemaSpecifier->isValid())
584 return {Scopes.scopesForIndexQuery(),
false};
587 Scopes.AccessibleScopes.push_back(
"");
588 llvm::StringRef SpelledSpecifier = Lexer::getSourceText(
589 CharSourceRange::getCharRange(SemaSpecifier->getRange()),
590 CCSema.SourceMgr, clang::LangOptions());
591 if (SpelledSpecifier.consume_front(
"::"))
592 Scopes.AccessibleScopes = {
""};
593 Scopes.UnresolvedQualifier = SpelledSpecifier;
595 if (!Scopes.UnresolvedQualifier->empty())
596 *Scopes.UnresolvedQualifier +=
"::";
598 return {Scopes.scopesForIndexQuery(),
false};
605 case CodeCompletionContext::CCC_TopLevel:
606 case CodeCompletionContext::CCC_ObjCInterface:
607 case CodeCompletionContext::CCC_ObjCImplementation:
608 case CodeCompletionContext::CCC_ObjCIvarList:
609 case CodeCompletionContext::CCC_ClassStructUnion:
610 case CodeCompletionContext::CCC_Statement:
611 case CodeCompletionContext::CCC_Expression:
612 case CodeCompletionContext::CCC_ObjCMessageReceiver:
613 case CodeCompletionContext::CCC_EnumTag:
614 case CodeCompletionContext::CCC_UnionTag:
615 case CodeCompletionContext::CCC_ClassOrStructTag:
616 case CodeCompletionContext::CCC_ObjCProtocolName:
617 case CodeCompletionContext::CCC_Namespace:
618 case CodeCompletionContext::CCC_Type:
619 case CodeCompletionContext::CCC_ParenthesizedExpression:
620 case CodeCompletionContext::CCC_ObjCInterfaceName:
621 case CodeCompletionContext::CCC_ObjCCategoryName:
622 case CodeCompletionContext::CCC_Symbol:
623 case CodeCompletionContext::CCC_SymbolOrNewName:
625 case CodeCompletionContext::CCC_OtherWithMacros:
626 case CodeCompletionContext::CCC_DotMemberAccess:
627 case CodeCompletionContext::CCC_ArrowMemberAccess:
628 case CodeCompletionContext::CCC_ObjCPropertyAccess:
629 case CodeCompletionContext::CCC_MacroName:
630 case CodeCompletionContext::CCC_MacroNameUse:
631 case CodeCompletionContext::CCC_PreprocessorExpression:
632 case CodeCompletionContext::CCC_PreprocessorDirective:
633 case CodeCompletionContext::CCC_SelectorName:
634 case CodeCompletionContext::CCC_TypeQualifiers:
635 case CodeCompletionContext::CCC_ObjCInstanceMessage:
636 case CodeCompletionContext::CCC_ObjCClassMessage:
637 case CodeCompletionContext::CCC_IncludedFile:
639 case CodeCompletionContext::CCC_Other:
640 case CodeCompletionContext::CCC_NaturalLanguage:
641 case CodeCompletionContext::CCC_Recovery:
642 case CodeCompletionContext::CCC_NewName:
645 llvm_unreachable(
"unknown code completion context");
648 static bool isInjectedClass(
const NamedDecl &D) {
649 if (
auto *R = dyn_cast_or_null<RecordDecl>(&D))
650 if (R->isInjectedClassName())
656 static bool isBlacklistedMember(
const NamedDecl &D) {
659 if (D.getKind() == Decl::CXXDestructor)
662 if (isInjectedClass(D))
665 auto NameKind = D.getDeclName().getNameKind();
666 if (NameKind == DeclarationName::CXXOperatorName ||
667 NameKind == DeclarationName::CXXLiteralOperatorName ||
668 NameKind == DeclarationName::CXXConversionFunctionName)
679 struct CompletionRecorder :
public CodeCompleteConsumer {
680 CompletionRecorder(
const CodeCompleteOptions &Opts,
681 llvm::unique_function<
void()> ResultsCallback)
682 : CodeCompleteConsumer(Opts.getClangCompleteOpts()),
683 CCContext(CodeCompletionContext::CCC_Other), Opts(Opts),
684 CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
685 CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) {
686 assert(this->ResultsCallback);
694 void ProcessCodeCompleteResults(
class Sema &S, CodeCompletionContext Context,
695 CodeCompletionResult *InResults,
696 unsigned NumResults)
override final {
705 if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
706 log(
"Code complete: Ignoring sema code complete callback with Recovery " 713 if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
716 log(
"Multiple code complete callbacks (parser backtracked?). " 717 "Dropping results from context {0}, keeping results from {1}.",
718 getCompletionKindString(Context.getKind()),
719 getCompletionKindString(this->CCContext.getKind()));
727 for (
unsigned I = 0; I < NumResults; ++I) {
728 auto &Result = InResults[I];
730 if (Result.Hidden && Result.Declaration &&
731 Result.Declaration->isCXXClassMember())
733 if (!Opts.IncludeIneligibleResults &&
734 (Result.Availability == CXAvailability_NotAvailable ||
735 Result.Availability == CXAvailability_NotAccessible))
737 if (Result.Declaration &&
738 !Context.getBaseType().isNull()
739 && isBlacklistedMember(*Result.Declaration))
743 if (Result.Declaration && !Context.getCXXScopeSpecifier().hasValue() &&
744 isInjectedClass(*Result.Declaration))
747 Result.StartsNestedNameSpecifier =
false;
748 Results.push_back(Result);
753 CodeCompletionAllocator &getAllocator()
override {
return *CCAllocator; }
754 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
758 llvm::StringRef getName(
const CodeCompletionResult &Result) {
759 switch (Result.Kind) {
760 case CodeCompletionResult::RK_Declaration:
761 if (
auto *ID = Result.Declaration->getIdentifier())
762 return ID->getName();
764 case CodeCompletionResult::RK_Keyword:
765 return Result.Keyword;
766 case CodeCompletionResult::RK_Macro:
767 return Result.Macro->getName();
768 case CodeCompletionResult::RK_Pattern:
769 return Result.Pattern->getTypedText();
771 auto *CCS = codeCompletionString(Result);
772 return CCS->getTypedText();
777 CodeCompletionString *codeCompletionString(
const CodeCompletionResult &R) {
779 return const_cast<CodeCompletionResult &
>(R).CreateCodeCompletionString(
780 *CCSema, CCContext, *CCAllocator,
CCTUInfo,
785 CodeCompleteOptions Opts;
786 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
788 llvm::unique_function<void()> ResultsCallback;
791 struct ScoredSignature {
799 class SignatureHelpCollector final :
public CodeCompleteConsumer {
801 SignatureHelpCollector(
const clang::CodeCompleteOptions &CodeCompleteOpts,
802 const SymbolIndex *
Index, SignatureHelp &SigHelp)
803 : CodeCompleteConsumer(CodeCompleteOpts), SigHelp(SigHelp),
804 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
807 void ProcessOverloadCandidates(Sema &S,
unsigned CurrentArg,
808 OverloadCandidate *Candidates,
809 unsigned NumCandidates,
810 SourceLocation OpenParLoc)
override {
811 assert(!OpenParLoc.isInvalid());
812 SourceManager &SrcMgr = S.getSourceManager();
813 OpenParLoc = SrcMgr.getFileLoc(OpenParLoc);
814 if (SrcMgr.isInMainFile(OpenParLoc))
817 elog(
"Location oustide main file in signature help: {0}",
818 OpenParLoc.printToString(SrcMgr));
820 std::vector<ScoredSignature> ScoredSignatures;
821 SigHelp.signatures.reserve(NumCandidates);
822 ScoredSignatures.reserve(NumCandidates);
826 SigHelp.activeSignature = 0;
827 assert(CurrentArg <= (
unsigned)std::numeric_limits<int>::max() &&
828 "too many arguments");
829 SigHelp.activeParameter =
static_cast<int>(CurrentArg);
830 for (
unsigned I = 0; I < NumCandidates; ++I) {
831 OverloadCandidate
Candidate = Candidates[I];
835 if (
auto *Func = Candidate.getFunction()) {
836 if (
auto *Pattern = Func->getTemplateInstantiationPattern())
837 Candidate = OverloadCandidate(Pattern);
840 const auto *CCS = Candidate.CreateSignatureString(
842 assert(CCS &&
"Expected the CodeCompletionString to be non-null");
843 ScoredSignatures.push_back(processOverloadCandidate(
845 Candidate.getFunction()
852 llvm::DenseMap<SymbolID, std::string> FetchedDocs;
854 LookupRequest IndexRequest;
855 for (
const auto &S : ScoredSignatures) {
858 IndexRequest.IDs.insert(*S.IDForDoc);
860 Index->lookup(IndexRequest, [&](
const Symbol &S) {
861 if (!S.Documentation.empty())
862 FetchedDocs[S.ID] = S.Documentation;
864 log(
"SigHelp: requested docs for {0} symbols from the index, got {1} " 865 "symbols with non-empty docs in the response",
866 IndexRequest.IDs.size(), FetchedDocs.size());
869 llvm::sort(ScoredSignatures, [](
const ScoredSignature &L,
870 const ScoredSignature &R) {
878 if (L.Quality.NumberOfParameters != R.Quality.NumberOfParameters)
879 return L.Quality.NumberOfParameters < R.Quality.NumberOfParameters;
880 if (L.Quality.NumberOfOptionalParameters !=
881 R.Quality.NumberOfOptionalParameters)
882 return L.Quality.NumberOfOptionalParameters <
883 R.Quality.NumberOfOptionalParameters;
884 if (L.Quality.Kind != R.Quality.Kind) {
885 using OC = CodeCompleteConsumer::OverloadCandidate;
886 switch (L.Quality.Kind) {
887 case OC::CK_Function:
889 case OC::CK_FunctionType:
890 return R.Quality.Kind != OC::CK_Function;
891 case OC::CK_FunctionTemplate:
894 llvm_unreachable(
"Unknown overload candidate type.");
896 if (L.Signature.label.size() != R.Signature.label.size())
897 return L.Signature.label.size() < R.Signature.label.size();
898 return L.Signature.label < R.Signature.label;
901 for (
auto &SS : ScoredSignatures) {
903 SS.IDForDoc ? FetchedDocs.find(*SS.IDForDoc) : FetchedDocs.end();
904 if (IndexDocIt != FetchedDocs.end())
905 SS.Signature.documentation = IndexDocIt->second;
907 SigHelp.signatures.push_back(std::move(SS.Signature));
911 GlobalCodeCompletionAllocator &getAllocator()
override {
return *
Allocator; }
913 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
916 void processParameterChunk(llvm::StringRef ChunkText,
919 unsigned ParamStartOffset =
lspLength(Signature.label);
920 unsigned ParamEndOffset = ParamStartOffset +
lspLength(ChunkText);
924 Signature.label += ChunkText;
925 ParameterInformation
Info;
926 Info.labelOffsets.emplace(ParamStartOffset, ParamEndOffset);
928 Info.labelString = ChunkText;
930 Signature.parameters.push_back(std::move(Info));
933 void processOptionalChunk(
const CodeCompletionString &CCS,
935 SignatureQualitySignals &Signal)
const {
936 for (
const auto &Chunk : CCS) {
937 switch (Chunk.Kind) {
938 case CodeCompletionString::CK_Optional:
939 assert(Chunk.Optional &&
940 "Expected the optional code completion string to be non-null.");
941 processOptionalChunk(*Chunk.Optional,
Signature, Signal);
943 case CodeCompletionString::CK_VerticalSpace:
945 case CodeCompletionString::CK_CurrentParameter:
946 case CodeCompletionString::CK_Placeholder:
947 processParameterChunk(Chunk.Text,
Signature);
948 Signal.NumberOfOptionalParameters++;
959 ScoredSignature processOverloadCandidate(
const OverloadCandidate &
Candidate,
960 const CodeCompletionString &CCS,
961 llvm::StringRef DocComment)
const {
963 SignatureQualitySignals Signal;
969 for (
const auto &Chunk : CCS) {
970 switch (Chunk.Kind) {
971 case CodeCompletionString::CK_ResultType:
974 assert(!ReturnType &&
"Unexpected CK_ResultType");
975 ReturnType = Chunk.Text;
977 case CodeCompletionString::CK_CurrentParameter:
978 case CodeCompletionString::CK_Placeholder:
979 processParameterChunk(Chunk.Text, Signature);
980 Signal.NumberOfParameters++;
982 case CodeCompletionString::CK_Optional: {
984 assert(Chunk.Optional &&
985 "Expected the optional code completion string to be non-null.");
986 processOptionalChunk(*Chunk.Optional, Signature, Signal);
989 case CodeCompletionString::CK_VerticalSpace:
992 Signature.label += Chunk.Text;
997 Signature.label +=
" -> ";
1000 dlog(
"Signal for {0}: {1}", Signature, Signal);
1001 ScoredSignature Result;
1002 Result.Signature = std::move(Signature);
1003 Result.Quality = Signal;
1005 Result.Signature.documentation.empty() &&
Candidate.getFunction()
1011 SignatureHelp &SigHelp;
1012 std::shared_ptr<clang::GlobalCodeCompletionAllocator>
Allocator;
1014 const SymbolIndex *
Index;
1017 struct SemaCompleteInput {
1023 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS;
1026 void loadMainFilePreambleMacros(
const Preprocessor &
PP,
1031 ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource();
1034 IdentifierInfoLookup *PreambleIdentifiers =
1035 PP.getIdentifierTable().getExternalIdentifierLookup();
1036 if (!PreambleIdentifiers || !PreambleMacros)
1038 for (
const auto &MacroName : Preamble.Macros.Names)
1039 if (
auto *II = PreambleIdentifiers->get(MacroName.getKey()))
1040 if (II->isOutOfDate())
1041 PreambleMacros->updateOutOfDateIdentifier(*II);
1046 bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
1047 const clang::CodeCompleteOptions &Options,
1048 const SemaCompleteInput &Input,
1049 IncludeStructure *Includes =
nullptr) {
1050 trace::Span Tracer(
"Sema completion");
1051 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS = Input.VFS;
1052 if (Input.Preamble && Input.Preamble->StatCache)
1053 VFS = Input.Preamble->StatCache->getConsumingFS(std::move(VFS));
1054 ParseInputs ParseInput;
1055 ParseInput.CompileCommand = Input.Command;
1056 ParseInput.FS =
VFS;
1057 ParseInput.Contents = Input.Contents;
1058 ParseInput.Opts = ParseOptions();
1063 elog(
"Couldn't create CompilerInvocation");
1066 auto &FrontendOpts = CI->getFrontendOpts();
1067 FrontendOpts.SkipFunctionBodies =
true;
1069 CI->getLangOpts()->SpellChecking =
false;
1071 FrontendOpts.CodeCompleteOpts = Options;
1072 FrontendOpts.CodeCompletionAt.FileName = Input.FileName;
1073 std::tie(FrontendOpts.CodeCompletionAt.Line,
1074 FrontendOpts.CodeCompletionAt.Column) =
1077 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
1078 llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName);
1080 CI->getDiagnosticOpts().IgnoreWarnings =
true;
1087 PreambleBounds PreambleRegion =
1088 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
1089 bool CompletingInPreamble = PreambleRegion.Size > Input.Offset;
1094 (Input.Preamble && !CompletingInPreamble) ? &Input.Preamble->Preamble
1096 std::move(ContentsBuffer), std::move(VFS), IgnoreDiags);
1097 Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble;
1098 Clang->setCodeCompletionConsumer(Consumer.release());
1101 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
1102 log(
"BeginSourceFile() failed when running codeComplete for {0}",
1113 loadMainFilePreambleMacros(Clang->getPreprocessor(), *Input.Preamble);
1115 Clang->getPreprocessor().addPPCallbacks(
1118 log(
"Execute() failed when running codeComplete for {0}: {1}",
1119 Input.FileName,
toString(std::move(Err)));
1122 Action.EndSourceFile();
1128 bool allowIndex(CodeCompletionContext &CC) {
1129 if (!contextAllowsIndex(CC.getKind()))
1132 auto Scope = CC.getCXXScopeSpecifier();
1135 NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
1140 switch (NameSpec->getKind()) {
1141 case NestedNameSpecifier::Global:
1143 case NestedNameSpecifier::NamespaceAlias:
1145 case NestedNameSpecifier::Super:
1146 case NestedNameSpecifier::TypeSpec:
1147 case NestedNameSpecifier::TypeSpecWithTemplate:
1152 llvm_unreachable(
"invalid NestedNameSpecifier kind");
1155 std::future<SymbolSlab> startAsyncFuzzyFind(
const SymbolIndex &
Index,
1156 const FuzzyFindRequest &Req) {
1157 return runAsync<SymbolSlab>([&
Index, Req]() {
1158 trace::Span Tracer(
"Async fuzzyFind");
1160 Index.fuzzyFind(Req, [&Syms](
const Symbol &Sym) { Syms.insert(Sym); });
1161 return std::move(Syms).build();
1168 FuzzyFindRequest speculativeFuzzyFindRequestForCompletion(
1169 FuzzyFindRequest CachedReq,
const CompletionPrefix &HeuristicPrefix) {
1170 CachedReq.Query = HeuristicPrefix.Name;
1203 class CodeCompleteFlow {
1205 IncludeStructure Includes;
1206 SpeculativeFuzzyFind *SpecFuzzyFind;
1207 const CodeCompleteOptions &Opts;
1210 CompletionRecorder *Recorder =
nullptr;
1212 bool IsUsingDeclaration =
false;
1214 int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0;
1215 bool Incomplete =
false;
1216 CompletionPrefix HeuristicPrefix;
1217 llvm::Optional<FuzzyMatcher> Filter;
1218 Range ReplacedRange;
1219 std::vector<std::string> QueryScopes;
1221 llvm::Optional<ScopeDistance> ScopeProximity;
1222 llvm::Optional<OpaqueType> PreferredType;
1224 bool AllScopes =
false;
1225 llvm::StringSet<> ContextWords;
1228 llvm::Optional<IncludeInserter> Inserter;
1229 llvm::Optional<URIDistance> FileProximity;
1234 llvm::Optional<FuzzyFindRequest> SpecReq;
1238 CodeCompleteFlow(
PathRef FileName,
const IncludeStructure &Includes,
1239 SpeculativeFuzzyFind *SpecFuzzyFind,
1240 const CodeCompleteOptions &Opts)
1241 :
FileName(FileName), Includes(Includes), SpecFuzzyFind(SpecFuzzyFind),
1244 CodeCompleteResult run(
const SemaCompleteInput &SemaCCInput) && {
1245 trace::Span Tracer(
"CodeCompleteFlow");
1248 populateContextWords(SemaCCInput.Contents);
1249 if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq.hasValue()) {
1250 assert(!SpecFuzzyFind->Result.valid());
1251 SpecReq = speculativeFuzzyFindRequestForCompletion(
1252 *SpecFuzzyFind->CachedReq, HeuristicPrefix);
1253 SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq);
1259 CodeCompleteResult Output;
1260 auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() {
1261 assert(Recorder &&
"Recorder is not set");
1262 CCContextKind = Recorder->CCContext.getKind();
1263 IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration();
1265 SemaCCInput.FileName, SemaCCInput.Contents, SemaCCInput.VFS.get());
1269 SemaCCInput.FileName, SemaCCInput.Contents, Style,
1270 SemaCCInput.Command.Directory,
1271 &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
1272 for (
const auto &Inc : Includes.MainFileIncludes)
1273 Inserter->addExisting(Inc);
1279 FileDistanceOptions ProxOpts{};
1280 const auto &SM = Recorder->CCSema->getSourceManager();
1281 llvm::StringMap<SourceParams> ProxSources;
1282 for (
auto &
Entry : Includes.includeDepth(
1283 SM.getFileEntryForID(SM.getMainFileID())->getName())) {
1284 auto &Source = ProxSources[
Entry.getKey()];
1285 Source.Cost =
Entry.getValue() * ProxOpts.IncludeCost;
1289 if (
Entry.getValue() > 0)
1290 Source.MaxUpTraversals = 1;
1292 FileProximity.emplace(ProxSources, ProxOpts);
1294 Output = runWithSema();
1297 getCompletionKindString(CCContextKind));
1298 log(
"Code complete: sema context {0}, query scopes [{1}] (AnyScope={2}), " 1299 "expected type {3}{4}",
1300 getCompletionKindString(CCContextKind),
1301 llvm::join(QueryScopes.begin(), QueryScopes.end(),
","), AllScopes,
1302 PreferredType ? Recorder->CCContext.getPreferredType().getAsString()
1304 IsUsingDeclaration ?
", inside using declaration" :
"");
1307 Recorder = RecorderOwner.get();
1309 semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(),
1310 SemaCCInput, &Includes);
1311 logResults(Output, Tracer);
1315 void logResults(
const CodeCompleteResult &Output,
const trace::Span &Tracer) {
1318 SPAN_ATTACH(Tracer,
"merged_results", NSemaAndIndex);
1319 SPAN_ATTACH(Tracer,
"identifier_results", NIdent);
1320 SPAN_ATTACH(Tracer,
"returned_results", int64_t(Output.Completions.size()));
1321 SPAN_ATTACH(Tracer,
"incomplete", Output.HasMore);
1322 log(
"Code complete: {0} results from Sema, {1} from Index, " 1323 "{2} matched, {3} from identifiers, {4} returned{5}.",
1324 NSema, NIndex, NSemaAndIndex, NIdent, Output.Completions.size(),
1325 Output.HasMore ?
" (incomplete)" :
"");
1326 assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit);
1332 runWithoutSema(llvm::StringRef Content,
size_t Offset,
1333 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS) && {
1334 trace::Span Tracer(
"CodeCompleteWithoutSema");
1337 populateContextWords(Content);
1338 CCContextKind = CodeCompletionContext::CCC_Recovery;
1339 IsUsingDeclaration =
false;
1340 Filter = FuzzyMatcher(HeuristicPrefix.Name);
1342 ReplacedRange.start = ReplacedRange.end =
Pos;
1343 ReplacedRange.start.character -= HeuristicPrefix.Name.size();
1345 llvm::StringMap<SourceParams> ProxSources;
1347 FileProximity.emplace(ProxSources);
1351 Inserter.emplace(FileName, Content, Style,
1355 std::vector<RawIdentifier> IdentifierResults;
1356 for (
const auto &IDAndCount : Identifiers) {
1358 ID.Name = IDAndCount.first();
1359 ID.References = IDAndCount.second;
1361 if (ID.Name == HeuristicPrefix.Name)
1363 if (ID.References > 0)
1364 IdentifierResults.push_back(std::move(ID));
1370 SpecifiedScope Scopes;
1371 Scopes.AccessibleScopes =
1373 for (std::string &S : Scopes.AccessibleScopes)
1376 if (HeuristicPrefix.Qualifier.empty())
1377 AllScopes = Opts.AllScopes;
1378 else if (HeuristicPrefix.Qualifier.startswith(
"::")) {
1379 Scopes.AccessibleScopes = {
""};
1380 Scopes.UnresolvedQualifier = HeuristicPrefix.Qualifier.drop_front(2);
1382 Scopes.UnresolvedQualifier = HeuristicPrefix.Qualifier;
1384 QueryScopes = Scopes.scopesForIndexQuery();
1385 ScopeProximity.emplace(QueryScopes);
1387 SymbolSlab IndexResults = Opts.Index ? queryIndex() : SymbolSlab();
1389 CodeCompleteResult Output = toCodeCompleteResult(mergeResults(
1390 {}, IndexResults, IdentifierResults));
1391 Output.RanParser =
false;
1392 logResults(Output, Tracer);
1397 void populateContextWords(llvm::StringRef Content) {
1399 unsigned RangeEnd = HeuristicPrefix.Qualifier.begin() - Content.data(),
1400 RangeBegin = RangeEnd;
1401 for (
size_t I = 0; I < 3 && RangeBegin > 0; ++I) {
1402 auto PrevNL = Content.rfind(
'\n', RangeBegin);
1403 if (PrevNL == StringRef::npos) {
1407 RangeBegin = PrevNL;
1410 ContextWords =
collectWords(Content.slice(RangeBegin, RangeEnd));
1411 dlog(
"Completion context words: {0}",
1417 CodeCompleteResult runWithSema() {
1418 const auto &CodeCompletionRange = CharSourceRange::getCharRange(
1419 Recorder->CCSema->getPreprocessor().getCodeCompletionTokenRange());
1425 if (CodeCompletionRange.isValid()) {
1427 CodeCompletionRange);
1430 Recorder->CCSema->getSourceManager(),
1431 Recorder->CCSema->getPreprocessor().getCodeCompletionLoc());
1432 ReplacedRange.start = ReplacedRange.end =
Pos;
1434 Filter = FuzzyMatcher(
1435 Recorder->CCSema->getPreprocessor().getCodeCompletionFilter());
1436 std::tie(QueryScopes, AllScopes) = getQueryScopes(
1437 Recorder->CCContext, *Recorder->CCSema, HeuristicPrefix, Opts);
1438 if (!QueryScopes.empty())
1439 ScopeProximity.emplace(QueryScopes);
1442 Recorder->CCContext.getPreferredType());
1448 auto IndexResults = (Opts.Index && allowIndex(Recorder->CCContext))
1451 trace::Span Tracer(
"Populate CodeCompleteResult");
1454 mergeResults(Recorder->Results, IndexResults, {});
1455 return toCodeCompleteResult(Top);
1459 toCodeCompleteResult(
const std::vector<ScoredBundle> &Scored) {
1460 CodeCompleteResult Output;
1463 for (
auto &C : Scored) {
1464 Output.Completions.push_back(toCodeCompletion(C.first));
1465 Output.Completions.back().Score = C.second;
1466 Output.Completions.back().CompletionTokenRange = ReplacedRange;
1468 Output.HasMore = Incomplete;
1469 Output.Context = CCContextKind;
1473 SymbolSlab queryIndex() {
1474 trace::Span Tracer(
"Query index");
1475 SPAN_ATTACH(Tracer,
"limit", int64_t(Opts.Limit));
1478 FuzzyFindRequest Req;
1480 Req.Limit = Opts.Limit;
1481 Req.Query = Filter->pattern();
1482 Req.RestrictForCodeCompletion =
true;
1483 Req.Scopes = QueryScopes;
1484 Req.AnyScope = AllScopes;
1486 Req.ProximityPaths.push_back(FileName);
1488 Req.PreferredTypes.push_back(PreferredType->raw());
1489 vlog(
"Code complete: fuzzyFind({0:2})",
toJSON(Req));
1492 SpecFuzzyFind->NewReq = Req;
1493 if (SpecFuzzyFind && SpecFuzzyFind->Result.valid() && (*SpecReq == Req)) {
1494 vlog(
"Code complete: speculative fuzzy request matches the actual index " 1495 "request. Waiting for the speculative index results.");
1498 trace::Span WaitSpec(
"Wait speculative results");
1499 return SpecFuzzyFind->Result.get();
1502 SPAN_ATTACH(Tracer,
"Speculative results",
false);
1506 if (Opts.Index->fuzzyFind(
1507 Req, [&](
const Symbol &Sym) { ResultsBuilder.insert(Sym); }))
1509 return std::move(ResultsBuilder).build();
1517 std::vector<ScoredBundle>
1518 mergeResults(
const std::vector<CodeCompletionResult> &SemaResults,
1519 const SymbolSlab &IndexResults,
1520 const std::vector<RawIdentifier> &IdentifierResults) {
1521 trace::Span Tracer(
"Merge and score results");
1522 std::vector<CompletionCandidate::Bundle> Bundles;
1523 llvm::DenseMap<size_t, size_t> BundleLookup;
1524 auto AddToBundles = [&](
const CodeCompletionResult *
SemaResult,
1527 CompletionCandidate C;
1531 if (C.IndexResult) {
1532 C.Name = IndexResult->Name;
1534 }
else if (C.SemaResult) {
1535 C.Name = Recorder->getName(*SemaResult);
1540 if (
auto OverloadSet = C.overloadSet(Opts)) {
1541 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
1543 Bundles.emplace_back();
1544 Bundles[Ret.first->second].push_back(std::move(C));
1546 Bundles.emplace_back();
1547 Bundles.back().push_back(std::move(C));
1550 llvm::DenseSet<const Symbol *> UsedIndexResults;
1551 auto CorrespondingIndexResult =
1552 [&](
const CodeCompletionResult &
SemaResult) ->
const Symbol * {
1554 getSymbolID(SemaResult, Recorder->CCSema->getSourceManager())) {
1555 auto I = IndexResults.find(*SymID);
1556 if (I != IndexResults.end()) {
1557 UsedIndexResults.insert(&*I);
1564 for (
auto &SemaResult : SemaResults)
1565 AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult),
nullptr);
1567 for (
const auto &IndexResult : IndexResults) {
1568 if (UsedIndexResults.count(&IndexResult))
1570 AddToBundles(
nullptr, &IndexResult,
nullptr);
1573 for (
const auto &Ident : IdentifierResults)
1574 AddToBundles(
nullptr,
nullptr, &Ident);
1576 TopN<ScoredBundle, ScoredBundleGreater> Top(
1577 Opts.Limit == 0 ? std::numeric_limits<size_t>::max() : Opts.Limit);
1578 for (
auto &Bundle : Bundles)
1579 addCandidate(Top, std::move(Bundle));
1580 return std::move(Top).items();
1583 llvm::Optional<float> fuzzyScore(
const CompletionCandidate &C) {
1586 if (C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro &&
1587 !C.Name.startswith_lower(Filter->pattern()))
1589 return Filter->match(C.Name);
1593 void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates,
1594 CompletionCandidate::Bundle Bundle) {
1596 SymbolRelevanceSignals Relevance;
1597 Relevance.Context = CCContextKind;
1598 Relevance.Name = Bundle.front().Name;
1600 Relevance.FileProximityMatch = FileProximity.getPointer();
1602 Relevance.ScopeProximityMatch = ScopeProximity.getPointer();
1604 Relevance.HadContextType =
true;
1605 Relevance.ContextWords = &ContextWords;
1607 auto &First = Bundle.front();
1608 if (
auto FuzzyScore = fuzzyScore(First))
1609 Relevance.NameMatch = *FuzzyScore;
1613 bool FromIndex =
false;
1617 Relevance.merge(*
Candidate.IndexResult);
1618 Origin |=
Candidate.IndexResult->Origin;
1620 if (!
Candidate.IndexResult->Type.empty())
1621 Relevance.HadSymbolType |=
true;
1622 if (PreferredType &&
1623 PreferredType->raw() ==
Candidate.IndexResult->Type) {
1624 Relevance.TypeMatchesPreferred =
true;
1630 if (PreferredType) {
1632 Recorder->CCSema->getASTContext(), *
Candidate.SemaResult)) {
1633 Relevance.HadSymbolType |=
true;
1634 if (PreferredType == CompletionType)
1635 Relevance.TypeMatchesPreferred =
true;
1641 Quality.References =
Candidate.IdentifierResult->References;
1647 CodeCompletion::Scores Scores;
1648 Scores.Quality = Quality.evaluate();
1649 Scores.Relevance = Relevance.evaluate();
1652 Scores.ExcludingName = Relevance.NameMatch
1653 ? Scores.Total / Relevance.NameMatch
1656 dlog(
"CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
1657 llvm::to_string(Origin), Scores.Total, llvm::to_string(Quality),
1658 llvm::to_string(Relevance));
1661 NIndex += FromIndex;
1662 NSemaAndIndex += bool(Origin & SymbolOrigin::AST) && FromIndex;
1664 if (Candidates.push({std::move(Bundle), Scores}))
1668 CodeCompletion toCodeCompletion(
const CompletionCandidate::Bundle &Bundle) {
1669 llvm::Optional<CodeCompletionBuilder>
Builder;
1670 for (
const auto &Item : Bundle) {
1671 CodeCompletionString *SemaCCS =
1672 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult)
1675 Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() :
nullptr,
1676 Item, SemaCCS, QueryScopes, *Inserter,
FileName,
1677 CCContextKind, Opts,
1678 !IsUsingDeclaration);
1680 Builder->add(Item, SemaCCS);
1682 return Builder->build();
1689 clang::CodeCompleteOptions Result;
1690 Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
1691 Result.IncludeMacros = IncludeMacros;
1692 Result.IncludeGlobals =
true;
1697 Result.IncludeBriefComments =
false;
1702 Result.LoadExternal = !
Index;
1703 Result.IncludeFixIts = IncludeFixIts;
1710 assert(Offset <= Content.size());
1711 StringRef Rest = Content.take_front(Offset);
1716 while (!Rest.empty() && isIdentifierBody(Rest.back()))
1717 Rest = Rest.drop_back();
1718 Result.
Name = Content.slice(Rest.size(),
Offset);
1721 while (Rest.consume_back(
"::") && !Rest.endswith(
":"))
1722 while (!Rest.empty() && isIdentifierBody(Rest.back()))
1723 Rest = Rest.drop_back();
1725 Content.slice(Rest.size(), Result.
Name.begin() - Content.begin());
1733 Position Pos, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS,
1737 elog(
"Code completion position was invalid {0}",
Offset.takeError());
1740 auto Flow = CodeCompleteFlow(
1742 SpecFuzzyFind, Opts);
1744 ? std::move(Flow).runWithoutSema(Contents, *
Offset, VFS)
1745 : std::move(Flow).run(
1750 const tooling::CompileCommand &
Command,
1753 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS,
1757 elog(
"Code completion position was invalid {0}",
Offset.takeError());
1761 clang::CodeCompleteOptions Options;
1762 Options.IncludeGlobals =
false;
1763 Options.IncludeMacros =
false;
1764 Options.IncludeCodePatterns =
false;
1765 Options.IncludeBriefComments =
false;
1768 std::make_unique<SignatureHelpCollector>(Options, Index, Result),
1775 auto InTopLevelScope = [](
const NamedDecl &ND) {
1776 switch (ND.getDeclContext()->getDeclKind()) {
1777 case Decl::TranslationUnit:
1779 case Decl::LinkageSpec:
1791 if (InTopLevelScope(ND))
1794 if (
const auto *EnumDecl = dyn_cast<clang::EnumDecl>(ND.getDeclContext()))
1795 return InTopLevelScope(*EnumDecl) && !EnumDecl->isScoped();
1802 const auto *InsertInclude = Includes.empty() ? nullptr : &Includes[0];
1803 LSP.
label = ((InsertInclude && InsertInclude->Insertion)
1806 (Opts.
ShowOrigins ?
"[" + llvm::to_string(Origin) +
"]" :
"") +
1810 LSP.
detail = BundleSize > 1 ? llvm::formatv(
"[{0} overloads]", BundleSize)
1814 LSP.
detail +=
"\n" + InsertInclude->Header;
1818 LSP.
textEdit = {CompletionTokenRange, RequiredQualifier +
Name};
1826 for (
const auto &
FixIt : FixIts) {
1842 if (InsertInclude && InsertInclude->Insertion)
1858 <<
" (" << getCompletionKindString(R.
Context) <<
")" std::string insertText
A string that should be inserted to a document when selecting this completion.
std::vector< std::string > AccessibleScopes
bool ShowOrigins
Expose origins of completion items in the label (for debugging).
const tooling::CompileCommand & Command
llvm::StringSet collectWords(llvm::StringRef Content)
Collects words from the source code.
std::shared_ptr< clang::GlobalCodeCompletionAllocator > Allocator
const FunctionDecl * Decl
SignatureQualitySignals Quality
llvm::json::Value toJSON(const FuzzyFindRequest &Request)
CodeCompletionContext::Kind Context
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
llvm::Optional< TextEdit > textEdit
An edit which is applied to a document when selecting this completion.
Always use text-based completion.
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
static llvm::Optional< OpaqueType > fromType(ASTContext &Ctx, QualType Type)
Construct an instance from a clang::QualType.
The primary text to be inserted is treated as a snippet.
llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS
CompletionItemKind kind
The kind of this completion item.
size_t lspLength(llvm::StringRef Code)
bool EnableSnippets
When true, completion items will contain expandable code snippets in completion (e.g.
clang::find_all_symbols::SymbolInfo::SymbolKind SymbolKind
The primary text to be inserted is treated as a plain string.
std::string printNamespaceScope(const DeclContext &DC)
Returns the first enclosing namespace scope starting from DC.
std::vector< CodeCompletion > Completions
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
std::pair< StringRef, StringRef > splitQualifiedName(StringRef QName)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
llvm::StringRef PathRef
A typedef to represent a ref to file path.
llvm::Optional< std::string > UnresolvedQualifier
std::vector< CodeCompletionResult > Results
std::string sortText
A string that should be used when comparing this item with other items.
std::string getDocComment(const ASTContext &Ctx, const CodeCompletionResult &Result, bool CommentsFromHeaders)
Gets a minimally formatted documentation comment of Result, with comment markers stripped.
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)
Documents should not be synced at all.
std::string documentation
A human-readable string that represents a doc-comment.
void vlog(const char *Fmt, Ts &&... Vals)
std::vector< TextEdit > additionalTextEdits
An optional array of additional text edits that are applied when selecting this completion.
void elog(const char *Fmt, Ts &&... Vals)
std::vector< std::string > visibleNamespaces(llvm::StringRef Code, const format::FormatStyle &Style)
Heuristically determine namespaces visible at a point, without parsing Code.
bool isRangeConsecutive(const Range &Left, const Range &Right)
CompletionItemKind
The kind of a completion entry.
std::string getReturnType(const CodeCompletionString &CCS)
Gets detail to be used as the detail field in an LSP completion item.
SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, const SymbolIndex *Index)
std::string detail
A human-readable string with additional information about this item, like type or symbol information...
llvm::Optional< float > Score
std::pair< size_t, size_t > offsetToClangLineColumn(llvm::StringRef Code, size_t Offset)
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
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.
bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx)
std::string filterText
A string that should be used when filtering a set of completion items.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
A speculative and asynchronous fuzzy find index request (based on cached request) that can be sent be...
bool deprecated
Indicates if this item is deprecated.
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
static const char * toString(OffsetEncoding OE)
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.
enum clang::clangd::CodeCompleteOptions::CodeCompletionParse RunParser
const Symbol * IndexResult
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
clang::CodeCompleteOptions getClangCompleteOpts() const
Returns options that can be passed to clang's completion engine.
std::string SnippetSuffix
llvm::StringRef Qualifier
Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc)
Turn a SourceLocation into a [line, column] pair.
format::FormatStyle getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content, llvm::vfs::FileSystem *FS)
Choose the clang-format style we should apply to a certain file.
CodeCompleteResult codeComplete(PathRef FileName, const tooling::CompileCommand &Command, const PreambleData *Preamble, llvm::StringRef Contents, Position Pos, llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem > VFS, CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind)
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
CodeCompletionBuilder Builder
float score
This is Clangd extension.
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
Represents the signature of a callable.
bool isExplicitTemplateSpecialization(const NamedDecl *D)
Indicates if D is an explicit template specialization, e.g.
const PreambleData * Preamble
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
llvm::SmallVector< llvm::StringRef, 1 > RankedIncludeHeaders
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
std::string label
The label of this completion item.
CompletionItem render(const CodeCompleteOptions &) const
struct clang::clangd::CodeCompleteOptions::IncludeInsertionIndicator IncludeIndicator
CharSourceRange Range
SourceRange for the file name.
llvm::SmallVector< llvm::StringRef, 1 > getRankedIncludes(const Symbol &Sym)
CodeCompletionTUInfo CCTUInfo
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.
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, std::string *RequiredQualifiers, bool CompletingPattern)
Formats the signature for an item, as a display string and snippet.
const CodeCompletionResult * SemaResult
std::vector< const char * > Expected
const RawIdentifier * IdentifierResult
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
llvm::Optional< FixItHint > FixIt
Indicates if the symbol is deprecated.
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
IncludeStructure Includes
CompletionPrefix guessCompletionPrefix(llvm::StringRef Content, unsigned Offset)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
The parsed preamble and associated data.
InsertTextFormat insertTextFormat
The format of the insert text.
llvm::StringMap< unsigned > collectIdentifiers(llvm::StringRef Content, const format::FormatStyle &Style)
Collects identifiers with counts in the source code.
CodeCompletionContext CCContext
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
llvm::Optional< SymbolID > IDForDoc
static llvm::Optional< OpaqueType > fromCompletionResult(ASTContext &Ctx, const CodeCompletionResult &R)
Create a type from a code completion result.
Range halfOpenToRange(const SourceManager &SM, CharSourceRange R)
const SymbolIndex * Index