34 #include "clang/ASTMatchers/ASTMatchFinder.h" 35 #include "clang/Basic/LangOptions.h" 36 #include "clang/Format/Format.h" 37 #include "clang/Frontend/CompilerInstance.h" 38 #include "clang/Frontend/FrontendActions.h" 39 #include "clang/Index/USRGeneration.h" 40 #include "clang/Sema/CodeCompleteConsumer.h" 41 #include "clang/Sema/Sema.h" 42 #include "clang/Tooling/Core/Replacement.h" 43 #include "llvm/Support/Format.h" 44 #include "llvm/Support/FormatVariadic.h" 45 #include "llvm/Support/ScopedPrinter.h" 49 #define DEBUG_TYPE "CodeComplete" 62 case SK::NamespaceAlias:
83 case SK::ConversionFunction:
91 case SK::EnumConstant:
93 case SK::InstanceMethod:
95 case SK::StaticMethod:
98 case SK::InstanceProperty:
99 case SK::ClassProperty:
100 case SK::StaticProperty:
105 llvm_unreachable(
"Unhandled clang::index::SymbolKind.");
109 toCompletionItemKind(CodeCompletionResult::ResultKind ResKind,
110 const NamedDecl *Decl) {
112 return toCompletionItemKind(index::getSymbolInfo(Decl).Kind);
114 case CodeCompletionResult::RK_Declaration:
115 llvm_unreachable(
"RK_Declaration without Decl");
116 case CodeCompletionResult::RK_Keyword:
118 case CodeCompletionResult::RK_Macro:
121 case CodeCompletionResult::RK_Pattern:
124 llvm_unreachable(
"Unhandled CodeCompletionResult::ResultKind.");
131 getOptionalParameters(
const CodeCompletionString &CCS,
132 std::vector<ParameterInformation> &Parameters) {
134 for (
const auto &Chunk : CCS) {
135 switch (Chunk.Kind) {
136 case CodeCompletionString::CK_Optional:
137 assert(Chunk.Optional &&
138 "Expected the optional code completion string to be non-null.");
139 Result += getOptionalParameters(*Chunk.Optional, Parameters);
141 case CodeCompletionString::CK_VerticalSpace:
143 case CodeCompletionString::CK_Placeholder:
147 case CodeCompletionString::CK_CurrentParameter: {
151 Result += Chunk.Text;
152 ParameterInformation
Info;
153 Info.label = Chunk.Text;
154 Parameters.push_back(std::move(Info));
158 Result += Chunk.Text;
167 static llvm::Expected<HeaderFile> toHeaderFile(StringRef Header,
168 llvm::StringRef HintPath) {
170 return HeaderFile{Header.str(),
true};
173 return U.takeError();
177 return IncludePath.takeError();
178 if (!IncludePath->empty())
179 return HeaderFile{std::move(*IncludePath),
true};
183 return Resolved.takeError();
184 return HeaderFile{std::move(*Resolved),
false};
189 struct CompletionCandidate {
197 size_t overloadSet()
const {
198 SmallString<256> Scratch;
200 switch (IndexResult->SymInfo.Kind) {
201 case index::SymbolKind::ClassMethod:
202 case index::SymbolKind::InstanceMethod:
203 case index::SymbolKind::StaticMethod:
204 assert(
false &&
"Don't expect members from index in code completion");
206 case index::SymbolKind::Function:
210 (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch),
211 headerToInsertIfNotPresent().getValueOr(
""));
218 const NamedDecl *D = SemaResult->Declaration;
219 if (!D || !D->isFunctionOrFunctionTemplate())
222 llvm::raw_svector_ostream OS(Scratch);
223 D->printQualifiedName(OS);
225 return hash_combine(Scratch, headerToInsertIfNotPresent().getValueOr(
""));
228 llvm::Optional<llvm::StringRef> headerToInsertIfNotPresent()
const {
229 if (!IndexResult || !IndexResult->Detail ||
230 IndexResult->Detail->IncludeHeader.empty())
232 if (SemaResult && SemaResult->Declaration) {
235 auto &SM = SemaResult->Declaration->getASTContext().getSourceManager();
236 for (
const Decl *RD : SemaResult->Declaration->redecls())
237 if (SM.isInMainFile(SM.getExpansionLoc(RD->getLocStart())))
240 return IndexResult->Detail->IncludeHeader;
243 using Bundle = llvm::SmallVector<CompletionCandidate, 4>;
246 std::pair<CompletionCandidate::Bundle, CodeCompletion::Scores>;
247 struct ScoredBundleGreater {
248 bool operator()(
const ScoredBundle &L,
const ScoredBundle &R) {
249 if (L.second.Total != R.second.Total)
250 return L.second.Total > R.second.Total;
251 return L.first.front().Name <
252 R.first.front().Name;
263 struct CodeCompletionBuilder {
264 CodeCompletionBuilder(ASTContext &ASTCtx,
const CompletionCandidate &C,
265 CodeCompletionString *SemaCCS,
266 const IncludeInserter &Includes, StringRef
FileName,
267 const CodeCompleteOptions &Opts)
268 : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments) {
272 Completion.Name = llvm::StringRef(SemaCCS->getTypedText());
273 if (Completion.Scope.empty()) {
274 if ((C.SemaResult->Kind == CodeCompletionResult::RK_Declaration) ||
275 (C.SemaResult->Kind == CodeCompletionResult::RK_Pattern))
276 if (
const auto *D = C.SemaResult->getDeclaration())
277 if (
const auto *ND = llvm::dyn_cast<NamedDecl>(D))
282 toCompletionItemKind(C.SemaResult->Kind, C.SemaResult->Declaration);
285 Completion.Origin |= C.IndexResult->Origin;
286 if (Completion.Scope.empty())
287 Completion.Scope = C.IndexResult->Scope;
289 Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
290 if (Completion.Name.empty())
291 Completion.Name = C.IndexResult->Name;
293 if (
auto Inserted = C.headerToInsertIfNotPresent()) {
295 auto Include = [&]() -> Expected<std::pair<std::string, bool>> {
296 auto ResolvedDeclaring =
297 toHeaderFile(C.IndexResult->CanonicalDeclaration.FileURI, FileName);
298 if (!ResolvedDeclaring)
299 return ResolvedDeclaring.takeError();
300 auto ResolvedInserted = toHeaderFile(*Inserted, FileName);
301 if (!ResolvedInserted)
302 return ResolvedInserted.takeError();
303 return std::make_pair(Includes.calculateIncludePath(*ResolvedDeclaring,
305 Includes.shouldInsertInclude(*ResolvedDeclaring,
309 Completion.Header = Include->first;
311 Completion.HeaderInsertion = Includes.insert(Include->first);
313 log(
"Failed to generate include insertion edits for adding header " 314 "(FileURI='{0}', IncludeHeader='{1}') into {2}",
315 C.IndexResult->CanonicalDeclaration.FileURI,
316 C.IndexResult->Detail->IncludeHeader, FileName);
320 void add(
const CompletionCandidate &C, CodeCompletionString *SemaCCS) {
321 assert(
bool(C.SemaResult) ==
bool(SemaCCS));
323 BundledEntry &S =
Bundled.back();
326 &Completion.RequiredQualifier);
328 }
else if (C.IndexResult) {
329 S.Signature = C.IndexResult->Signature;
330 S.SnippetSuffix = C.IndexResult->CompletionSnippetSuffix;
331 if (
auto *D = C.IndexResult->Detail)
332 S.ReturnType = D->ReturnType;
334 if (ExtractDocumentation && Completion.Documentation.empty()) {
335 if (C.IndexResult && C.IndexResult->Detail)
336 Completion.Documentation = C.IndexResult->Detail->Documentation;
337 else if (C.SemaResult)
338 Completion.Documentation =
getDocComment(ASTCtx, *C.SemaResult,
343 CodeCompletion build() {
344 Completion.ReturnType = summarizeReturnType();
345 Completion.Signature = summarizeSignature();
346 Completion.SnippetSuffix = summarizeSnippet();
347 Completion.BundleSize =
Bundled.size();
348 return std::move(Completion);
352 struct BundledEntry {
359 template <std::
string BundledEntry::*Member>
360 const std::string *onlyValue()
const {
362 for (
auto I = B + 1; I != E; ++I)
363 if (I->*Member != B->*Member)
365 return &(B->*Member);
368 std::string summarizeReturnType()
const {
369 if (
auto *RT = onlyValue<&BundledEntry::ReturnType>())
374 std::string summarizeSnippet()
const {
375 if (
auto *
Snippet = onlyValue<&BundledEntry::SnippetSuffix>())
381 std::string summarizeSignature()
const {
382 if (
auto *
Signature = onlyValue<&BundledEntry::Signature>())
389 CodeCompletion Completion;
390 SmallVector<BundledEntry, 1>
Bundled;
391 bool ExtractDocumentation;
395 llvm::Optional<SymbolID> getSymbolID(
const CodeCompletionResult &R) {
397 case CodeCompletionResult::RK_Declaration:
398 case CodeCompletionResult::RK_Pattern: {
399 llvm::SmallString<128> USR;
400 if (clang::index::generateUSRForDecl(R.Declaration, USR))
404 case CodeCompletionResult::RK_Macro:
406 case CodeCompletionResult::RK_Keyword:
409 llvm_unreachable(
"unknown CodeCompletionResult kind");
414 struct SpecifiedScope {
442 std::vector<std::string> scopesForIndexQuery() {
443 std::vector<std::string>
Results;
444 for (llvm::StringRef AS : AccessibleScopes) {
445 Results.push_back(AS);
446 if (UnresolvedQualifier)
454 std::vector<std::string> getQueryScopes(CodeCompletionContext &
CCContext,
455 const SourceManager &SM) {
456 auto GetAllAccessibleScopes = [](CodeCompletionContext &
CCContext) {
458 for (
auto *Context : CCContext.getVisitedContexts()) {
459 if (isa<TranslationUnitDecl>(Context))
460 Info.AccessibleScopes.push_back(
"");
461 else if (
const auto *NS = dyn_cast<NamespaceDecl>(Context))
462 Info.AccessibleScopes.push_back(NS->getQualifiedNameAsString() +
"::");
467 auto SS = CCContext.getCXXScopeSpecifier();
476 return GetAllAccessibleScopes(CCContext).scopesForIndexQuery();
481 if ((*SS)->isValid()) {
482 return GetAllAccessibleScopes(CCContext).scopesForIndexQuery();
490 Info.AccessibleScopes.push_back(
"");
492 Info.UnresolvedQualifier =
493 Lexer::getSourceText(CharSourceRange::getCharRange((*SS)->getRange()), SM,
494 clang::LangOptions())
497 if (!Info.UnresolvedQualifier->empty())
498 *Info.UnresolvedQualifier +=
"::";
500 return Info.scopesForIndexQuery();
507 case CodeCompletionContext::CCC_TopLevel:
508 case CodeCompletionContext::CCC_ObjCInterface:
509 case CodeCompletionContext::CCC_ObjCImplementation:
510 case CodeCompletionContext::CCC_ObjCIvarList:
511 case CodeCompletionContext::CCC_ClassStructUnion:
512 case CodeCompletionContext::CCC_Statement:
513 case CodeCompletionContext::CCC_Expression:
514 case CodeCompletionContext::CCC_ObjCMessageReceiver:
515 case CodeCompletionContext::CCC_EnumTag:
516 case CodeCompletionContext::CCC_UnionTag:
517 case CodeCompletionContext::CCC_ClassOrStructTag:
518 case CodeCompletionContext::CCC_ObjCProtocolName:
519 case CodeCompletionContext::CCC_Namespace:
520 case CodeCompletionContext::CCC_Type:
521 case CodeCompletionContext::CCC_Name:
522 case CodeCompletionContext::CCC_PotentiallyQualifiedName:
523 case CodeCompletionContext::CCC_ParenthesizedExpression:
524 case CodeCompletionContext::CCC_ObjCInterfaceName:
525 case CodeCompletionContext::CCC_ObjCCategoryName:
527 case CodeCompletionContext::CCC_Other:
528 case CodeCompletionContext::CCC_OtherWithMacros:
529 case CodeCompletionContext::CCC_DotMemberAccess:
530 case CodeCompletionContext::CCC_ArrowMemberAccess:
531 case CodeCompletionContext::CCC_ObjCPropertyAccess:
532 case CodeCompletionContext::CCC_MacroName:
533 case CodeCompletionContext::CCC_MacroNameUse:
534 case CodeCompletionContext::CCC_PreprocessorExpression:
535 case CodeCompletionContext::CCC_PreprocessorDirective:
536 case CodeCompletionContext::CCC_NaturalLanguage:
537 case CodeCompletionContext::CCC_SelectorName:
538 case CodeCompletionContext::CCC_TypeQualifiers:
539 case CodeCompletionContext::CCC_ObjCInstanceMessage:
540 case CodeCompletionContext::CCC_ObjCClassMessage:
541 case CodeCompletionContext::CCC_Recovery:
544 llvm_unreachable(
"unknown code completion context");
548 static bool isBlacklistedMember(
const NamedDecl &D) {
551 if (D.getKind() == Decl::CXXDestructor)
554 if (
auto *R = dyn_cast_or_null<RecordDecl>(&D))
555 if (R->isInjectedClassName())
558 auto NameKind = D.getDeclName().getNameKind();
559 if (NameKind == DeclarationName::CXXOperatorName ||
560 NameKind == DeclarationName::CXXLiteralOperatorName ||
561 NameKind == DeclarationName::CXXConversionFunctionName)
572 struct CompletionRecorder :
public CodeCompleteConsumer {
573 CompletionRecorder(
const CodeCompleteOptions &Opts,
574 llvm::unique_function<
void()> ResultsCallback)
575 : CodeCompleteConsumer(Opts.getClangCompleteOpts(),
577 CCContext(CodeCompletionContext::CCC_Other), Opts(Opts),
578 CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
579 CCTUInfo(CCAllocator), ResultsCallback(std::move(ResultsCallback)) {
580 assert(this->ResultsCallback);
588 void ProcessCodeCompleteResults(
class Sema &S, CodeCompletionContext Context,
589 CodeCompletionResult *InResults,
590 unsigned NumResults)
override final {
599 if (Context.getKind() == CodeCompletionContext::CCC_Recovery) {
600 log(
"Code complete: Ignoring sema code complete callback with Recovery " 607 if (NumResults == 0 && !contextAllowsIndex(Context.getKind()))
610 log(
"Multiple code complete callbacks (parser backtracked?). " 611 "Dropping results from context {0}, keeping results from {1}.",
612 getCompletionKindString(Context.getKind()),
613 getCompletionKindString(this->CCContext.getKind()));
621 for (
unsigned I = 0; I < NumResults; ++I) {
622 auto &Result = InResults[I];
625 if (Result.Hidden && (!Result.Qualifier || Result.QualifierIsInformative))
627 if (!Opts.IncludeIneligibleResults &&
628 (Result.Availability == CXAvailability_NotAvailable ||
629 Result.Availability == CXAvailability_NotAccessible))
631 if (Result.Declaration &&
632 !Context.getBaseType().isNull()
633 && isBlacklistedMember(*Result.Declaration))
636 Result.StartsNestedNameSpecifier =
false;
637 Results.push_back(Result);
642 CodeCompletionAllocator &getAllocator()
override {
return *CCAllocator; }
643 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
647 llvm::StringRef getName(
const CodeCompletionResult &Result) {
648 switch (Result.Kind) {
649 case CodeCompletionResult::RK_Declaration:
650 if (
auto *ID = Result.Declaration->getIdentifier())
651 return ID->getName();
653 case CodeCompletionResult::RK_Keyword:
654 return Result.Keyword;
655 case CodeCompletionResult::RK_Macro:
656 return Result.Macro->getName();
657 case CodeCompletionResult::RK_Pattern:
658 return Result.Pattern->getTypedText();
660 auto *CCS = codeCompletionString(Result);
661 return CCS->getTypedText();
666 CodeCompletionString *codeCompletionString(
const CodeCompletionResult &R) {
668 return const_cast<CodeCompletionResult &
>(R).CreateCodeCompletionString(
669 *CCSema, CCContext, *CCAllocator, CCTUInfo,
674 CodeCompleteOptions Opts;
675 std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
676 CodeCompletionTUInfo CCTUInfo;
677 llvm::unique_function<void()> ResultsCallback;
680 class SignatureHelpCollector final :
public CodeCompleteConsumer {
683 SignatureHelpCollector(
const clang::CodeCompleteOptions &CodeCompleteOpts,
684 SignatureHelp &SigHelp)
685 : CodeCompleteConsumer(CodeCompleteOpts,
false),
687 Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
688 CCTUInfo(Allocator) {}
690 void ProcessOverloadCandidates(Sema &S,
unsigned CurrentArg,
691 OverloadCandidate *Candidates,
692 unsigned NumCandidates)
override {
693 SigHelp.signatures.reserve(NumCandidates);
697 SigHelp.activeSignature = 0;
698 assert(CurrentArg <= (
unsigned)std::numeric_limits<int>::max() &&
699 "too many arguments");
700 SigHelp.activeParameter =
static_cast<int>(CurrentArg);
701 for (
unsigned I = 0; I < NumCandidates; ++I) {
702 const auto &Candidate = Candidates[I];
703 const auto *CCS = Candidate.CreateSignatureString(
704 CurrentArg, S, *Allocator, CCTUInfo,
true);
705 assert(CCS &&
"Expected the CodeCompletionString to be non-null");
707 SigHelp.signatures.push_back(processOverloadCandidate(
714 GlobalCodeCompletionAllocator &getAllocator()
override {
return *Allocator; }
716 CodeCompletionTUInfo &getCodeCompletionTUInfo()
override {
return CCTUInfo; }
722 processOverloadCandidate(
const OverloadCandidate &Candidate,
723 const CodeCompletionString &CCS,
724 llvm::StringRef DocComment)
const {
725 SignatureInformation Result;
730 for (
const auto &Chunk : CCS) {
731 switch (Chunk.Kind) {
732 case CodeCompletionString::CK_ResultType:
735 assert(!ReturnType &&
"Unexpected CK_ResultType");
736 ReturnType = Chunk.Text;
738 case CodeCompletionString::CK_Placeholder:
742 case CodeCompletionString::CK_CurrentParameter: {
746 Result.label += Chunk.Text;
747 ParameterInformation
Info;
748 Info.label = Chunk.Text;
749 Result.parameters.push_back(std::move(Info));
752 case CodeCompletionString::CK_Optional: {
754 assert(Chunk.Optional &&
755 "Expected the optional code completion string to be non-null.");
757 getOptionalParameters(*Chunk.Optional, Result.parameters);
760 case CodeCompletionString::CK_VerticalSpace:
763 Result.label += Chunk.Text;
768 Result.label +=
" -> ";
774 SignatureHelp &SigHelp;
775 std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
776 CodeCompletionTUInfo CCTUInfo;
780 struct SemaCompleteInput {
786 IntrusiveRefCntPtr<vfs::FileSystem>
VFS;
787 std::shared_ptr<PCHContainerOperations>
PCHs;
792 bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
793 const clang::CodeCompleteOptions &Options,
794 const SemaCompleteInput &Input,
795 IncludeStructure *Includes =
nullptr) {
796 trace::Span Tracer(
"Sema completion");
797 std::vector<const char *> ArgStrs;
798 for (
const auto &S : Input.Command.CommandLine)
799 ArgStrs.push_back(S.c_str());
801 if (Input.VFS->setCurrentWorkingDirectory(Input.Command.Directory)) {
802 log(
"Couldn't set working directory");
807 IgnoreDiagnostics DummyDiagsConsumer;
808 auto CI = createInvocationFromCommandLine(
810 CompilerInstance::createDiagnostics(
new DiagnosticOptions,
811 &DummyDiagsConsumer,
false),
814 elog(
"Couldn't create CompilerInvocation");
817 auto &FrontendOpts = CI->getFrontendOpts();
818 FrontendOpts.DisableFree =
false;
819 FrontendOpts.SkipFunctionBodies =
true;
820 CI->getLangOpts()->CommentOpts.ParseAllComments =
true;
822 CI->getLangOpts()->SpellChecking =
false;
824 FrontendOpts.CodeCompleteOpts = Options;
825 FrontendOpts.CodeCompletionAt.FileName = Input.FileName;
828 elog(
"Code completion position was invalid {0}", Offset.takeError());
831 std::tie(FrontendOpts.CodeCompletionAt.Line,
832 FrontendOpts.CodeCompletionAt.Column) =
835 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
836 llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName);
838 CI->getDiagnosticOpts().IgnoreWarnings =
true;
845 std::move(CI), Input.Preamble, std::move(ContentsBuffer),
846 std::move(Input.PCHs), std::move(Input.VFS), DummyDiagsConsumer);
847 Clang->setCodeCompletionConsumer(Consumer.release());
850 if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
851 log(
"BeginSourceFile() failed when running codeComplete for {0}",
856 Clang->getPreprocessor().addPPCallbacks(
858 if (!Action.Execute()) {
859 log(
"Execute() failed when running codeComplete for {0}", Input.FileName);
862 Action.EndSourceFile();
868 bool allowIndex(CodeCompletionContext &CC) {
869 if (!contextAllowsIndex(CC.getKind()))
872 auto Scope = CC.getCXXScopeSpecifier();
875 NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep();
880 switch (NameSpec->getKind()) {
881 case NestedNameSpecifier::Global:
883 case NestedNameSpecifier::NamespaceAlias:
885 case NestedNameSpecifier::Super:
886 case NestedNameSpecifier::TypeSpec:
887 case NestedNameSpecifier::TypeSpecWithTemplate:
889 case NestedNameSpecifier::Identifier:
892 llvm_unreachable(
"invalid NestedNameSpecifier kind");
898 clang::CodeCompleteOptions Result;
899 Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
900 Result.IncludeMacros = IncludeMacros;
901 Result.IncludeGlobals =
true;
906 Result.IncludeBriefComments =
false;
911 Result.LoadExternal = !Index;
950 CompletionRecorder *Recorder =
nullptr;
951 int NSema = 0, NIndex = 0, NBoth = 0;
952 bool Incomplete =
false;
953 llvm::Optional<FuzzyMatcher> Filter;
954 std::vector<std::string> QueryScopes;
957 llvm::Optional<IncludeInserter> Inserter;
958 llvm::Optional<URIDistance> FileProximity;
964 : FileName(FileName), Includes(Includes), Opts(Opts) {}
973 auto RecorderOwner = llvm::make_unique<CompletionRecorder>(Opts, [&]() {
974 assert(Recorder &&
"Recorder is not set");
976 format::getStyle(format::DefaultFormatStyle, SemaCCInput.FileName,
977 format::DefaultFallbackStyle, SemaCCInput.Contents,
978 SemaCCInput.VFS.get());
980 log(
"getStyle() failed for file {0}: {1}. Fallback is LLVM style.",
981 SemaCCInput.FileName, Style.takeError());
982 Style = format::getLLVMStyle();
987 SemaCCInput.FileName, SemaCCInput.Contents, *Style,
988 SemaCCInput.Command.Directory,
989 Recorder->CCSema->getPreprocessor().getHeaderSearchInfo());
991 Inserter->addExisting(Inc);
998 const auto &SM = Recorder->CCSema->getSourceManager();
999 llvm::StringMap<SourceParams> ProxSources;
1001 SM.getFileEntryForID(SM.getMainFileID())->getName())) {
1002 auto &Source = ProxSources[
Entry.getKey()];
1003 Source.Cost =
Entry.getValue() * ProxOpts.IncludeCost;
1007 if (
Entry.getValue() > 0)
1008 Source.MaxUpTraversals = 1;
1010 FileProximity.emplace(ProxSources, ProxOpts);
1012 Output = runWithSema();
1015 getCompletionKindString(Recorder->CCContext.getKind()));
1016 log(
"Code complete: sema context {0}, query scopes [{1}]",
1017 getCompletionKindString(Recorder->CCContext.getKind()),
1018 llvm::join(QueryScopes.begin(), QueryScopes.end(),
","));
1021 Recorder = RecorderOwner.get();
1022 semaCodeComplete(std::move(RecorderOwner), Opts.getClangCompleteOpts(),
1023 SemaCCInput, &Includes);
1030 log(
"Code complete: {0} results from Sema, {1} from Index, " 1031 "{2} matched, {3} returned{4}.",
1033 Output.
HasMore ?
" (incomplete)" :
"");
1034 assert(!Opts.Limit || Output.
Completions.size() <= Opts.Limit);
1045 Recorder->CCSema->getPreprocessor().getCodeCompletionFilter());
1046 QueryScopes = getQueryScopes(Recorder->CCContext,
1047 Recorder->CCSema->getSourceManager());
1053 auto IndexResults = (Opts.
Index && allowIndex(Recorder->CCContext))
1057 auto Top = mergeResults(Recorder->Results, IndexResults);
1060 for (
auto &C : Top) {
1061 Output.
Completions.push_back(toCodeCompletion(C.first));
1065 Output.
Context = Recorder->CCContext.getKind();
1078 Req.
Query = Filter->pattern();
1080 Req.
Scopes = QueryScopes;
1083 vlog(
"Code complete: fuzzyFind(\"{0}\", scopes=[{1}])", Req.
Query,
1087 Req, [&](
const Symbol &Sym) { ResultsBuilder.insert(Sym); }))
1089 return std::move(ResultsBuilder).build();
1095 std::vector<ScoredBundle>
1096 mergeResults(
const std::vector<CodeCompletionResult> &SemaResults,
1099 std::vector<CompletionCandidate::Bundle> Bundles;
1100 llvm::DenseMap<size_t, size_t> BundleLookup;
1101 auto AddToBundles = [&](
const CodeCompletionResult *
SemaResult,
1103 CompletionCandidate C;
1108 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size());
1110 Bundles.emplace_back();
1111 Bundles[Ret.first->second].push_back(std::move(C));
1113 Bundles.emplace_back();
1114 Bundles.back().push_back(std::move(C));
1117 llvm::DenseSet<const Symbol *> UsedIndexResults;
1118 auto CorrespondingIndexResult =
1120 if (
auto SymID = getSymbolID(SemaResult)) {
1121 auto I = IndexResults.
find(*SymID);
1122 if (I != IndexResults.
end()) {
1123 UsedIndexResults.insert(&*I);
1130 for (
auto &SemaResult : Recorder->Results)
1131 AddToBundles(&SemaResult, CorrespondingIndexResult(SemaResult));
1140 Opts.
Limit == 0 ? std::numeric_limits<size_t>::max() : Opts.
Limit);
1141 for (
auto &Bundle : Bundles)
1142 addCandidate(Top, std::move(Bundle));
1143 return std::move(Top).items();
1146 Optional<float> fuzzyScore(
const CompletionCandidate &C) {
1149 if (C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro &&
1150 !C.Name.startswith_lower(Filter->pattern()))
1152 return Filter->match(C.Name);
1157 CompletionCandidate::Bundle Bundle) {
1160 Relevance.
Context = Recorder->CCContext.getKind();
1163 auto &First = Bundle.front();
1164 if (
auto FuzzyScore = fuzzyScore(First))
1169 bool FromIndex =
false;
1170 for (
const auto &Candidate : Bundle) {
1171 if (Candidate.IndexResult) {
1172 Quality.
merge(*Candidate.IndexResult);
1173 Relevance.
merge(*Candidate.IndexResult);
1174 Origin |= Candidate.IndexResult->Origin;
1177 if (Candidate.SemaResult) {
1178 Quality.
merge(*Candidate.SemaResult);
1179 Relevance.
merge(*Candidate.SemaResult);
1193 dlog(
"CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name,
1194 llvm::to_string(Origin), Scores.
Total, llvm::to_string(Quality),
1195 llvm::to_string(Relevance));
1198 NIndex += FromIndex;
1199 NBoth += bool(Origin & SymbolOrigin::AST) && FromIndex;
1200 if (Candidates.
push({std::move(Bundle), Scores}))
1204 CodeCompletion toCodeCompletion(
const CompletionCandidate::Bundle &Bundle) {
1205 llvm::Optional<CodeCompletionBuilder> Builder;
1206 for (
const auto &Item : Bundle) {
1207 CodeCompletionString *SemaCCS =
1208 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult)
1211 Builder.emplace(Recorder->CCSema->getASTContext(), Item, SemaCCS,
1214 Builder->add(Item, SemaCCS);
1216 return Builder->build();
1221 const tooling::CompileCommand &
Command,
1222 PrecompiledPreamble
const *
Preamble,
1225 IntrusiveRefCntPtr<vfs::FileSystem>
VFS,
1226 std::shared_ptr<PCHContainerOperations>
PCHs,
1233 const tooling::CompileCommand &
Command,
1234 PrecompiledPreamble
const *
Preamble,
1236 IntrusiveRefCntPtr<vfs::FileSystem>
VFS,
1237 std::shared_ptr<PCHContainerOperations>
PCHs) {
1239 clang::CodeCompleteOptions Options;
1240 Options.IncludeGlobals =
false;
1241 Options.IncludeMacros =
false;
1242 Options.IncludeCodePatterns =
false;
1243 Options.IncludeBriefComments =
false;
1245 semaCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
1254 auto InTopLevelScope = hasDeclContext(
1255 anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
1256 return !match(decl(anyOf(InTopLevelScope,
1258 enumDecl(InTopLevelScope, unless(isScoped()))))),
1267 (Opts.
ShowOrigins ?
"[" + llvm::to_string(Origin) +
"]" :
"") +
1271 LSP.
detail = BundleSize > 1 ? llvm::formatv(
"[{0} overloads]", BundleSize)
1273 if (!Header.empty())
1274 LSP.
detail +=
"\n" + Header;
1283 if (HeaderInsertion)
1295 <<
" (" << 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
bool BundleOverloads
Combine overloads into a single completion item where possible.
std::pair< size_t, size_t > offsetToClangLineColumn(StringRef Code, size_t Offset)
CodeCompleteFlow(PathRef FileName, const IncludeStructure &Includes, const CodeCompleteOptions &Opts)
size_t Limit
Limit the number of results returned (0 means no limit).
CodeCompletionContext::Kind Context
void merge(const CodeCompletionResult &SemaCCResult)
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
size_t MaxCandidateCount
The number of top candidates to return.
CodeCompleteResult codeComplete(PathRef FileName, const tooling::CompileCommand &Command, PrecompiledPreamble const *Preamble, const IncludeStructure &PreambleInclusions, StringRef Contents, Position Pos, IntrusiveRefCntPtr< vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHs, CodeCompleteOptions Opts)
Get code completions at a specified Pos in FileName.
bool RestrictForCodeCompletion
If set to true, only symbols for completion support will be considered.
SignatureHelp signatureHelp(PathRef FileName, const tooling::CompileCommand &Command, PrecompiledPreamble const *Preamble, StringRef Contents, Position Pos, IntrusiveRefCntPtr< vfs::FileSystem > VFS, std::shared_ptr< PCHContainerOperations > PCHs)
Get signature help at a specified Pos in FileName.
CompletionItemKind kind
The kind of this completion item.
bool EnableSnippets
When true, completion items will contain expandable code snippets in completion (e.g.
clang::find_all_symbols::SymbolInfo::SymbolKind SymbolKind
std::vector< CodeCompletion > Completions
const_iterator find(const SymbolID &SymID) const
void merge(const CodeCompletionResult &SemaResult)
std::string sortText(float Score, llvm::StringRef Name)
Returns a string that sorts in the same order as (-Score, Tiebreak), for LSP.
virtual bool fuzzyFind(const FuzzyFindRequest &Req, llvm::function_ref< void(const Symbol &)> Callback) const =0
Matches symbols in the index fuzzily and applies Callback on each matched symbol before returning...
llvm::StringRef PathRef
A typedef to represent a ref to file path.
llvm::Optional< std::string > UnresolvedQualifier
std::vector< CodeCompletionResult > Results
CodeCompletionContext::Kind Context
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.
Documents should not be synced at all.
Attributes of a symbol that affect how much we like it.
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 > Scopes
If this is non-empty, symbols must be in at least one of the scopes (e.g.
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.
llvm::Expected< size_t > positionToOffset(StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
std::string detail
A human-readable string with additional information about this item, like type or symbol information...
URIDistance * FileProximityMatch
enum clang::clangd::SymbolRelevanceSignals::QueryType Query
bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx)
std::string filterText
A string that should be used when filtering a set of completion items.
llvm::unique_function< void()> Action
void log(const char *Fmt, Ts &&... Vals)
std::string Query
A query string for the fuzzy find.
bool push(value_type &&V)
const Symbol * IndexResult
std::string formatDocumentation(const CodeCompletionString &CCS, llvm::StringRef DocComment)
Assembles formatted documentation for a completion result.
PrecompiledPreamble const * Preamble
clang::CodeCompleteOptions getClangCompleteOpts() const
Returns options that can be passed to clang's completion engine.
std::string SnippetSuffix
IntrusiveRefCntPtr< vfs::FileSystem > VFS
float evaluateSymbolAndRelevance(float SymbolQuality, float SymbolRelevance)
Combine symbol quality and relevance into a single score.
const SymbolIndex * Index
If Index is set, it is used to augment the code completion results.
Represents the signature of a callable.
void getSignature(const CodeCompletionString &CCS, std::string *Signature, std::string *Snippet, std::string *RequiredQualifiers)
Formats the signature for an item, as a display string and snippet.
std::vector< Inclusion > MainFileIncludes
std::unique_ptr< PPCallbacks > collectIncludeStructureCallback(const SourceManager &SM, IncludeStructure *Out)
Returns a PPCallback that visits all inclusions in the main file.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::vector< std::string > ProximityPaths
Contextually relevant files (e.g.
std::string label
The label of this completion item.
std::unique_ptr< CompilerInstance > prepareCompilerInstance(std::unique_ptr< clang::CompilerInvocation > CI, const PrecompiledPreamble *Preamble, std::unique_ptr< llvm::MemoryBuffer > Buffer, std::shared_ptr< PCHContainerOperations > PCHs, IntrusiveRefCntPtr< vfs::FileSystem > VFS, DiagnosticConsumer &DiagsClient)
Creates a compiler instance, configured so that:
CompletionItem render(const CodeCompleteOptions &) const
llvm::StringMap< unsigned > includeDepth(llvm::StringRef Root) const
std::shared_ptr< PCHContainerOperations > PCHs
struct clang::clangd::CodeCompleteOptions::IncludeInsertionIndicator IncludeIndicator
std::pair< llvm::StringRef, llvm::StringRef > splitQualifiedName(llvm::StringRef QName)
From "a::b::c", return {"a::b::", "c"}.
const CodeCompletionResult * SemaResult
static llvm::Expected< std::string > resolve(const URI &U, llvm::StringRef HintPath="")
Resolves the absolute path of U.
float NameMatch
0-1+ fuzzy-match score for unqualified name. Must be explicitly assigned.
const_iterator end() const
static llvm::Expected< std::string > includeSpelling(const URI &U)
Gets the preferred spelling of this file for #include, if there is one, e.g.
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)
std::string getParameterDocComment(const ASTContext &Ctx, const CodeCompleteConsumer::OverloadCandidate &Result, unsigned ArgIndex, bool CommentsFromHeaders)
Gets a minimally formatted documentation for parameter of Result, corresponding to argument number Ar...
Records an event whose duration is the lifetime of the Span object.
InsertTextFormat insertTextFormat
The format of the insert text.
std::array< uint8_t, 20 > SymbolID
bool isLiteralInclude(llvm::StringRef Include)
Returns true if Include is literal include like "path" or <path>.
Attributes of a symbol-query pair that affect how much we like it.
CodeCompletionContext CCContext
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) &&
raw_ostream & operator<<(raw_ostream &OS, const CodeCompletion &C)
TopN<T> is a lossy container that preserves only the "best" N elements.