diff options
Diffstat (limited to 'clang-tools-extra/clangd/ASTManager.h')
-rw-r--r-- | clang-tools-extra/clangd/ASTManager.h | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/clang-tools-extra/clangd/ASTManager.h b/clang-tools-extra/clangd/ASTManager.h new file mode 100644 index 00000000000..e213822a845 --- /dev/null +++ b/clang-tools-extra/clangd/ASTManager.h @@ -0,0 +1,162 @@ +//===--- ASTManager.h - Clang AST manager -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_ASTMANAGER_H + +#include "DocumentStore.h" +#include "JSONRPCDispatcher.h" +#include "Protocol.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include <condition_variable> +#include <deque> +#include <thread> + +namespace clang { +class ASTUnit; +class DiagnosticsEngine; +class PCHContainerOperations; +namespace tooling { +class CompilationDatabase; +} // namespace tooling + +namespace clangd { + +/// Using 'unsigned' here to avoid undefined behaviour on overflow. +typedef unsigned DocVersion; + +/// Stores ASTUnit and FixIts map for an opened document. +class DocData { +public: + typedef std::map<clangd::Diagnostic, std::vector<clang::tooling::Replacement>> + DiagnosticToReplacementMap; + +public: + void setAST(std::unique_ptr<ASTUnit> AST); + ASTUnit *getAST() const; + + void cacheFixIts(DiagnosticToReplacementMap FixIts); + std::vector<clang::tooling::Replacement> + getFixIts(const clangd::Diagnostic &D) const; + +private: + std::unique_ptr<ASTUnit> AST; + DiagnosticToReplacementMap FixIts; +}; + +enum class ASTManagerRequestType { ParseAndPublishDiagnostics, RemoveDocData }; + +/// A request to the worker thread +class ASTManagerRequest { +public: + ASTManagerRequest() = default; + ASTManagerRequest(ASTManagerRequestType Type, std::string File, + DocVersion Version); + + ASTManagerRequestType Type; + std::string File; + DocVersion Version; +}; + +class ASTManager : public DocumentStoreListener { +public: + ASTManager(JSONOutput &Output, DocumentStore &Store, bool RunSynchronously); + ~ASTManager() override; + + void onDocumentAdd(StringRef File) override; + void onDocumentRemove(StringRef File) override; + + /// Get code completions at a specified \p Line and \p Column in \p File. + /// + /// This function is thread-safe and returns completion items that own the + /// data they contain. + std::vector<CompletionItem> codeComplete(StringRef File, unsigned Line, + unsigned Column); + + /// Get the fixes associated with a certain diagnostic in a specified file as + /// replacements. + /// + /// This function is thread-safe. It returns a copy to avoid handing out + /// references to unguarded data. + std::vector<clang::tooling::Replacement> + getFixIts(StringRef File, const clangd::Diagnostic &D); + + DocumentStore &getStore() const { return Store; } + +private: + JSONOutput &Output; + DocumentStore &Store; + + // Set to true if requests should block instead of being processed + // asynchronously. + bool RunSynchronously; + + /// Loads a compilation database for File. May return nullptr if it fails. The + /// database is cached for subsequent accesses. + clang::tooling::CompilationDatabase * + getOrCreateCompilationDatabaseForFile(StringRef File); + // Creates a new ASTUnit for the document at File. + // FIXME: This calls chdir internally, which is thread unsafe. + std::unique_ptr<clang::ASTUnit> + createASTUnitForFile(StringRef File, const DocumentStore &Docs); + + /// If RunSynchronously is false, queues the request to be run on the worker + /// thread. + /// If RunSynchronously is true, runs the request handler immediately on the + /// main thread. + void queueOrRun(ASTManagerRequestType RequestType, StringRef File); + + void runWorker(); + void handleRequest(ASTManagerRequestType RequestType, StringRef File); + + /// Parses files and publishes diagnostics. + /// This function is called on the worker thread in asynchronous mode and + /// on the main thread in synchronous mode. + void parseFileAndPublishDiagnostics(StringRef File); + + /// Caches compilation databases loaded from directories(keys are directories). + llvm::StringMap<std::unique_ptr<clang::tooling::CompilationDatabase>> + CompilationDatabases; + + /// Clang objects. + /// A map from filenames to DocData structures that store ASTUnit and Fixits for + /// the files. The ASTUnits are used for generating diagnostics and fix-it-s + /// asynchronously by the worker thread and synchronously for code completion. + llvm::StringMap<DocData> DocDatas; + std::shared_ptr<clang::PCHContainerOperations> PCHs; + /// A lock for access to the DocDatas, CompilationDatabases and PCHs. + std::mutex ClangObjectLock; + + /// Stores latest versions of the tracked documents to discard outdated requests. + /// Guarded by RequestLock. + /// TODO(ibiryukov): the entries are neved deleted from this map. + llvm::StringMap<DocVersion> DocVersions; + + /// A LIFO queue of requests. Note that requests are discarded if the `version` + /// field is not equal to the one stored inside DocVersions. + /// TODO(krasimir): code completion should always have priority over parsing + /// for diagnostics. + std::deque<ASTManagerRequest> RequestQueue; + /// Setting Done to true will make the worker thread terminate. + bool Done = false; + /// Condition variable to wake up the worker thread. + std::condition_variable ClangRequestCV; + /// Lock for accesses to RequestQueue, DocVersions and Done. + std::mutex RequestLock; + + /// We run parsing on a separate thread. This thread looks into RequestQueue to + /// find requests to handle and terminates when Done is set to true. + std::thread ClangWorker; +}; + +} // namespace clangd +} // namespace clang + +#endif |