From 07f0cdbf382aa955126ff3e90e74816186390b52 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 25 May 2018 22:48:58 -0700 Subject: [PATCH] Simplify; improve $ccls/inheritanceHierarchy --- src/messages/ccls_inheritance_hierarchy.cc | 21 +- src/messages/initialize.cc | 218 +++++++++--------- src/messages/text_document_did_change.cc | 14 +- src/messages/text_document_did_open.cc | 2 +- src/messages/text_document_did_save.cc | 14 +- .../workspace_did_change_watched_files.cc | 15 +- src/project.cc | 12 +- src/queue_manager.cc | 16 +- src/queue_manager.h | 2 - 9 files changed, 141 insertions(+), 173 deletions(-) diff --git a/src/messages/ccls_inheritance_hierarchy.cc b/src/messages/ccls_inheritance_hierarchy.cc index 3f960544..bbf255a1 100644 --- a/src/messages/ccls_inheritance_hierarchy.cc +++ b/src/messages/ccls_inheritance_hierarchy.cc @@ -2,6 +2,8 @@ #include "query_utils.h" #include "queue_manager.h" +#include + namespace { MethodType kMethodType = "$ccls/inheritanceHierarchy"; @@ -79,19 +81,22 @@ bool ExpandHelper(MessageHandler* m, int levels, Q& entity) { const auto* def = entity.AnyDef(); - if (!def) { + if (def) { + entry->name = def->Name(qualified); + if (def->spell) { + if (auto loc = GetLsLocation(m->db, m->working_files, *def->spell)) + entry->location = *loc; + } + } else if (!derived) { entry->numChildren = 0; return false; } - entry->name = def->Name(qualified); - if (def->spell) { - if (std::optional loc = - GetLsLocation(m->db, m->working_files, *def->spell)) - entry->location = *loc; - } + std::unordered_set seen; if (derived) { if (levels > 0) { for (auto usr : entity.derived) { + if (seen.insert(usr).second) + continue; Out_CclsInheritanceHierarchy::Entry entry1; entry1.id = std::to_string(usr); entry1.usr = usr; @@ -105,6 +110,8 @@ bool ExpandHelper(MessageHandler* m, } else { if (levels > 0) { for (auto usr : def->bases) { + if (seen.insert(usr).second) + continue; Out_CclsInheritanceHierarchy::Entry entry1; entry1.id = std::to_string(usr); entry1.usr = usr; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index a2d21e41..fc4bc4d9 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -267,12 +267,8 @@ struct lsTextDocumentClientCapabilities { // and `${3:foo}`. `$0` defines the final tab stop, it defaults to // the end of the snippet. Placeholders with equal identifiers are linked, // that is typing in one will update others too. - std::optional snippetSupport; - }; - - // The client supports the following `CompletionItem` specific - // capabilities. - std::optional completionItem; + bool snippetSupport = false; + } completionItem; } completion; struct lsGenericDynamicReg { @@ -426,114 +422,110 @@ struct Handler_Initialize : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } void Run(In_InitializeRequest* request) override { - // Log initialization parameters. - rapidjson::StringBuffer output; - rapidjson::Writer writer(output); - JsonWriter json_writer(&writer); - Reflect(json_writer, request->params.initializationOptions); - LOG_S(INFO) << "Init parameters: " << output.GetString(); - std::unique_ptr config; - - if (request->params.rootUri) { - std::string project_path = - NormalizePath(request->params.rootUri->GetPath()); - LOG_S(INFO) << "[querydb] Initialize in directory " << project_path - << " with uri " << request->params.rootUri->raw_uri; - - { - if (request->params.initializationOptions) - config = std::make_unique(*request->params.initializationOptions); - else - config = std::make_unique(); - rapidjson::Document reader; - reader.Parse(g_init_options.c_str()); - if (!reader.HasParseError()) { - JsonReader json_reader{&reader}; - try { - Reflect(json_reader, *config); - } catch (std::invalid_argument&) { - // This will not trigger because parse error is handled in - // MessageRegistry::Parse in lsp.cc - } - } - - if (config->cacheDirectory.empty()) { - LOG_S(ERROR) << "cacheDirectory cannot be empty."; - exit(1); - } else { - config->cacheDirectory = NormalizePath(config->cacheDirectory); - EnsureEndsInSlash(config->cacheDirectory); - } - } - - // Client capabilities - { - const auto& cap = request->params.capabilities.textDocument; - if (cap.completion.completionItem) - config->client.snippetSupport = - cap.completion.completionItem->snippetSupport.value_or(false); - } - - // Ensure there is a resource directory. - if (config->clang.resourceDir.empty()) - config->clang.resourceDir = GetDefaultResourceDirectory(); - LOG_S(INFO) << "Using -resource-dir=" << config->clang.resourceDir; - - // Send initialization before starting indexers, so we don't send a - // status update too early. - // TODO: query request->params.capabilities.textDocument and support - // only things the client supports. - - Out_InitializeResponse out; - out.id = request->id; - - QueueManager::WriteStdout(kMethodType, out); - - // Set project root. - EnsureEndsInSlash(project_path); - config->projectRoot = project_path; - // Create two cache directories for files inside and outside of the - // project. - sys::fs::create_directories(config->cacheDirectory + - EscapeFileName(config->projectRoot)); - sys::fs::create_directories(config->cacheDirectory + '@' + - EscapeFileName(config->projectRoot)); - - g_config = std::move(config); - Timer time; - diag_engine->Init(); - semantic_cache->Init(); - - // Open up / load the project. - project->Load(project_path); - time.ResetAndPrint("[perf] Loaded compilation entries (" + - std::to_string(project->entries.size()) + " files)"); - - // Start indexer threads. Start this after loading the project, as that - // may take a long time. Indexer threads will emit status/progress - // reports. - if (g_config->index.threads == 0) - g_config->index.threads = std::thread::hardware_concurrency(); - - LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers"; - for (int i = 0; i < g_config->index.threads; i++) { - std::thread([=]() { - g_thread_id = i + 1; - std::string name = "indexer" + std::to_string(i); - SetThreadName(name.c_str()); - Indexer_Main(diag_engine, vfs, project, working_files, waiter); - }).detach(); - } - - // Start scanning include directories before dispatching project - // files, because that takes a long time. - include_complete->Rescan(); - - time.Reset(); - project->Index(QueueManager::instance(), working_files, request->id); - // We need to support multiple concurrent index processes. - time.ResetAndPrint("[perf] Dispatched initial index requests"); + auto& params = request->params; + if (!params.rootUri) + return; + { + rapidjson::StringBuffer output; + rapidjson::Writer writer(output); + JsonWriter json_writer(&writer); + Reflect(json_writer, params.initializationOptions); + LOG_S(INFO) << "initializationOptions: " << output.GetString(); } + + std::string project_path = NormalizePath(params.rootUri->GetPath()); + LOG_S(INFO) << "initialize in directory " << project_path << " with uri " + << params.rootUri->raw_uri; + + { + if (params.initializationOptions) + g_config = std::make_unique(*params.initializationOptions); + else + g_config = std::make_unique(); + rapidjson::Document reader; + reader.Parse(g_init_options.c_str()); + if (!reader.HasParseError()) { + JsonReader json_reader{&reader}; + try { + Reflect(json_reader, *g_config); + } catch (std::invalid_argument&) { + // This will not trigger because parse error is handled in + // MessageRegistry::Parse in lsp.cc + } + } + + if (g_config->cacheDirectory.empty()) { + LOG_S(ERROR) << "cacheDirectory cannot be empty."; + exit(1); + } else { + g_config->cacheDirectory = NormalizePath(g_config->cacheDirectory); + EnsureEndsInSlash(g_config->cacheDirectory); + } + } + + // Client capabilities + const auto& capabilities = params.capabilities; + g_config->client.snippetSupport = + capabilities.textDocument.completion.completionItem.snippetSupport; + + // Ensure there is a resource directory. + if (g_config->clang.resourceDir.empty()) + g_config->clang.resourceDir = GetDefaultResourceDirectory(); + LOG_S(INFO) << "Using -resource-dir=" << g_config->clang.resourceDir; + + // Send initialization before starting indexers, so we don't send a + // status update too early. + // TODO: query request->params.capabilities.textDocument and support + // only things the client supports. + + Out_InitializeResponse out; + out.id = request->id; + + QueueManager::WriteStdout(kMethodType, out); + + // Set project root. + EnsureEndsInSlash(project_path); + g_config->projectRoot = project_path; + // Create two cache directories for files inside and outside of the + // project. + sys::fs::create_directories(g_config->cacheDirectory + + EscapeFileName(g_config->projectRoot)); + sys::fs::create_directories(g_config->cacheDirectory + '@' + + EscapeFileName(g_config->projectRoot)); + + Timer time; + diag_engine->Init(); + semantic_cache->Init(); + + // Open up / load the project. + project->Load(project_path); + time.ResetAndPrint("[perf] Loaded compilation entries (" + + std::to_string(project->entries.size()) + " files)"); + + // Start indexer threads. Start this after loading the project, as that + // may take a long time. Indexer threads will emit status/progress + // reports. + if (g_config->index.threads == 0) + g_config->index.threads = std::thread::hardware_concurrency(); + + LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers"; + for (int i = 0; i < g_config->index.threads; i++) { + std::thread([=]() { + g_thread_id = i + 1; + std::string name = "indexer" + std::to_string(i); + SetThreadName(name.c_str()); + Indexer_Main(diag_engine, vfs, project, working_files, waiter); + }).detach(); + } + + // Start scanning include directories before dispatching project + // files, because that takes a long time. + include_complete->Rescan(); + + time.Reset(); + project->Index(QueueManager::instance(), working_files, request->id); + // We need to support multiple concurrent index processes. + time.ResetAndPrint("[perf] Dispatched initial index requests"); } }; REGISTER_MESSAGE_HANDLER(Handler_Initialize); diff --git a/src/messages/text_document_did_change.cc b/src/messages/text_document_did_change.cc index 10a646ca..b09b1829 100644 --- a/src/messages/text_document_did_change.cc +++ b/src/messages/text_document_did_change.cc @@ -26,16 +26,10 @@ struct Handler_TextDocumentDidChange std::string path = request->params.textDocument.uri.GetPath(); working_files->OnChange(request->params); if (g_config->index.onDidChange) { - std::optional content = ReadContent(path); - if (!content) { - LOG_S(ERROR) << "Unable to read file content after saving " << path; - } else { - Project::Entry entry = project->FindCompilationEntryForFile(path); - QueueManager::instance()->index_request.PushBack( - Index_Request(entry.filename, entry.args, true /*is_interactive*/, - *content), - true); - } + Project::Entry entry = project->FindCompilationEntryForFile(path); + QueueManager::instance()->index_request.PushBack( + Index_Request(entry.filename, entry.args, true /*is_interactive*/), + true); } clang_complete->NotifyEdit(path); clang_complete->DiagnosticsUpdate( diff --git a/src/messages/text_document_did_open.cc b/src/messages/text_document_did_open.cc index c3ae0b07..a91afb1c 100644 --- a/src/messages/text_document_did_open.cc +++ b/src/messages/text_document_did_open.cc @@ -65,7 +65,7 @@ struct Handler_TextDocumentDidOpen QueueManager::instance()->index_request.PushBack( Index_Request(entry.filename, params.args.size() ? params.args : entry.args, - true /*is_interactive*/, params.textDocument.text), + true /*is_interactive*/), true /* priority */); clang_complete->FlushSession(entry.filename); diff --git a/src/messages/text_document_did_save.cc b/src/messages/text_document_did_save.cc index c6891c2c..3e5a9011 100644 --- a/src/messages/text_document_did_save.cc +++ b/src/messages/text_document_did_save.cc @@ -48,16 +48,10 @@ struct Handler_TextDocumentDidSave // if so, ignore that index response. // TODO: send as priority request if (!g_config->index.onDidChange) { - std::optional content = ReadContent(path); - if (!content) { - LOG_S(ERROR) << "Unable to read file content after saving " << path; - } else { - Project::Entry entry = project->FindCompilationEntryForFile(path); - QueueManager::instance()->index_request.PushBack( - Index_Request(entry.filename, entry.args, true /*is_interactive*/, - *content), - true); - } + Project::Entry entry = project->FindCompilationEntryForFile(path); + QueueManager::instance()->index_request.PushBack( + Index_Request(entry.filename, entry.args, true /*is_interactive*/), + true); } clang_complete->NotifySave(path); diff --git a/src/messages/workspace_did_change_watched_files.cc b/src/messages/workspace_did_change_watched_files.cc index 6dbac73c..e15e9e21 100644 --- a/src/messages/workspace_did_change_watched_files.cc +++ b/src/messages/workspace_did_change_watched_files.cc @@ -54,20 +54,15 @@ struct Handler_WorkspaceDidChangeWatchedFiles switch (event.type) { case lsFileChangeType::Created: case lsFileChangeType::Changed: { - std::optional content = ReadContent(path); - if (!content) - LOG_S(ERROR) << "Unable to read file content after saving " << path; - else { - QueueManager::instance()->index_request.PushBack( - Index_Request(path, entry.args, is_interactive, *content)); - if (is_interactive) - clang_complete->NotifySave(path); - } + QueueManager::instance()->index_request.PushBack( + Index_Request(path, entry.args, is_interactive)); + if (is_interactive) + clang_complete->NotifySave(path); break; } case lsFileChangeType::Deleted: QueueManager::instance()->index_request.PushBack( - Index_Request(path, entry.args, is_interactive, std::string())); + Index_Request(path, entry.args, is_interactive)); break; } } diff --git a/src/project.cc b/src/project.cc index 4800033b..3ca211d4 100644 --- a/src/project.cc +++ b/src/project.cc @@ -458,19 +458,13 @@ void Project::Index(QueueManager* queue, WorkingFiles* wfiles, lsRequestId id) { ForAllFilteredFiles([&](int i, const Project::Entry& entry) { - std::optional content = ReadContent(entry.filename); - if (!content) { - LOG_S(ERROR) << "When loading project, canont read file " - << entry.filename; - return; - } bool is_interactive = wfiles->GetFileByFilename(entry.filename) != nullptr; - queue->index_request.PushBack(Index_Request(entry.filename, entry.args, - is_interactive, *content, id)); + queue->index_request.PushBack( + Index_Request(entry.filename, entry.args, is_interactive, id)); }); // Dummy request to indicate that project is loaded and // trigger refreshing semantic highlight for all working files. - queue->index_request.PushBack(Index_Request("", {}, false, "")); + queue->index_request.PushBack(Index_Request("", {}, false)); } TEST_SUITE("Project") { diff --git a/src/queue_manager.cc b/src/queue_manager.cc index 87cb794a..623c72df 100644 --- a/src/queue_manager.cc +++ b/src/queue_manager.cc @@ -6,17 +6,11 @@ #include -Index_Request::Index_Request( - const std::string& path, - const std::vector& args, - bool is_interactive, - const std::string& contents, - lsRequestId id) - : path(path), - args(args), - is_interactive(is_interactive), - contents(contents), - id(id) {} +Index_Request::Index_Request(const std::string& path, + const std::vector& args, + bool is_interactive, + lsRequestId id) + : path(path), args(args), is_interactive(is_interactive), id(id) {} Index_OnIndexed::Index_OnIndexed(IndexUpdate&& update, PerformanceImportFile perf) diff --git a/src/queue_manager.h b/src/queue_manager.h index 03f3909c..13ee57b4 100644 --- a/src/queue_manager.h +++ b/src/queue_manager.h @@ -19,13 +19,11 @@ struct Index_Request { // TODO: make |args| a string that is parsed lazily. std::vector args; bool is_interactive; - std::string contents; // Preloaded contents. lsRequestId id; Index_Request(const std::string& path, const std::vector& args, bool is_interactive, - const std::string& contents, lsRequestId id = {}); };