mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
Add PreambleStatCache
This commit is contained in:
parent
31314555bb
commit
2592dd41dd
@ -25,7 +25,99 @@ using namespace llvm;
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
namespace chrono = std::chrono;
|
namespace chrono = std::chrono;
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR < 8
|
||||||
|
namespace clang::vfs {
|
||||||
|
struct ProxyFileSystem : FileSystem {
|
||||||
|
explicit ProxyFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
|
||||||
|
: FS(std::move(FS)) {}
|
||||||
|
llvm::ErrorOr<Status> status(const Twine &Path) override {
|
||||||
|
return FS->status(Path);
|
||||||
|
}
|
||||||
|
llvm::ErrorOr<std::unique_ptr<File>>
|
||||||
|
openFileForRead(const Twine &Path) override {
|
||||||
|
return FS->openFileForRead(Path);
|
||||||
|
}
|
||||||
|
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
|
||||||
|
return FS->dir_begin(Dir, EC);
|
||||||
|
}
|
||||||
|
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
|
||||||
|
return FS->getCurrentWorkingDirectory();
|
||||||
|
}
|
||||||
|
std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
|
||||||
|
return FS->setCurrentWorkingDirectory(Path);
|
||||||
|
}
|
||||||
|
#if LLVM_VERSION_MAJOR == 7
|
||||||
|
std::error_code getRealPath(const Twine &Path,
|
||||||
|
SmallVectorImpl<char> &Output) const override {
|
||||||
|
return FS->getRealPath(Path, Output);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
FileSystem &getUnderlyingFS() { return *FS; }
|
||||||
|
IntrusiveRefCntPtr<FileSystem> FS;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
|
struct PreambleStatCache {
|
||||||
|
llvm::StringMap<ErrorOr<vfs::Status>> Cache;
|
||||||
|
|
||||||
|
void Update(Twine Path, ErrorOr<vfs::Status> S) {
|
||||||
|
Cache.try_emplace(Path.str(), std::move(S));
|
||||||
|
}
|
||||||
|
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem>
|
||||||
|
Producer(IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||||
|
struct VFS : vfs::ProxyFileSystem {
|
||||||
|
PreambleStatCache &Cache;
|
||||||
|
|
||||||
|
VFS(IntrusiveRefCntPtr<vfs::FileSystem> FS, PreambleStatCache &Cache)
|
||||||
|
: ProxyFileSystem(std::move(FS)), Cache(Cache) {}
|
||||||
|
llvm::ErrorOr<std::unique_ptr<vfs::File>>
|
||||||
|
openFileForRead(const Twine &Path) override {
|
||||||
|
auto File = getUnderlyingFS().openFileForRead(Path);
|
||||||
|
if (!File || !*File)
|
||||||
|
return File;
|
||||||
|
Cache.Update(Path, File->get()->status());
|
||||||
|
return File;
|
||||||
|
}
|
||||||
|
llvm::ErrorOr<vfs::Status> status(const Twine &Path) override {
|
||||||
|
auto S = getUnderlyingFS().status(Path);
|
||||||
|
Cache.Update(Path, S);
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new VFS(std::move(FS), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem>
|
||||||
|
Consumer(IntrusiveRefCntPtr<vfs::FileSystem> FS) {
|
||||||
|
struct VFS : vfs::ProxyFileSystem {
|
||||||
|
const PreambleStatCache &Cache;
|
||||||
|
VFS(IntrusiveRefCntPtr<vfs::FileSystem> FS,
|
||||||
|
const PreambleStatCache &Cache)
|
||||||
|
: ProxyFileSystem(std::move(FS)), Cache(Cache) {}
|
||||||
|
llvm::ErrorOr<vfs::Status> status(const Twine &Path) override {
|
||||||
|
auto I = Cache.Cache.find(Path.str());
|
||||||
|
if (I != Cache.Cache.end())
|
||||||
|
return I->getValue();
|
||||||
|
return getUnderlyingFS().status(Path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return new VFS(std::move(FS), *this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PreambleData {
|
||||||
|
PreambleData(clang::PrecompiledPreamble P, std::vector<Diag> diags,
|
||||||
|
std::unique_ptr<PreambleStatCache> stat_cache)
|
||||||
|
: Preamble(std::move(P)), diags(std::move(diags)),
|
||||||
|
stat_cache(std::move(stat_cache)) {}
|
||||||
|
clang::PrecompiledPreamble Preamble;
|
||||||
|
std::vector<Diag> diags;
|
||||||
|
std::unique_ptr<PreambleStatCache> stat_cache;
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::string StripFileType(const std::string &path) {
|
std::string StripFileType(const std::string &path) {
|
||||||
@ -160,31 +252,29 @@ public:
|
|||||||
|
|
||||||
std::unique_ptr<CompilerInstance> BuildCompilerInstance(
|
std::unique_ptr<CompilerInstance> BuildCompilerInstance(
|
||||||
CompletionSession &session, std::unique_ptr<CompilerInvocation> CI,
|
CompletionSession &session, std::unique_ptr<CompilerInvocation> CI,
|
||||||
DiagnosticConsumer &DC, const WorkingFiles::Snapshot &snapshot,
|
IntrusiveRefCntPtr<vfs::FileSystem> FS, DiagnosticConsumer &DC,
|
||||||
|
const PreambleData *preamble, const WorkingFiles::Snapshot &snapshot,
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Bufs) {
|
std::vector<std::unique_ptr<llvm::MemoryBuffer>> &Bufs) {
|
||||||
std::string main = ResolveIfRelative(
|
std::string main = ResolveIfRelative(
|
||||||
session.file.directory,
|
session.file.directory,
|
||||||
sys::path::convert_to_slash(CI->getFrontendOpts().Inputs[0].getFile()));
|
sys::path::convert_to_slash(CI->getFrontendOpts().Inputs[0].getFile()));
|
||||||
for (auto &file : snapshot.files) {
|
for (auto &file : snapshot.files) {
|
||||||
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content));
|
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(file.content));
|
||||||
if (file.filename == main)
|
if (preamble && file.filename == main) {
|
||||||
if (auto Preamble = session.GetPreamble()) {
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
Preamble->Preamble.OverridePreamble(*CI, session.FS,
|
preamble->Preamble.OverridePreamble(*CI, FS, Bufs.back().get());
|
||||||
Bufs.back().get());
|
|
||||||
#else
|
#else
|
||||||
Preamble->Preamble.AddImplicitPreamble(*CI, session.FS,
|
preamble->Preamble.AddImplicitPreamble(*CI, FS, Bufs.back().get());
|
||||||
Bufs.back().get());
|
|
||||||
#endif
|
#endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CI->getPreprocessorOpts().addRemappedFile(file.filename,
|
CI->getPreprocessorOpts().addRemappedFile(file.filename,
|
||||||
Bufs.back().get());
|
Bufs.back().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Clang = std::make_unique<CompilerInstance>(session.PCH);
|
auto Clang = std::make_unique<CompilerInstance>(session.PCH);
|
||||||
Clang->setInvocation(std::move(CI));
|
Clang->setInvocation(std::move(CI));
|
||||||
Clang->setVirtualFileSystem(session.FS);
|
Clang->setVirtualFileSystem(FS);
|
||||||
Clang->createDiagnostics(&DC, false);
|
Clang->createDiagnostics(&DC, false);
|
||||||
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
Clang->setTarget(TargetInfo::CreateTargetInfo(
|
||||||
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
|
||||||
@ -209,6 +299,37 @@ bool Parse(CompilerInstance &Clang) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BuildPreamble(CompletionSession &session, CompilerInvocation &CI,
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS,
|
||||||
|
const std::string &main,
|
||||||
|
std::unique_ptr<PreambleStatCache> stat_cache) {
|
||||||
|
std::shared_ptr<PreambleData> OldP = session.GetPreamble();
|
||||||
|
std::string content = session.wfiles->GetContent(main);
|
||||||
|
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
||||||
|
llvm::MemoryBuffer::getMemBuffer(content);
|
||||||
|
auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), Buf.get(), 0);
|
||||||
|
if (OldP && OldP->Preamble.CanReuse(CI, Buf.get(), Bounds, FS.get()))
|
||||||
|
return;
|
||||||
|
CI.getDiagnosticOpts().IgnoreWarnings = false;
|
||||||
|
CI.getFrontendOpts().SkipFunctionBodies = true;
|
||||||
|
CI.getLangOpts()->CommentOpts.ParseAllComments = true;
|
||||||
|
CI.getLangOpts()->RetainCommentsFromSystemHeaders = true;
|
||||||
|
#if LLVM_VERSION_MAJOR >= 7
|
||||||
|
CI.getPreprocessorOpts().WriteCommentListToPCH = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
StoreDiags DC(main);
|
||||||
|
IntrusiveRefCntPtr<DiagnosticsEngine> DE =
|
||||||
|
CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(), &DC, false);
|
||||||
|
PreambleCallbacks PP;
|
||||||
|
if (auto NewPreamble = PrecompiledPreamble::Build(
|
||||||
|
CI, Buf.get(), Bounds, *DE, FS, session.PCH, true, PP)) {
|
||||||
|
std::lock_guard lock(session.mutex);
|
||||||
|
session.preamble = std::make_shared<PreambleData>(
|
||||||
|
std::move(*NewPreamble), DC.Take(), std::move(stat_cache));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *CompletionPreloadMain(void *manager_) {
|
void *CompletionPreloadMain(void *manager_) {
|
||||||
auto *manager = static_cast<CompletionManager*>(manager_);
|
auto *manager = static_cast<CompletionManager*>(manager_);
|
||||||
set_thread_name("comp-preload");
|
set_thread_name("comp-preload");
|
||||||
@ -224,9 +345,11 @@ void *CompletionPreloadMain(void *manager_) {
|
|||||||
const auto &args = session->file.args;
|
const auto &args = session->file.args;
|
||||||
WorkingFiles::Snapshot snapshot =
|
WorkingFiles::Snapshot snapshot =
|
||||||
session->wfiles->AsSnapshot({StripFileType(session->file.filename)});
|
session->wfiles->AsSnapshot({StripFileType(session->file.filename)});
|
||||||
|
auto stat_cache = std::make_unique<PreambleStatCache>();
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS = stat_cache->Producer(session->FS);
|
||||||
if (std::unique_ptr<CompilerInvocation> CI =
|
if (std::unique_ptr<CompilerInvocation> CI =
|
||||||
BuildCompilerInvocation(args, session->FS))
|
BuildCompilerInvocation(args, FS))
|
||||||
session->BuildPreamble(*CI, request.path);
|
BuildPreamble(*session, *CI, FS, request.path, std::move(stat_cache));
|
||||||
|
|
||||||
int debounce =
|
int debounce =
|
||||||
is_open ? g_config->diagnostics.onOpen : g_config->diagnostics.onSave;
|
is_open ? g_config->diagnostics.onOpen : g_config->diagnostics.onSave;
|
||||||
@ -260,9 +383,11 @@ void *CompletionMain(void *manager_) {
|
|||||||
|
|
||||||
std::shared_ptr<CompletionSession> session =
|
std::shared_ptr<CompletionSession> session =
|
||||||
manager->TryGetSession(path, false);
|
manager->TryGetSession(path, false);
|
||||||
|
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS =
|
||||||
|
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
|
||||||
std::unique_ptr<CompilerInvocation> CI =
|
std::unique_ptr<CompilerInvocation> CI =
|
||||||
BuildCompilerInvocation(session->file.args, session->FS);
|
BuildCompilerInvocation(session->file.args, FS);
|
||||||
if (!CI)
|
if (!CI)
|
||||||
continue;
|
continue;
|
||||||
auto &FOpts = CI->getFrontendOpts();
|
auto &FOpts = CI->getFrontendOpts();
|
||||||
@ -277,7 +402,8 @@ void *CompletionMain(void *manager_) {
|
|||||||
WorkingFiles::Snapshot snapshot =
|
WorkingFiles::Snapshot snapshot =
|
||||||
manager->working_files_->AsSnapshot({StripFileType(path)});
|
manager->working_files_->AsSnapshot({StripFileType(path)});
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
||||||
auto Clang = BuildCompilerInstance(*session, std::move(CI), DC, snapshot, Bufs);
|
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
||||||
|
preamble.get(), snapshot, Bufs);
|
||||||
if (!Clang)
|
if (!Clang)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -337,9 +463,11 @@ void *DiagnosticMain(void *manager_) {
|
|||||||
|
|
||||||
std::shared_ptr<CompletionSession> session =
|
std::shared_ptr<CompletionSession> session =
|
||||||
manager->TryGetSession(path, false);
|
manager->TryGetSession(path, false);
|
||||||
|
std::shared_ptr<PreambleData> preamble = session->GetPreamble();
|
||||||
|
IntrusiveRefCntPtr<vfs::FileSystem> FS =
|
||||||
|
preamble ? preamble->stat_cache->Consumer(session->FS) : session->FS;
|
||||||
std::unique_ptr<CompilerInvocation> CI =
|
std::unique_ptr<CompilerInvocation> CI =
|
||||||
BuildCompilerInvocation(session->file.args, session->FS);
|
BuildCompilerInvocation(session->file.args, FS);
|
||||||
if (!CI)
|
if (!CI)
|
||||||
continue;
|
continue;
|
||||||
CI->getDiagnosticOpts().IgnoreWarnings = false;
|
CI->getDiagnosticOpts().IgnoreWarnings = false;
|
||||||
@ -348,7 +476,8 @@ void *DiagnosticMain(void *manager_) {
|
|||||||
WorkingFiles::Snapshot snapshot =
|
WorkingFiles::Snapshot snapshot =
|
||||||
manager->working_files_->AsSnapshot({StripFileType(path)});
|
manager->working_files_->AsSnapshot({StripFileType(path)});
|
||||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
|
||||||
auto Clang = BuildCompilerInstance(*session, std::move(CI), DC, snapshot, Bufs);
|
auto Clang = BuildCompilerInstance(*session, std::move(CI), FS, DC,
|
||||||
|
preamble.get(), snapshot, Bufs);
|
||||||
if (!Clang)
|
if (!Clang)
|
||||||
continue;
|
continue;
|
||||||
if (!Parse(*Clang))
|
if (!Parse(*Clang))
|
||||||
@ -428,35 +557,6 @@ std::shared_ptr<PreambleData> CompletionSession::GetPreamble() {
|
|||||||
return preamble;
|
return preamble;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionSession::BuildPreamble(CompilerInvocation &CI,
|
|
||||||
const std::string &main) {
|
|
||||||
std::shared_ptr<PreambleData> OldP = GetPreamble();
|
|
||||||
std::string content = wfiles->GetContent(main);
|
|
||||||
std::unique_ptr<llvm::MemoryBuffer> Buf =
|
|
||||||
llvm::MemoryBuffer::getMemBuffer(content);
|
|
||||||
auto Bounds = ComputePreambleBounds(*CI.getLangOpts(), Buf.get(), 0);
|
|
||||||
if (OldP && OldP->Preamble.CanReuse(CI, Buf.get(), Bounds, FS.get()))
|
|
||||||
return;
|
|
||||||
CI.getDiagnosticOpts().IgnoreWarnings = false;
|
|
||||||
CI.getFrontendOpts().SkipFunctionBodies = true;
|
|
||||||
CI.getLangOpts()->RetainCommentsFromSystemHeaders = true;
|
|
||||||
CI.getLangOpts()->CommentOpts.ParseAllComments = true;
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7
|
|
||||||
CI.getPreprocessorOpts().WriteCommentListToPCH = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
StoreDiags DC(main);
|
|
||||||
IntrusiveRefCntPtr<DiagnosticsEngine> DE =
|
|
||||||
CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(), &DC, false);
|
|
||||||
PreambleCallbacks PP;
|
|
||||||
if (auto NewPreamble = PrecompiledPreamble::Build(CI, Buf.get(), Bounds,
|
|
||||||
*DE, FS, PCH, true, PP)) {
|
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
|
||||||
preamble =
|
|
||||||
std::make_shared<PreambleData>(std::move(*NewPreamble), DC.Take());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ccls
|
} // namespace ccls
|
||||||
|
|
||||||
CompletionManager::CompletionManager(Project *project,
|
CompletionManager::CompletionManager(Project *project,
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
|
struct PreambleData;
|
||||||
|
|
||||||
struct DiagBase {
|
struct DiagBase {
|
||||||
Range range;
|
Range range;
|
||||||
std::string message;
|
std::string message;
|
||||||
@ -35,13 +37,6 @@ struct Diag : DiagBase {
|
|||||||
std::vector<lsTextEdit> edits;
|
std::vector<lsTextEdit> edits;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PreambleData {
|
|
||||||
PreambleData(clang::PrecompiledPreamble P, std::vector<Diag> diags)
|
|
||||||
: Preamble(std::move(P)), diags(std::move(diags)) {}
|
|
||||||
clang::PrecompiledPreamble Preamble;
|
|
||||||
std::vector<Diag> diags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CompletionSession
|
struct CompletionSession
|
||||||
: public std::enable_shared_from_this<CompletionSession> {
|
: public std::enable_shared_from_this<CompletionSession> {
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
@ -61,7 +56,6 @@ struct CompletionSession
|
|||||||
: file(file), wfiles(wfiles), PCH(PCH) {}
|
: file(file), wfiles(wfiles), PCH(PCH) {}
|
||||||
|
|
||||||
std::shared_ptr<PreambleData> GetPreamble();
|
std::shared_ptr<PreambleData> GetPreamble();
|
||||||
void BuildPreamble(clang::CompilerInvocation &CI, const std::string &main);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user