[clang-tools-extra] r319655 - [clangd] Split CodeComplete into a separate file. NFC
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Mon Dec 4 05:49:59 PST 2017
Author: sammccall
Date: Mon Dec 4 05:49:59 2017
New Revision: 319655
URL: http://llvm.org/viewvc/llvm-project?rev=319655&view=rev
Log:
[clangd] Split CodeComplete into a separate file. NFC
Summary: Shared details of ClangdUnit and CodeComplete moved to a new Compiler file.
Reviewers: ilya-biryukov
Subscribers: klimek, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D40719
Added:
clang-tools-extra/trunk/clangd/CodeComplete.cpp
clang-tools-extra/trunk/clangd/CodeComplete.h
clang-tools-extra/trunk/clangd/Compiler.cpp
clang-tools-extra/trunk/clangd/Compiler.h
Modified:
clang-tools-extra/trunk/clangd/CMakeLists.txt
clang-tools-extra/trunk/clangd/ClangdServer.h
clang-tools-extra/trunk/clangd/ClangdUnit.cpp
clang-tools-extra/trunk/clangd/ClangdUnit.h
Modified: clang-tools-extra/trunk/clangd/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CMakeLists.txt?rev=319655&r1=319654&r2=319655&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/CMakeLists.txt Mon Dec 4 05:49:59 2017
@@ -7,6 +7,8 @@ add_clang_library(clangDaemon
ClangdServer.cpp
ClangdUnit.cpp
ClangdUnitStore.cpp
+ CodeComplete.cpp
+ Compiler.cpp
DraftStore.cpp
FuzzyMatch.cpp
GlobalCompilationDatabase.cpp
Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=319655&r1=319654&r2=319655&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Mon Dec 4 05:49:59 2017
@@ -20,6 +20,7 @@
#include "llvm/ADT/StringRef.h"
#include "ClangdUnit.h"
+#include "CodeComplete.h"
#include "Function.h"
#include "Protocol.h"
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.cpp?rev=319655&r1=319654&r2=319655&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.cpp Mon Dec 4 05:49:59 2017
@@ -9,6 +9,7 @@
#include "ClangdUnit.h"
+#include "Compiler.h"
#include "Logger.h"
#include "Trace.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -20,7 +21,6 @@
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Tooling/CompilationDatabase.h"
@@ -120,44 +120,6 @@ static int getSeverity(DiagnosticsEngine
llvm_unreachable("Unknown diagnostic level!");
}
-/// Get the optional chunk as a string. This function is possibly recursive.
-///
-/// The parameter info for each parameter is appended to the Parameters.
-std::string
-getOptionalParameters(const CodeCompletionString &CCS,
- std::vector<ParameterInformation> &Parameters) {
- std::string Result;
- for (const auto &Chunk : CCS) {
- switch (Chunk.Kind) {
- case CodeCompletionString::CK_Optional:
- assert(Chunk.Optional &&
- "Expected the optional code completion string to be non-null.");
- Result += getOptionalParameters(*Chunk.Optional, Parameters);
- break;
- case CodeCompletionString::CK_VerticalSpace:
- break;
- case CodeCompletionString::CK_Placeholder:
- // A string that acts as a placeholder for, e.g., a function call
- // argument.
- // Intentional fallthrough here.
- case CodeCompletionString::CK_CurrentParameter: {
- // A piece of text that describes the parameter that corresponds to
- // the code-completion location within a function call, message send,
- // macro invocation, etc.
- Result += Chunk.Text;
- ParameterInformation Info;
- Info.label = Chunk.Text;
- Parameters.push_back(std::move(Info));
- break;
- }
- default:
- Result += Chunk.Text;
- break;
- }
- }
- return Result;
-}
-
llvm::Optional<DiagWithFixIts> toClangdDiag(const StoredDiagnostic &D) {
auto Location = D.getLocation();
if (!Location.isValid() || !Location.getManager().isInMainFile(Location))
@@ -193,722 +155,12 @@ private:
std::vector<DiagWithFixIts> &Output;
};
-class EmptyDiagsConsumer : public DiagnosticConsumer {
-public:
- void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
- const clang::Diagnostic &Info) override {}
-};
-
-std::unique_ptr<CompilerInvocation>
-createCompilerInvocation(ArrayRef<const char *> ArgList,
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
- auto CI = createInvocationFromCommandLine(ArgList, std::move(Diags),
- std::move(VFS));
- // We rely on CompilerInstance to manage the resource (i.e. free them on
- // EndSourceFile), but that won't happen if DisableFree is set to true.
- // Since createInvocationFromCommandLine sets it to true, we have to override
- // it.
- CI->getFrontendOpts().DisableFree = false;
- return CI;
-}
-
-/// Creates a CompilerInstance from \p CI, with main buffer overriden to \p
-/// Buffer and arguments to read the PCH from \p Preamble, if \p Preamble is not
-/// null. Note that vfs::FileSystem inside returned instance may differ from \p
-/// VFS if additional file remapping were set in command-line arguments.
-/// On some errors, returns null. When non-null value is returned, it's expected
-/// to be consumed by the FrontendAction as it will have a pointer to the \p
-/// Buffer that will only be deleted if BeginSourceFile is called.
-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) {
- assert(VFS && "VFS is null");
- assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&
- "Setting RetainRemappedFileBuffers to true will cause a memory leak "
- "of ContentsBuffer");
-
- // NOTE: we use Buffer.get() when adding remapped files, so we have to make
- // sure it will be released if no error is emitted.
- if (Preamble) {
- Preamble->AddImplicitPreamble(*CI, VFS, Buffer.get());
- } else {
- CI->getPreprocessorOpts().addRemappedFile(
- CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get());
- }
-
- auto Clang = llvm::make_unique<CompilerInstance>(PCHs);
- Clang->setInvocation(std::move(CI));
- Clang->createDiagnostics(&DiagsClient, false);
-
- if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
- Clang->getInvocation(), Clang->getDiagnostics(), VFS))
- VFS = VFSWithRemapping;
- Clang->setVirtualFileSystem(VFS);
-
- Clang->setTarget(TargetInfo::CreateTargetInfo(
- Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
- if (!Clang->hasTarget())
- return nullptr;
-
- // RemappedFileBuffers will handle the lifetime of the Buffer pointer,
- // release it.
- Buffer.release();
- return Clang;
-}
-
template <class T> bool futureIsReady(std::shared_future<T> const &Future) {
return Future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
} // namespace
-namespace {
-
-CompletionItemKind getKindOfDecl(CXCursorKind CursorKind) {
- switch (CursorKind) {
- case CXCursor_MacroInstantiation:
- case CXCursor_MacroDefinition:
- return CompletionItemKind::Text;
- case CXCursor_CXXMethod:
- return CompletionItemKind::Method;
- case CXCursor_FunctionDecl:
- case CXCursor_FunctionTemplate:
- return CompletionItemKind::Function;
- case CXCursor_Constructor:
- case CXCursor_Destructor:
- return CompletionItemKind::Constructor;
- case CXCursor_FieldDecl:
- return CompletionItemKind::Field;
- case CXCursor_VarDecl:
- case CXCursor_ParmDecl:
- return CompletionItemKind::Variable;
- case CXCursor_ClassDecl:
- case CXCursor_StructDecl:
- case CXCursor_UnionDecl:
- case CXCursor_ClassTemplate:
- case CXCursor_ClassTemplatePartialSpecialization:
- return CompletionItemKind::Class;
- case CXCursor_Namespace:
- case CXCursor_NamespaceAlias:
- case CXCursor_NamespaceRef:
- return CompletionItemKind::Module;
- case CXCursor_EnumConstantDecl:
- return CompletionItemKind::Value;
- case CXCursor_EnumDecl:
- return CompletionItemKind::Enum;
- case CXCursor_TypeAliasDecl:
- case CXCursor_TypeAliasTemplateDecl:
- case CXCursor_TypedefDecl:
- case CXCursor_MemberRef:
- case CXCursor_TypeRef:
- return CompletionItemKind::Reference;
- default:
- return CompletionItemKind::Missing;
- }
-}
-
-CompletionItemKind getKind(CodeCompletionResult::ResultKind ResKind,
- CXCursorKind CursorKind) {
- switch (ResKind) {
- case CodeCompletionResult::RK_Declaration:
- return getKindOfDecl(CursorKind);
- case CodeCompletionResult::RK_Keyword:
- return CompletionItemKind::Keyword;
- case CodeCompletionResult::RK_Macro:
- return CompletionItemKind::Text; // unfortunately, there's no 'Macro'
- // completion items in LSP.
- case CodeCompletionResult::RK_Pattern:
- return CompletionItemKind::Snippet;
- }
- llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
-}
-
-std::string escapeSnippet(const llvm::StringRef Text) {
- std::string Result;
- Result.reserve(Text.size()); // Assume '$', '}' and '\\' are rare.
- for (const auto Character : Text) {
- if (Character == '$' || Character == '}' || Character == '\\')
- Result.push_back('\\');
- Result.push_back(Character);
- }
- return Result;
-}
-
-std::string getDocumentation(const CodeCompletionString &CCS) {
- // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
- // information in the documentation field.
- std::string Result;
- const unsigned AnnotationCount = CCS.getAnnotationCount();
- if (AnnotationCount > 0) {
- Result += "Annotation";
- if (AnnotationCount == 1) {
- Result += ": ";
- } else /* AnnotationCount > 1 */ {
- Result += "s: ";
- }
- for (unsigned I = 0; I < AnnotationCount; ++I) {
- Result += CCS.getAnnotation(I);
- Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
- }
- }
- // Add brief documentation (if there is any).
- if (CCS.getBriefComment() != nullptr) {
- if (!Result.empty()) {
- // This means we previously added annotations. Add an extra newline
- // character to make the annotations stand out.
- Result.push_back('\n');
- }
- Result += CCS.getBriefComment();
- }
- return Result;
-}
-
-/// A scored code completion result.
-/// It may be promoted to a CompletionItem if it's among the top-ranked results.
-struct CompletionCandidate {
- CompletionCandidate(CodeCompletionResult &Result)
- : Result(&Result), Score(score(Result)) {}
-
- CodeCompletionResult *Result;
- float Score; // 0 to 1, higher is better.
-
- // Comparison reflects rank: better candidates are smaller.
- bool operator<(const CompletionCandidate &C) const {
- if (Score != C.Score)
- return Score > C.Score;
- return *Result < *C.Result;
- }
-
- // Returns a string that sorts in the same order as operator<, for LSP.
- // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and
- // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo"
- std::string sortText() const {
- std::string S, NameStorage;
- llvm::raw_string_ostream OS(S);
- write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
- /*Width=*/2 * sizeof(Score));
- OS << Result->getOrderedName(NameStorage);
- return OS.str();
- }
-
-private:
- static float score(const CodeCompletionResult &Result) {
- // Priority 80 is a really bad score.
- float Score = 1 - std::min<float>(80, Result.Priority) / 80;
-
- switch (static_cast<CXAvailabilityKind>(Result.Availability)) {
- case CXAvailability_Available:
- // No penalty.
- break;
- case CXAvailability_Deprecated:
- Score *= 0.1f;
- break;
- case CXAvailability_NotAccessible:
- case CXAvailability_NotAvailable:
- Score = 0;
- break;
- }
- return Score;
- }
-
- // Produces an integer that sorts in the same order as F.
- // That is: a < b <==> encodeFloat(a) < encodeFloat(b).
- static uint32_t encodeFloat(float F) {
- static_assert(std::numeric_limits<float>::is_iec559, "");
- static_assert(sizeof(float) == sizeof(uint32_t), "");
- constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
-
- // Get the bits of the float. Endianness is the same as for integers.
- uint32_t U;
- memcpy(&U, &F, sizeof(float));
- // IEEE 754 floats compare like sign-magnitude integers.
- if (U & TopBit) // Negative float.
- return 0 - U; // Map onto the low half of integers, order reversed.
- return U + TopBit; // Positive floats map onto the high half of integers.
- }
-};
-
-class CompletionItemsCollector : public CodeCompleteConsumer {
-public:
- CompletionItemsCollector(const clangd::CodeCompleteOptions &CodeCompleteOpts,
- CompletionList &Items)
- : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
- /*OutputIsBinary=*/false),
- ClangdOpts(CodeCompleteOpts), Items(Items),
- Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
- CCTUInfo(Allocator) {}
-
- void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
- CodeCompletionResult *Results,
- unsigned NumResults) override final {
- StringRef Filter = S.getPreprocessor().getCodeCompletionFilter();
- std::priority_queue<CompletionCandidate> Candidates;
- for (unsigned I = 0; I < NumResults; ++I) {
- auto &Result = Results[I];
- if (!ClangdOpts.IncludeIneligibleResults &&
- (Result.Availability == CXAvailability_NotAvailable ||
- Result.Availability == CXAvailability_NotAccessible))
- continue;
- if (!Filter.empty() && !fuzzyMatch(S, Context, Filter, Result))
- continue;
- Candidates.emplace(Result);
- if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {
- Candidates.pop();
- Items.isIncomplete = true;
- }
- }
- while (!Candidates.empty()) {
- auto &Candidate = Candidates.top();
- const auto *CCS = Candidate.Result->CreateCodeCompletionString(
- S, Context, *Allocator, CCTUInfo,
- CodeCompleteOpts.IncludeBriefComments);
- assert(CCS && "Expected the CodeCompletionString to be non-null");
- Items.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS));
- Candidates.pop();
- }
- std::reverse(Items.items.begin(), Items.items.end());
- }
-
- GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
-
- CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
-
-private:
- bool fuzzyMatch(Sema &S, const CodeCompletionContext &CCCtx, StringRef Filter,
- CodeCompletionResult Result) {
- switch (Result.Kind) {
- case CodeCompletionResult::RK_Declaration:
- if (auto *ID = Result.Declaration->getIdentifier())
- return fuzzyMatch(Filter, ID->getName());
- break;
- case CodeCompletionResult::RK_Keyword:
- return fuzzyMatch(Filter, Result.Keyword);
- case CodeCompletionResult::RK_Macro:
- return fuzzyMatch(Filter, Result.Macro->getName());
- case CodeCompletionResult::RK_Pattern:
- return fuzzyMatch(Filter, Result.Pattern->getTypedText());
- }
- auto *CCS = Result.CreateCodeCompletionString(
- S, CCCtx, *Allocator, CCTUInfo, /*IncludeBriefComments=*/false);
- return fuzzyMatch(Filter, CCS->getTypedText());
- }
-
- // Checks whether Target matches the Filter.
- // Currently just requires a case-insensitive subsequence match.
- // FIXME: make stricter and word-based: 'unique_ptr' should not match 'que'.
- // FIXME: return a score to be incorporated into ranking.
- static bool fuzzyMatch(StringRef Filter, StringRef Target) {
- size_t TPos = 0;
- for (char C : Filter) {
- TPos = Target.find_lower(C, TPos);
- if (TPos == StringRef::npos)
- return false;
- }
- return true;
- }
-
- CompletionItem
- ProcessCodeCompleteResult(const CompletionCandidate &Candidate,
- const CodeCompletionString &CCS) const {
-
- // Adjust this to InsertTextFormat::Snippet iff we encounter a
- // CK_Placeholder chunk in SnippetCompletionItemsCollector.
- CompletionItem Item;
- Item.insertTextFormat = InsertTextFormat::PlainText;
-
- Item.documentation = getDocumentation(CCS);
- Item.sortText = Candidate.sortText();
-
- // Fill in the label, detail, insertText and filterText fields of the
- // CompletionItem.
- ProcessChunks(CCS, Item);
-
- // Fill in the kind field of the CompletionItem.
- Item.kind = getKind(Candidate.Result->Kind, Candidate.Result->CursorKind);
-
- return Item;
- }
-
- virtual void ProcessChunks(const CodeCompletionString &CCS,
- CompletionItem &Item) const = 0;
-
- clangd::CodeCompleteOptions ClangdOpts;
- CompletionList &Items;
- std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
- CodeCompletionTUInfo CCTUInfo;
-
-}; // CompletionItemsCollector
-
-bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
- return Chunk.Kind == CodeCompletionString::CK_Informative &&
- StringRef(Chunk.Text).endswith("::");
-}
-
-class PlainTextCompletionItemsCollector final
- : public CompletionItemsCollector {
-
-public:
- PlainTextCompletionItemsCollector(
- const clangd::CodeCompleteOptions &CodeCompleteOpts,
- CompletionList &Items)
- : CompletionItemsCollector(CodeCompleteOpts, Items) {}
-
-private:
- void ProcessChunks(const CodeCompletionString &CCS,
- CompletionItem &Item) const override {
- for (const auto &Chunk : CCS) {
- // Informative qualifier chunks only clutter completion results, skip
- // them.
- if (isInformativeQualifierChunk(Chunk))
- continue;
-
- switch (Chunk.Kind) {
- case CodeCompletionString::CK_TypedText:
- // There's always exactly one CK_TypedText chunk.
- Item.insertText = Item.filterText = Chunk.Text;
- Item.label += Chunk.Text;
- break;
- case CodeCompletionString::CK_ResultType:
- assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
- Item.detail = Chunk.Text;
- break;
- case CodeCompletionString::CK_Optional:
- break;
- default:
- Item.label += Chunk.Text;
- break;
- }
- }
- }
-}; // PlainTextCompletionItemsCollector
-
-class SnippetCompletionItemsCollector final : public CompletionItemsCollector {
-
-public:
- SnippetCompletionItemsCollector(
- const clangd::CodeCompleteOptions &CodeCompleteOpts,
- CompletionList &Items)
- : CompletionItemsCollector(CodeCompleteOpts, Items) {}
-
-private:
- void ProcessChunks(const CodeCompletionString &CCS,
- CompletionItem &Item) const override {
- unsigned ArgCount = 0;
- for (const auto &Chunk : CCS) {
- // Informative qualifier chunks only clutter completion results, skip
- // them.
- if (isInformativeQualifierChunk(Chunk))
- continue;
-
- switch (Chunk.Kind) {
- case CodeCompletionString::CK_TypedText:
- // The piece of text that the user is expected to type to match
- // the code-completion string, typically a keyword or the name of
- // a declarator or macro.
- Item.filterText = Chunk.Text;
- LLVM_FALLTHROUGH;
- case CodeCompletionString::CK_Text:
- // A piece of text that should be placed in the buffer,
- // e.g., parentheses or a comma in a function call.
- Item.label += Chunk.Text;
- Item.insertText += Chunk.Text;
- break;
- case CodeCompletionString::CK_Optional:
- // A code completion string that is entirely optional.
- // For example, an optional code completion string that
- // describes the default arguments in a function call.
-
- // FIXME: Maybe add an option to allow presenting the optional chunks?
- break;
- case CodeCompletionString::CK_Placeholder:
- // A string that acts as a placeholder for, e.g., a function call
- // argument.
- ++ArgCount;
- Item.insertText += "${" + std::to_string(ArgCount) + ':' +
- escapeSnippet(Chunk.Text) + '}';
- Item.label += Chunk.Text;
- Item.insertTextFormat = InsertTextFormat::Snippet;
- break;
- case CodeCompletionString::CK_Informative:
- // A piece of text that describes something about the result
- // but should not be inserted into the buffer.
- // For example, the word "const" for a const method, or the name of
- // the base class for methods that are part of the base class.
- Item.label += Chunk.Text;
- // Don't put the informative chunks in the insertText.
- break;
- case CodeCompletionString::CK_ResultType:
- // A piece of text that describes the type of an entity or,
- // for functions and methods, the return type.
- assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
- Item.detail = Chunk.Text;
- break;
- case CodeCompletionString::CK_CurrentParameter:
- // A piece of text that describes the parameter that corresponds to
- // the code-completion location within a function call, message send,
- // macro invocation, etc.
- //
- // This should never be present while collecting completion items,
- // only while collecting overload candidates.
- llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
- "CompletionItems");
- break;
- case CodeCompletionString::CK_LeftParen:
- // A left parenthesis ('(').
- case CodeCompletionString::CK_RightParen:
- // A right parenthesis (')').
- case CodeCompletionString::CK_LeftBracket:
- // A left bracket ('[').
- case CodeCompletionString::CK_RightBracket:
- // A right bracket (']').
- case CodeCompletionString::CK_LeftBrace:
- // A left brace ('{').
- case CodeCompletionString::CK_RightBrace:
- // A right brace ('}').
- case CodeCompletionString::CK_LeftAngle:
- // A left angle bracket ('<').
- case CodeCompletionString::CK_RightAngle:
- // A right angle bracket ('>').
- case CodeCompletionString::CK_Comma:
- // A comma separator (',').
- case CodeCompletionString::CK_Colon:
- // A colon (':').
- case CodeCompletionString::CK_SemiColon:
- // A semicolon (';').
- case CodeCompletionString::CK_Equal:
- // An '=' sign.
- case CodeCompletionString::CK_HorizontalSpace:
- // Horizontal whitespace (' ').
- Item.insertText += Chunk.Text;
- Item.label += Chunk.Text;
- break;
- case CodeCompletionString::CK_VerticalSpace:
- // Vertical whitespace ('\n' or '\r\n', depending on the
- // platform).
- Item.insertText += Chunk.Text;
- // Don't even add a space to the label.
- break;
- }
- }
- }
-}; // SnippetCompletionItemsCollector
-
-class SignatureHelpCollector final : public CodeCompleteConsumer {
-
-public:
- SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
- SignatureHelp &SigHelp)
- : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
- SigHelp(SigHelp),
- Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
- CCTUInfo(Allocator) {}
-
- void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
- OverloadCandidate *Candidates,
- unsigned NumCandidates) override {
- SigHelp.signatures.reserve(NumCandidates);
- // FIXME(rwols): How can we determine the "active overload candidate"?
- // Right now the overloaded candidates seem to be provided in a "best fit"
- // order, so I'm not too worried about this.
- SigHelp.activeSignature = 0;
- assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
- "too many arguments");
- SigHelp.activeParameter = static_cast<int>(CurrentArg);
- for (unsigned I = 0; I < NumCandidates; ++I) {
- const auto &Candidate = Candidates[I];
- const auto *CCS = Candidate.CreateSignatureString(
- CurrentArg, S, *Allocator, CCTUInfo, true);
- assert(CCS && "Expected the CodeCompletionString to be non-null");
- SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS));
- }
- }
-
- GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
-
- CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
-
-private:
- SignatureInformation
- ProcessOverloadCandidate(const OverloadCandidate &Candidate,
- const CodeCompletionString &CCS) const {
- SignatureInformation Result;
- const char *ReturnType = nullptr;
-
- Result.documentation = getDocumentation(CCS);
-
- for (const auto &Chunk : CCS) {
- switch (Chunk.Kind) {
- case CodeCompletionString::CK_ResultType:
- // A piece of text that describes the type of an entity or,
- // for functions and methods, the return type.
- assert(!ReturnType && "Unexpected CK_ResultType");
- ReturnType = Chunk.Text;
- break;
- case CodeCompletionString::CK_Placeholder:
- // A string that acts as a placeholder for, e.g., a function call
- // argument.
- // Intentional fallthrough here.
- case CodeCompletionString::CK_CurrentParameter: {
- // A piece of text that describes the parameter that corresponds to
- // the code-completion location within a function call, message send,
- // macro invocation, etc.
- Result.label += Chunk.Text;
- ParameterInformation Info;
- Info.label = Chunk.Text;
- Result.parameters.push_back(std::move(Info));
- break;
- }
- case CodeCompletionString::CK_Optional: {
- // The rest of the parameters are defaulted/optional.
- assert(Chunk.Optional &&
- "Expected the optional code completion string to be non-null.");
- Result.label +=
- getOptionalParameters(*Chunk.Optional, Result.parameters);
- break;
- }
- case CodeCompletionString::CK_VerticalSpace:
- break;
- default:
- Result.label += Chunk.Text;
- break;
- }
- }
- if (ReturnType) {
- Result.label += " -> ";
- Result.label += ReturnType;
- }
- return Result;
- }
-
- SignatureHelp &SigHelp;
- std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
- CodeCompletionTUInfo CCTUInfo;
-
-}; // SignatureHelpCollector
-
-bool invokeCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
- const clang::CodeCompleteOptions &Options,
- PathRef FileName,
- const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- clangd::Logger &Logger) {
- std::vector<const char *> ArgStrs;
- for (const auto &S : Command.CommandLine)
- ArgStrs.push_back(S.c_str());
-
- VFS->setCurrentWorkingDirectory(Command.Directory);
-
- std::unique_ptr<CompilerInvocation> CI;
- EmptyDiagsConsumer DummyDiagsConsumer;
- {
- IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
- CompilerInstance::createDiagnostics(new DiagnosticOptions,
- &DummyDiagsConsumer, false);
- CI = createCompilerInvocation(ArgStrs, CommandLineDiagsEngine, VFS);
- }
- assert(CI && "Couldn't create CompilerInvocation");
-
- std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
- llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
-
- // Attempt to reuse the PCH from precompiled preamble, if it was built.
- if (Preamble) {
- auto Bounds =
- ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
- if (!Preamble->CanReuse(*CI, ContentsBuffer.get(), Bounds, VFS.get()))
- Preamble = nullptr;
- }
-
- auto Clang = prepareCompilerInstance(
- std::move(CI), Preamble, std::move(ContentsBuffer), std::move(PCHs),
- std::move(VFS), DummyDiagsConsumer);
- auto &DiagOpts = Clang->getDiagnosticOpts();
- DiagOpts.IgnoreWarnings = true;
-
- auto &FrontendOpts = Clang->getFrontendOpts();
- FrontendOpts.SkipFunctionBodies = true;
- FrontendOpts.CodeCompleteOpts = Options;
- FrontendOpts.CodeCompletionAt.FileName = FileName;
- FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
- FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
-
- Clang->setCodeCompletionConsumer(Consumer.release());
-
- SyntaxOnlyAction Action;
- if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
- Logger.log("BeginSourceFile() failed when running codeComplete for " +
- FileName);
- return false;
- }
- if (!Action.Execute()) {
- Logger.log("Execute() failed when running codeComplete for " + FileName);
- return false;
- }
-
- Action.EndSourceFile();
-
- return true;
-}
-
-} // namespace
-
-clang::CodeCompleteOptions
-clangd::CodeCompleteOptions::getClangCompleteOpts() const {
- clang::CodeCompleteOptions Result;
- Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
- Result.IncludeMacros = IncludeMacros;
- Result.IncludeGlobals = IncludeGlobals;
- Result.IncludeBriefComments = IncludeBriefComments;
-
- return Result;
-}
-
-CompletionList
-clangd::codeComplete(PathRef FileName, const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- clangd::CodeCompleteOptions Opts, clangd::Logger &Logger) {
- CompletionList Results;
- std::unique_ptr<CodeCompleteConsumer> Consumer;
- if (Opts.EnableSnippets) {
- Consumer =
- llvm::make_unique<SnippetCompletionItemsCollector>(Opts, Results);
- } else {
- Consumer =
- llvm::make_unique<PlainTextCompletionItemsCollector>(Opts, Results);
- }
- invokeCodeComplete(std::move(Consumer), Opts.getClangCompleteOpts(), FileName,
- Command, Preamble, Contents, Pos, std::move(VFS),
- std::move(PCHs), Logger);
- return Results;
-}
-
-SignatureHelp
-clangd::signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- clangd::Logger &Logger) {
- SignatureHelp Result;
- clang::CodeCompleteOptions Options;
- Options.IncludeGlobals = false;
- Options.IncludeMacros = false;
- Options.IncludeCodePatterns = false;
- Options.IncludeBriefComments = true;
- invokeCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
- Options, FileName, Command, Preamble, Contents, Pos,
- std::move(VFS), std::move(PCHs), Logger);
- return Result;
-}
-
void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
}
@@ -946,7 +198,7 @@ ParsedAST::Build(std::unique_ptr<clang::
// UnitDiagsConsumer is local, we can not store it in CompilerInstance that
// has a longer lifetime.
- Clang->getDiagnostics().setClient(new EmptyDiagsConsumer);
+ Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
@@ -1302,11 +554,14 @@ CppFile::deferRebuild(StringRef NewConte
{
// FIXME(ibiryukov): store diagnostics from CommandLine when we start
// reporting them.
- EmptyDiagsConsumer CommandLineDiagsConsumer;
+ IgnoreDiagnostics IgnoreDiagnostics;
IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
CompilerInstance::createDiagnostics(new DiagnosticOptions,
- &CommandLineDiagsConsumer, false);
- CI = createCompilerInvocation(ArgStrs, CommandLineDiagsEngine, VFS);
+ &IgnoreDiagnostics, false);
+ CI =
+ createInvocationFromCommandLine(ArgStrs, CommandLineDiagsEngine, VFS);
+ // createInvocationFromCommandLine sets DisableFree.
+ CI->getFrontendOpts().DisableFree = false;
}
assert(CI && "Couldn't create CompilerInvocation");
Modified: clang-tools-extra/trunk/clangd/ClangdUnit.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdUnit.h?rev=319655&r1=319654&r2=319655&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdUnit.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdUnit.h Mon Dec 4 05:49:59 2017
@@ -256,56 +256,6 @@ private:
clangd::Logger &Logger;
};
-struct CodeCompleteOptions {
- /// Returns options that can be passed to clang's completion engine.
- clang::CodeCompleteOptions getClangCompleteOpts() const;
-
- /// When true, completion items will contain expandable code snippets in
- /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int
- /// b})).
- bool EnableSnippets = false;
-
- /// Add code patterns to completion results.
- /// If EnableSnippets is false, this options is ignored and code patterns will
- /// always be omitted.
- bool IncludeCodePatterns = true;
-
- /// Add macros to code completion results.
- bool IncludeMacros = true;
-
- /// Add globals to code completion results.
- bool IncludeGlobals = true;
-
- /// Add brief comments to completion items, if available.
- /// FIXME(ibiryukov): it looks like turning this option on significantly slows
- /// down completion, investigate if it can be made faster.
- bool IncludeBriefComments = true;
-
- /// Include results that are not legal completions in the current context.
- /// For example, private members are usually inaccessible.
- bool IncludeIneligibleResults = false;
-
- /// Limit the number of results returned (0 means no limit).
- /// If more results are available, we set CompletionList.isIncomplete.
- size_t Limit = 0;
-};
-
-/// Get code completions at a specified \p Pos in \p FileName.
-CompletionList
-codeComplete(PathRef FileName, const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble, StringRef Contents,
- Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- clangd::CodeCompleteOptions Opts, clangd::Logger &Logger);
-
-/// Get signature help at a specified \p Pos in \p FileName.
-SignatureHelp signatureHelp(PathRef FileName,
- const tooling::CompileCommand &Command,
- PrecompiledPreamble const *Preamble,
- StringRef Contents, Position Pos,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS,
- std::shared_ptr<PCHContainerOperations> PCHs,
- clangd::Logger &Logger);
/// Get the beginning SourceLocation at a specified \p Pos.
SourceLocation getBeginningOfIdentifier(ParsedAST &Unit, const Position &Pos,
Added: clang-tools-extra/trunk/clangd/CodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeComplete.cpp?rev=319655&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeComplete.cpp (added)
+++ clang-tools-extra/trunk/clangd/CodeComplete.cpp Mon Dec 4 05:49:59 2017
@@ -0,0 +1,706 @@
+//===--- CodeComplete.cpp ---------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// AST-based completions are provided using the completion hooks in Sema.
+//
+// Signature help works in a similar way as code completion, but it is simpler
+// as there are typically fewer candidates.
+//
+//===---------------------------------------------------------------------===//
+
+#include "CodeComplete.h"
+#include "Compiler.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/Sema.h"
+#include <queue>
+
+namespace clang {
+namespace clangd {
+namespace {
+
+CompletionItemKind getKindOfDecl(CXCursorKind CursorKind) {
+ switch (CursorKind) {
+ case CXCursor_MacroInstantiation:
+ case CXCursor_MacroDefinition:
+ return CompletionItemKind::Text;
+ case CXCursor_CXXMethod:
+ return CompletionItemKind::Method;
+ case CXCursor_FunctionDecl:
+ case CXCursor_FunctionTemplate:
+ return CompletionItemKind::Function;
+ case CXCursor_Constructor:
+ case CXCursor_Destructor:
+ return CompletionItemKind::Constructor;
+ case CXCursor_FieldDecl:
+ return CompletionItemKind::Field;
+ case CXCursor_VarDecl:
+ case CXCursor_ParmDecl:
+ return CompletionItemKind::Variable;
+ case CXCursor_ClassDecl:
+ case CXCursor_StructDecl:
+ case CXCursor_UnionDecl:
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ return CompletionItemKind::Class;
+ case CXCursor_Namespace:
+ case CXCursor_NamespaceAlias:
+ case CXCursor_NamespaceRef:
+ return CompletionItemKind::Module;
+ case CXCursor_EnumConstantDecl:
+ return CompletionItemKind::Value;
+ case CXCursor_EnumDecl:
+ return CompletionItemKind::Enum;
+ case CXCursor_TypeAliasDecl:
+ case CXCursor_TypeAliasTemplateDecl:
+ case CXCursor_TypedefDecl:
+ case CXCursor_MemberRef:
+ case CXCursor_TypeRef:
+ return CompletionItemKind::Reference;
+ default:
+ return CompletionItemKind::Missing;
+ }
+}
+
+CompletionItemKind getKind(CodeCompletionResult::ResultKind ResKind,
+ CXCursorKind CursorKind) {
+ switch (ResKind) {
+ case CodeCompletionResult::RK_Declaration:
+ return getKindOfDecl(CursorKind);
+ case CodeCompletionResult::RK_Keyword:
+ return CompletionItemKind::Keyword;
+ case CodeCompletionResult::RK_Macro:
+ return CompletionItemKind::Text; // unfortunately, there's no 'Macro'
+ // completion items in LSP.
+ case CodeCompletionResult::RK_Pattern:
+ return CompletionItemKind::Snippet;
+ }
+ llvm_unreachable("Unhandled CodeCompletionResult::ResultKind.");
+}
+
+std::string escapeSnippet(const llvm::StringRef Text) {
+ std::string Result;
+ Result.reserve(Text.size()); // Assume '$', '}' and '\\' are rare.
+ for (const auto Character : Text) {
+ if (Character == '$' || Character == '}' || Character == '\\')
+ Result.push_back('\\');
+ Result.push_back(Character);
+ }
+ return Result;
+}
+
+std::string getDocumentation(const CodeCompletionString &CCS) {
+ // Things like __attribute__((nonnull(1,3))) and [[noreturn]]. Present this
+ // information in the documentation field.
+ std::string Result;
+ const unsigned AnnotationCount = CCS.getAnnotationCount();
+ if (AnnotationCount > 0) {
+ Result += "Annotation";
+ if (AnnotationCount == 1) {
+ Result += ": ";
+ } else /* AnnotationCount > 1 */ {
+ Result += "s: ";
+ }
+ for (unsigned I = 0; I < AnnotationCount; ++I) {
+ Result += CCS.getAnnotation(I);
+ Result.push_back(I == AnnotationCount - 1 ? '\n' : ' ');
+ }
+ }
+ // Add brief documentation (if there is any).
+ if (CCS.getBriefComment() != nullptr) {
+ if (!Result.empty()) {
+ // This means we previously added annotations. Add an extra newline
+ // character to make the annotations stand out.
+ Result.push_back('\n');
+ }
+ Result += CCS.getBriefComment();
+ }
+ return Result;
+}
+
+/// Get the optional chunk as a string. This function is possibly recursive.
+///
+/// The parameter info for each parameter is appended to the Parameters.
+std::string
+getOptionalParameters(const CodeCompletionString &CCS,
+ std::vector<ParameterInformation> &Parameters) {
+ std::string Result;
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_Optional:
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result += getOptionalParameters(*Chunk.Optional, Parameters);
+ break;
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Parameters.push_back(std::move(Info));
+ break;
+ }
+ default:
+ Result += Chunk.Text;
+ break;
+ }
+ }
+ return Result;
+}
+
+
+/// A scored code completion result.
+/// It may be promoted to a CompletionItem if it's among the top-ranked results.
+struct CompletionCandidate {
+ CompletionCandidate(CodeCompletionResult &Result)
+ : Result(&Result), Score(score(Result)) {}
+
+ CodeCompletionResult *Result;
+ float Score; // 0 to 1, higher is better.
+
+ // Comparison reflects rank: better candidates are smaller.
+ bool operator<(const CompletionCandidate &C) const {
+ if (Score != C.Score)
+ return Score > C.Score;
+ return *Result < *C.Result;
+ }
+
+ // Returns a string that sorts in the same order as operator<, for LSP.
+ // Conceptually, this is [-Score, Name]. We convert -Score to an integer, and
+ // hex-encode it for readability. Example: [0.5, "foo"] -> "41000000foo"
+ std::string sortText() const {
+ std::string S, NameStorage;
+ llvm::raw_string_ostream OS(S);
+ write_hex(OS, encodeFloat(-Score), llvm::HexPrintStyle::Lower,
+ /*Width=*/2 * sizeof(Score));
+ OS << Result->getOrderedName(NameStorage);
+ return OS.str();
+ }
+
+private:
+ static float score(const CodeCompletionResult &Result) {
+ // Priority 80 is a really bad score.
+ float Score = 1 - std::min<float>(80, Result.Priority) / 80;
+
+ switch (static_cast<CXAvailabilityKind>(Result.Availability)) {
+ case CXAvailability_Available:
+ // No penalty.
+ break;
+ case CXAvailability_Deprecated:
+ Score *= 0.1f;
+ break;
+ case CXAvailability_NotAccessible:
+ case CXAvailability_NotAvailable:
+ Score = 0;
+ break;
+ }
+ return Score;
+ }
+
+ // Produces an integer that sorts in the same order as F.
+ // That is: a < b <==> encodeFloat(a) < encodeFloat(b).
+ static uint32_t encodeFloat(float F) {
+ static_assert(std::numeric_limits<float>::is_iec559, "");
+ static_assert(sizeof(float) == sizeof(uint32_t), "");
+ constexpr uint32_t TopBit = ~(~uint32_t{0} >> 1);
+
+ // Get the bits of the float. Endianness is the same as for integers.
+ uint32_t U;
+ memcpy(&U, &F, sizeof(float));
+ // IEEE 754 floats compare like sign-magnitude integers.
+ if (U & TopBit) // Negative float.
+ return 0 - U; // Map onto the low half of integers, order reversed.
+ return U + TopBit; // Positive floats map onto the high half of integers.
+ }
+};
+
+class CompletionItemsCollector : public CodeCompleteConsumer {
+public:
+ CompletionItemsCollector(const CodeCompleteOptions &CodeCompleteOpts,
+ CompletionList &Items)
+ : CodeCompleteConsumer(CodeCompleteOpts.getClangCompleteOpts(),
+ /*OutputIsBinary=*/false),
+ ClangdOpts(CodeCompleteOpts), Items(Items),
+ Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+ CCTUInfo(Allocator) {}
+
+ void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *Results,
+ unsigned NumResults) override final {
+ StringRef Filter = S.getPreprocessor().getCodeCompletionFilter();
+ std::priority_queue<CompletionCandidate> Candidates;
+ for (unsigned I = 0; I < NumResults; ++I) {
+ auto &Result = Results[I];
+ if (!ClangdOpts.IncludeIneligibleResults &&
+ (Result.Availability == CXAvailability_NotAvailable ||
+ Result.Availability == CXAvailability_NotAccessible))
+ continue;
+ if (!Filter.empty() && !fuzzyMatch(S, Context, Filter, Result))
+ continue;
+ Candidates.emplace(Result);
+ if (ClangdOpts.Limit && Candidates.size() > ClangdOpts.Limit) {
+ Candidates.pop();
+ Items.isIncomplete = true;
+ }
+ }
+ while (!Candidates.empty()) {
+ auto &Candidate = Candidates.top();
+ const auto *CCS = Candidate.Result->CreateCodeCompletionString(
+ S, Context, *Allocator, CCTUInfo,
+ CodeCompleteOpts.IncludeBriefComments);
+ assert(CCS && "Expected the CodeCompletionString to be non-null");
+ Items.items.push_back(ProcessCodeCompleteResult(Candidate, *CCS));
+ Candidates.pop();
+ }
+ std::reverse(Items.items.begin(), Items.items.end());
+ }
+
+ GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ bool fuzzyMatch(Sema &S, const CodeCompletionContext &CCCtx, StringRef Filter,
+ CodeCompletionResult Result) {
+ switch (Result.Kind) {
+ case CodeCompletionResult::RK_Declaration:
+ if (auto *ID = Result.Declaration->getIdentifier())
+ return fuzzyMatch(Filter, ID->getName());
+ break;
+ case CodeCompletionResult::RK_Keyword:
+ return fuzzyMatch(Filter, Result.Keyword);
+ case CodeCompletionResult::RK_Macro:
+ return fuzzyMatch(Filter, Result.Macro->getName());
+ case CodeCompletionResult::RK_Pattern:
+ return fuzzyMatch(Filter, Result.Pattern->getTypedText());
+ }
+ auto *CCS = Result.CreateCodeCompletionString(
+ S, CCCtx, *Allocator, CCTUInfo, /*IncludeBriefComments=*/false);
+ return fuzzyMatch(Filter, CCS->getTypedText());
+ }
+
+ // Checks whether Target matches the Filter.
+ // Currently just requires a case-insensitive subsequence match.
+ // FIXME: make stricter and word-based: 'unique_ptr' should not match 'que'.
+ // FIXME: return a score to be incorporated into ranking.
+ static bool fuzzyMatch(StringRef Filter, StringRef Target) {
+ size_t TPos = 0;
+ for (char C : Filter) {
+ TPos = Target.find_lower(C, TPos);
+ if (TPos == StringRef::npos)
+ return false;
+ }
+ return true;
+ }
+
+ CompletionItem
+ ProcessCodeCompleteResult(const CompletionCandidate &Candidate,
+ const CodeCompletionString &CCS) const {
+
+ // Adjust this to InsertTextFormat::Snippet iff we encounter a
+ // CK_Placeholder chunk in SnippetCompletionItemsCollector.
+ CompletionItem Item;
+ Item.insertTextFormat = InsertTextFormat::PlainText;
+
+ Item.documentation = getDocumentation(CCS);
+ Item.sortText = Candidate.sortText();
+
+ // Fill in the label, detail, insertText and filterText fields of the
+ // CompletionItem.
+ ProcessChunks(CCS, Item);
+
+ // Fill in the kind field of the CompletionItem.
+ Item.kind = getKind(Candidate.Result->Kind, Candidate.Result->CursorKind);
+
+ return Item;
+ }
+
+ virtual void ProcessChunks(const CodeCompletionString &CCS,
+ CompletionItem &Item) const = 0;
+
+ CodeCompleteOptions ClangdOpts;
+ CompletionList &Items;
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+ CodeCompletionTUInfo CCTUInfo;
+
+}; // CompletionItemsCollector
+
+bool isInformativeQualifierChunk(CodeCompletionString::Chunk const &Chunk) {
+ return Chunk.Kind == CodeCompletionString::CK_Informative &&
+ StringRef(Chunk.Text).endswith("::");
+}
+
+class PlainTextCompletionItemsCollector final
+ : public CompletionItemsCollector {
+
+public:
+ PlainTextCompletionItemsCollector(
+ const CodeCompleteOptions &CodeCompleteOpts,
+ CompletionList &Items)
+ : CompletionItemsCollector(CodeCompleteOpts, Items) {}
+
+private:
+ void ProcessChunks(const CodeCompletionString &CCS,
+ CompletionItem &Item) const override {
+ for (const auto &Chunk : CCS) {
+ // Informative qualifier chunks only clutter completion results, skip
+ // them.
+ if (isInformativeQualifierChunk(Chunk))
+ continue;
+
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_TypedText:
+ // There's always exactly one CK_TypedText chunk.
+ Item.insertText = Item.filterText = Chunk.Text;
+ Item.label += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_ResultType:
+ assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
+ Item.detail = Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Optional:
+ break;
+ default:
+ Item.label += Chunk.Text;
+ break;
+ }
+ }
+ }
+}; // PlainTextCompletionItemsCollector
+
+class SnippetCompletionItemsCollector final : public CompletionItemsCollector {
+
+public:
+ SnippetCompletionItemsCollector(
+ const CodeCompleteOptions &CodeCompleteOpts,
+ CompletionList &Items)
+ : CompletionItemsCollector(CodeCompleteOpts, Items) {}
+
+private:
+ void ProcessChunks(const CodeCompletionString &CCS,
+ CompletionItem &Item) const override {
+ unsigned ArgCount = 0;
+ for (const auto &Chunk : CCS) {
+ // Informative qualifier chunks only clutter completion results, skip
+ // them.
+ if (isInformativeQualifierChunk(Chunk))
+ continue;
+
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_TypedText:
+ // The piece of text that the user is expected to type to match
+ // the code-completion string, typically a keyword or the name of
+ // a declarator or macro.
+ Item.filterText = Chunk.Text;
+ LLVM_FALLTHROUGH;
+ case CodeCompletionString::CK_Text:
+ // A piece of text that should be placed in the buffer,
+ // e.g., parentheses or a comma in a function call.
+ Item.label += Chunk.Text;
+ Item.insertText += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Optional:
+ // A code completion string that is entirely optional.
+ // For example, an optional code completion string that
+ // describes the default arguments in a function call.
+
+ // FIXME: Maybe add an option to allow presenting the optional chunks?
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ ++ArgCount;
+ Item.insertText += "${" + std::to_string(ArgCount) + ':' +
+ escapeSnippet(Chunk.Text) + '}';
+ Item.label += Chunk.Text;
+ Item.insertTextFormat = InsertTextFormat::Snippet;
+ break;
+ case CodeCompletionString::CK_Informative:
+ // A piece of text that describes something about the result
+ // but should not be inserted into the buffer.
+ // For example, the word "const" for a const method, or the name of
+ // the base class for methods that are part of the base class.
+ Item.label += Chunk.Text;
+ // Don't put the informative chunks in the insertText.
+ break;
+ case CodeCompletionString::CK_ResultType:
+ // A piece of text that describes the type of an entity or,
+ // for functions and methods, the return type.
+ assert(Item.detail.empty() && "Unexpected extraneous CK_ResultType");
+ Item.detail = Chunk.Text;
+ break;
+ case CodeCompletionString::CK_CurrentParameter:
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ //
+ // This should never be present while collecting completion items,
+ // only while collecting overload candidates.
+ llvm_unreachable("Unexpected CK_CurrentParameter while collecting "
+ "CompletionItems");
+ break;
+ case CodeCompletionString::CK_LeftParen:
+ // A left parenthesis ('(').
+ case CodeCompletionString::CK_RightParen:
+ // A right parenthesis (')').
+ case CodeCompletionString::CK_LeftBracket:
+ // A left bracket ('[').
+ case CodeCompletionString::CK_RightBracket:
+ // A right bracket (']').
+ case CodeCompletionString::CK_LeftBrace:
+ // A left brace ('{').
+ case CodeCompletionString::CK_RightBrace:
+ // A right brace ('}').
+ case CodeCompletionString::CK_LeftAngle:
+ // A left angle bracket ('<').
+ case CodeCompletionString::CK_RightAngle:
+ // A right angle bracket ('>').
+ case CodeCompletionString::CK_Comma:
+ // A comma separator (',').
+ case CodeCompletionString::CK_Colon:
+ // A colon (':').
+ case CodeCompletionString::CK_SemiColon:
+ // A semicolon (';').
+ case CodeCompletionString::CK_Equal:
+ // An '=' sign.
+ case CodeCompletionString::CK_HorizontalSpace:
+ // Horizontal whitespace (' ').
+ Item.insertText += Chunk.Text;
+ Item.label += Chunk.Text;
+ break;
+ case CodeCompletionString::CK_VerticalSpace:
+ // Vertical whitespace ('\n' or '\r\n', depending on the
+ // platform).
+ Item.insertText += Chunk.Text;
+ // Don't even add a space to the label.
+ break;
+ }
+ }
+ }
+}; // SnippetCompletionItemsCollector
+
+class SignatureHelpCollector final : public CodeCompleteConsumer {
+
+public:
+ SignatureHelpCollector(const clang::CodeCompleteOptions &CodeCompleteOpts,
+ SignatureHelp &SigHelp)
+ : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
+ SigHelp(SigHelp),
+ Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
+ CCTUInfo(Allocator) {}
+
+ void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
+ OverloadCandidate *Candidates,
+ unsigned NumCandidates) override {
+ SigHelp.signatures.reserve(NumCandidates);
+ // FIXME(rwols): How can we determine the "active overload candidate"?
+ // Right now the overloaded candidates seem to be provided in a "best fit"
+ // order, so I'm not too worried about this.
+ SigHelp.activeSignature = 0;
+ assert(CurrentArg <= (unsigned)std::numeric_limits<int>::max() &&
+ "too many arguments");
+ SigHelp.activeParameter = static_cast<int>(CurrentArg);
+ for (unsigned I = 0; I < NumCandidates; ++I) {
+ const auto &Candidate = Candidates[I];
+ const auto *CCS = Candidate.CreateSignatureString(
+ CurrentArg, S, *Allocator, CCTUInfo, true);
+ assert(CCS && "Expected the CodeCompletionString to be non-null");
+ SigHelp.signatures.push_back(ProcessOverloadCandidate(Candidate, *CCS));
+ }
+ }
+
+ GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ SignatureInformation
+ ProcessOverloadCandidate(const OverloadCandidate &Candidate,
+ const CodeCompletionString &CCS) const {
+ SignatureInformation Result;
+ const char *ReturnType = nullptr;
+
+ Result.documentation = getDocumentation(CCS);
+
+ for (const auto &Chunk : CCS) {
+ switch (Chunk.Kind) {
+ case CodeCompletionString::CK_ResultType:
+ // A piece of text that describes the type of an entity or,
+ // for functions and methods, the return type.
+ assert(!ReturnType && "Unexpected CK_ResultType");
+ ReturnType = Chunk.Text;
+ break;
+ case CodeCompletionString::CK_Placeholder:
+ // A string that acts as a placeholder for, e.g., a function call
+ // argument.
+ // Intentional fallthrough here.
+ case CodeCompletionString::CK_CurrentParameter: {
+ // A piece of text that describes the parameter that corresponds to
+ // the code-completion location within a function call, message send,
+ // macro invocation, etc.
+ Result.label += Chunk.Text;
+ ParameterInformation Info;
+ Info.label = Chunk.Text;
+ Result.parameters.push_back(std::move(Info));
+ break;
+ }
+ case CodeCompletionString::CK_Optional: {
+ // The rest of the parameters are defaulted/optional.
+ assert(Chunk.Optional &&
+ "Expected the optional code completion string to be non-null.");
+ Result.label +=
+ getOptionalParameters(*Chunk.Optional, Result.parameters);
+ break;
+ }
+ case CodeCompletionString::CK_VerticalSpace:
+ break;
+ default:
+ Result.label += Chunk.Text;
+ break;
+ }
+ }
+ if (ReturnType) {
+ Result.label += " -> ";
+ Result.label += ReturnType;
+ }
+ return Result;
+ }
+
+ SignatureHelp &SigHelp;
+ std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
+ CodeCompletionTUInfo CCTUInfo;
+
+}; // SignatureHelpCollector
+
+bool invokeCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
+ const clang::CodeCompleteOptions &Options,
+ PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ Logger &Logger) {
+ std::vector<const char *> ArgStrs;
+ for (const auto &S : Command.CommandLine)
+ ArgStrs.push_back(S.c_str());
+
+ VFS->setCurrentWorkingDirectory(Command.Directory);
+
+ IgnoreDiagnostics DummyDiagsConsumer;
+ auto CI = createInvocationFromCommandLine(
+ ArgStrs,
+ CompilerInstance::createDiagnostics(new DiagnosticOptions,
+ &DummyDiagsConsumer, false),
+ VFS);
+ assert(CI && "Couldn't create CompilerInvocation");
+
+ std::unique_ptr<llvm::MemoryBuffer> ContentsBuffer =
+ llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName);
+
+ // Attempt to reuse the PCH from precompiled preamble, if it was built.
+ if (Preamble) {
+ auto Bounds =
+ ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0);
+ if (!Preamble->CanReuse(*CI, ContentsBuffer.get(), Bounds, VFS.get()))
+ Preamble = nullptr;
+ }
+
+ auto Clang = prepareCompilerInstance(
+ std::move(CI), Preamble, std::move(ContentsBuffer), std::move(PCHs),
+ std::move(VFS), DummyDiagsConsumer);
+ auto &DiagOpts = Clang->getDiagnosticOpts();
+ DiagOpts.IgnoreWarnings = true;
+
+ auto &FrontendOpts = Clang->getFrontendOpts();
+ FrontendOpts.SkipFunctionBodies = true;
+ FrontendOpts.CodeCompleteOpts = Options;
+ FrontendOpts.CodeCompletionAt.FileName = FileName;
+ FrontendOpts.CodeCompletionAt.Line = Pos.line + 1;
+ FrontendOpts.CodeCompletionAt.Column = Pos.character + 1;
+
+ Clang->setCodeCompletionConsumer(Consumer.release());
+
+ SyntaxOnlyAction Action;
+ if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
+ Logger.log("BeginSourceFile() failed when running codeComplete for " +
+ FileName);
+ return false;
+ }
+ if (!Action.Execute()) {
+ Logger.log("Execute() failed when running codeComplete for " + FileName);
+ return false;
+ }
+
+ Action.EndSourceFile();
+
+ return true;
+}
+
+} // namespace
+
+clang::CodeCompleteOptions CodeCompleteOptions::getClangCompleteOpts() const {
+ clang::CodeCompleteOptions Result;
+ Result.IncludeCodePatterns = EnableSnippets && IncludeCodePatterns;
+ Result.IncludeMacros = IncludeMacros;
+ Result.IncludeGlobals = IncludeGlobals;
+ Result.IncludeBriefComments = IncludeBriefComments;
+
+ return Result;
+}
+
+CompletionList codeComplete(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ CodeCompleteOptions Opts, Logger &Logger) {
+ CompletionList Results;
+ std::unique_ptr<CodeCompleteConsumer> Consumer;
+ if (Opts.EnableSnippets) {
+ Consumer =
+ llvm::make_unique<SnippetCompletionItemsCollector>(Opts, Results);
+ } else {
+ Consumer =
+ llvm::make_unique<PlainTextCompletionItemsCollector>(Opts, Results);
+ }
+ invokeCodeComplete(std::move(Consumer), Opts.getClangCompleteOpts(), FileName,
+ Command, Preamble, Contents, Pos, std::move(VFS),
+ std::move(PCHs), Logger);
+ return Results;
+}
+
+SignatureHelp
+signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs, Logger &Logger) {
+ SignatureHelp Result;
+ clang::CodeCompleteOptions Options;
+ Options.IncludeGlobals = false;
+ Options.IncludeMacros = false;
+ Options.IncludeCodePatterns = false;
+ Options.IncludeBriefComments = true;
+ invokeCodeComplete(llvm::make_unique<SignatureHelpCollector>(Options, Result),
+ Options, FileName, Command, Preamble, Contents, Pos,
+ std::move(VFS), std::move(PCHs), Logger);
+ return Result;
+}
+
+} // namespace clangd
+} // namespace clang
Added: clang-tools-extra/trunk/clangd/CodeComplete.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/CodeComplete.h?rev=319655&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/CodeComplete.h (added)
+++ clang-tools-extra/trunk/clangd/CodeComplete.h Mon Dec 4 05:49:59 2017
@@ -0,0 +1,82 @@
+//===--- CodeComplete.h -----------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Code completion provides suggestions for what the user might type next.
+// After "std::string S; S." we might suggest members of std::string.
+// Signature help describes the parameters of a function as you type them.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CODECOMPLETE_H
+
+#include "Logger.h"
+#include "Path.h"
+#include "Protocol.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
+#include "clang/Sema/CodeCompleteOptions.h"
+#include "clang/Tooling/CompilationDatabase.h"
+
+namespace clang {
+class PCHContainerOperations;
+namespace clangd {
+
+struct CodeCompleteOptions {
+ /// Returns options that can be passed to clang's completion engine.
+ clang::CodeCompleteOptions getClangCompleteOpts() const;
+
+ /// When true, completion items will contain expandable code snippets in
+ /// completion (e.g. `return ${1:expression}` or `foo(${1:int a}, ${2:int
+ /// b})).
+ bool EnableSnippets = false;
+
+ /// Add code patterns to completion results.
+ /// If EnableSnippets is false, this options is ignored and code patterns will
+ /// always be omitted.
+ bool IncludeCodePatterns = true;
+
+ /// Add macros to code completion results.
+ bool IncludeMacros = true;
+
+ /// Add globals to code completion results.
+ bool IncludeGlobals = true;
+
+ /// Add brief comments to completion items, if available.
+ /// FIXME(ibiryukov): it looks like turning this option on significantly slows
+ /// down completion, investigate if it can be made faster.
+ bool IncludeBriefComments = true;
+
+ /// Include results that are not legal completions in the current context.
+ /// For example, private members are usually inaccessible.
+ bool IncludeIneligibleResults = false;
+
+ /// Limit the number of results returned (0 means no limit).
+ /// If more results are available, we set CompletionList.isIncomplete.
+ size_t Limit = 0;
+};
+
+/// Get code completions at a specified \p Pos in \p FileName.
+CompletionList codeComplete(PathRef FileName,
+ const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble,
+ StringRef Contents, Position Pos,
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs,
+ CodeCompleteOptions Opts, Logger &Logger);
+
+/// Get signature help at a specified \p Pos in \p FileName.
+SignatureHelp
+signatureHelp(PathRef FileName, const tooling::CompileCommand &Command,
+ PrecompiledPreamble const *Preamble, StringRef Contents,
+ Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
+ std::shared_ptr<PCHContainerOperations> PCHs, Logger &Logger);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
Added: clang-tools-extra/trunk/clangd/Compiler.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Compiler.cpp?rev=319655&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/Compiler.cpp (added)
+++ clang-tools-extra/trunk/clangd/Compiler.cpp Mon Dec 4 05:49:59 2017
@@ -0,0 +1,65 @@
+//===--- Compiler.cpp -------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+#include "Compiler.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+namespace clang {
+namespace clangd {
+
+/// Creates a CompilerInstance from \p CI, with main buffer overriden to \p
+/// Buffer and arguments to read the PCH from \p Preamble, if \p Preamble is not
+/// null. Note that vfs::FileSystem inside returned instance may differ from \p
+/// VFS if additional file remapping were set in command-line arguments.
+/// On some errors, returns null. When non-null value is returned, it's expected
+/// to be consumed by the FrontendAction as it will have a pointer to the \p
+/// Buffer that will only be deleted if BeginSourceFile is called.
+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) {
+ assert(VFS && "VFS is null");
+ assert(!CI->getPreprocessorOpts().RetainRemappedFileBuffers &&
+ "Setting RetainRemappedFileBuffers to true will cause a memory leak "
+ "of ContentsBuffer");
+
+ // NOTE: we use Buffer.get() when adding remapped files, so we have to make
+ // sure it will be released if no error is emitted.
+ if (Preamble) {
+ Preamble->AddImplicitPreamble(*CI, VFS, Buffer.get());
+ } else {
+ CI->getPreprocessorOpts().addRemappedFile(
+ CI->getFrontendOpts().Inputs[0].getFile(), Buffer.get());
+ }
+
+ auto Clang = llvm::make_unique<CompilerInstance>(PCHs);
+ Clang->setInvocation(std::move(CI));
+ Clang->createDiagnostics(&DiagsClient, false);
+
+ if (auto VFSWithRemapping = createVFSFromCompilerInvocation(
+ Clang->getInvocation(), Clang->getDiagnostics(), VFS))
+ VFS = VFSWithRemapping;
+ Clang->setVirtualFileSystem(VFS);
+
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return nullptr;
+
+ // RemappedFileBuffers will handle the lifetime of the Buffer pointer,
+ // release it.
+ Buffer.release();
+ return Clang;
+}
+
+} // namespace clangd
+} // namespace clang
Added: clang-tools-extra/trunk/clangd/Compiler.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Compiler.h?rev=319655&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/Compiler.h (added)
+++ clang-tools-extra/trunk/clangd/Compiler.h Mon Dec 4 05:49:59 2017
@@ -0,0 +1,46 @@
+//===--- Compiler.h ---------------------------------------------*- C++-*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Shared utilities for invoking the clang compiler.
+// ClangdUnit takes care of much of this, but some features like CodeComplete
+// run their own compile actions that share logic.
+//
+//===---------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_COMPILER_H
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/PrecompiledPreamble.h"
+
+namespace clang {
+namespace clangd {
+
+class IgnoreDiagnostics : public DiagnosticConsumer {
+public:
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const clang::Diagnostic &Info) override {}
+};
+
+/// Creates a CompilerInstance with the main file contens overridden.
+/// The preamble will be reused unless it is null.
+/// Note that the vfs::FileSystem inside returned instance may differ if
+/// additional file remappings occur in command-line arguments.
+/// On some errors, returns null. When non-null value is returned, it's expected
+/// to be consumed by the FrontendAction as it will have a pointer to the
+/// MainFile buffer that will only be deleted if BeginSourceFile is called.
+std::unique_ptr<CompilerInstance> prepareCompilerInstance(
+ std::unique_ptr<clang::CompilerInvocation>, const PrecompiledPreamble *,
+ std::unique_ptr<llvm::MemoryBuffer> MainFile,
+ std::shared_ptr<PCHContainerOperations>,
+ IntrusiveRefCntPtr<vfs::FileSystem>, DiagnosticConsumer &);
+
+} // namespace clangd
+} // namespace clang
+
+#endif
More information about the cfe-commits
mailing list