hanchenye-llvm-project/clang-tools-extra/clangd/ASTManager.h

163 lines
5.5 KiB
C++

//===--- 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