40 #include "clang/AST/Decl.h" 41 #include "clang/AST/DeclBase.h" 42 #include "clang/Basic/CharInfo.h" 43 #include "clang/Basic/LangOptions.h" 44 #include "clang/Basic/SourceLocation.h" 45 #include "clang/Format/Format.h" 46 #include "clang/Frontend/CompilerInstance.h" 47 #include "clang/Frontend/FrontendActions.h" 48 #include "clang/Lex/ExternalPreprocessorSource.h" 49 #include "clang/Lex/Preprocessor.h" 50 #include "clang/Lex/PreprocessorOptions.h" 51 #include "clang/Sema/CodeCompleteConsumer.h" 52 #include "clang/Sema/DeclSpec.h" 53 #include "clang/Sema/Sema.h" 54 #include "llvm/ADT/ArrayRef.h" 55 #include "llvm/ADT/None.h" 56 #include "llvm/ADT/Optional.h" 57 #include "llvm/ADT/SmallVector.h" 58 #include "llvm/ADT/StringExtras.h" 59 #include "llvm/ADT/StringRef.h" 60 #include "llvm/Support/Compiler.h" 61 #include "llvm/Support/Debug.h" 62 #include "llvm/Support/Error.h" 63 #include "llvm/Support/Format.h" 64 #include "llvm/Support/FormatVariadic.h" 65 #include "llvm/Support/ScopedPrinter.h" 70 #define DEBUG_TYPE "CodeComplete" 83 case SK::NamespaceAlias:
106 case SK::ConversionFunction:
116 case SK::InstanceMethod:
117 case SK::ClassMethod:
118 case SK::StaticMethod:
121 case SK::InstanceProperty:
122 case SK::ClassProperty:
123 case SK::StaticProperty:
128 llvm_unreachable(
"Unhandled clang::index::SymbolKind.");
132 toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
133 const NamedDecl *Decl,
137 if (CtxKind == CodeCompletionContext::CCC_IncludedFile)
140 case CodeCompletionResult::RK_Declaration:
141 llvm_unreachable(
"RK_Declaration without Decl");
142 case CodeCompletionResult::RK_Keyword:
144 case CodeCompletionResult::RK_Macro:
147 case CodeCompletionResult::RK_Pattern:
150 llvm_unreachable(
"Unhandled CodeCompletionResult::ResultKind.");
154 struct RawIdentifier {
161 struct CompletionCandidate {
162 llvm::StringRef
Name;
171 size_t overloadSet(
const CodeCompleteOptions &Opts)
const {
172 if (!Opts.BundleOverloads.getValueOr(
false))
174 llvm::SmallString<256> Scratch;
176 switch (IndexResult->SymInfo.Kind) {
177 case index::SymbolKind::ClassMethod:
178 case index::SymbolKind::InstanceMethod:
179 case index::SymbolKind::StaticMethod:
181 llvm_unreachable(
"Don't expect members from index in code completion");
185 case index::SymbolKind::Function:
188 return llvm::hash_combine(
189 (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch),
190 headerToInsertIfAllowed(Opts).getValueOr(
""));
197 const NamedDecl *
D = SemaResult->Declaration;
198 if (!D || !D->isFunctionOrFunctionTemplate())
201 llvm::raw_svector_ostream OS(Scratch);
202 D->printQualifiedName(OS);
204 return llvm::hash_combine(Scratch,
205 headerToInsertIfAllowed(Opts).getValueOr(
""));
207 assert(IdentifierResult);
212 llvm::Optional<llvm::StringRef>
213 headerToInsertIfAllowed(
const CodeCompleteOptions &Opts)
const {
215 RankedIncludeHeaders.empty())
217 if (SemaResult && SemaResult->Declaration) {
220 auto &SM = SemaResult->Declaration->getASTContext().getSourceManager();
221 for (
const Decl *RD : SemaResult->Declaration->redecls())
222 if (SM.isInMainFile(SM.getExpansionLoc(RD->getBeginLoc())))
225 return RankedIncludeHeaders[0];
228 using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
231 std::pair<CompletionCandidate::Bundle, CodeCompletion::Scores>;
232 struct ScoredBundleGreater {
233 bool operator()(
const ScoredBundle &L,
const ScoredBundle &R) {
234 if (L.second.Total != R.second.Total)
235 return L.second.Total > R.second.Total;
236 return L.first.front().Name <
237 R.first.front().Name;
248 struct CodeCompletionBuilder {
249 CodeCompletionBuilder(ASTContext *ASTCtx,
const CompletionCandidate &C,
250 CodeCompletionString *SemaCCS,
251 llvm::ArrayRef<std::string> QueryScopes,
252 const IncludeInserter &Includes,
255 const CodeCompleteOptions &Opts)
256 : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments),
257 EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets) {
262 Completion.Name = llvm::StringRef(SemaCCS->getTypedText());
263 if (Completion.Scope.empty()) {
264 if ((C.SemaResult->Kind == CodeCompletionResult::RK_Declaration) ||
265 (C.SemaResult->Kind == CodeCompletionResult::RK_Pattern))
266 if (
const auto *
D = C.SemaResult->getDeclaration())
267 if (
const auto *ND = dyn_cast<NamedDecl>(
D))
271 Completion.Kind = toCompletionItemKind(
272 C.SemaResult->Kind, C.SemaResult->Declaration, ContextKind);
276 Completion.Name.back() ==
'/')
278 for (
const auto &
FixIt : C.SemaResult->FixIts) {
280 FixIt, ASTCtx->getSourceManager(), ASTCtx->getLangOpts()));
282 llvm::sort(Completion.FixIts, [](
const TextEdit &
X,
const TextEdit &Y) {
283 return std::tie(X.range.start.line, X.range.start.character) <
284 std::tie(Y.range.start.line, Y.range.start.character);
286 Completion.Deprecated |=
287 (C.SemaResult->Availability == CXAvailability_Deprecated);
290 Completion.Origin |= C.IndexResult->Origin;
291 if (Completion.Scope.empty())
292 Completion.Scope = C.IndexResult->Scope;
294 Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
295 if (Completion.Name.empty())
296 Completion.Name = C.IndexResult->Name;
299 if (Completion.RequiredQualifier.empty() && !C.SemaResult) {
300 llvm::StringRef ShortestQualifier = C.IndexResult->Scope;
301 for (llvm::StringRef Scope : QueryScopes) {
302 llvm::StringRef Qualifier = C.IndexResult->Scope;
303 if (Qualifier.consume_front(Scope) &&
304 Qualifier.size() < ShortestQualifier.size())
305 ShortestQualifier = Qualifier;
307 Completion.RequiredQualifier = ShortestQualifier;
311 if (C.IdentifierResult) {
314 Completion.Name = C.IdentifierResult->Name;
318 auto Inserted = [&](llvm::StringRef Header)
321 URI::parse(C.IndexResult->CanonicalDeclaration.FileURI);
323 return DeclaringURI.takeError();
324 auto ResolvedDeclaring =
URI::resolve(*DeclaringURI, FileName);
325 if (!ResolvedDeclaring)
326 return ResolvedDeclaring.takeError();
328 if (!ResolvedInserted)
329 return ResolvedInserted.takeError();
330 auto Spelled = Includes.calculateIncludePath(*ResolvedInserted, FileName);
332 return llvm::createStringError(llvm::inconvertibleErrorCode(),
333 "Header not on include path");
334 return std::make_pair(
336 Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted));
338 bool ShouldInsert = C.headerToInsertIfAllowed(Opts).hasValue();
340 for (
const auto &Inc : C.RankedIncludeHeaders) {
341 if (
auto ToInclude = Inserted(Inc)) {
342 CodeCompletion::IncludeCandidate Include;
343 Include.Header = ToInclude->first;
344 if (ToInclude->second && ShouldInsert)
345 Include.Insertion = Includes.insert(ToInclude->first);
346 Completion.Includes.push_back(std::move(Include));
348 log(
"Failed to generate include insertion edits for adding header " 349 "(FileURI='{0}', IncludeHeader='{1}') into {2}: {3}",
350 C.IndexResult->CanonicalDeclaration.FileURI, Inc, FileName,
351 ToInclude.takeError());
354 std::stable_partition(Completion.Includes.begin(),
355 Completion.Includes.end(),
356 [](
const CodeCompletion::IncludeCandidate &I) {
357 return !I.Insertion.hasValue();
361 void add(
const CompletionCandidate &C, CodeCompletionString *SemaCCS) {
362 assert(
bool(C.SemaResult) ==
bool(SemaCCS));
363 Bundled.emplace_back();
364 BundledEntry &S = Bundled.back();
366 bool IsPattern = C.SemaResult->Kind == CodeCompletionResult::RK_Pattern;
368 &Completion.RequiredQualifier, IsPattern);
370 }
else if (C.IndexResult) {
371 S.Signature = C.IndexResult->Signature;
372 S.SnippetSuffix = C.IndexResult->CompletionSnippetSuffix;
373 S.ReturnType = C.IndexResult->ReturnType;
375 if (ExtractDocumentation && Completion.Documentation.empty()) {
377 Completion.Documentation = C.IndexResult->Documentation;
378 else if (C.SemaResult)
379 Completion.Documentation =
getDocComment(*ASTCtx, *C.SemaResult,
384 CodeCompletion build() {
385 Completion.ReturnType = summarizeReturnType();
386 Completion.Signature = summarizeSignature();
387 Completion.SnippetSuffix = summarizeSnippet();
388 Completion.BundleSize = Bundled.size();
389 return std::move(Completion);
393 struct BundledEntry {
400 template <std::
string BundledEntry::*Member>
401 const std::string *onlyValue()
const {
402 auto B = Bundled.begin(), E = Bundled.end();
403 for (
auto I = B + 1; I != E; ++I)
404 if (I->*Member != B->*Member)
406 return &(B->*Member);
409 template <
bool BundledEntry::*Member>
const bool *onlyValue()
const {
410 auto B = Bundled.begin(), E = Bundled.end();
411 for (
auto I = B + 1; I != E; ++I)
412 if (I->*Member != B->*Member)
414 return &(B->*Member);
417 std::string summarizeReturnType()
const {
418 if (
auto *RT = onlyValue<&BundledEntry::ReturnType>())
423 std::string summarizeSnippet()
const {
424 auto *
Snippet = onlyValue<&BundledEntry::SnippetSuffix>();
430 if (EnableFunctionArgSnippets)
446 bool EmptyArgs = llvm::StringRef(*Snippet).endswith(
"()");
448 return EmptyArgs ?
"<$1>()$0" :
"<$1>($0)";
450 return EmptyArgs ?
"()" :
"($0)";
461 if (llvm::StringRef(*Snippet).endswith(
"<>"))
468 std::string summarizeSignature()
const {
469 if (
auto *
Signature = onlyValue<&BundledEntry::Signature>())
477 CodeCompletion Completion;
478 llvm::SmallVector<BundledEntry, 1> Bundled;
479 bool ExtractDocumentation;
480 bool EnableFunctionArgSnippets;
484 llvm::Optional<SymbolID>
getSymbolID(
const CodeCompletionResult &R,
485 const SourceManager &SM) {
487 case CodeCompletionResult::RK_Declaration:
488 case CodeCompletionResult::RK_Pattern: {
491 case CodeCompletionResult::RK_Macro:
493 case CodeCompletionResult::RK_Keyword:
496 llvm_unreachable(
"unknown CodeCompletionResult kind");
501 struct SpecifiedScope {
529 std::vector<std::string> scopesForIndexQuery() {
531 for (llvm::StringRef AS : AccessibleScopes)
533 (AS + (UnresolvedQualifier ? *UnresolvedQualifier :
"")).str());
534 return {Results.begin(), Results.end()};
541 std::pair<std::vector<std::string>,
bool>
543 const CompletionPrefix &HeuristicPrefix,
544 const CodeCompleteOptions &Opts) {
545 SpecifiedScope Scopes;
546 for (
auto *Context : CCContext.getVisitedContexts()) {
547 if (isa<TranslationUnitDecl>(Context))
548 Scopes.AccessibleScopes.push_back(
"");
549 else if (isa<NamespaceDecl>(Context))
553 const CXXScopeSpec *SemaSpecifier =
554 CCContext.getCXXScopeSpecifier().getValueOr(
nullptr);
556 if (!SemaSpecifier) {
559 if (!HeuristicPrefix.Qualifier.empty()) {
560 vlog(
"Sema said no scope specifier, but we saw {0} in the source code",
561 HeuristicPrefix.Qualifier);
562 StringRef SpelledSpecifier = HeuristicPrefix.Qualifier;
563 if (SpelledSpecifier.consume_front(
"::"))
564 Scopes.AccessibleScopes = {
""};
565 Scopes.UnresolvedQualifier = SpelledSpecifier;
566 return {Scopes.scopesForIndexQuery(),
false};
569 std::vector<std::string> EnclosingAtFront;
571 EnclosingAtFront.push_back(EnclosingScope);
572 for (
auto &S : Scopes.scopesForIndexQuery()) {
573 if (EnclosingScope != S)
574 EnclosingAtFront.push_back(std::move(S));
577 return {EnclosingAtFront, Opts.AllScopes};
580 if (SemaSpecifier && SemaSpecifier->isValid())
581 return {Scopes.scopesForIndexQuery(),
false};
584 Scopes.AccessibleScopes.push_back(
"");
585 llvm::StringRef SpelledSpecifier = Lexer::getSourceText(
586 CharSourceRange::getCharRange(SemaSpecifier->getRange()),
587 CCSema.SourceMgr, clang::LangOptions());
588 if (SpelledSpecifier.consume_front(
"::"))
589 Scopes.AccessibleScopes = {
""};
590 Scopes.UnresolvedQualifier = SpelledSpecifier;
592 if (!Scopes.UnresolvedQualifier->empty())
593 *Scopes.UnresolvedQualifier +=
"::";
595 return {Scopes.scopesForIndexQuery(),
false};
602 case CodeCompletionContext::CCC_TopLevel:
603 case CodeCompletionContext::CCC_ObjCInterface:
604 case CodeCompletionContext::CCC_ObjCImplementation:
605 case CodeCompletionContext::CCC_ObjCIvarList:
606 case CodeCompletionContext::CCC_ClassStructUnion:
607 case CodeCompletionContext::CCC_Statement:
608 case CodeCompletionContext::CCC_Expression:
609 case CodeCompletionContext::CCC_ObjCMessageReceiver:
610 case CodeCompletionContext::CCC_EnumTag:
611 case CodeCompletionContext::CCC_UnionTag:
612 case CodeCompletionContext::CCC_ClassOrStructTag:
613 case CodeCompletionContext::CCC_ObjCProtocolName:
614 case CodeCompletionContext::CCC_Namespace:
615 case CodeCompletionContext::CCC_Type:
616 case CodeCompletionContext::CCC_ParenthesizedExpression:
617 case CodeCompletionContext::CCC_ObjCInterfaceName:
618 case CodeCompletionContext::CCC_ObjCCategoryName:
619 case CodeCompletionContext::CCC_Symbol:
620 case CodeCompletionContext::CCC_SymbolOrNewName:
622 case CodeCompletionContext::CCC_OtherWithMacros:
623 case CodeCompletionContext::CCC_DotMemberAccess:
624 case CodeCompletionContext::CCC_ArrowMemberAccess:
625 case CodeCompletionContext::CCC_ObjCPropertyAccess:
626 case CodeCompletionContext::CCC_MacroName:
627 case CodeCompletionContext::CCC_MacroNameUse:
628 case CodeCompletionContext::CCC_PreprocessorExpression:
629 case CodeCompletionContext::CCC_PreprocessorDirective:
630 case CodeCompletionContext::CCC_SelectorName:
631 case CodeCompletionContext::CCC_TypeQualifiers:
632 case CodeCompletionContext::CCC_ObjCInstanceMessage:
633 case CodeCompletionContext::CCC_ObjCClassMessage:
634 case CodeCompletionContext::CCC_IncludedFile:
636 case CodeCompletionContext::CCC_Other:
637 case CodeCompletionContext::CCC_NaturalLanguage:
638 case CodeCompletionContext::CCC_Recovery:
639 case CodeCompletionContext::CCC_NewName:
642 llvm_unreachable(
"unknown code completion context");
645 static bool isInjectedClass(
const NamedDecl &
D) {
646 if (
auto *R = dyn_cast_or_null<RecordDecl>(&D))
647 if (R->isInjectedClassName())
653 static bool isBlacklistedMember(
const NamedDecl &
D) {
656 if (D.getKind() == Decl::CXXDestructor)
659 if (isInjectedClass(D))
662 auto NameKind = D.getDeclName().getNameKind();
663 if (NameKind == DeclarationName::CXXOperatorName ||
664 NameKind == DeclarationName::CXXLiteralOperatorName ||
665 NameKind == DeclarationName::CXXConversionFunctionName)
676 struct CompletionRecorder :
public CodeCompleteConsumer {
677 CompletionRecorder(
const CodeCompleteOptions &Opts,
678 llvm::unique_function<
void()> ResultsCallback)
679 : CodeCompleteConsumer(Opts.getClangCompleteOpts()),
680 CCContext(CodeCompletionContext::CCC_Other), Opts(Opts),
681 CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
682 CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) {
683 assert(this->ResultsCallback);
691 void ProcessCodeCompleteResults(
class Sema &S, CodeCompletionContext Context,
692 CodeCompletionResult *InResults,
693 unsigned NumResults)
override final {
702 if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
703 log(
"Code complete: Ignoring sema code complete callback with Recovery " 710 if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
713 log(
"Multiple code complete callbacks (parser backtracked?). " 714 "Dropping results from context {0}, keeping results from {1}.",
715 getCompletionKindString(Context.getKind()),
716 getCompletionKindString(this->CCContext.getKind()));
724 for (
unsigned I = 0; I < NumResults; ++I) {
725 auto &
Result = InResults[I];
728 Result.Declaration->isCXXClassMember())
730 if (!Opts.IncludeIneligibleResults &&
731 (
Result.Availability == CXAvailability_NotAvailable ||
732 Result.Availability == CXAvailability_NotAccessible))
735 !Context.getBaseType().isNull()
736 && isBlacklistedMember(*
Result.Declaration))
740 if (
Result.Declaration && !Context.getCXXScopeSpecifier().hasValue() &&
741 isInjectedClass(*
Result.Declaration))
744 Result.StartsNestedNameSpecifier =
false;
745 Results.push_back(
Result);
750 CodeCompletionAllocator &getAllocator()
override {
return *CCAllocator; }
751 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
755 llvm::StringRef getName(
const CodeCompletionResult &
Result) {
756 switch (Result.Kind) {
757 case CodeCompletionResult::RK_Declaration:
758 if (
auto *ID = Result.Declaration->getIdentifier())
759 return ID->getName();
761 case CodeCompletionResult::RK_Keyword:
762 return Result.Keyword;
763 case CodeCompletionResult::RK_Macro:
764 return Result.Macro->getName();
765 case CodeCompletionResult::RK_Pattern:
766 return Result.Pattern->getTypedText();
768 auto *CCS = codeCompletionString(Result);
769 return CCS->getTypedText();
774 CodeCompletionString *codeCompletionString(
const CodeCompletionResult &R) {
776 return const_cast<CodeCompletionResult &
>(R).CreateCodeCompletionString(
777 *CCSema, CCContext, *CCAllocator,
CCTUInfo,
782 CodeCompleteOptions Opts;
783 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
785 llvm::unique_function<void()> ResultsCallback;
788 struct ScoredSignature {
796 class SignatureHelpCollector final :
public CodeCompleteConsumer {
798 SignatureHelpCollector(
const clang::CodeCompleteOptions &CodeCompleteOpts,
799 const SymbolIndex *
Index, SignatureHelp &SigHelp)
800 : CodeCompleteConsumer(CodeCompleteOpts), SigHelp(SigHelp),
801 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
804 void ProcessOverloadCandidates(Sema &S,
unsigned CurrentArg,
805 OverloadCandidate *Candidates,
806 unsigned NumCandidates,
807 SourceLocation OpenParLoc)
override {
808 assert(!OpenParLoc.isInvalid());
809 SourceManager &SrcMgr = S.getSourceManager();
810 OpenParLoc = SrcMgr.getFileLoc(OpenParLoc);
811 if (SrcMgr.isInMainFile(OpenParLoc))
814 elog(
"Location oustide main file in signature help: {0}",
815 OpenParLoc.printToString(SrcMgr));
817 std::vector<ScoredSignature> ScoredSignatures;
818 SigHelp.signatures.reserve(NumCandidates);
819 ScoredSignatures.reserve(NumCandidates);
823 SigHelp.activeSignature = 0;
824 assert(CurrentArg <= (
unsigned)std::numeric_limits<int>::max() &&
825 "too many arguments");
826 SigHelp.activeParameter =
static_cast<int>(CurrentArg);
827 for (
unsigned I = 0; I < NumCandidates; ++I) {
828 OverloadCandidate
Candidate = Candidates[I];
832 if (
auto *Func = Candidate.getFunction()) {
833 if (
auto *Pattern = Func->getTemplateInstantiationPattern())
834 Candidate = OverloadCandidate(Pattern);
837 const auto *CCS = Candidate.CreateSignatureString(
839 assert(CCS &&
"Expected the CodeCompletionString to be non-null");
840 ScoredSignatures.push_back(processOverloadCandidate(
842 Candidate.getFunction()
849 llvm::DenseMap<SymbolID, std::string> FetchedDocs;
851 LookupRequest IndexRequest;
852 for (
const auto &S : ScoredSignatures) {
855 IndexRequest.IDs.insert(*S.IDForDoc);
857 Index->lookup(IndexRequest, [&](
const Symbol &S) {
858 if (!S.Documentation.empty())
859 FetchedDocs[S.ID] = S.Documentation;
861 log(
"SigHelp: requested docs for {0} symbols from the index, got {1} " 862 "symbols with non-empty docs in the response",
863 IndexRequest.IDs.size(), FetchedDocs.size());
866 llvm::sort(ScoredSignatures, [](
const ScoredSignature &L,
867 const ScoredSignature &R) {
875 if (L.Quality.NumberOfParameters != R.Quality.NumberOfParameters)
876 return L.Quality.NumberOfParameters < R.Quality.NumberOfParameters;
877 if (L.Quality.NumberOfOptionalParameters !=
878 R.Quality.NumberOfOptionalParameters)
879 return L.Quality.NumberOfOptionalParameters <
880 R.Quality.NumberOfOptionalParameters;
881 if (L.Quality.Kind != R.Quality.Kind) {
882 using OC = CodeCompleteConsumer::OverloadCandidate;
883 switch (L.Quality.Kind) {
884 case OC::CK_Function:
886 case OC::CK_FunctionType:
887 return R.Quality.Kind != OC::CK_Function;
888 case OC::CK_FunctionTemplate:
891 llvm_unreachable(
"Unknown overload candidate type.");
893 if (L.Signature.label.size() != R.Signature.label.size())
894 return L.Signature.label.size() < R.Signature.label.size();
895 return L.Signature.label < R.Signature.label;
898 for (
auto &SS : ScoredSignatures) {
900 SS.IDForDoc ? FetchedDocs.find(*SS.IDForDoc) : FetchedDocs.end();
901 if (IndexDocIt != FetchedDocs.end())
902 SS.Signature.documentation = IndexDocIt->second;
904 SigHelp.signatures.push_back(std::move(SS.Signature));
908 GlobalCodeCompletionAllocator &getAllocator()
override {
return *
Allocator; }
910 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
913 void processParameterChunk(llvm::StringRef ChunkText,
916 unsigned ParamStartOffset =
lspLength(Signature.label);
917 unsigned ParamEndOffset = ParamStartOffset +
lspLength(ChunkText);
921 Signature.label += ChunkText;
922 ParameterInformation
Info;
923 Info.labelOffsets.emplace(ParamStartOffset, ParamEndOffset);
925 Info.labelString = ChunkText;
927 Signature.parameters.push_back(std::move(Info));
930 void processOptionalChunk(
const CodeCompletionString &CCS,
932 SignatureQualitySignals &Signal)
const {
933 for (
const auto &Chunk : CCS) {
934 switch (Chunk.Kind) {
935 case CodeCompletionString::CK_Optional:
936 assert(Chunk.Optional &&
937 "Expected the optional code completion string to be non-null.");
938 processOptionalChunk(*Chunk.Optional,
Signature, Signal);
940 case CodeCompletionString::CK_VerticalSpace:
942 case CodeCompletionString::CK_CurrentParameter:
943 case CodeCompletionString::CK_Placeholder:
944 processParameterChunk(Chunk.Text,
Signature);
945 Signal.NumberOfOptionalParameters++;
956 ScoredSignature processOverloadCandidate(
const OverloadCandidate &
Candidate,
957 const CodeCompletionString &CCS,
958 llvm::StringRef DocComment)
const {
960 SignatureQualitySignals Signal;
966 for (
const auto &Chunk : CCS) {
967 switch (Chunk.Kind) {
968 case CodeCompletionString::CK_ResultType:
971 assert(!ReturnType &&
"Unexpected CK_ResultType");
972 ReturnType = Chunk.Text;
974 case CodeCompletionString::CK_CurrentParameter:
975 case CodeCompletionString::CK_Placeholder:
976 processParameterChunk(Chunk.Text, Signature);
977 Signal.NumberOfParameters++;
979 case CodeCompletionString::CK_Optional: {
981 assert(Chunk.Optional &&
982 "Expected the optional code completion string to be non-null.");
983 processOptionalChunk(*Chunk.Optional, Signature, Signal);
986 case CodeCompletionString::CK_VerticalSpace:
989 Signature.label += Chunk.Text;
994 Signature.label +=
" -> ";
997 dlog(
"Signal for {0}: {1}", Signature, Signal);
999 Result.Signature = std::move(Signature);
1000 Result.Quality = Signal;
1002 Result.Signature.documentation.empty() &&
Candidate.getFunction()
1008 SignatureHelp &SigHelp;
1009 std::shared_ptr<clang::GlobalCodeCompletionAllocator>
Allocator;
1011 const SymbolIndex *
Index;
1014 struct SemaCompleteInput {
1020 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS;
1023 void loadMainFilePreambleMacros(
const Preprocessor &PP,
1028 ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource();
1031 IdentifierInfoLookup *PreambleIdentifiers =
1032 PP.getIdentifierTable().getExternalIdentifierLookup();
1033 if (!PreambleIdentifiers || !PreambleMacros)
1035 for (
const auto &MacroName : Preamble.MainFileMacros)
1036 if (
auto *II = PreambleIdentifiers->get(MacroName))
1037 if (II->isOutOfDate())
1038 PreambleMacros->updateOutOfDateIdentifier(*II);
1043 bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
1044 const clang::CodeCompleteOptions &Options,
1045 const SemaCompleteInput &Input,
1046 IncludeStructure *Includes =
nullptr) {
1047 trace::Span Tracer(
"Sema completion");
1048 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS = Input.VFS;
1049 if (Input.Preamble && Input.Preamble->StatCache)
1050 VFS = Input.Preamble->StatCache->getConsumingFS(std::move(VFS));
1051 ParseInputs ParseInput;
1052 ParseInput.CompileCommand = Input.Command;
1053 ParseInput.FS =
VFS;
1054 ParseInput.Contents = Input.Contents;
1055 ParseInput.Opts = ParseOptions();
1058 elog(
"Couldn't create CompilerInvocation");
1061 auto &FrontendOpts = CI->getFrontendOpts();
1062 FrontendOpts.SkipFunctionBodies =
true;
1064 CI->getLangOpts()->SpellChecking =
false;
1066 FrontendOpts.CodeCompleteOpts = Options;
1067 FrontendOpts.CodeCompletionAt.FileName = Input.FileName;
1068 std::tie(FrontendOpts.CodeCompletionAt.Line,
1069 FrontendOpts.CodeCompletionAt.Column) =
1072 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
1073 llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName);
1075 CI->getDiagnosticOpts().IgnoreWarnings =
true;
1082 PreambleBounds PreambleRegion =
1083 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
1084 bool CompletingInPreamble = PreambleRegion.Size > Input.Offset;
1087 IgnoreDiagnostics DummyDiagsConsumer;
1090 (Input.Preamble && !CompletingInPreamble) ? &Input.Preamble->Preamble
1092 std::move(ContentsBuffer), std::move(VFS), DummyDiagsConsumer);
1093 Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble;
1094 Clang->setCodeCompletionConsumer(Consumer.release());
1097 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
1098 log(
"BeginSourceFile() failed when running codeComplete for {0}",
1109 loadMainFilePreambleMacros(Clang->getPreprocessor(), *Input.Preamble);
1111 Clang->getPreprocessor().addPPCallbacks(
1114 log(
"Execute() failed when running codeComplete for {0}: {1}",
1115 Input.FileName,
toString(std::move(Err)));
1118 Action.EndSourceFile();
1124 bool allowIndex(CodeCompletionContext &CC) {
1125 if (!contextAllowsIndex(CC.getKind()))
1128 auto Scope = CC.getCXXScopeSpecifier();
1131 NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
1136 switch (NameSpec->getKind()) {
1137 case NestedNameSpecifier::Global:
1139 case NestedNameSpecifier::NamespaceAlias:
1141 case NestedNameSpecifier::Super:
1142 case NestedNameSpecifier::TypeSpec:
1143 case NestedNameSpecifier::TypeSpecWithTemplate:
1148 llvm_unreachable(
"invalid NestedNameSpecifier kind");
1151 std::future<SymbolSlab> startAsyncFuzzyFind(
const SymbolIndex &
Index,
1152 const FuzzyFindRequest &Req) {
1153 return runAsync<SymbolSlab>([&
Index, Req]() {
1154 trace::Span Tracer(
"Async fuzzyFind");
1156 Index.fuzzyFind(Req, [&Syms](
const Symbol &Sym) { Syms.insert(Sym); });
1157 return std::move(Syms).build();
1164 FuzzyFindRequest speculativeFuzzyFindRequestForCompletion(
1165 FuzzyFindRequest CachedReq,
const CompletionPrefix &HeuristicPrefix) {
1166 CachedReq.Query = HeuristicPrefix.Name;
1199 class CodeCompleteFlow {
1201 IncludeStructure Includes;
1202 SpeculativeFuzzyFind *SpecFuzzyFind;
1203 const CodeCompleteOptions &Opts;
1206 CompletionRecorder *Recorder =
nullptr;
1209 int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0;
1210 bool Incomplete =
false;
1211 CompletionPrefix HeuristicPrefix;
1212 llvm::Optional<FuzzyMatcher> Filter;
1213 Range ReplacedRange;
1214 std::vector<std::string> QueryScopes;
1216 llvm::Optional<ScopeDistance> ScopeProximity;
1217 llvm::Optional<OpaqueType> PreferredType;
1219 bool AllScopes =
false;
1220 llvm::StringSet<> ContextWords;
1223 llvm::Optional<IncludeInserter> Inserter;
1224 llvm::Optional<URIDistance> FileProximity;
1229 llvm::Optional<FuzzyFindRequest> SpecReq;
1233 CodeCompleteFlow(
PathRef FileName,
const IncludeStructure &Includes,
1234 SpeculativeFuzzyFind *SpecFuzzyFind,
1235 const CodeCompleteOptions &Opts)
1236 :
FileName(FileName), Includes(Includes), SpecFuzzyFind(SpecFuzzyFind),
1239 CodeCompleteResult run(
const SemaCompleteInput &SemaCCInput) && {
1240 trace::Span Tracer(
"CodeCompleteFlow");
1243 populateContextWords(SemaCCInput.Contents);
1244 if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq.hasValue()) {
1245 assert(!SpecFuzzyFind->Result.valid());
1246 SpecReq = speculativeFuzzyFindRequestForCompletion(
1247 *SpecFuzzyFind->CachedReq, HeuristicPrefix);
1248 SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq);
1254 CodeCompleteResult Output;
1255 auto RecorderOwner = llvm::make_unique<CompletionRecorder>(Opts, [&]() {
1256 assert(Recorder &&
"Recorder is not set");
1257 CCContextKind = Recorder->CCContext.getKind();
1259 SemaCCInput.FileName, SemaCCInput.Contents, SemaCCInput.VFS.get());
1263 SemaCCInput.FileName, SemaCCInput.Contents, Style,
1264 SemaCCInput.Command.Directory,
1265 &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
1266 for (
const auto &Inc : Includes.MainFileIncludes)
1267 Inserter->addExisting(Inc);
1273 FileDistanceOptions ProxOpts{};
1274 const auto &SM = Recorder->CCSema->getSourceManager();
1275 llvm::StringMap<SourceParams> ProxSources;
1276 for (
auto &
Entry : Includes.includeDepth(
1277 SM.getFileEntryForID(SM.getMainFileID())->getName())) {
1278 auto &Source = ProxSources[
Entry.getKey()];
1279 Source.Cost =
Entry.getValue() * ProxOpts.IncludeCost;
1283 if (
Entry.getValue() > 0)
1284 Source.MaxUpTraversals = 1;
1286 FileProximity.emplace(ProxSources, ProxOpts);
1288 Output = runWithSema();
1291 getCompletionKindString(CCContextKind));
1292 log(
"Code complete: sema context {0}, query scopes [{1}] (AnyScope={2}), " 1293 "expected type {3}",
1294 getCompletionKindString(CCContextKind),
1295 llvm::join(QueryScopes.begin(), QueryScopes.end(),
","), AllScopes,
1296 PreferredType ? Recorder->CCContext.getPreferredType().getAsString()
1300 Recorder = RecorderOwner.get();
1302 semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(),
1303 SemaCCInput, &Includes);
1304 logResults(Output, Tracer);
1308 void logResults(
const CodeCompleteResult &Output,
const trace::Span &Tracer) {
1311 SPAN_ATTACH(Tracer,
"merged_results", NSemaAndIndex);
1312 SPAN_ATTACH(Tracer,
"identifier_results", NIdent);
1313 SPAN_ATTACH(Tracer,
"returned_results", int64_t(Output.Completions.size()));
1314 SPAN_ATTACH(Tracer,
"incomplete", Output.HasMore);
1315 log(
"Code complete: {0} results from Sema, {1} from Index, " 1316 "{2} matched, {3} from identifiers, {4} returned{5}.",
1317 NSema, NIndex, NSemaAndIndex, NIdent, Output.Completions.size(),
1318 Output.HasMore ?
" (incomplete)" :
"");
1319 assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit);
1325 runWithoutSema(llvm::StringRef Content,
size_t Offset,
1326 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS) && {
1327 trace::Span Tracer(
"CodeCompleteWithoutSema");
1330 populateContextWords(Content);
1331 CCContextKind = CodeCompletionContext::CCC_Recovery;
1332 Filter = FuzzyMatcher(HeuristicPrefix.Name);
1334 ReplacedRange.start = ReplacedRange.end = Pos;
1335 ReplacedRange.start.character -= HeuristicPrefix.Name.size();
1337 llvm::StringMap<SourceParams> ProxSources;
1339 FileProximity.emplace(ProxSources);
1343 Inserter.emplace(FileName, Content, Style,
1347 std::vector<RawIdentifier> IdentifierResults;
1348 for (
const auto &IDAndCount : Identifiers) {
1350 ID.Name = IDAndCount.first();
1351 ID.References = IDAndCount.second;
1353 if (ID.Name == HeuristicPrefix.Name)
1355 if (ID.References > 0)
1356 IdentifierResults.push_back(std::move(ID));
1362 SpecifiedScope Scopes;
1363 Scopes.AccessibleScopes =
1365 for (std::string &S : Scopes.AccessibleScopes)
1368 if (HeuristicPrefix.Qualifier.empty())
1369 AllScopes = Opts.AllScopes;
1370 else if (HeuristicPrefix.Qualifier.startswith(
"::")) {
1371 Scopes.AccessibleScopes = {
""};
1372 Scopes.UnresolvedQualifier = HeuristicPrefix.Qualifier.drop_front(2);
1374 Scopes.UnresolvedQualifier = HeuristicPrefix.Qualifier;
1376 QueryScopes = Scopes.scopesForIndexQuery();
1377 ScopeProximity.emplace(QueryScopes);
1379 SymbolSlab IndexResults = Opts.Index ? queryIndex() : SymbolSlab();
1381 CodeCompleteResult Output = toCodeCompleteResult(mergeResults(
1382 {}, IndexResults, IdentifierResults));
1383 Output.RanParser =
false;
1384 logResults(Output, Tracer);
1389 void populateContextWords(llvm::StringRef Content) {
1391 unsigned RangeEnd = HeuristicPrefix.Qualifier.begin() - Content.data(),
1392 RangeBegin = RangeEnd;
1393 for (
size_t I = 0; I < 3 && RangeBegin > 0; ++I) {
1394 auto PrevNL = Content.rfind(
'\n', RangeBegin);
1395 if (PrevNL == StringRef::npos) {
1399 RangeBegin = PrevNL;
1402 ContextWords =
collectWords(Content.slice(RangeBegin, RangeEnd));
1403 dlog(
"Completion context words: {0}",
1409 CodeCompleteResult runWithSema() {
1410 const auto &CodeCompletionRange = CharSourceRange::getCharRange(
1411 Recorder->CCSema->getPreprocessor().getCodeCompletionTokenRange());
1417 if (CodeCompletionRange.isValid()) {
1419 CodeCompletionRange);
1422 Recorder->CCSema->getSourceManager(),
1423 Recorder->CCSema->getPreprocessor().getCodeCompletionLoc());
1424 ReplacedRange.start = ReplacedRange.end = Pos;
1426 Filter = FuzzyMatcher(
1427 Recorder->CCSema->getPreprocessor().getCodeCompletionFilter());
1428 std::tie(QueryScopes, AllScopes) = getQueryScopes(
1429 Recorder->CCContext, *Recorder->CCSema, HeuristicPrefix, Opts);
1430 if (!QueryScopes.empty())
1431 ScopeProximity.emplace(QueryScopes);
1434 Recorder->CCContext.getPreferredType());
1440 auto IndexResults = (Opts.Index && allowIndex(Recorder->CCContext))
1443 trace::Span Tracer(
"Populate CodeCompleteResult");
1446 mergeResults(Recorder->Results, IndexResults, {});
1447 return toCodeCompleteResult(Top);
1451 toCodeCompleteResult(
const std::vector<ScoredBundle> &Scored) {
1452 CodeCompleteResult Output;
1455 for (
auto &C : Scored) {
1456 Output.Completions.push_back(toCodeCompletion(C.first));
1457 Output.Completions.back().Score = C.second;
1458 Output.Completions.back().CompletionTokenRange = ReplacedRange;
1460 Output.HasMore = Incomplete;
1461 Output.Context = CCContextKind;
1465 SymbolSlab queryIndex() {
1466 trace::Span Tracer(
"Query index");
1467 SPAN_ATTACH(Tracer,
"limit", int64_t(Opts.Limit));
1470 FuzzyFindRequest Req;
1472 Req.Limit = Opts.Limit;
1473 Req.Query = Filter->pattern();
1474 Req.RestrictForCodeCompletion =
true;
1475 Req.Scopes = QueryScopes;
1476 Req.AnyScope = AllScopes;
1478 Req.ProximityPaths.push_back(FileName);
1480 Req.PreferredTypes.push_back(PreferredType->raw());
1481 vlog(
"Code complete: fuzzyFind({0:2})",
toJSON(Req));
1484 SpecFuzzyFind->NewReq = Req;
1485 if (SpecFuzzyFind && SpecFuzzyFind->Result.valid() && (*SpecReq == Req)) {
1486 vlog(
"Code complete: speculative fuzzy request matches the actual index " 1487 "request. Waiting for the speculative index results.");
1490 trace::Span WaitSpec(
"Wait speculative results");
1491 return SpecFuzzyFind->Result.get();
1494 SPAN_ATTACH(Tracer,
"Speculative results",
false);
1498 if (Opts.Index->fuzzyFind(
1499 Req, [&](
const Symbol &Sym) { ResultsBuilder.insert(Sym); }))
1501 return std::move(ResultsBuilder).build();
1509 std::vector<ScoredBundle>
1510 mergeResults(
const std::vector<CodeCompletionResult> &SemaResults,
1511 const SymbolSlab &IndexResults,
1512 const std::vector<RawIdentifier> &IdentifierResults) {
1513 trace::Span Tracer(
"Merge and score results");
1514 std::vector<CompletionCandidate::Bundle> Bundles;
1515 llvm::DenseMap<size_t, size_t> BundleLookup;
1516 auto AddToBundles = [&](
const CodeCompletionResult *
SemaResult,
1519 CompletionCandidate C;
1523 if (C.IndexResult) {
1524 C.Name = IndexResult->Name;
1526 }
else if (C.SemaResult) {
1527 C.Name = Recorder->getName(*SemaResult);
1532 if (
auto OverloadSet = C.overloadSet(Opts)) {
1533 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
1535 Bundles.emplace_back();
1536 Bundles[Ret.first->second].push_back(std::move(C));
1538 Bundles.emplace_back();
1539 Bundles.back().push_back(std::move(C));
1542 llvm::DenseSet<const Symbol *> UsedIndexResults;
1543 auto CorrespondingIndexResult =
1544 [&](
const CodeCompletionResult &
SemaResult) ->
const Symbol * {
1546 getSymbolID(SemaResult, Recorder->CCSema->getSourceManager())) {
1547 auto I = IndexResults.find(*SymID);
1548 if (I != IndexResults.end()) {
1549 UsedIndexResults.insert(&*I);
1556 for (
auto &SemaResult : SemaResults)
1557 AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult),
nullptr);
1559 for (
const auto &IndexResult : IndexResults) {
1560 if (UsedIndexResults.count(&IndexResult))
1562 AddToBundles(
nullptr, &IndexResult,
nullptr);
1565 for (
const auto &Ident : IdentifierResults)
1566 AddToBundles(
nullptr,
nullptr, &Ident);
1568 TopN<ScoredBundle, ScoredBundleGreater> Top(
1569 Opts.Limit == 0 ? std::numeric_limits<size_t>::max() : Opts.Limit);
1570 for (
auto &Bundle : Bundles)
1571 addCandidate(Top, std::move(Bundle));
1572 return std::move(Top).items();
1575 llvm::Optional<float> fuzzyScore(
const CompletionCandidate &C) {
1578 if (C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro &&
1579 !C.Name.startswith_lower(Filter->pattern()))
1581 return Filter->match(C.Name);
1585 void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates,
1586 CompletionCandidate::Bundle Bundle) {
1588 SymbolRelevanceSignals Relevance;
1589 Relevance.Context = CCContextKind;
1590 Relevance.Name = Bundle.front().Name;
1592 Relevance.FileProximityMatch = FileProximity.getPointer();
1594 Relevance.ScopeProximityMatch = ScopeProximity.getPointer();
1596 Relevance.HadContextType =
true;
1597 Relevance.ContextWords = &ContextWords;
1599 auto &First = Bundle.front();
1600 if (
auto FuzzyScore = fuzzyScore(First))
1601 Relevance.NameMatch = *FuzzyScore;
1605 bool FromIndex =
false;
1609 Relevance.merge(*
Candidate.IndexResult);
1610 Origin |=
Candidate.IndexResult->Origin;
1612 if (!
Candidate.IndexResult->Type.empty())
1613 Relevance.HadSymbolType |=
true;
1614 if (PreferredType &&
1615 PreferredType->raw() ==
Candidate.IndexResult->Type) {
1616 Relevance.TypeMatchesPreferred =
true;
1622 if (PreferredType) {
1624 Recorder->CCSema->getASTContext(), *
Candidate.SemaResult)) {
1625 Relevance.HadSymbolType |=
true;
1626 if (PreferredType == CompletionType)
1627 Relevance.TypeMatchesPreferred =
true;
1633 Quality.References =
Candidate.IdentifierResult->References;
1639 CodeCompletion::Scores Scores;
1640 Scores.Quality = Quality.evaluate();
1641 Scores.Relevance = Relevance.evaluate();
1644 Scores.ExcludingName = Relevance.NameMatch
1645 ? Scores.Total / Relevance.NameMatch
1648 dlog(
"CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
1649 llvm::to_string(Origin), Scores.Total, llvm::to_string(Quality),
1650 llvm::to_string(Relevance));
1653 NIndex += FromIndex;
1654 NSemaAndIndex += bool(Origin & SymbolOrigin::AST) && FromIndex;
1656 if (Candidates.push({std::move(Bundle), Scores}))
1660 CodeCompletion toCodeCompletion(
const CompletionCandidate::Bundle &Bundle) {
1661 llvm::Optional<CodeCompletionBuilder>
Builder;
1662 for (
const auto &Item : Bundle) {
1663 CodeCompletionString *SemaCCS =
1664 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult)
1667 Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() :
nullptr,
1668 Item, SemaCCS, QueryScopes, *Inserter,
FileName,
1669 CCContextKind, Opts);
1671 Builder->add(Item, SemaCCS);
1673 return Builder->build();
1677 template <
class T>
bool isExplicitTemplateSpecialization(
const NamedDecl &ND) {
1678 if (
const auto *TD = dyn_cast<T>(&ND))
1679 if (TD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
1687 clang::CodeCompleteOptions
Result;
1688 Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
1689 Result.IncludeMacros = IncludeMacros;
1690 Result.IncludeGlobals =
true;
1695 Result.IncludeBriefComments =
false;
1700 Result.LoadExternal = !
Index;
1701 Result.IncludeFixIts = IncludeFixIts;
1708 assert(Offset <= Content.size());
1709 StringRef Rest = Content.take_front(Offset);
1714 while (!Rest.empty() && isIdentifierBody(Rest.back()))
1715 Rest = Rest.drop_back();
1716 Result.
Name = Content.slice(Rest.size(),
Offset);
1719 while (Rest.consume_back(
"::") && !Rest.endswith(
":"))
1720 while (!Rest.empty() && isIdentifierBody(Rest.back()))
1721 Rest = Rest.drop_back();
1723 Content.slice(Rest.size(), Result.
Name.begin() - Content.begin());
1731 Position Pos, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS,
1735 elog(
"Code completion position was invalid {0}",
Offset.takeError());
1738 auto Flow = CodeCompleteFlow(
1740 SpecFuzzyFind, Opts);
1742 ? std::move(Flow).runWithoutSema(Contents, *
Offset, VFS)
1743 : std::move(Flow).run(
1748 const tooling::CompileCommand &
Command,
1751 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
VFS,
1755 elog(
"Code completion position was invalid {0}",
Offset.takeError());
1759 clang::CodeCompleteOptions Options;
1760 Options.IncludeGlobals =
false;
1761 Options.IncludeMacros =
false;
1762 Options.IncludeCodePatterns =
false;
1763 Options.IncludeBriefComments =
false;
1766 llvm::make_unique<SignatureHelpCollector>(Options, Index, Result),
1773 auto InTopLevelScope = [](
const NamedDecl &ND) {
1774 switch (ND.getDeclContext()->getDeclKind()) {
1775 case Decl::TranslationUnit:
1777 case Decl::LinkageSpec:
1786 if (isExplicitTemplateSpecialization<FunctionDecl>(ND) ||
1787 isExplicitTemplateSpecialization<CXXRecordDecl>(ND) ||
1788 isExplicitTemplateSpecialization<VarDecl>(ND))
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)
1856 <<
" (" << 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
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)
std::unique_ptr< CompilerInvocation > buildCompilerInvocation(const ParseInputs &Inputs)
Builds compiler invocation that could be used to build AST or preamble.
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
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.
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
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.
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
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 llvm::Expected< URI > parse(llvm::StringRef Uri)
Parse a URI string "<scheme>:[//<authority>/]<path>".
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)
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