diff --git a/src/clang_complete.cc b/src/clang_complete.cc index 36c00f39..76259761 100644 --- a/src/clang_complete.cc +++ b/src/clang_complete.cc @@ -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 request = + std::unique_ptr 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 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( - project_->FindCompilationEntryForFile(filename), working_files_, PCH); + project_->FindCompilationEntryForFile(path), working_files_, PCH); preloaded_sessions_.Insert(session->file.filename, session); return true; } std::shared_ptr -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 lock(sessions_lock_); // Try to find a preloaded session. std::shared_ptr 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 session = - completion_sessions_.TryGet(filename); + completion_sessions_.TryGet(path); if (!session && create_if_needed) { session = std::make_shared( - 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 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 lock(sessions_lock_); diff --git a/src/clang_complete.h b/src/clang_complete.hh similarity index 91% rename from src/clang_complete.h rename to src/clang_complete.hh index dd4007ce..2d170cd0 100644 --- a/src/clang_complete.h +++ b/src/clang_complete.hh @@ -64,7 +64,7 @@ struct CompletionSession }; } -struct ClangCompleteManager { +struct CompletionManager { using OnDiagnostic = std::function diagnostics)>; using OnComplete = std::function - 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); diff --git a/src/config.h b/src/config.h index 2835b68f..b7e1c850 100644 --- a/src/config.h +++ b/src/config.h @@ -142,6 +142,8 @@ struct Config { // If true, diagnostics will be reported for textDocument/didOpen. bool onOpen = true; + bool spellChecking = true; + std::vector 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, diff --git a/src/indexer.cc b/src/indexer.cc index 07321395..29d1fa96 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -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 #include @@ -1180,7 +1181,8 @@ void Init() { } std::vector> -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 &args, const std::vector> &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> 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 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; diff --git a/src/indexer.h b/src/indexer.h index 20f97a03..2bbce4e0 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -272,10 +272,14 @@ struct IndexFile { std::string ToString(); }; +struct CompletionManager; +struct WorkingFiles; + namespace ccls::idx { void Init(); std::vector> -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 &args, - const std::vector>& remapped); -} // namespace ccls::idx + const std::vector> &remapped); +} diff --git a/src/message_handler.h b/src/message_handler.h index d6fc4a71..b0a2cd23 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -14,7 +14,7 @@ #include #include -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; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 37f961e1..f860f4b6 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -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 { 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(); } diff --git a/src/messages/textDocument_codeLens.cc b/src/messages/textDocument_codeLens.cc index c7b62e8e..78a03c4b 100644 --- a/src/messages/textDocument_codeLens.cc +++ b/src/messages/textDocument_codeLens.cc @@ -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" diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index 87d818aa..7b7792a2 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -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 &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 results, bool is_cached_result) { assert(!is_cached_result); diff --git a/src/messages/textDocument_didChange.cc b/src/messages/textDocument_didChange.cc index c58e8cd8..2e0a494e 100644 --- a/src/messages/textDocument_didChange.cc +++ b/src/messages/textDocument_didChange.cc @@ -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" diff --git a/src/messages/textDocument_didClose.cc b/src/messages/textDocument_didClose.cc index f9d487f3..2509e20d 100644 --- a/src/messages/textDocument_didClose.cc +++ b/src/messages/textDocument_didClose.cc @@ -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" diff --git a/src/messages/textDocument_didOpen.cc b/src/messages/textDocument_didOpen.cc index c8624beb..f68ba84d 100644 --- a/src/messages/textDocument_didOpen.cc +++ b/src/messages/textDocument_didOpen.cc @@ -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" diff --git a/src/messages/textDocument_didSave.cc b/src/messages/textDocument_didSave.cc index 2cf37f46..25c8bc81 100644 --- a/src/messages/textDocument_didSave.cc +++ b/src/messages/textDocument_didSave.cc @@ -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" diff --git a/src/messages/textDocument_signatureHelp.cc b/src/messages/textDocument_signatureHelp.cc index 4724b15c..866b3a16 100644 --- a/src/messages/textDocument_signatureHelp.cc +++ b/src/messages/textDocument_signatureHelp.cc @@ -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 &results, bool is_cached_result) { diff --git a/src/messages/workspace_didChangeConfiguration.cc b/src/messages/workspace_didChangeConfiguration.cc index 7eb1dcfd..7ae555a8 100644 --- a/src/messages/workspace_didChangeConfiguration.cc +++ b/src/messages/workspace_didChangeConfiguration.cc @@ -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" diff --git a/src/messages/workspace_didChangeWatchedFiles.cc b/src/messages/workspace_didChangeWatchedFiles.cc index 9fcedcf4..8a41616f 100644 --- a/src/messages/workspace_didChangeWatchedFiles.cc +++ b/src/messages/workspace_didChangeWatchedFiles.cc @@ -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" diff --git a/src/pipeline.cc b/src/pipeline.cc index f1864242..27a414b5 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -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 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 opt_request = index_request->TryPopFront(); if (!opt_request) @@ -247,12 +248,12 @@ bool Indexer_Parse(DiagnosticsPublisher *diag_pub, WorkingFiles *working_files, std::vector> 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_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 diagnostics) { diag_pub.Publish(&working_files, path, diagnostics); diff --git a/src/pipeline.hh b/src/pipeline.hh index 4a3f2b39..4ebd5f43 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -11,6 +11,7 @@ #include #include +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 &args, diff --git a/src/test.cc b/src/test.cc index ee5c6412..4d734601 100644 --- a/src/test.cc +++ b/src/test.cc @@ -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) {}, + [](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;