Reuse preamble (built by "comp-preload") in indexer

This commit is contained in:
Fangrui Song 2018-09-08 12:07:43 -07:00
parent b8c0b5ad9e
commit 0ae7d9d0a4
19 changed files with 121 additions and 102 deletions

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "clang_utils.h"
#include "filesystem.hh"
@ -513,7 +513,7 @@ bool Parse(CompilerInstance &Clang) {
return true;
}
void CompletionPreloadMain(ClangCompleteManager *completion_manager) {
void CompletionPreloadMain(CompletionManager *completion_manager) {
while (true) {
// Fetching the completion request blocks until we have a request.
auto request = completion_manager->preload_requests_.Dequeue();
@ -538,10 +538,10 @@ void CompletionPreloadMain(ClangCompleteManager *completion_manager) {
}
}
void CompletionMain(ClangCompleteManager *completion_manager) {
void CompletionMain(CompletionManager *completion_manager) {
while (true) {
// Fetching the completion request blocks until we have a request.
std::unique_ptr<ClangCompleteManager::CompletionRequest> request =
std::unique_ptr<CompletionManager::CompletionRequest> request =
completion_manager->completion_request_.Dequeue();
// Drop older requests if we're not buffering.
@ -594,10 +594,10 @@ void CompletionMain(ClangCompleteManager *completion_manager) {
}
}
void DiagnosticMain(ClangCompleteManager *manager) {
void DiagnosticMain(CompletionManager *manager) {
while (true) {
// Fetching the completion request blocks until we have a request.
ClangCompleteManager::DiagnosticRequest request =
CompletionManager::DiagnosticRequest request =
manager->diagnostic_request_.Dequeue();
std::string path = request.document.uri.GetPath();
@ -688,10 +688,10 @@ void CompletionSession::BuildPreamble(CompilerInvocation &CI) {
} // namespace ccls
ClangCompleteManager::ClangCompleteManager(Project *project,
WorkingFiles *working_files,
OnDiagnostic on_diagnostic,
OnDropped on_dropped)
CompletionManager::CompletionManager(Project *project,
WorkingFiles *working_files,
OnDiagnostic on_diagnostic,
OnDropped on_dropped)
: project_(project), working_files_(working_files),
on_diagnostic_(on_diagnostic), on_dropped_(on_dropped),
preloaded_sessions_(kMaxPreloadedSessions),
@ -714,7 +714,7 @@ ClangCompleteManager::ClangCompleteManager(Project *project,
.detach();
}
void ClangCompleteManager::CodeComplete(
void CompletionManager::CodeComplete(
const lsRequestId &id,
const lsTextDocumentPositionParams &completion_location,
const OnComplete &on_complete) {
@ -723,7 +723,7 @@ void ClangCompleteManager::CodeComplete(
on_complete));
}
void ClangCompleteManager::DiagnosticsUpdate(
void CompletionManager::DiagnosticsUpdate(
const lsTextDocumentIdentifier &document) {
bool has = false;
diagnostic_request_.Iterate([&](const DiagnosticRequest &request) {
@ -735,29 +735,13 @@ void ClangCompleteManager::DiagnosticsUpdate(
true /*priority*/);
}
void ClangCompleteManager::NotifyView(const std::string &filename) {
//
// On view, we reparse only if the file has not been parsed. The existence of
// a CompletionSession instance implies the file is already parsed or will be
// parsed soon.
//
void CompletionManager::NotifyView(const std::string &path) {
// Only reparse the file if we create a new CompletionSession.
if (EnsureCompletionOrCreatePreloadSession(filename))
preload_requests_.PushBack(PreloadRequest(filename), true);
if (EnsureCompletionOrCreatePreloadSession(path))
preload_requests_.PushBack(PreloadRequest(path), true);
}
void ClangCompleteManager::NotifyEdit(const std::string &filename) {
//
// We treat an edit like a view, because the completion logic will handle
// moving the CompletionSession instance from preloaded to completion
// storage.
//
NotifyView(filename);
}
void ClangCompleteManager::NotifySave(const std::string &filename) {
void CompletionManager::NotifySave(const std::string &filename) {
//
// On save, always reparse.
//
@ -766,7 +750,7 @@ void ClangCompleteManager::NotifySave(const std::string &filename) {
preload_requests_.PushBack(PreloadRequest(filename), true);
}
void ClangCompleteManager::NotifyClose(const std::string &filename) {
void CompletionManager::NotifyClose(const std::string &filename) {
//
// On close, we clear any existing CompletionSession instance.
//
@ -786,63 +770,63 @@ void ClangCompleteManager::NotifyClose(const std::string &filename) {
assert((preloaded_ptr && completion_ptr) == false);
}
bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
const std::string &filename) {
bool CompletionManager::EnsureCompletionOrCreatePreloadSession(
const std::string &path) {
std::lock_guard<std::mutex> lock(sessions_lock_);
// Check for an existing CompletionSession.
if (preloaded_sessions_.TryGet(filename) ||
completion_sessions_.TryGet(filename)) {
if (preloaded_sessions_.TryGet(path) ||
completion_sessions_.TryGet(path)) {
return false;
}
// No CompletionSession, create new one.
auto session = std::make_shared<ccls::CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_, PCH);
project_->FindCompilationEntryForFile(path), working_files_, PCH);
preloaded_sessions_.Insert(session->file.filename, session);
return true;
}
std::shared_ptr<ccls::CompletionSession>
ClangCompleteManager::TryGetSession(const std::string &filename,
bool mark_as_completion,
bool create_if_needed) {
CompletionManager::TryGetSession(const std::string &path,
bool mark_as_completion,
bool create_if_needed) {
std::lock_guard<std::mutex> lock(sessions_lock_);
// Try to find a preloaded session.
std::shared_ptr<ccls::CompletionSession> preloaded =
preloaded_sessions_.TryGet(filename);
preloaded_sessions_.TryGet(path);
if (preloaded) {
// If this request is for a completion, we should move it to
// |completion_sessions|.
if (mark_as_completion) {
preloaded_sessions_.TryTake(filename);
completion_sessions_.Insert(filename, preloaded);
preloaded_sessions_.TryTake(path);
completion_sessions_.Insert(path, preloaded);
}
return preloaded;
}
// Try to find a completion session. If none create one.
std::shared_ptr<ccls::CompletionSession> session =
completion_sessions_.TryGet(filename);
completion_sessions_.TryGet(path);
if (!session && create_if_needed) {
session = std::make_shared<ccls::CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_, PCH);
completion_sessions_.Insert(filename, session);
project_->FindCompilationEntryForFile(path), working_files_, PCH);
completion_sessions_.Insert(path, session);
}
return session;
}
void ClangCompleteManager::FlushSession(const std::string &filename) {
void CompletionManager::FlushSession(const std::string &path) {
std::lock_guard<std::mutex> lock(sessions_lock_);
preloaded_sessions_.TryTake(filename);
completion_sessions_.TryTake(filename);
preloaded_sessions_.TryTake(path);
completion_sessions_.TryTake(path);
}
void ClangCompleteManager::FlushAllSessions() {
void CompletionManager::FlushAllSessions() {
LOG_S(INFO) << "flush all clang complete sessions";
std::lock_guard<std::mutex> lock(sessions_lock_);

View File

@ -64,7 +64,7 @@ struct CompletionSession
};
}
struct ClangCompleteManager {
struct CompletionManager {
using OnDiagnostic = std::function<void(
std::string path, std::vector<lsDiagnostic> diagnostics)>;
using OnComplete = std::function<void(
@ -94,8 +94,8 @@ struct ClangCompleteManager {
lsTextDocumentIdentifier document;
};
ClangCompleteManager(Project *project, WorkingFiles *working_files,
OnDiagnostic on_diagnostic, OnDropped on_dropped);
CompletionManager(Project *project, WorkingFiles *working_files,
OnDiagnostic on_diagnostic, OnDropped on_dropped);
// Start a code completion at the given location. |on_complete| will run when
// completion results are available. |on_complete| may run on any thread.
@ -107,27 +107,25 @@ struct ClangCompleteManager {
// Notify the completion manager that |filename| has been viewed and we
// should begin preloading completion data.
void NotifyView(const std::string &filename);
// Notify the completion manager that |filename| has been edited.
void NotifyEdit(const std::string &filename);
void NotifyView(const std::string &path);
// Notify the completion manager that |filename| has been saved. This
// triggers a reparse.
void NotifySave(const std::string &filename);
void NotifySave(const std::string &path);
// Notify the completion manager that |filename| has been closed. Any existing
// completion session will be dropped.
void NotifyClose(const std::string &filename);
void NotifyClose(const std::string &path);
// Ensures there is a completion or preloaded session. Returns true if a new
// session was created.
bool EnsureCompletionOrCreatePreloadSession(const std::string &filename);
bool EnsureCompletionOrCreatePreloadSession(const std::string &path);
// Tries to find an edit session for |filename|. This will move the session
// from view to edit.
std::shared_ptr<ccls::CompletionSession>
TryGetSession(const std::string &filename, bool mark_as_completion,
TryGetSession(const std::string &path, bool mark_as_completion,
bool create_if_needed);
// Flushes all saved sessions with the supplied filename
void FlushSession(const std::string &filename);
void FlushSession(const std::string &path);
// Flushes all saved sessions
void FlushAllSessions(void);

View File

@ -142,6 +142,8 @@ struct Config {
// If true, diagnostics will be reported for textDocument/didOpen.
bool onOpen = true;
bool spellChecking = true;
std::vector<std::string> whitelist;
} diagnostics;
@ -226,7 +228,7 @@ MAKE_REFLECT_STRUCT(Config::Completion, caseSensitivity, dropOldRequests,
includeMaxPathSize, includeSuffixWhitelist,
includeWhitelist);
MAKE_REFLECT_STRUCT(Config::Diagnostics, blacklist, frequencyMs, onChange,
onOpen, whitelist)
onOpen, spellChecking, whitelist)
MAKE_REFLECT_STRUCT(Config::Highlight, lsRanges, blacklist, whitelist)
MAKE_REFLECT_STRUCT(Config::Index, blacklist, comments, enabled, multiVersion,
multiVersionBlacklist, multiVersionWhitelist, onChange,

View File

@ -3,12 +3,13 @@
#include "indexer.h"
#include "clang_complete.hh"
#include "clang_tu.h"
#include "log.hh"
#include "match.h"
#include "platform.h"
#include "serializer.h"
using ccls::Intern;
using namespace ccls;
#include <clang/AST/AST.h>
#include <clang/Frontend/FrontendAction.h>
@ -1180,7 +1181,8 @@ void Init() {
}
std::vector<std::unique_ptr<IndexFile>>
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
Index(CompletionManager *completion, WorkingFiles *wfiles, VFS *vfs,
const std::string &opt_wdir, const std::string &file,
const std::vector<std::string> &args,
const std::vector<std::pair<std::string, std::string>> &remapped) {
if (!g_config->index.enabled)
@ -1196,13 +1198,32 @@ Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
CI->getLangOpts()->CommentOpts.ParseAllComments =
g_config->index.comments > 1;
CI->getLangOpts()->RetainCommentsFromSystemHeaders = true;
std::string buf = wfiles->GetContent(file);
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Bufs;
for (auto &[filename, content] : remapped) {
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(content));
CI->getPreprocessorOpts().addRemappedFile(
filename == file ? CI->getFrontendOpts().Inputs[0].getFile()
: StringRef(filename),
Bufs.back().get());
if (buf.size()) {
// If there is a completion session, reuse its preamble if exists.
bool done_remap = false;
std::shared_ptr<CompletionSession> session =
completion->TryGetSession(file, false, false);
if (session)
if (auto preamble = session->GetPreamble()) {
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(buf));
auto Bounds = ComputePreambleBounds(*CI->getLangOpts(), Bufs.back().get(), 0);
if (preamble->Preamble.CanReuse(*CI, Bufs.back().get(), Bounds,
FS.get())) {
preamble->Preamble.AddImplicitPreamble(*CI, FS, Bufs.back().get());
done_remap = true;
}
}
for (auto &[filename, content] : remapped) {
if (filename == file && done_remap)
continue;
Bufs.push_back(llvm::MemoryBuffer::getMemBuffer(content));
CI->getPreprocessorOpts().addRemappedFile(
filename == file ? CI->getFrontendOpts().Inputs[0].getFile()
: StringRef(filename),
Bufs.back().get());
}
}
DiagnosticConsumer DC;

View File

@ -272,10 +272,14 @@ struct IndexFile {
std::string ToString();
};
struct CompletionManager;
struct WorkingFiles;
namespace ccls::idx {
void Init();
std::vector<std::unique_ptr<IndexFile>>
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
Index(CompletionManager *complete, WorkingFiles *wfiles, VFS *vfs,
const std::string &opt_wdir, const std::string &file,
const std::vector<std::string> &args,
const std::vector<std::pair<std::string, std::string>>& remapped);
} // namespace ccls::idx
const std::vector<std::pair<std::string, std::string>> &remapped);
}

View File

@ -14,7 +14,7 @@
#include <unordered_map>
#include <vector>
struct ClangCompleteManager;
struct CompletionManager;
struct CodeCompleteCache;
struct Config;
class DiagnosticsPublisher;
@ -107,7 +107,7 @@ struct MessageHandler {
ImportManager *import_manager = nullptr;
SemanticHighlightSymbolCache *semantic_cache = nullptr;
WorkingFiles *working_files = nullptr;
ClangCompleteManager *clang_complete = nullptr;
CompletionManager *clang_complete = nullptr;
IncludeComplete *include_complete = nullptr;
CodeCompleteCache *global_code_complete_cache = nullptr;
CodeCompleteCache *non_global_code_complete_cache = nullptr;

View File

@ -1,6 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.hh"
#include "filesystem.hh"
#include "include_complete.h"
#include "log.hh"
@ -483,7 +484,8 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
g_thread_id = i + 1;
std::string name = "indexer" + std::to_string(i);
set_thread_name(name.c_str());
pipeline::Indexer_Main(diag_pub, vfs, project, working_files);
pipeline::Indexer_Main(clang_complete, diag_pub, vfs, project,
working_files);
})
.detach();
}

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "lsp_code_action.h"
#include "message_handler.h"
#include "pipeline.hh"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "fuzzy_match.h"
#include "include_complete.h"
#include "message_handler.h"
@ -368,7 +368,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
pipeline::WriteStdout(kMethodType, out);
} else {
ClangCompleteManager::OnComplete callback = std::bind(
CompletionManager::OnComplete callback = std::bind(
[this, request, params, is_global_completion, existing_completion,
has_open_paren](const std::vector<lsCompletionItem> &results,
bool is_cached_result) {
@ -408,7 +408,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
!global_code_complete_cache->cached_results_.empty();
});
if (is_cache_match) {
ClangCompleteManager::OnComplete freshen_global =
CompletionManager::OnComplete freshen_global =
[this](std::vector<lsCompletionItem> results,
bool is_cached_result) {
assert(!is_cached_result);

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "project.h"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "working_files.h"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "include_complete.h"
#include "message_handler.h"
#include "pipeline.hh"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "project.h"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
using namespace ccls;
@ -102,7 +102,7 @@ struct Handler_TextDocumentSignatureHelp : MessageHandler {
if (search.empty())
return;
ClangCompleteManager::OnComplete callback = std::bind(
CompletionManager::OnComplete callback = std::bind(
[this](InMessage *message, std::string search, int active_param,
const std::vector<lsCompletionItem> &results,
bool is_cached_result) {

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "project.h"

View File

@ -1,7 +1,7 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.h"
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "project.h"

View File

@ -3,7 +3,7 @@
#include "pipeline.hh"
#include "clang_complete.h"
#include "clang_complete.hh"
#include "config.h"
#include "include_complete.h"
#include "log.hh"
@ -153,7 +153,8 @@ std::unique_ptr<IndexFile> RawCacheLoad(const std::string &path) {
IndexFile::kMajorVersion);
}
bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
bool Indexer_Parse(CompletionManager *completion,
DiagnosticsPublisher *diag_pub, WorkingFiles *wfiles,
Project *project, VFS *vfs, const GroupMatch &matcher) {
std::optional<Index_Request> opt_request = index_request->TryPopFront();
if (!opt_request)
@ -247,12 +248,12 @@ bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files,
std::vector<std::pair<std::string, std::string>> remapped;
if (g_config->index.onChange) {
std::string content = working_files->GetContent(request.path);
std::string content = wfiles->GetContent(request.path);
if (content.size())
remapped.emplace_back(request.path, content);
}
auto indexes =
idx::Index(vfs, entry.directory, path_to_index, entry.args, remapped);
auto indexes = idx::Index(completion, wfiles, vfs, entry.directory,
path_to_index, entry.args, remapped);
if (indexes.empty()) {
if (g_config->index.enabled && request.id.Valid()) {
@ -336,11 +337,13 @@ void Init() {
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter);
}
void Indexer_Main(DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
void Indexer_Main(CompletionManager *completion,
DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
WorkingFiles *working_files) {
GroupMatch matcher(g_config->index.whitelist, g_config->index.blacklist);
while (true)
if (!Indexer_Parse(diag_pub, working_files, project, vfs, matcher))
if (!Indexer_Parse(completion, diag_pub, working_files, project, vfs,
matcher))
indexer_waiter->Wait(index_request);
}
@ -452,7 +455,7 @@ void MainLoop() {
VFS vfs;
DiagnosticsPublisher diag_pub;
ClangCompleteManager clang_complete(
CompletionManager clang_complete(
&project, &working_files,
[&](std::string path, std::vector<lsDiagnostic> diagnostics) {
diag_pub.Publish(&working_files, path, diagnostics);

View File

@ -11,6 +11,7 @@
#include <unordered_map>
#include <vector>
struct CompletionManager;
struct GroupMatch;
struct VFS;
struct Project;
@ -40,10 +41,9 @@ namespace pipeline {
void Init();
void LaunchStdin();
void LaunchStdout();
void Indexer_Main(DiagnosticsPublisher* diag_pub,
VFS* vfs,
Project* project,
WorkingFiles* working_files);
void Indexer_Main(CompletionManager *complete,
DiagnosticsPublisher *diag_pub, VFS *vfs, Project *project,
WorkingFiles *working_files);
void MainLoop();
void Index(const std::string &path, const std::vector<std::string> &args,

View File

@ -3,6 +3,7 @@
#include "test.h"
#include "clang_complete.hh"
#include "filesystem.hh"
#include "indexer.h"
#include "platform.h"
@ -289,7 +290,11 @@ bool RunIndexTests(const std::string &filter_path, bool enable_update) {
// Run test.
g_config = new Config;
VFS vfs;
auto dbs = ccls::idx::Index(&vfs, "", path, flags, {});
CompletionManager completion(
nullptr, nullptr, [&](std::string, std::vector<lsDiagnostic>) {},
[](lsRequestId id) {});
WorkingFiles wfiles;
auto dbs = ccls::idx::Index(&completion, &wfiles, &vfs, "", path, flags, {});
for (const auto &entry : all_expected_output) {
const std::string &expected_path = entry.first;