Mercurial > hg > CbC > CbC_llvm
comparison clang-tools-extra/clangd/CodeComplete.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
comparison
equal
deleted
inserted
replaced
220:42394fc6a535 | 221:79ff65ed7e25 |
---|---|
36 #include "index/Index.h" | 36 #include "index/Index.h" |
37 #include "index/Symbol.h" | 37 #include "index/Symbol.h" |
38 #include "index/SymbolOrigin.h" | 38 #include "index/SymbolOrigin.h" |
39 #include "support/Logger.h" | 39 #include "support/Logger.h" |
40 #include "support/Threading.h" | 40 #include "support/Threading.h" |
41 #include "support/ThreadsafeFS.h" | |
41 #include "support/Trace.h" | 42 #include "support/Trace.h" |
42 #include "clang/AST/Decl.h" | 43 #include "clang/AST/Decl.h" |
43 #include "clang/AST/DeclBase.h" | 44 #include "clang/AST/DeclBase.h" |
44 #include "clang/Basic/CharInfo.h" | 45 #include "clang/Basic/CharInfo.h" |
45 #include "clang/Basic/LangOptions.h" | 46 #include "clang/Basic/LangOptions.h" |
46 #include "clang/Basic/SourceLocation.h" | 47 #include "clang/Basic/SourceLocation.h" |
48 #include "clang/Basic/TokenKinds.h" | |
47 #include "clang/Format/Format.h" | 49 #include "clang/Format/Format.h" |
48 #include "clang/Frontend/CompilerInstance.h" | 50 #include "clang/Frontend/CompilerInstance.h" |
49 #include "clang/Frontend/FrontendActions.h" | 51 #include "clang/Frontend/FrontendActions.h" |
50 #include "clang/Lex/ExternalPreprocessorSource.h" | 52 #include "clang/Lex/ExternalPreprocessorSource.h" |
53 #include "clang/Lex/Lexer.h" | |
51 #include "clang/Lex/Preprocessor.h" | 54 #include "clang/Lex/Preprocessor.h" |
52 #include "clang/Lex/PreprocessorOptions.h" | 55 #include "clang/Lex/PreprocessorOptions.h" |
53 #include "clang/Sema/CodeCompleteConsumer.h" | 56 #include "clang/Sema/CodeCompleteConsumer.h" |
54 #include "clang/Sema/DeclSpec.h" | 57 #include "clang/Sema/DeclSpec.h" |
55 #include "clang/Sema/Sema.h" | 58 #include "clang/Sema/Sema.h" |
65 #include "llvm/Support/Format.h" | 68 #include "llvm/Support/Format.h" |
66 #include "llvm/Support/FormatVariadic.h" | 69 #include "llvm/Support/FormatVariadic.h" |
67 #include "llvm/Support/ScopedPrinter.h" | 70 #include "llvm/Support/ScopedPrinter.h" |
68 #include <algorithm> | 71 #include <algorithm> |
69 #include <iterator> | 72 #include <iterator> |
73 #include <limits> | |
70 | 74 |
71 // We log detailed candidate here if you run with -debug-only=codecomplete. | 75 // We log detailed candidate here if you run with -debug-only=codecomplete. |
72 #define DEBUG_TYPE "CodeComplete" | 76 #define DEBUG_TYPE "CodeComplete" |
73 | 77 |
74 namespace clang { | 78 namespace clang { |
168 const RawIdentifier *IdentifierResult = nullptr; | 172 const RawIdentifier *IdentifierResult = nullptr; |
169 llvm::SmallVector<llvm::StringRef, 1> RankedIncludeHeaders; | 173 llvm::SmallVector<llvm::StringRef, 1> RankedIncludeHeaders; |
170 | 174 |
171 // Returns a token identifying the overload set this is part of. | 175 // Returns a token identifying the overload set this is part of. |
172 // 0 indicates it's not part of any overload set. | 176 // 0 indicates it's not part of any overload set. |
173 size_t overloadSet(const CodeCompleteOptions &Opts) const { | 177 size_t overloadSet(const CodeCompleteOptions &Opts, llvm::StringRef FileName, |
178 IncludeInserter *Inserter) const { | |
174 if (!Opts.BundleOverloads.getValueOr(false)) | 179 if (!Opts.BundleOverloads.getValueOr(false)) |
175 return 0; | 180 return 0; |
181 | |
182 // Depending on the index implementation, we can see different header | |
183 // strings (literal or URI) mapping to the same file. We still want to | |
184 // bundle those, so we must resolve the header to be included here. | |
185 std::string HeaderForHash; | |
186 if (Inserter) { | |
187 if (auto Header = headerToInsertIfAllowed(Opts)) { | |
188 if (auto HeaderFile = toHeaderFile(*Header, FileName)) { | |
189 if (auto Spelled = | |
190 Inserter->calculateIncludePath(*HeaderFile, FileName)) | |
191 HeaderForHash = *Spelled; | |
192 } else { | |
193 vlog("Code completion header path manipulation failed {0}", | |
194 HeaderFile.takeError()); | |
195 } | |
196 } | |
197 } | |
198 | |
176 llvm::SmallString<256> Scratch; | 199 llvm::SmallString<256> Scratch; |
177 if (IndexResult) { | 200 if (IndexResult) { |
178 switch (IndexResult->SymInfo.Kind) { | 201 switch (IndexResult->SymInfo.Kind) { |
179 case index::SymbolKind::ClassMethod: | 202 case index::SymbolKind::ClassMethod: |
180 case index::SymbolKind::InstanceMethod: | 203 case index::SymbolKind::InstanceMethod: |
187 case index::SymbolKind::Function: | 210 case index::SymbolKind::Function: |
188 // We can't group overloads together that need different #includes. | 211 // We can't group overloads together that need different #includes. |
189 // This could break #include insertion. | 212 // This could break #include insertion. |
190 return llvm::hash_combine( | 213 return llvm::hash_combine( |
191 (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch), | 214 (IndexResult->Scope + IndexResult->Name).toStringRef(Scratch), |
192 headerToInsertIfAllowed(Opts).getValueOr("")); | 215 HeaderForHash); |
193 default: | 216 default: |
194 return 0; | 217 return 0; |
195 } | 218 } |
196 } | 219 } |
197 if (SemaResult) { | 220 if (SemaResult) { |
201 return 0; | 224 return 0; |
202 { | 225 { |
203 llvm::raw_svector_ostream OS(Scratch); | 226 llvm::raw_svector_ostream OS(Scratch); |
204 D->printQualifiedName(OS); | 227 D->printQualifiedName(OS); |
205 } | 228 } |
206 return llvm::hash_combine(Scratch, | 229 return llvm::hash_combine(Scratch, HeaderForHash); |
207 headerToInsertIfAllowed(Opts).getValueOr("")); | |
208 } | 230 } |
209 assert(IdentifierResult); | 231 assert(IdentifierResult); |
210 return 0; | 232 return 0; |
211 } | 233 } |
212 | 234 |
252 CodeCompletionString *SemaCCS, | 274 CodeCompletionString *SemaCCS, |
253 llvm::ArrayRef<std::string> QueryScopes, | 275 llvm::ArrayRef<std::string> QueryScopes, |
254 const IncludeInserter &Includes, | 276 const IncludeInserter &Includes, |
255 llvm::StringRef FileName, | 277 llvm::StringRef FileName, |
256 CodeCompletionContext::Kind ContextKind, | 278 CodeCompletionContext::Kind ContextKind, |
257 const CodeCompleteOptions &Opts, bool GenerateSnippets) | 279 const CodeCompleteOptions &Opts, |
258 : ASTCtx(ASTCtx), ExtractDocumentation(Opts.IncludeComments), | 280 bool IsUsingDeclaration, tok::TokenKind NextTokenKind) |
281 : ASTCtx(ASTCtx), | |
259 EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets), | 282 EnableFunctionArgSnippets(Opts.EnableFunctionArgSnippets), |
260 GenerateSnippets(GenerateSnippets) { | 283 IsUsingDeclaration(IsUsingDeclaration), NextTokenKind(NextTokenKind) { |
261 add(C, SemaCCS); | 284 add(C, SemaCCS); |
262 if (C.SemaResult) { | 285 if (C.SemaResult) { |
263 assert(ASTCtx); | 286 assert(ASTCtx); |
264 Completion.Origin |= SymbolOrigin::AST; | 287 Completion.Origin |= SymbolOrigin::AST; |
265 Completion.Name = std::string(llvm::StringRef(SemaCCS->getTypedText())); | 288 Completion.Name = std::string(llvm::StringRef(SemaCCS->getTypedText())); |
327 auto ResolvedInserted = toHeaderFile(Header, FileName); | 350 auto ResolvedInserted = toHeaderFile(Header, FileName); |
328 if (!ResolvedInserted) | 351 if (!ResolvedInserted) |
329 return ResolvedInserted.takeError(); | 352 return ResolvedInserted.takeError(); |
330 auto Spelled = Includes.calculateIncludePath(*ResolvedInserted, FileName); | 353 auto Spelled = Includes.calculateIncludePath(*ResolvedInserted, FileName); |
331 if (!Spelled) | 354 if (!Spelled) |
332 return llvm::createStringError(llvm::inconvertibleErrorCode(), | 355 return error("Header not on include path"); |
333 "Header not on include path"); | |
334 return std::make_pair( | 356 return std::make_pair( |
335 std::move(*Spelled), | 357 std::move(*Spelled), |
336 Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted)); | 358 Includes.shouldInsertInclude(*ResolvedDeclaring, *ResolvedInserted)); |
337 }; | 359 }; |
338 bool ShouldInsert = C.headerToInsertIfAllowed(Opts).hasValue(); | 360 bool ShouldInsert = C.headerToInsertIfAllowed(Opts).hasValue(); |
370 } else if (C.IndexResult) { | 392 } else if (C.IndexResult) { |
371 S.Signature = std::string(C.IndexResult->Signature); | 393 S.Signature = std::string(C.IndexResult->Signature); |
372 S.SnippetSuffix = std::string(C.IndexResult->CompletionSnippetSuffix); | 394 S.SnippetSuffix = std::string(C.IndexResult->CompletionSnippetSuffix); |
373 S.ReturnType = std::string(C.IndexResult->ReturnType); | 395 S.ReturnType = std::string(C.IndexResult->ReturnType); |
374 } | 396 } |
375 if (ExtractDocumentation && !Completion.Documentation) { | 397 if (!Completion.Documentation) { |
376 auto SetDoc = [&](llvm::StringRef Doc) { | 398 auto SetDoc = [&](llvm::StringRef Doc) { |
377 if (!Doc.empty()) { | 399 if (!Doc.empty()) { |
378 Completion.Documentation.emplace(); | 400 Completion.Documentation.emplace(); |
379 parseDocumentation(Doc, *Completion.Documentation); | 401 parseDocumentation(Doc, *Completion.Documentation); |
380 } | 402 } |
426 return *RT; | 448 return *RT; |
427 return ""; | 449 return ""; |
428 } | 450 } |
429 | 451 |
430 std::string summarizeSnippet() const { | 452 std::string summarizeSnippet() const { |
431 if (!GenerateSnippets) | 453 if (IsUsingDeclaration) |
432 return ""; | 454 return ""; |
433 auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>(); | 455 auto *Snippet = onlyValue<&BundledEntry::SnippetSuffix>(); |
434 if (!Snippet) | 456 if (!Snippet) |
435 // All bundles are function calls. | 457 // All bundles are function calls. |
436 // FIXME(ibiryukov): sometimes add template arguments to a snippet, e.g. | 458 // FIXME(ibiryukov): sometimes add template arguments to a snippet, e.g. |
437 // we need to complete 'forward<$1>($0)'. | 459 // we need to complete 'forward<$1>($0)'. |
438 return "($0)"; | 460 return "($0)"; |
461 // Suppress function argument snippets cursor is followed by left | |
462 // parenthesis (and potentially arguments) or if there are potentially | |
463 // template arguments. There are cases where it would be wrong (e.g. next | |
464 // '<' token is a comparison rather than template argument list start) but | |
465 // it is less common and suppressing snippet provides better UX. | |
466 if (Completion.Kind == CompletionItemKind::Function || | |
467 Completion.Kind == CompletionItemKind::Method || | |
468 Completion.Kind == CompletionItemKind::Constructor) { | |
469 // If there is a potential template argument list, drop snippet and just | |
470 // complete symbol name. Ideally, this could generate an edit that would | |
471 // paste function arguments after template argument list but it would be | |
472 // complicated. Example: | |
473 // | |
474 // fu^<int> -> function<int> | |
475 if (NextTokenKind == tok::less && Snippet->front() == '<') | |
476 return ""; | |
477 // Potentially followed by argument list. | |
478 if (NextTokenKind == tok::l_paren) { | |
479 // If snippet contains template arguments we will emit them and drop | |
480 // function arguments. Example: | |
481 // | |
482 // fu^(42) -> function<int>(42); | |
483 if (Snippet->front() == '<') { | |
484 // Find matching '>'. Snippet->find('>') will not work in cases like | |
485 // template <typename T=std::vector<int>>. Hence, iterate through | |
486 // the snippet until the angle bracket balance reaches zero. | |
487 int Balance = 0; | |
488 size_t I = 0; | |
489 do { | |
490 if (Snippet->at(I) == '>') | |
491 --Balance; | |
492 else if (Snippet->at(I) == '<') | |
493 ++Balance; | |
494 ++I; | |
495 } while (Balance > 0); | |
496 return Snippet->substr(0, I); | |
497 } | |
498 return ""; | |
499 } | |
500 } | |
439 if (EnableFunctionArgSnippets) | 501 if (EnableFunctionArgSnippets) |
440 return *Snippet; | 502 return *Snippet; |
441 | 503 |
442 // Replace argument snippets with a simplified pattern. | 504 // Replace argument snippets with a simplified pattern. |
443 if (Snippet->empty()) | 505 if (Snippet->empty()) |
483 | 545 |
484 // ASTCtx can be nullptr if not run with sema. | 546 // ASTCtx can be nullptr if not run with sema. |
485 ASTContext *ASTCtx; | 547 ASTContext *ASTCtx; |
486 CodeCompletion Completion; | 548 CodeCompletion Completion; |
487 llvm::SmallVector<BundledEntry, 1> Bundled; | 549 llvm::SmallVector<BundledEntry, 1> Bundled; |
488 bool ExtractDocumentation; | |
489 bool EnableFunctionArgSnippets; | 550 bool EnableFunctionArgSnippets; |
490 /// When false, no snippets are generated argument lists. | 551 // No snippets will be generated for using declarations and when the function |
491 bool GenerateSnippets; | 552 // arguments are already present. |
553 bool IsUsingDeclaration; | |
554 tok::TokenKind NextTokenKind; | |
492 }; | 555 }; |
493 | 556 |
494 // Determine the symbol ID for a Sema code completion result, if possible. | 557 // Determine the symbol ID for a Sema code completion result, if possible. |
495 llvm::Optional<SymbolID> getSymbolID(const CodeCompletionResult &R, | 558 SymbolID getSymbolID(const CodeCompletionResult &R, const SourceManager &SM) { |
496 const SourceManager &SM) { | |
497 switch (R.Kind) { | 559 switch (R.Kind) { |
498 case CodeCompletionResult::RK_Declaration: | 560 case CodeCompletionResult::RK_Declaration: |
499 case CodeCompletionResult::RK_Pattern: { | 561 case CodeCompletionResult::RK_Pattern: { |
500 // Computing USR caches linkage, which may change after code completion. | 562 // Computing USR caches linkage, which may change after code completion. |
501 if (hasUnstableLinkage(R.Declaration)) | 563 if (hasUnstableLinkage(R.Declaration)) |
502 return llvm::None; | 564 return {}; |
503 return clang::clangd::getSymbolID(R.Declaration); | 565 return clang::clangd::getSymbolID(R.Declaration); |
504 } | 566 } |
505 case CodeCompletionResult::RK_Macro: | 567 case CodeCompletionResult::RK_Macro: |
506 return clang::clangd::getSymbolID(R.Macro->getName(), R.MacroDefInfo, SM); | 568 return clang::clangd::getSymbolID(R.Macro->getName(), R.MacroDefInfo, SM); |
507 case CodeCompletionResult::RK_Keyword: | 569 case CodeCompletionResult::RK_Keyword: |
508 return None; | 570 return {}; |
509 } | 571 } |
510 llvm_unreachable("unknown CodeCompletionResult kind"); | 572 llvm_unreachable("unknown CodeCompletionResult kind"); |
511 } | 573 } |
512 | 574 |
513 // Scopes of the partial identifier we're trying to complete. | 575 // Scopes of the partial identifier we're trying to complete. |
661 if (R->isInjectedClassName()) | 723 if (R->isInjectedClassName()) |
662 return true; | 724 return true; |
663 return false; | 725 return false; |
664 } | 726 } |
665 | 727 |
666 // Some member calls are blacklisted because they're so rarely useful. | 728 // Some member calls are excluded because they're so rarely useful. |
667 static bool isBlacklistedMember(const NamedDecl &D) { | 729 static bool isExcludedMember(const NamedDecl &D) { |
668 // Destructor completion is rarely useful, and works inconsistently. | 730 // Destructor completion is rarely useful, and works inconsistently. |
669 // (s.^ completes ~string, but s.~st^ is an error). | 731 // (s.^ completes ~string, but s.~st^ is an error). |
670 if (D.getKind() == Decl::CXXDestructor) | 732 if (D.getKind() == Decl::CXXDestructor) |
671 return true; | 733 return true; |
672 // Injected name may be useful for A::foo(), but who writes A::A::foo()? | 734 // Injected name may be useful for A::foo(), but who writes A::A::foo()? |
745 (Result.Availability == CXAvailability_NotAvailable || | 807 (Result.Availability == CXAvailability_NotAvailable || |
746 Result.Availability == CXAvailability_NotAccessible)) | 808 Result.Availability == CXAvailability_NotAccessible)) |
747 continue; | 809 continue; |
748 if (Result.Declaration && | 810 if (Result.Declaration && |
749 !Context.getBaseType().isNull() // is this a member-access context? | 811 !Context.getBaseType().isNull() // is this a member-access context? |
750 && isBlacklistedMember(*Result.Declaration)) | 812 && isExcludedMember(*Result.Declaration)) |
751 continue; | 813 continue; |
752 // Skip injected class name when no class scope is not explicitly set. | 814 // Skip injected class name when no class scope is not explicitly set. |
753 // E.g. show injected A::A in `using A::A^` but not in "A^". | 815 // E.g. show injected A::A in `using A::A^` but not in "A^". |
754 if (Result.Declaration && !Context.getCXXScopeSpecifier().hasValue() && | 816 if (Result.Declaration && !Context.getCXXScopeSpecifier().hasValue() && |
755 isInjectedClass(*Result.Declaration)) | 817 isInjectedClass(*Result.Declaration)) |
798 CodeCompletionTUInfo CCTUInfo; | 860 CodeCompletionTUInfo CCTUInfo; |
799 llvm::unique_function<void()> ResultsCallback; | 861 llvm::unique_function<void()> ResultsCallback; |
800 }; | 862 }; |
801 | 863 |
802 struct ScoredSignature { | 864 struct ScoredSignature { |
803 // When set, requires documentation to be requested from the index with this | 865 // When not null, requires documentation to be requested from the index with |
804 // ID. | 866 // this ID. |
805 llvm::Optional<SymbolID> IDForDoc; | 867 SymbolID IDForDoc; |
806 SignatureInformation Signature; | 868 SignatureInformation Signature; |
807 SignatureQualitySignals Quality; | 869 SignatureQualitySignals Quality; |
808 }; | 870 }; |
809 | 871 |
810 class SignatureHelpCollector final : public CodeCompleteConsumer { | 872 class SignatureHelpCollector final : public CodeCompleteConsumer { |
864 if (Index) { | 926 if (Index) { |
865 LookupRequest IndexRequest; | 927 LookupRequest IndexRequest; |
866 for (const auto &S : ScoredSignatures) { | 928 for (const auto &S : ScoredSignatures) { |
867 if (!S.IDForDoc) | 929 if (!S.IDForDoc) |
868 continue; | 930 continue; |
869 IndexRequest.IDs.insert(*S.IDForDoc); | 931 IndexRequest.IDs.insert(S.IDForDoc); |
870 } | 932 } |
871 Index->lookup(IndexRequest, [&](const Symbol &S) { | 933 Index->lookup(IndexRequest, [&](const Symbol &S) { |
872 if (!S.Documentation.empty()) | 934 if (!S.Documentation.empty()) |
873 FetchedDocs[S.ID] = std::string(S.Documentation); | 935 FetchedDocs[S.ID] = std::string(S.Documentation); |
874 }); | 936 }); |
909 return L.Signature.label < R.Signature.label; | 971 return L.Signature.label < R.Signature.label; |
910 }); | 972 }); |
911 | 973 |
912 for (auto &SS : ScoredSignatures) { | 974 for (auto &SS : ScoredSignatures) { |
913 auto IndexDocIt = | 975 auto IndexDocIt = |
914 SS.IDForDoc ? FetchedDocs.find(*SS.IDForDoc) : FetchedDocs.end(); | 976 SS.IDForDoc ? FetchedDocs.find(SS.IDForDoc) : FetchedDocs.end(); |
915 if (IndexDocIt != FetchedDocs.end()) | 977 if (IndexDocIt != FetchedDocs.end()) |
916 SS.Signature.documentation = IndexDocIt->second; | 978 SS.Signature.documentation = IndexDocIt->second; |
917 | 979 |
918 SigHelp.signatures.push_back(std::move(SS.Signature)); | 980 SigHelp.signatures.push_back(std::move(SS.Signature)); |
919 } | 981 } |
1027 const SymbolIndex *Index; | 1089 const SymbolIndex *Index; |
1028 }; // SignatureHelpCollector | 1090 }; // SignatureHelpCollector |
1029 | 1091 |
1030 struct SemaCompleteInput { | 1092 struct SemaCompleteInput { |
1031 PathRef FileName; | 1093 PathRef FileName; |
1032 const tooling::CompileCommand &Command; | 1094 size_t Offset; |
1033 const PreambleData &Preamble; | 1095 const PreambleData &Preamble; |
1034 const PreamblePatch &Patch; | 1096 const llvm::Optional<PreamblePatch> Patch; |
1035 llvm::StringRef Contents; | 1097 const ParseInputs &ParseInput; |
1036 size_t Offset; | |
1037 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS; | |
1038 }; | 1098 }; |
1039 | 1099 |
1040 void loadMainFilePreambleMacros(const Preprocessor &PP, | 1100 void loadMainFilePreambleMacros(const Preprocessor &PP, |
1041 const PreambleData &Preamble) { | 1101 const PreambleData &Preamble) { |
1042 // The ExternalPreprocessorSource has our macros, if we know where to look. | 1102 // The ExternalPreprocessorSource has our macros, if we know where to look. |
1043 // We can read all the macros using PreambleMacros->ReadDefinedMacros(), | 1103 // We can read all the macros using PreambleMacros->ReadDefinedMacros(), |
1044 // but this includes transitively included files, so may deserialize a lot. | 1104 // but this includes transitively included files, so may deserialize a lot. |
1045 ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource(); | 1105 ExternalPreprocessorSource *PreambleMacros = PP.getExternalSource(); |
1046 // As we have the names of the macros, we can look up their IdentifierInfo | 1106 // As we have the names of the macros, we can look up their IdentifierInfo |
1047 // and then use this to load just the macros we want. | 1107 // and then use this to load just the macros we want. |
1108 const auto &ITable = PP.getIdentifierTable(); | |
1048 IdentifierInfoLookup *PreambleIdentifiers = | 1109 IdentifierInfoLookup *PreambleIdentifiers = |
1049 PP.getIdentifierTable().getExternalIdentifierLookup(); | 1110 ITable.getExternalIdentifierLookup(); |
1111 | |
1050 if (!PreambleIdentifiers || !PreambleMacros) | 1112 if (!PreambleIdentifiers || !PreambleMacros) |
1051 return; | 1113 return; |
1052 for (const auto &MacroName : Preamble.Macros.Names) | 1114 for (const auto &MacroName : Preamble.Macros.Names) { |
1115 if (ITable.find(MacroName.getKey()) != ITable.end()) | |
1116 continue; | |
1053 if (auto *II = PreambleIdentifiers->get(MacroName.getKey())) | 1117 if (auto *II = PreambleIdentifiers->get(MacroName.getKey())) |
1054 if (II->isOutOfDate()) | 1118 if (II->isOutOfDate()) |
1055 PreambleMacros->updateOutOfDateIdentifier(*II); | 1119 PreambleMacros->updateOutOfDateIdentifier(*II); |
1120 } | |
1056 } | 1121 } |
1057 | 1122 |
1058 // Invokes Sema code completion on a file. | 1123 // Invokes Sema code completion on a file. |
1059 // If \p Includes is set, it will be updated based on the compiler invocation. | 1124 // If \p Includes is set, it will be updated based on the compiler invocation. |
1060 bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, | 1125 bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer, |
1061 const clang::CodeCompleteOptions &Options, | 1126 const clang::CodeCompleteOptions &Options, |
1062 const SemaCompleteInput &Input, | 1127 const SemaCompleteInput &Input, |
1063 IncludeStructure *Includes = nullptr) { | 1128 IncludeStructure *Includes = nullptr) { |
1064 trace::Span Tracer("Sema completion"); | 1129 trace::Span Tracer("Sema completion"); |
1065 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = Input.VFS; | |
1066 if (Input.Preamble.StatCache) | |
1067 VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); | |
1068 ParseInputs ParseInput; | |
1069 ParseInput.CompileCommand = Input.Command; | |
1070 ParseInput.FS = VFS; | |
1071 ParseInput.Contents = std::string(Input.Contents); | |
1072 // FIXME: setup the recoveryAST and recoveryASTType in ParseInput properly. | |
1073 | 1130 |
1074 IgnoreDiagnostics IgnoreDiags; | 1131 IgnoreDiagnostics IgnoreDiags; |
1075 auto CI = buildCompilerInvocation(ParseInput, IgnoreDiags); | 1132 auto CI = buildCompilerInvocation(Input.ParseInput, IgnoreDiags); |
1076 if (!CI) { | 1133 if (!CI) { |
1077 elog("Couldn't create CompilerInvocation"); | 1134 elog("Couldn't create CompilerInvocation"); |
1078 return false; | 1135 return false; |
1079 } | 1136 } |
1080 auto &FrontendOpts = CI->getFrontendOpts(); | 1137 auto &FrontendOpts = CI->getFrontendOpts(); |
1088 // Setup code completion. | 1145 // Setup code completion. |
1089 FrontendOpts.CodeCompleteOpts = Options; | 1146 FrontendOpts.CodeCompleteOpts = Options; |
1090 FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName); | 1147 FrontendOpts.CodeCompletionAt.FileName = std::string(Input.FileName); |
1091 std::tie(FrontendOpts.CodeCompletionAt.Line, | 1148 std::tie(FrontendOpts.CodeCompletionAt.Line, |
1092 FrontendOpts.CodeCompletionAt.Column) = | 1149 FrontendOpts.CodeCompletionAt.Column) = |
1093 offsetToClangLineColumn(Input.Contents, Input.Offset); | 1150 offsetToClangLineColumn(Input.ParseInput.Contents, Input.Offset); |
1094 | 1151 |
1095 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer = | 1152 std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer = |
1096 llvm::MemoryBuffer::getMemBufferCopy(Input.Contents, Input.FileName); | 1153 llvm::MemoryBuffer::getMemBuffer(Input.ParseInput.Contents, |
1154 Input.FileName); | |
1097 // The diagnostic options must be set before creating a CompilerInstance. | 1155 // The diagnostic options must be set before creating a CompilerInstance. |
1098 CI->getDiagnosticOpts().IgnoreWarnings = true; | 1156 CI->getDiagnosticOpts().IgnoreWarnings = true; |
1099 // We reuse the preamble whether it's valid or not. This is a | 1157 // We reuse the preamble whether it's valid or not. This is a |
1100 // correctness/performance tradeoff: building without a preamble is slow, and | 1158 // correctness/performance tradeoff: building without a preamble is slow, and |
1101 // completion is latency-sensitive. | 1159 // completion is latency-sensitive. |
1102 // However, if we're completing *inside* the preamble section of the draft, | 1160 // However, if we're completing *inside* the preamble section of the draft, |
1103 // overriding the preamble will break sema completion. Fortunately we can just | 1161 // overriding the preamble will break sema completion. Fortunately we can just |
1104 // skip all includes in this case; these completions are really simple. | 1162 // skip all includes in this case; these completions are really simple. |
1105 PreambleBounds PreambleRegion = | 1163 PreambleBounds PreambleRegion = |
1106 ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0); | 1164 ComputePreambleBounds(*CI->getLangOpts(), *ContentsBuffer, 0); |
1107 bool CompletingInPreamble = PreambleRegion.Size > Input.Offset; | 1165 bool CompletingInPreamble = Input.Offset < PreambleRegion.Size || |
1108 Input.Patch.apply(*CI); | 1166 (!PreambleRegion.PreambleEndsAtStartOfLine && |
1167 Input.Offset == PreambleRegion.Size); | |
1168 if (Input.Patch) | |
1169 Input.Patch->apply(*CI); | |
1109 // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise | 1170 // NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise |
1110 // the remapped buffers do not get freed. | 1171 // the remapped buffers do not get freed. |
1172 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = | |
1173 Input.ParseInput.TFS->view(Input.ParseInput.CompileCommand.Directory); | |
1174 if (Input.Preamble.StatCache) | |
1175 VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS)); | |
1111 auto Clang = prepareCompilerInstance( | 1176 auto Clang = prepareCompilerInstance( |
1112 std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr, | 1177 std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr, |
1113 std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); | 1178 std::move(ContentsBuffer), std::move(VFS), IgnoreDiags); |
1114 Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble; | 1179 Clang->getPreprocessorOpts().SingleFileParseMode = CompletingInPreamble; |
1115 Clang->setCodeCompletionConsumer(Consumer.release()); | 1180 Clang->setCodeCompletionConsumer(Consumer.release()); |
1224 | 1289 |
1225 // Sema takes ownership of Recorder. Recorder is valid until Sema cleanup. | 1290 // Sema takes ownership of Recorder. Recorder is valid until Sema cleanup. |
1226 CompletionRecorder *Recorder = nullptr; | 1291 CompletionRecorder *Recorder = nullptr; |
1227 CodeCompletionContext::Kind CCContextKind = CodeCompletionContext::CCC_Other; | 1292 CodeCompletionContext::Kind CCContextKind = CodeCompletionContext::CCC_Other; |
1228 bool IsUsingDeclaration = false; | 1293 bool IsUsingDeclaration = false; |
1294 // The snippets will not be generated if the token following completion | |
1295 // location is an opening parenthesis (tok::l_paren) because this would add | |
1296 // extra parenthesis. | |
1297 tok::TokenKind NextTokenKind = tok::eof; | |
1229 // Counters for logging. | 1298 // Counters for logging. |
1230 int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0; | 1299 int NSema = 0, NIndex = 0, NSemaAndIndex = 0, NIdent = 0; |
1231 bool Incomplete = false; // Would more be available with a higher limit? | 1300 bool Incomplete = false; // Would more be available with a higher limit? |
1232 CompletionPrefix HeuristicPrefix; | 1301 CompletionPrefix HeuristicPrefix; |
1233 llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs. | 1302 llvm::Optional<FuzzyMatcher> Filter; // Initialized once Sema runs. |
1257 : FileName(FileName), Includes(Includes), SpecFuzzyFind(SpecFuzzyFind), | 1326 : FileName(FileName), Includes(Includes), SpecFuzzyFind(SpecFuzzyFind), |
1258 Opts(Opts) {} | 1327 Opts(Opts) {} |
1259 | 1328 |
1260 CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && { | 1329 CodeCompleteResult run(const SemaCompleteInput &SemaCCInput) && { |
1261 trace::Span Tracer("CodeCompleteFlow"); | 1330 trace::Span Tracer("CodeCompleteFlow"); |
1262 HeuristicPrefix = | 1331 HeuristicPrefix = guessCompletionPrefix(SemaCCInput.ParseInput.Contents, |
1263 guessCompletionPrefix(SemaCCInput.Contents, SemaCCInput.Offset); | 1332 SemaCCInput.Offset); |
1264 populateContextWords(SemaCCInput.Contents); | 1333 populateContextWords(SemaCCInput.ParseInput.Contents); |
1265 if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq.hasValue()) { | 1334 if (Opts.Index && SpecFuzzyFind && SpecFuzzyFind->CachedReq.hasValue()) { |
1266 assert(!SpecFuzzyFind->Result.valid()); | 1335 assert(!SpecFuzzyFind->Result.valid()); |
1267 SpecReq = speculativeFuzzyFindRequestForCompletion( | 1336 SpecReq = speculativeFuzzyFindRequestForCompletion( |
1268 *SpecFuzzyFind->CachedReq, HeuristicPrefix); | 1337 *SpecFuzzyFind->CachedReq, HeuristicPrefix); |
1269 SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq); | 1338 SpecFuzzyFind->Result = startAsyncFuzzyFind(*Opts.Index, *SpecReq); |
1275 CodeCompleteResult Output; | 1344 CodeCompleteResult Output; |
1276 auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() { | 1345 auto RecorderOwner = std::make_unique<CompletionRecorder>(Opts, [&]() { |
1277 assert(Recorder && "Recorder is not set"); | 1346 assert(Recorder && "Recorder is not set"); |
1278 CCContextKind = Recorder->CCContext.getKind(); | 1347 CCContextKind = Recorder->CCContext.getKind(); |
1279 IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); | 1348 IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration(); |
1280 auto Style = getFormatStyleForFile( | 1349 auto Style = getFormatStyleForFile(SemaCCInput.FileName, |
1281 SemaCCInput.FileName, SemaCCInput.Contents, SemaCCInput.VFS.get()); | 1350 SemaCCInput.ParseInput.Contents, |
1351 *SemaCCInput.ParseInput.TFS); | |
1352 const auto NextToken = Lexer::findNextToken( | |
1353 Recorder->CCSema->getPreprocessor().getCodeCompletionLoc(), | |
1354 Recorder->CCSema->getSourceManager(), Recorder->CCSema->LangOpts); | |
1355 if (NextToken) | |
1356 NextTokenKind = NextToken->getKind(); | |
1282 // If preprocessor was run, inclusions from preprocessor callback should | 1357 // If preprocessor was run, inclusions from preprocessor callback should |
1283 // already be added to Includes. | 1358 // already be added to Includes. |
1284 Inserter.emplace( | 1359 Inserter.emplace( |
1285 SemaCCInput.FileName, SemaCCInput.Contents, Style, | 1360 SemaCCInput.FileName, SemaCCInput.ParseInput.Contents, Style, |
1286 SemaCCInput.Command.Directory, | 1361 SemaCCInput.ParseInput.CompileCommand.Directory, |
1287 &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo()); | 1362 &Recorder->CCSema->getPreprocessor().getHeaderSearchInfo()); |
1288 for (const auto &Inc : Includes.MainFileIncludes) | 1363 for (const auto &Inc : Includes.MainFileIncludes) |
1289 Inserter->addExisting(Inc); | 1364 Inserter->addExisting(Inc); |
1290 | 1365 |
1291 // Most of the cost of file proximity is in initializing the FileDistance | 1366 // Most of the cost of file proximity is in initializing the FileDistance |
1342 assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit); | 1417 assert(!Opts.Limit || Output.Completions.size() <= Opts.Limit); |
1343 // We don't assert that isIncomplete means we hit a limit. | 1418 // We don't assert that isIncomplete means we hit a limit. |
1344 // Indexes may choose to impose their own limits even if we don't have one. | 1419 // Indexes may choose to impose their own limits even if we don't have one. |
1345 } | 1420 } |
1346 | 1421 |
1347 CodeCompleteResult | 1422 CodeCompleteResult runWithoutSema(llvm::StringRef Content, size_t Offset, |
1348 runWithoutSema(llvm::StringRef Content, size_t Offset, | 1423 const ThreadsafeFS &TFS) && { |
1349 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) && { | |
1350 trace::Span Tracer("CodeCompleteWithoutSema"); | 1424 trace::Span Tracer("CodeCompleteWithoutSema"); |
1351 // Fill in fields normally set by runWithSema() | 1425 // Fill in fields normally set by runWithSema() |
1352 HeuristicPrefix = guessCompletionPrefix(Content, Offset); | 1426 HeuristicPrefix = guessCompletionPrefix(Content, Offset); |
1353 populateContextWords(Content); | 1427 populateContextWords(Content); |
1354 CCContextKind = CodeCompletionContext::CCC_Recovery; | 1428 CCContextKind = CodeCompletionContext::CCC_Recovery; |
1360 | 1434 |
1361 llvm::StringMap<SourceParams> ProxSources; | 1435 llvm::StringMap<SourceParams> ProxSources; |
1362 ProxSources[FileName].Cost = 0; | 1436 ProxSources[FileName].Cost = 0; |
1363 FileProximity.emplace(ProxSources); | 1437 FileProximity.emplace(ProxSources); |
1364 | 1438 |
1365 auto Style = getFormatStyleForFile(FileName, Content, VFS.get()); | 1439 auto Style = getFormatStyleForFile(FileName, Content, TFS); |
1366 // This will only insert verbatim headers. | 1440 // This will only insert verbatim headers. |
1367 Inserter.emplace(FileName, Content, Style, | 1441 Inserter.emplace(FileName, Content, Style, |
1368 /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr); | 1442 /*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr); |
1369 | 1443 |
1370 auto Identifiers = collectIdentifiers(Content, Style); | 1444 auto Identifiers = collectIdentifiers(Content, Style); |
1553 C.Name = Recorder->getName(*SemaResult); | 1627 C.Name = Recorder->getName(*SemaResult); |
1554 } else { | 1628 } else { |
1555 assert(IdentifierResult); | 1629 assert(IdentifierResult); |
1556 C.Name = IdentifierResult->Name; | 1630 C.Name = IdentifierResult->Name; |
1557 } | 1631 } |
1558 if (auto OverloadSet = C.overloadSet(Opts)) { | 1632 if (auto OverloadSet = C.overloadSet( |
1633 Opts, FileName, Inserter ? Inserter.getPointer() : nullptr)) { | |
1559 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size()); | 1634 auto Ret = BundleLookup.try_emplace(OverloadSet, Bundles.size()); |
1560 if (Ret.second) | 1635 if (Ret.second) |
1561 Bundles.emplace_back(); | 1636 Bundles.emplace_back(); |
1562 Bundles[Ret.first->second].push_back(std::move(C)); | 1637 Bundles[Ret.first->second].push_back(std::move(C)); |
1563 } else { | 1638 } else { |
1568 llvm::DenseSet<const Symbol *> UsedIndexResults; | 1643 llvm::DenseSet<const Symbol *> UsedIndexResults; |
1569 auto CorrespondingIndexResult = | 1644 auto CorrespondingIndexResult = |
1570 [&](const CodeCompletionResult &SemaResult) -> const Symbol * { | 1645 [&](const CodeCompletionResult &SemaResult) -> const Symbol * { |
1571 if (auto SymID = | 1646 if (auto SymID = |
1572 getSymbolID(SemaResult, Recorder->CCSema->getSourceManager())) { | 1647 getSymbolID(SemaResult, Recorder->CCSema->getSourceManager())) { |
1573 auto I = IndexResults.find(*SymID); | 1648 auto I = IndexResults.find(SymID); |
1574 if (I != IndexResults.end()) { | 1649 if (I != IndexResults.end()) { |
1575 UsedIndexResults.insert(&*I); | 1650 UsedIndexResults.insert(&*I); |
1576 return &*I; | 1651 return &*I; |
1577 } | 1652 } |
1578 } | 1653 } |
1598 return std::move(Top).items(); | 1673 return std::move(Top).items(); |
1599 } | 1674 } |
1600 | 1675 |
1601 llvm::Optional<float> fuzzyScore(const CompletionCandidate &C) { | 1676 llvm::Optional<float> fuzzyScore(const CompletionCandidate &C) { |
1602 // Macros can be very spammy, so we only support prefix completion. | 1677 // Macros can be very spammy, so we only support prefix completion. |
1603 // We won't end up with underfull index results, as macros are sema-only. | 1678 if (((C.SemaResult && |
1604 if (C.SemaResult && C.SemaResult->Kind == CodeCompletionResult::RK_Macro && | 1679 C.SemaResult->Kind == CodeCompletionResult::RK_Macro) || |
1680 (C.IndexResult && | |
1681 C.IndexResult->SymInfo.Kind == index::SymbolKind::Macro)) && | |
1605 !C.Name.startswith_lower(Filter->pattern())) | 1682 !C.Name.startswith_lower(Filter->pattern())) |
1606 return None; | 1683 return None; |
1607 return Filter->match(C.Name); | 1684 return Filter->match(C.Name); |
1685 } | |
1686 | |
1687 CodeCompletion::Scores | |
1688 evaluateCompletion(const SymbolQualitySignals &Quality, | |
1689 const SymbolRelevanceSignals &Relevance) { | |
1690 using RM = CodeCompleteOptions::CodeCompletionRankingModel; | |
1691 CodeCompletion::Scores Scores; | |
1692 switch (Opts.RankingModel) { | |
1693 case RM::Heuristics: | |
1694 Scores.Quality = Quality.evaluateHeuristics(); | |
1695 Scores.Relevance = Relevance.evaluateHeuristics(); | |
1696 Scores.Total = | |
1697 evaluateSymbolAndRelevance(Scores.Quality, Scores.Relevance); | |
1698 // NameMatch is in fact a multiplier on total score, so rescoring is | |
1699 // sound. | |
1700 Scores.ExcludingName = | |
1701 Relevance.NameMatch > std::numeric_limits<float>::epsilon() | |
1702 ? Scores.Total / Relevance.NameMatch | |
1703 : Scores.Quality; | |
1704 return Scores; | |
1705 | |
1706 case RM::DecisionForest: | |
1707 DecisionForestScores DFScores = Opts.DecisionForestScorer( | |
1708 Quality, Relevance, Opts.DecisionForestBase); | |
1709 Scores.ExcludingName = DFScores.ExcludingName; | |
1710 Scores.Total = DFScores.Total; | |
1711 return Scores; | |
1712 } | |
1713 llvm_unreachable("Unhandled CodeCompletion ranking model."); | |
1608 } | 1714 } |
1609 | 1715 |
1610 // Scores a candidate and adds it to the TopN structure. | 1716 // Scores a candidate and adds it to the TopN structure. |
1611 void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates, | 1717 void addCandidate(TopN<ScoredBundle, ScoredBundleGreater> &Candidates, |
1612 CompletionCandidate::Bundle Bundle) { | 1718 CompletionCandidate::Bundle Bundle) { |
1613 SymbolQualitySignals Quality; | 1719 SymbolQualitySignals Quality; |
1614 SymbolRelevanceSignals Relevance; | 1720 SymbolRelevanceSignals Relevance; |
1615 Relevance.Context = CCContextKind; | 1721 Relevance.Context = CCContextKind; |
1616 Relevance.Name = Bundle.front().Name; | 1722 Relevance.Name = Bundle.front().Name; |
1723 Relevance.FilterLength = HeuristicPrefix.Name.size(); | |
1617 Relevance.Query = SymbolRelevanceSignals::CodeComplete; | 1724 Relevance.Query = SymbolRelevanceSignals::CodeComplete; |
1618 Relevance.FileProximityMatch = FileProximity.getPointer(); | 1725 Relevance.FileProximityMatch = FileProximity.getPointer(); |
1619 if (ScopeProximity) | 1726 if (ScopeProximity) |
1620 Relevance.ScopeProximityMatch = ScopeProximity.getPointer(); | 1727 Relevance.ScopeProximityMatch = ScopeProximity.getPointer(); |
1621 if (PreferredType) | 1728 if (PreferredType) |
1622 Relevance.HadContextType = true; | 1729 Relevance.HadContextType = true; |
1623 Relevance.ContextWords = &ContextWords; | 1730 Relevance.ContextWords = &ContextWords; |
1731 Relevance.MainFileSignals = Opts.MainFileSignals; | |
1624 | 1732 |
1625 auto &First = Bundle.front(); | 1733 auto &First = Bundle.front(); |
1626 if (auto FuzzyScore = fuzzyScore(First)) | 1734 if (auto FuzzyScore = fuzzyScore(First)) |
1627 Relevance.NameMatch = *FuzzyScore; | 1735 Relevance.NameMatch = *FuzzyScore; |
1628 else | 1736 else |
1660 Relevance.Scope = SymbolRelevanceSignals::FileScope; | 1768 Relevance.Scope = SymbolRelevanceSignals::FileScope; |
1661 Origin |= SymbolOrigin::Identifier; | 1769 Origin |= SymbolOrigin::Identifier; |
1662 } | 1770 } |
1663 } | 1771 } |
1664 | 1772 |
1665 CodeCompletion::Scores Scores; | 1773 CodeCompletion::Scores Scores = evaluateCompletion(Quality, Relevance); |
1666 Scores.Quality = Quality.evaluate(); | |
1667 Scores.Relevance = Relevance.evaluate(); | |
1668 Scores.Total = evaluateSymbolAndRelevance(Scores.Quality, Scores.Relevance); | |
1669 // NameMatch is in fact a multiplier on total score, so rescoring is sound. | |
1670 Scores.ExcludingName = Relevance.NameMatch | |
1671 ? Scores.Total / Relevance.NameMatch | |
1672 : Scores.Quality; | |
1673 | |
1674 if (Opts.RecordCCResult) | 1774 if (Opts.RecordCCResult) |
1675 Opts.RecordCCResult(toCodeCompletion(Bundle), Quality, Relevance, | 1775 Opts.RecordCCResult(toCodeCompletion(Bundle), Quality, Relevance, |
1676 Scores.Total); | 1776 Scores.Total); |
1677 | 1777 |
1678 dlog("CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name, | 1778 dlog("CodeComplete: {0} ({1}) = {2}\n{3}{4}\n", First.Name, |
1694 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult) | 1794 Item.SemaResult ? Recorder->codeCompletionString(*Item.SemaResult) |
1695 : nullptr; | 1795 : nullptr; |
1696 if (!Builder) | 1796 if (!Builder) |
1697 Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() : nullptr, | 1797 Builder.emplace(Recorder ? &Recorder->CCSema->getASTContext() : nullptr, |
1698 Item, SemaCCS, QueryScopes, *Inserter, FileName, | 1798 Item, SemaCCS, QueryScopes, *Inserter, FileName, |
1699 CCContextKind, Opts, | 1799 CCContextKind, Opts, IsUsingDeclaration, NextTokenKind); |
1700 /*GenerateSnippets=*/!IsUsingDeclaration); | |
1701 else | 1800 else |
1702 Builder->add(Item, SemaCCS); | 1801 Builder->add(Item, SemaCCS); |
1703 } | 1802 } |
1704 return Builder->build(); | 1803 return Builder->build(); |
1705 } | 1804 } |
1707 | 1806 |
1708 } // namespace | 1807 } // namespace |
1709 | 1808 |
1710 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { | 1809 clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const { |
1711 clang::CodeCompleteOptions Result; | 1810 clang::CodeCompleteOptions Result; |
1712 Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns; | 1811 Result.IncludeCodePatterns = EnableSnippets; |
1713 Result.IncludeMacros = IncludeMacros; | 1812 Result.IncludeMacros = true; |
1714 Result.IncludeGlobals = true; | 1813 Result.IncludeGlobals = true; |
1715 // We choose to include full comments and not do doxygen parsing in | 1814 // We choose to include full comments and not do doxygen parsing in |
1716 // completion. | 1815 // completion. |
1717 // FIXME: ideally, we should support doxygen in some form, e.g. do markdown | 1816 // FIXME: ideally, we should support doxygen in some form, e.g. do markdown |
1718 // formatting of the comments. | 1817 // formatting of the comments. |
1747 Content.slice(Rest.size(), Result.Name.begin() - Content.begin()); | 1846 Content.slice(Rest.size(), Result.Name.begin() - Content.begin()); |
1748 | 1847 |
1749 return Result; | 1848 return Result; |
1750 } | 1849 } |
1751 | 1850 |
1752 CodeCompleteResult | 1851 CodeCompleteResult codeComplete(PathRef FileName, Position Pos, |
1753 codeComplete(PathRef FileName, const tooling::CompileCommand &Command, | 1852 const PreambleData *Preamble, |
1754 const PreambleData *Preamble, llvm::StringRef Contents, | 1853 const ParseInputs &ParseInput, |
1755 Position Pos, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, | 1854 CodeCompleteOptions Opts, |
1756 CodeCompleteOptions Opts, SpeculativeFuzzyFind *SpecFuzzyFind) { | 1855 SpeculativeFuzzyFind *SpecFuzzyFind) { |
1757 auto Offset = positionToOffset(Contents, Pos); | 1856 auto Offset = positionToOffset(ParseInput.Contents, Pos); |
1758 if (!Offset) { | 1857 if (!Offset) { |
1759 elog("Code completion position was invalid {0}", Offset.takeError()); | 1858 elog("Code completion position was invalid {0}", Offset.takeError()); |
1760 return CodeCompleteResult(); | 1859 return CodeCompleteResult(); |
1761 } | 1860 } |
1762 auto Flow = CodeCompleteFlow( | 1861 auto Flow = CodeCompleteFlow( |
1763 FileName, Preamble ? Preamble->Includes : IncludeStructure(), | 1862 FileName, Preamble ? Preamble->Includes : IncludeStructure(), |
1764 SpecFuzzyFind, Opts); | 1863 SpecFuzzyFind, Opts); |
1765 return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) | 1864 return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse) |
1766 ? std::move(Flow).runWithoutSema(Contents, *Offset, VFS) | 1865 ? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset, |
1767 : std::move(Flow).run({FileName, Command, *Preamble, | 1866 *ParseInput.TFS) |
1867 : std::move(Flow).run({FileName, *Offset, *Preamble, | |
1768 // We want to serve code completions with | 1868 // We want to serve code completions with |
1769 // low latency, so don't bother patching. | 1869 // low latency, so don't bother patching. |
1770 PreamblePatch(), Contents, *Offset, VFS}); | 1870 /*PreamblePatch=*/llvm::None, ParseInput}); |
1771 } | 1871 } |
1772 | 1872 |
1773 SignatureHelp signatureHelp(PathRef FileName, | 1873 SignatureHelp signatureHelp(PathRef FileName, Position Pos, |
1774 const tooling::CompileCommand &Command, | |
1775 const PreambleData &Preamble, | 1874 const PreambleData &Preamble, |
1776 llvm::StringRef Contents, Position Pos, | 1875 const ParseInputs &ParseInput) { |
1777 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, | 1876 auto Offset = positionToOffset(ParseInput.Contents, Pos); |
1778 const SymbolIndex *Index) { | |
1779 auto Offset = positionToOffset(Contents, Pos); | |
1780 if (!Offset) { | 1877 if (!Offset) { |
1781 elog("Signature help position was invalid {0}", Offset.takeError()); | 1878 elog("Signature help position was invalid {0}", Offset.takeError()); |
1782 return SignatureHelp(); | 1879 return SignatureHelp(); |
1783 } | 1880 } |
1784 SignatureHelp Result; | 1881 SignatureHelp Result; |
1785 clang::CodeCompleteOptions Options; | 1882 clang::CodeCompleteOptions Options; |
1786 Options.IncludeGlobals = false; | 1883 Options.IncludeGlobals = false; |
1787 Options.IncludeMacros = false; | 1884 Options.IncludeMacros = false; |
1788 Options.IncludeCodePatterns = false; | 1885 Options.IncludeCodePatterns = false; |
1789 Options.IncludeBriefComments = false; | 1886 Options.IncludeBriefComments = false; |
1790 | |
1791 ParseInputs PI; | |
1792 PI.CompileCommand = Command; | |
1793 PI.Contents = Contents.str(); | |
1794 PI.FS = std::move(VFS); | |
1795 auto PP = PreamblePatch::create(FileName, PI, Preamble); | |
1796 semaCodeComplete( | 1887 semaCodeComplete( |
1797 std::make_unique<SignatureHelpCollector>(Options, Index, Result), Options, | 1888 std::make_unique<SignatureHelpCollector>(Options, ParseInput.Index, |
1798 {FileName, Command, Preamble, PP, Contents, *Offset, std::move(PI.FS)}); | 1889 Result), |
1890 Options, | |
1891 {FileName, *Offset, Preamble, | |
1892 PreamblePatch::create(FileName, ParseInput, Preamble), ParseInput}); | |
1799 return Result; | 1893 return Result; |
1800 } | 1894 } |
1801 | 1895 |
1802 bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx) { | 1896 bool isIndexedForCodeCompletion(const NamedDecl &ND, ASTContext &ASTCtx) { |
1803 auto InTopLevelScope = [](const NamedDecl &ND) { | 1897 auto InTopLevelScope = [](const NamedDecl &ND) { |