From bdbb68dffdb82c90a7234be279b5608553ed7c07 Mon Sep 17 00:00:00 2001 From: slavek-kucera <53339291+slavek-kucera@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:42:53 +0100 Subject: [PATCH] Resolve lifetime issues related to macro dependencies --- parser_library/include/workspace_manager.h | 2 +- parser_library/src/analyzer.cpp | 2 +- parser_library/src/analyzer.h | 4 +- parser_library/src/lsp/text_data_view.h | 2 +- .../src/processing/processing_manager.cpp | 2 +- .../src/processing/processing_manager.h | 3 +- .../statement_analyzers/lsp_analyzer.cpp | 2 +- .../statement_analyzers/lsp_analyzer.h | 6 +- parser_library/src/workspace_manager.cpp | 4 +- parser_library/src/workspace_manager_impl.h | 105 +++---- parser_library/src/workspaces/file.h | 4 +- parser_library/src/workspaces/file_impl.cpp | 6 +- parser_library/src/workspaces/file_impl.h | 7 +- parser_library/src/workspaces/file_manager.h | 22 +- .../src/workspaces/file_manager_impl.cpp | 109 ++----- .../src/workspaces/file_manager_impl.h | 23 +- parser_library/src/workspaces/processor.h | 5 +- .../src/workspaces/processor_file_impl.cpp | 62 ++-- .../src/workspaces/processor_file_impl.h | 27 +- parser_library/src/workspaces/workspace.cpp | 279 ++++++++++++------ parser_library/src/workspaces/workspace.h | 44 ++- .../test/debugging/debugger_test.cpp | 7 - parser_library/test/workspace/CMakeLists.txt | 1 - .../test/workspace/b4g_integration_test.cpp | 34 +-- .../test/workspace/diags_suppress_test.cpp | 12 +- .../test/workspace/file_manager_mock.h | 9 +- .../test/workspace/file_with_text.h | 40 --- .../test/workspace/files_parse_lib_provider.h | 9 +- .../test/workspace/instruction_sets_test.cpp | 14 +- .../test/workspace/load_config_test.cpp | 4 +- .../test/workspace/macro_cache_test.cpp | 68 +++-- .../test/workspace/processor_file_test.cpp | 18 +- .../test/workspace/workspace_test.cpp | 100 ++----- 33 files changed, 499 insertions(+), 537 deletions(-) delete mode 100644 parser_library/test/workspace/file_with_text.h diff --git a/parser_library/include/workspace_manager.h b/parser_library/include/workspace_manager.h index 236f5dce6..1d1f17b67 100644 --- a/parser_library/include/workspace_manager.h +++ b/parser_library/include/workspace_manager.h @@ -119,7 +119,7 @@ class PARSER_LIBRARY_EXPORT workspace_manager virtual completion_list completion( const char* document_uri, position pos, char trigger_char, completion_trigger_kind trigger_kind); - virtual sequence semantic_tokens(const char* document_uri); + virtual continuous_sequence semantic_tokens(const char* document_uri); virtual document_symbol_list document_symbol(const char* document_uri, long long limit); virtual void configuration_changed(const lib_config& new_config, const char* whole_settings); diff --git a/parser_library/src/analyzer.cpp b/parser_library/src/analyzer.cpp index f0c5bf601..f02dc5e96 100644 --- a/parser_library/src/analyzer.cpp +++ b/parser_library/src/analyzer.cpp @@ -102,7 +102,7 @@ std::unique_ptr analyzer_options::get_preprocessor(pro return std::make_unique(std::move(tmp)); } -analyzer::analyzer(const std::string& text, analyzer_options opts) +analyzer::analyzer(std::string_view text, analyzer_options opts) : diagnosable_ctx(opts.get_hlasm_context()) , ctx_(std::move(opts.get_context())) , src_proc_(opts.collect_hl_info == collect_highlighting_info::yes) diff --git a/parser_library/src/analyzer.h b/parser_library/src/analyzer.h index f7b87fa73..c4b787844 100644 --- a/parser_library/src/analyzer.h +++ b/parser_library/src/analyzer.h @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -146,7 +146,7 @@ class analyzer : public diagnosable_ctx processing::processing_manager mngr_; public: - analyzer(const std::string& text, analyzer_options opts = {}); + analyzer(std::string_view text, analyzer_options opts = {}); analyzing_context context() const; context::hlasm_context& hlasm_ctx(); diff --git a/parser_library/src/lsp/text_data_view.h b/parser_library/src/lsp/text_data_view.h index 5693a2ce9..3c75c2828 100644 --- a/parser_library/src/lsp/text_data_view.h +++ b/parser_library/src/lsp/text_data_view.h @@ -24,7 +24,7 @@ namespace hlasm_plugin::parser_library::lsp { class text_data_view { - std::string text; // FIXME: no longer view due to lifetime issues + std::string_view text; std::vector line_indices; public: diff --git a/parser_library/src/processing/processing_manager.cpp b/parser_library/src/processing/processing_manager.cpp index 3247a64b1..f9eff5bdf 100644 --- a/parser_library/src/processing/processing_manager.cpp +++ b/parser_library/src/processing/processing_manager.cpp @@ -33,7 +33,7 @@ processing_manager::processing_manager(std::unique_ptr base_p analyzing_context ctx, workspaces::library_data data, utils::resource::resource_location file_loc, - const std::string& file_text, + std::string_view file_text, workspaces::parse_lib_provider& lib_provider, statement_fields_parser& parser, std::shared_ptr> fade_msgs) diff --git a/parser_library/src/processing/processing_manager.h b/parser_library/src/processing/processing_manager.h index 0fa355b51..c02094f94 100644 --- a/parser_library/src/processing/processing_manager.h +++ b/parser_library/src/processing/processing_manager.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "analyzing_context.h" @@ -42,7 +43,7 @@ class processing_manager final : public processing_state_listener, public branch analyzing_context ctx, workspaces::library_data data, utils::resource::resource_location file_loc, - const std::string& file_text, + std::string_view file_text, workspaces::parse_lib_provider& lib_provider, statement_fields_parser& parser, std::shared_ptr> fade_msgs); diff --git a/parser_library/src/processing/statement_analyzers/lsp_analyzer.cpp b/parser_library/src/processing/statement_analyzers/lsp_analyzer.cpp index 231b2c3d6..8c2444d1c 100644 --- a/parser_library/src/processing/statement_analyzers/lsp_analyzer.cpp +++ b/parser_library/src/processing/statement_analyzers/lsp_analyzer.cpp @@ -62,7 +62,7 @@ constexpr std::array, 3> SET_i } // namespace -lsp_analyzer::lsp_analyzer(context::hlasm_context& hlasm_ctx, lsp::lsp_context& lsp_ctx, const std::string& file_text) +lsp_analyzer::lsp_analyzer(context::hlasm_context& hlasm_ctx, lsp::lsp_context& lsp_ctx, std::string_view file_text) : hlasm_ctx_(hlasm_ctx) , lsp_ctx_(lsp_ctx) , file_text_(file_text) diff --git a/parser_library/src/processing/statement_analyzers/lsp_analyzer.h b/parser_library/src/processing/statement_analyzers/lsp_analyzer.h index 0f32c6127..9645855b4 100644 --- a/parser_library/src/processing/statement_analyzers/lsp_analyzer.h +++ b/parser_library/src/processing/statement_analyzers/lsp_analyzer.h @@ -16,7 +16,7 @@ #define PROCESSING_LSP_ANALYZER_H #include -#include +#include #include "context/common_types.h" #include "context/copy_member.h" @@ -69,7 +69,7 @@ class lsp_analyzer : public statement_analyzer context::hlasm_context& hlasm_ctx_; lsp::lsp_context& lsp_ctx_; // text of the file this analyzer is assigned to - const std::string& file_text_; + std::string_view file_text_; bool in_macro_ = false; size_t macro_nest_ = 1; @@ -81,7 +81,7 @@ class lsp_analyzer : public statement_analyzer lsp::occurence_storage stmt_occurences_; public: - lsp_analyzer(context::hlasm_context& hlasm_ctx, lsp::lsp_context& lsp_ctx, const std::string& file_text); + lsp_analyzer(context::hlasm_context& hlasm_ctx, lsp::lsp_context& lsp_ctx, std::string_view file_text); void analyze(const context::hlasm_statement& statement, statement_provider_kind prov_kind, diff --git a/parser_library/src/workspace_manager.cpp b/parser_library/src/workspace_manager.cpp index 2f460cdd7..ecd2e41ff 100644 --- a/parser_library/src/workspace_manager.cpp +++ b/parser_library/src/workspace_manager.cpp @@ -134,9 +134,9 @@ completion_list workspace_manager::completion( return impl_->completion(document_uri, pos, trigger_char, trigger_kind); } -sequence workspace_manager::semantic_tokens(const char* document_uri) +continuous_sequence workspace_manager::semantic_tokens(const char* document_uri) { - return sequence(impl_->semantic_tokens(document_uri)); + return impl_->semantic_tokens(document_uri); } document_symbol_list workspace_manager::document_symbol(const char* document_uri, long long limit) diff --git a/parser_library/src/workspace_manager_impl.h b/parser_library/src/workspace_manager_impl.h index e302c4b70..d1286d88e 100644 --- a/parser_library/src/workspace_manager_impl.h +++ b/parser_library/src/workspace_manager_impl.h @@ -41,7 +41,6 @@ class workspace_manager::impl final : public diagnosable_impl public: impl(std::atomic* cancel = nullptr) : cancel_(cancel) - , file_manager_(cancel) , implicit_workspace_(file_manager_, global_config_, m_global_settings, cancel) , quiet_implicit_workspace_(file_manager_, supress_all, m_global_settings, cancel) {} @@ -51,6 +50,39 @@ class workspace_manager::impl final : public diagnosable_impl impl(impl&&) = delete; impl& operator=(impl&&) = delete; + static auto& ws_path_match(auto& self, std::string_view document_uri) + { + if (auto hlasm_id = extract_hlasm_id(document_uri); hlasm_id.has_value()) + { + if (auto related_ws = self.file_manager_.get_virtual_file_workspace(hlasm_id.value()); !related_ws.empty()) + for (auto& [_, ws] : self.workspaces_) + if (ws.uri() == related_ws.get_uri()) + return ws; + } + + size_t max = 0; + decltype(&self.workspaces_.begin()->second) max_ws = nullptr; + for (auto& [name, ws] : self.workspaces_) + { + size_t match = prefix_match(document_uri, ws.uri()); + if (match > max && match >= name.size()) + { + max = match; + max_ws = &ws; + } + } + if (max_ws != nullptr) + return *max_ws; + else if (document_uri.starts_with("file:") || document_uri.starts_with("untitled:")) + return self.implicit_workspace_; + else + return self.quiet_implicit_workspace_; + } + + // returns implicit workspace, if the file does not belong to any workspace + auto& ws_path_match(std::string_view document_uri) { return ws_path_match(*this, document_uri); } + auto& ws_path_match(std::string_view document_uri) const { return ws_path_match(*this, document_uri); } + size_t get_workspaces(ws_id* workspaces, size_t max_size) { size_t size = 0; @@ -246,19 +278,10 @@ class workspace_manager::impl final : public diagnosable_impl notify_diagnostics_consumers(); } - std::vector empty_tokens; - const std::vector& semantic_tokens(const char* document_uri) + continuous_sequence semantic_tokens(const char* document_uri) { - if (cancel_ && *cancel_) - return empty_tokens; - - utils::resource::resource_location doc(document_uri); - - auto file = file_manager_.find(doc); - if (dynamic_cast(file.get()) != nullptr) - return file_manager_.find_processor_file(doc)->get_hl_info(); - - return empty_tokens; + return make_continuous_sequence( + ws_path_match(document_uri).semantic_tokens(utils::resource::resource_location(document_uri))); } continuous_sequence get_virtual_file_content(unsigned long long id) const @@ -284,8 +307,8 @@ class workspace_manager::impl final : public diagnosable_impl private: void collect_diags() const override { - collect_diags_from_child(file_manager_); - + collect_diags_from_child(implicit_workspace_); + collect_diags_from_child(quiet_implicit_workspace_); for (auto& it : workspaces_) collect_diags_from_child(it.second); } @@ -310,43 +333,16 @@ class workspace_manager::impl final : public diagnosable_impl return result; } - // returns implicit workspace, if the file does not belong to any workspace - workspaces::workspace& ws_path_match(std::string_view document_uri) - { - if (auto hlasm_id = extract_hlasm_id(document_uri); hlasm_id.has_value()) - { - if (auto related_ws = file_manager_.get_virtual_file_workspace(hlasm_id.value()); !related_ws.empty()) - for (auto& [_, ws] : workspaces_) - if (ws.uri() == related_ws.get_uri()) - return ws; - } - - size_t max = 0; - workspaces::workspace* max_ws = nullptr; - for (auto& [name, ws] : workspaces_) - { - size_t match = prefix_match(document_uri, ws.uri()); - if (match > max && match >= name.size()) - { - max = match; - max_ws = &ws; - } - } - if (max_ws != nullptr) - return *max_ws; - else if (document_uri.starts_with("file:") || document_uri.starts_with("untitled:")) - return implicit_workspace_; - else - return quiet_implicit_workspace_; - } - void notify_diagnostics_consumers() { diags().clear(); collect_diags(); fade_messages_.clear(); - file_manager_.retrieve_fade_messages(fade_messages_); + implicit_workspace_.retrieve_fade_messages(fade_messages_); + quiet_implicit_workspace_.retrieve_fade_messages(fade_messages_); + for (const auto& [_, ws] : workspaces_) + ws.retrieve_fade_messages(fade_messages_); for (auto consumer : diag_consumers_) consumer->consume_diagnostics(diagnostic_list(diags().data(), diags().size()), @@ -356,16 +352,13 @@ class workspace_manager::impl final : public diagnosable_impl void notify_performance_consumers( const utils::resource::resource_location& document_uri, workspace_file_info ws_file_info) const { - auto file = file_manager_.find(document_uri); - auto proc_file = dynamic_cast(file.get()); - if (proc_file) - { - const auto& metrics = proc_file->get_metrics(); - for (auto consumer : parsing_metadata_consumers_) - { - consumer->consume_parsing_metadata({ metrics, ws_file_info }); - } - } + auto proc_file = ws_path_match(document_uri.get_uri()).find_processor_file(document_uri); + if (!proc_file) + return; + + parsing_metadata data { proc_file->get_metrics(), std::move(ws_file_info) }; + for (auto consumer : parsing_metadata_consumers_) + consumer->consume_parsing_metadata(data); } static size_t prefix_match(std::string_view first, std::string_view second) diff --git a/parser_library/src/workspaces/file.h b/parser_library/src/workspaces/file.h index c7d13c6a0..8125d9ac1 100644 --- a/parser_library/src/workspaces/file.h +++ b/parser_library/src/workspaces/file.h @@ -36,7 +36,7 @@ enum class update_file_result // Interface that represents both file opened in LSP // as well as a file opened by parser library from the disk. -class file : public virtual diagnosable +class file { public: virtual const file_location& get_location() = 0; @@ -57,8 +57,6 @@ class file : public virtual diagnosable virtual void did_change(range range, std::string new_text) = 0; virtual void did_close() = 0; - virtual void retrieve_fade_messages(std::vector& fms) const = 0; - protected: ~file() = default; }; diff --git a/parser_library/src/workspaces/file_impl.cpp b/parser_library/src/workspaces/file_impl.cpp index 13e58072c..970af7186 100644 --- a/parser_library/src/workspaces/file_impl.cpp +++ b/parser_library/src/workspaces/file_impl.cpp @@ -29,8 +29,6 @@ file_impl::file_impl(file_location location) , text_() {} -void file_impl::collect_diags() const {} - const file_location& file_impl::get_location() { return file_location_; } const std::string& file_impl::get_text() @@ -108,7 +106,9 @@ size_t find_newlines(std::string_view text, std::vector& lines) open_file_result file_impl::did_open(std::string new_text, version_t version) { bool identical = text_ == new_text; - text_ = std::move(new_text); + if (!identical) + text_ = std::move(new_text); + version_ = version; lines_ind_.clear(); diff --git a/parser_library/src/workspaces/file_impl.h b/parser_library/src/workspaces/file_impl.h index 5e27981b6..9c10a1fd2 100644 --- a/parser_library/src/workspaces/file_impl.h +++ b/parser_library/src/workspaces/file_impl.h @@ -29,7 +29,7 @@ namespace hlasm_plugin::parser_library::workspaces { // Implementation of the file interface. Implements LSP incremental changing // of contents of file as well as loading the file from disk. -class file_impl : public virtual file, public virtual diagnosable_impl +class file_impl : public virtual file { public: explicit file_impl(file_location location); @@ -39,8 +39,6 @@ class file_impl : public virtual file, public virtual diagnosable_impl file_impl(file_impl&&) = default; file_impl& operator=(file_impl&&) = default; - void collect_diags() const override; - const file_location& get_location() override; const std::string& get_text() override; version_t get_version() override; @@ -61,8 +59,7 @@ class file_impl : public virtual file, public virtual diagnosable_impl virtual ~file_impl() = default; bool is_bad() const { return bad_; } - - void retrieve_fade_messages(std::vector&) const override {}; + bool is_text_loaded() const { return up_to_date_; } protected: const std::string& get_text_ref(); diff --git a/parser_library/src/workspaces/file_manager.h b/parser_library/src/workspaces/file_manager.h index 72479c3fd..55bed25dc 100644 --- a/parser_library/src/workspaces/file_manager.h +++ b/parser_library/src/workspaces/file_manager.h @@ -33,8 +33,6 @@ namespace hlasm_plugin::parser_library::workspaces { -using file_ptr = std::shared_ptr; -using processor_file_ptr = std::shared_ptr; using list_directory_result = std::pair>, utils::path::list_directory_rc>; enum class open_file_result @@ -46,27 +44,17 @@ enum class open_file_result // Wraps an associative array of file names and files. // Implements LSP text synchronization methods. -class file_manager : public virtual diagnosable +class file_manager { public: // Adds a file with specified file name and returns it. // If such processor file already exists, it is returned. - virtual file_ptr add_file(const file_location&) = 0; - - // Adds processor file with specified file name and returns it. - // If such processor file already exists, it is returned. - // If such file already exists, it is changed into processor file. - virtual processor_file_ptr add_processor_file(const file_location&) = 0; - virtual processor_file_ptr get_processor_file(const file_location&) = 0; + virtual std::shared_ptr add_file(const file_location&) = 0; virtual void remove_file(const file_location&) = 0; // Finds file with specified file name, return nullptr if not found. - virtual file_ptr find(const file_location& key) const = 0; - // Finds processor file with specified file name. - // If there is a file with the file name, it is changed to processor_file. - // Returns nullptr if there is no such file. - virtual processor_file_ptr find_processor_file(const file_location& key) = 0; + virtual std::shared_ptr find(const file_location& key) const = 0; // Returns list of all files in a directory. Returns associative array with pairs file name - file location. virtual list_directory_result list_directory_files(const utils::resource::resource_location& directory) const = 0; @@ -94,9 +82,7 @@ class file_manager : public virtual diagnosable virtual open_file_result update_file(const file_location& document_loc) = 0; - virtual std::optional get_file_content(const utils::resource::resource_location&) = 0; - - virtual void retrieve_fade_messages(std::vector& fms) const = 0; + virtual std::optional get_file_content(const utils::resource::resource_location&) const = 0; protected: ~file_manager() = default; diff --git a/parser_library/src/workspaces/file_manager_impl.cpp b/parser_library/src/workspaces/file_manager_impl.cpp index 39a122748..830239676 100644 --- a/parser_library/src/workspaces/file_manager_impl.cpp +++ b/parser_library/src/workspaces/file_manager_impl.cpp @@ -15,8 +15,9 @@ #include "file_manager_impl.h" #include +#include -#include "processor_file_impl.h" +#include "file_impl.h" #include "utils/content_loader.h" #include "utils/path.h" #include "utils/path_conversions.h" @@ -24,65 +25,15 @@ namespace hlasm_plugin::parser_library::workspaces { -void file_manager_impl::collect_diags() const -{ - for (auto& it : files_) - collect_diags_from_child(*it.second); -} - -void file_manager_impl::retrieve_fade_messages(std::vector& fms) const -{ - for (const auto& [_, file_impl] : files_) - file_impl->retrieve_fade_messages(fms); -} - -file_ptr file_manager_impl::add_file(const file_location& file) +std::shared_ptr file_manager_impl::add_file(const file_location& file) { std::lock_guard guard(files_mutex); auto [ret, _] = files_.try_emplace(file, std::make_shared(file)); return ret->second; } -processor_file_ptr file_manager_impl::change_into_processor_file_if_not_already_(std::shared_ptr& to_change) -{ - auto processor = std::dynamic_pointer_cast(to_change); - if (processor) - return processor; - else - { - auto proc_file = std::make_shared(std::move(*to_change), *this, cancel_); - to_change = proc_file; - return proc_file; - } -} - -processor_file_ptr file_manager_impl::add_processor_file(const file_location& file) -{ - std::lock_guard guard(files_mutex); - auto ret = files_.find(file); - if (ret == files_.end()) - { - auto ptr = std::make_shared(file, *this, cancel_); - files_.try_emplace(file, ptr); - return ptr; - } - else - return change_into_processor_file_if_not_already_(ret->second); -} - -processor_file_ptr file_manager_impl::get_processor_file(const file_location& file) -{ - std::lock_guard guard(files_mutex); - auto ret = files_.find(file); - if (ret == files_.end()) - { - return std::make_shared(file, *this); - } - else - return change_into_processor_file_if_not_already_(ret->second); -} - -std::optional file_manager_impl::get_file_content(const utils::resource::resource_location& file_name) +std::optional file_manager_impl::get_file_content( + const utils::resource::resource_location& file_name) const { std::lock_guard guard(files_mutex); auto it = files_.find(file_name); @@ -105,7 +56,7 @@ void file_manager_impl::remove_file(const file_location& file) files_.erase(file); } -file_ptr file_manager_impl::find(const utils::resource::resource_location& key) const +std::shared_ptr file_manager_impl::find(const utils::resource::resource_location& key) const { std::lock_guard guard(files_mutex); auto ret = files_.find(key); @@ -115,16 +66,6 @@ file_ptr file_manager_impl::find(const utils::resource::resource_location& key) return ret->second; } -processor_file_ptr file_manager_impl::find_processor_file(const utils::resource::resource_location& key) -{ - std::lock_guard guard(files_mutex); - auto ret = files_.find(key); - if (ret == files_.end()) - return nullptr; - - return change_into_processor_file_if_not_already_(ret->second); -} - list_directory_result file_manager_impl::list_directory_files(const utils::resource::resource_location& directory) const { return utils::resource::list_directory_files(directory); @@ -146,11 +87,7 @@ void file_manager_impl::prepare_file_for_change_(std::shared_ptr& fil if (file.use_count() == 1) // TODO: possible weak_ptr issue return; // another shared ptr to this file exists, we need to create a copy - auto proc_file = std::dynamic_pointer_cast(file); - if (proc_file) - file = std::make_shared(*file, *this, cancel_); - else - file = std::make_shared(*file); + file = std::make_shared(*file); } open_file_result file_manager_impl::did_open_file( @@ -158,13 +95,14 @@ open_file_result file_manager_impl::did_open_file( { std::lock_guard guard(files_mutex); auto [ret, inserted] = files_.try_emplace(document_loc, std::make_shared(document_loc)); - prepare_file_for_change_(ret->second); + if (ret->second->is_text_loaded() && ret->second->get_text() != text) + prepare_file_for_change_(ret->second); auto changed = ret->second->did_open(std::move(text), version); return inserted ? open_file_result::changed_content : changed; } void file_manager_impl::did_change_file( - const file_location& document_loc, version_t, const document_change* changes, size_t ch_size) + const file_location& document_loc, version_t, const document_change* changes_start, size_t ch_size) { // TODO // the version is the version after the changes -> I don't see how is that useful @@ -177,15 +115,26 @@ void file_manager_impl::did_change_file( if (file == files_.end()) return; // if the file does not exist, no action is taken + if (!ch_size) + return; + prepare_file_for_change_(file->second); - for (size_t i = 0; i < ch_size; ++i) + auto last_whole = changes_start + ch_size; + while (last_whole != changes_start) { - std::string text_s(changes[i].text, changes[i].text_length); - if (changes[i].whole) + --last_whole; + if (last_whole->whole) + break; + } + + for (const auto& change : std::span(last_whole, changes_start + ch_size)) + { + std::string text_s(change.text, change.text_length); + if (change.whole) file->second->did_change(std::move(text_s)); else - file->second->did_change(changes[i].change_range, std::move(text_s)); + file->second->did_change(change.change_range, std::move(text_s)); } } @@ -196,9 +145,11 @@ void file_manager_impl::did_close_file(const file_location& document_loc) if (file == files_.end()) return; - prepare_file_for_change_(file->second); - // close the file externally - file->second->did_close(); + if (!file->second->is_text_loaded() + || file->second->get_text() == utils::resource::load_text(file->second->get_location())) + file->second->did_close(); // close the file externally, content is accurate + else + file->second = std::make_shared(file->second->get_location()); // our version is not accurate // if the file does not exist, no action is taken } diff --git a/parser_library/src/workspaces/file_manager_impl.h b/parser_library/src/workspaces/file_manager_impl.h index fa93ac91a..549c6c5b8 100644 --- a/parser_library/src/workspaces/file_manager_impl.h +++ b/parser_library/src/workspaces/file_manager_impl.h @@ -27,36 +27,28 @@ #include "utils/resource_location.h" namespace hlasm_plugin::parser_library::workspaces { - +class file_impl; #pragma warning(push) #pragma warning(disable : 4250) // Implementation of the file_manager interface. -class file_manager_impl : public file_manager, public diagnosable_impl +class file_manager_impl : public file_manager { mutable std::mutex files_mutex; mutable std::mutex virtual_files_mutex; - std::atomic* cancel_; public: - file_manager_impl(std::atomic* cancel = nullptr) - : cancel_(cancel) {}; + file_manager_impl() = default; file_manager_impl(const file_manager_impl&) = delete; file_manager_impl& operator=(const file_manager_impl&) = delete; file_manager_impl(file_manager_impl&&) = delete; file_manager_impl& operator=(file_manager_impl&&) = delete; - void collect_diags() const override; - void retrieve_fade_messages(std::vector& fms) const override; - - file_ptr add_file(const file_location&) override; - processor_file_ptr add_processor_file(const file_location&) override; - processor_file_ptr get_processor_file(const file_location&) override; + std::shared_ptr add_file(const file_location&) override; void remove_file(const file_location&) override; - file_ptr find(const utils::resource::resource_location& key) const override; - processor_file_ptr find_processor_file(const utils::resource::resource_location& key) override; + std::shared_ptr find(const utils::resource::resource_location& key) const override; list_directory_result list_directory_files(const utils::resource::resource_location& directory) const override; list_directory_result list_directory_subdirs_and_symlinks( @@ -81,7 +73,7 @@ class file_manager_impl : public file_manager, public diagnosable_impl open_file_result update_file(const file_location& document_loc) override; - std::optional get_file_content(const utils::resource::resource_location&) override; + std::optional get_file_content(const utils::resource::resource_location&) const override; private: struct virtual_file_entry @@ -105,8 +97,7 @@ class file_manager_impl : public file_manager, public diagnosable_impl utils::resource::resource_location_hasher> files_; - processor_file_ptr change_into_processor_file_if_not_already_(std::shared_ptr& ret); - void prepare_file_for_change_(std::shared_ptr& file); + static void prepare_file_for_change_(std::shared_ptr& file); protected: const auto& get_files() const { return files_; } diff --git a/parser_library/src/workspaces/processor.h b/parser_library/src/workspaces/processor.h index 819fcff77..fa264fd64 100644 --- a/parser_library/src/workspaces/processor.h +++ b/parser_library/src/workspaces/processor.h @@ -46,7 +46,7 @@ class processor : public virtual diagnosable }; // Interface that represents a file that can be parsed. -class processor_file : public virtual file, public processor +class processor_file : public processor { public: virtual const std::set& dependencies() = 0; @@ -56,6 +56,9 @@ class processor_file : public virtual file, public processor virtual const performance_metrics& get_metrics() = 0; virtual void erase_cache_of_opencode(const utils::resource::resource_location& opencode_file_location) = 0; virtual bool has_lsp_info() const = 0; + virtual void retrieve_fade_messages(std::vector& fms) const = 0; + virtual const file_location& get_location() const = 0; + virtual bool current_version() const = 0; protected: ~processor_file() = default; diff --git a/parser_library/src/workspaces/processor_file_impl.cpp b/parser_library/src/workspaces/processor_file_impl.cpp index 38c958f48..4092b16d5 100644 --- a/parser_library/src/workspaces/processor_file_impl.cpp +++ b/parser_library/src/workspaces/processor_file_impl.cpp @@ -20,30 +20,18 @@ #include #include "file.h" +#include "file_manager.h" namespace hlasm_plugin::parser_library::workspaces { -processor_file_impl::processor_file_impl( - utils::resource::resource_location file_loc, const file_manager& file_mngr, std::atomic* cancel) - : file_impl(std::move(file_loc)) +processor_file_impl::processor_file_impl(std::shared_ptr file, file_manager& file_mngr, std::atomic* cancel) + : file_mngr_(file_mngr) + , file_(std::move(file)) , cancel_(cancel) - , macro_cache_(file_mngr, *this) {}; - -processor_file_impl::processor_file_impl(file_impl&& f_impl, const file_manager& file_mngr, std::atomic* cancel) - : file_impl(std::move(f_impl)) - , cancel_(cancel) - , macro_cache_(file_mngr, *this) -{} - -processor_file_impl::processor_file_impl( - const file_impl& file, const file_manager& file_mngr, std::atomic* cancel) - : file_impl(file) - , cancel_(cancel) - , macro_cache_(file_mngr, *this) + , macro_cache_(file_mngr, *file_) {} -void processor_file_impl::collect_diags() const { file_impl::collect_diags(); } - +void processor_file_impl::collect_diags() const {} bool processor_file_impl::is_once_only() const { return false; } parse_result processor_file_impl::parse(parse_lib_provider& lib_provider, @@ -51,14 +39,14 @@ parse_result processor_file_impl::parse(parse_lib_provider& lib_provider, std::vector pp, virtual_file_monitor* vfm) { - if (!last_analyzer_opencode_) + if (!last_opencode_id_storage_) last_opencode_id_storage_ = std::make_shared(); const bool collect_hl = should_collect_hl(); auto fms = std::make_shared>(); - auto new_analyzer = std::make_unique(get_text(), + auto new_analyzer = std::make_unique(file_->get_text(), analyzer_options { - get_location(), + file_->get_location(), &lib_provider, std::move(asm_opts), collect_hl ? collect_highlighting_info::yes : collect_highlighting_info::no, @@ -82,7 +70,7 @@ parse_result processor_file_impl::parse(parse_lib_provider& lib_provider, dependencies_.clear(); for (auto& file : last_analyzer_->hlasm_ctx().get_visited_files()) - if (file != get_location()) + if (file != file_->get_location()) dependencies_.insert(file); files_to_close_.clear(); @@ -109,9 +97,9 @@ parse_result processor_file_impl::parse_macro( const bool collect_hl = should_collect_hl(ctx.hlasm_ctx.get()); auto fms = std::make_shared>(); - auto a = std::make_unique(get_text(), + auto a = std::make_unique(file_->get_text(), analyzer_options { - get_location(), + file_->get_location(), &lib_provider, std::move(ctx), data, @@ -186,14 +174,36 @@ bool processor_file_impl::should_collect_hl(context::hlasm_context* ctx) const // 1) The file is opened in the editor // 2) HL information was previously requested // 3) this macro is a top-level macro - return get_lsp_editing() || last_analyzer_with_lsp || ctx && ctx->processing_stack().parent().empty(); + return file_->get_lsp_editing() || last_analyzer_with_lsp || ctx && ctx->processing_stack().parent().empty(); } -bool processor_file_impl::has_lsp_info() const { return last_analyzer_with_lsp; } +bool processor_file_impl::has_lsp_info() const { return last_analyzer_ && last_analyzer_with_lsp; } void processor_file_impl::retrieve_fade_messages(std::vector& fms) const { fms.insert(std::end(fms), std::begin(*fade_messages_), std::end(*fade_messages_)); } +const file_location& processor_file_impl::get_location() const { return file_->get_location(); } + +bool processor_file_impl::current_version() const +{ + auto f = file_mngr_.find(get_location()); + return f == file_; +} + +void processor_file_impl::update_source() +{ + last_analyzer_.reset(); + used_files.clear(); + file_ = file_mngr_.add_file(get_location()); +} + +void processor_file_impl::store_used_files(std::unordered_map, + utils::resource::resource_location_hasher> uf) +{ + used_files = std::move(uf); +} + } // namespace hlasm_plugin::parser_library::workspaces diff --git a/parser_library/src/workspaces/processor_file_impl.h b/parser_library/src/workspaces/processor_file_impl.h index ba73ac094..a3001c395 100644 --- a/parser_library/src/workspaces/processor_file_impl.h +++ b/parser_library/src/workspaces/processor_file_impl.h @@ -21,7 +21,7 @@ #include "analyzer.h" #include "fade_messages.h" -#include "file_impl.h" +#include "file.h" #include "macro_cache.h" #include "processor.h" #include "utils/resource_location.h" @@ -33,14 +33,11 @@ class file_manager; // Implementation of the processor_file interface. Uses analyzer to parse the file // Then stores it until the next parsing so it is possible to retrieve parsing // information from it. -class processor_file_impl : public virtual file_impl, public virtual processor_file +class processor_file_impl final : public virtual processor_file, public diagnosable_impl { public: - processor_file_impl(utils::resource::resource_location file_loc, - const file_manager& file_mngr, - std::atomic* cancel = nullptr); - processor_file_impl(file_impl&&, const file_manager& file_mngr, std::atomic* cancel = nullptr); - processor_file_impl(const file_impl& file, const file_manager& file_mngr, std::atomic* cancel = nullptr); + processor_file_impl(std::shared_ptr file, file_manager& file_mngr, std::atomic* cancel = nullptr); + void collect_diags() const override; bool is_once_only() const override; // Starts parser with new (empty) context @@ -61,8 +58,19 @@ class processor_file_impl : public virtual file_impl, public virtual processor_f bool has_lsp_info() const override; void retrieve_fade_messages(std::vector& fms) const override; + const file_location& get_location() const override; + + bool current_version() const override; + + void update_source(); + std::shared_ptr current_source() const { return file_; } + void store_used_files(std::unordered_map, + utils::resource::resource_location_hasher> used_files); private: + file_manager& file_mngr_; + std::shared_ptr file_; std::unique_ptr last_analyzer_ = nullptr; std::shared_ptr last_opencode_id_storage_; bool last_analyzer_opencode_ = false; @@ -75,6 +83,11 @@ class processor_file_impl : public virtual file_impl, public virtual processor_f std::set dependencies_; std::set files_to_close_; + std::unordered_map, + utils::resource::resource_location_hasher> + used_files; + macro_cache macro_cache_; std::shared_ptr> fade_messages_ = diff --git a/parser_library/src/workspaces/workspace.cpp b/parser_library/src/workspaces/workspace.cpp index 010feae39..babaec891 100644 --- a/parser_library/src/workspaces/workspace.cpp +++ b/parser_library/src/workspaces/workspace.cpp @@ -18,14 +18,73 @@ #include #include "context/instruction.h" +#include "file_impl.h" #include "file_manager.h" #include "lsp/item_convertors.h" +#include "processor_file_impl.h" #include "utils/bk_tree.h" #include "utils/levenshtein_distance.h" #include "utils/path.h" namespace hlasm_plugin::parser_library::workspaces { +struct workspace_parse_lib_provider final : public parse_lib_provider +{ + workspace& ws; + std::vector> libraries; + std::unordered_map, + utils::resource::resource_location_hasher> + used_files; + + workspace_parse_lib_provider(workspace& ws, const utils::resource::resource_location& loc) + : ws(ws) + , libraries(ws.get_proc_grp_by_program(loc).libraries()) + {} + + // Inherited via parse_lib_provider + parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override + { + utils::resource::resource_location url; + for (auto&& lib : libraries) + { + if (!lib->has_file(library, &url)) + continue; + + auto found = ws.add_processor_file_impl(url).m_processor_file; + assert(found); + + used_files.try_emplace(url, found->current_source()); + + return found->parse_macro(*this, std::move(ctx), std::move(data)); + } + + return false; + } + bool has_library(const std::string& library, const utils::resource::resource_location&) const override + { + return std::any_of( + libraries.begin(), libraries.end(), [&library](const auto& lib) { return lib->has_file(library); }); + } + std::optional> get_library( + const std::string& library, const utils::resource::resource_location&) const override + { + utils::resource::resource_location url; + for (auto&& lib : libraries) + { + if (!lib->has_file(library, &url)) + continue; + + auto content = ws.file_manager_.get_file_content(url); + if (!content.has_value()) + return std::nullopt; + + return std::make_pair(std::move(content).value(), std::move(url)); + } + return std::nullopt; + } +}; + workspace::workspace(const utils::resource::resource_location& location, const std::string& name, file_manager& file_manager, @@ -67,37 +126,44 @@ void workspace::collect_diags() const used_b4g_configs.emplace(details.alternative_config); m_configuration.copy_diagnostics(*this, used_b4g_configs); + + for (const auto& [_, pfc] : m_processor_files) + collect_diags_from_child(*pfc.m_processor_file); +} + +void workspace::retrieve_fade_messages(std::vector& fms) const +{ + for (const auto& [key, value] : m_processor_files) + value.m_processor_file->retrieve_fade_messages(fms); } -std::vector workspace::find_related_opencodes( +std::vector> workspace::find_related_opencodes( const utils::resource::resource_location& document_loc) const { - std::vector opencodes; + std::vector> opencodes; + + if (auto f = find_processor_file(document_loc)) + opencodes.push_back(f); for (const auto& dep : dependants_) { - auto f = file_manager_.find_processor_file(dep); + auto f = find_processor_file(dep); if (!f) continue; if (f->dependencies().contains(document_loc)) opencodes.push_back(std::move(f)); } - if (opencodes.size()) - return opencodes; - - if (auto f = file_manager_.find_processor_file(document_loc)) - return { f }; - return {}; + return opencodes; } -void workspace::delete_diags(processor_file_ptr file) +void workspace::delete_diags(std::shared_ptr file) { file->diags().clear(); for (const auto& dep : file->dependencies()) { - auto dep_file = file_manager_.find_processor_file(dep); + auto dep_file = find_processor_file(dep); if (dep_file) dep_file->diags().clear(); } @@ -120,19 +186,21 @@ void workspace::reparse_after_config_refresh() // Reparse every opened file when configuration is changed for (auto& [fname, details] : opened_files_) { - auto found = file_manager_.find_processor_file(fname); - if (!found) + auto comp = find_processor_file_impl(fname); + if (!comp) continue; + details.alternative_config = m_configuration.load_alternative_config_if_needed(fname); - if (!found->parse(*this, get_asm_options(fname), get_preprocessor_options(fname), &fm_vfm_)) + workspace_parse_lib_provider ws_lib(*this, fname); + if (!comp->m_processor_file->parse(ws_lib, get_asm_options(fname), get_preprocessor_options(fname), &fm_vfm_)) continue; - (void)parse_successful(found); + (void)parse_successful(*comp, std::move(ws_lib)); } for (const auto& fname : dependants_) { - if (auto found = file_manager_.find_processor_file(fname); found) + if (auto found = find_processor_file(fname); found) filter_and_close_dependencies_(found->files_to_close(), found); } } @@ -144,21 +212,21 @@ bool trigger_reparse(const utils::resource::resource_location& file_location) } } // namespace -std::vector workspace::collect_dependants( - const utils::resource::resource_location& file_location) const +std::vector workspace::collect_dependants( + const utils::resource::resource_location& file_location) { - std::vector result; + std::vector result; for (const auto& dep : dependants_) { - auto f = file_manager_.find_processor_file(dep); - if (!f) + auto component = find_processor_file_impl(dep); + if (!component) continue; - for (auto& dep_location : f->dependencies()) + for (auto& dep_location : component->m_processor_file->dependencies()) { if (dep_location == file_location) { - result.push_back(f); + result.push_back(component); break; } } @@ -184,48 +252,58 @@ workspace_file_info workspace::parse_file( } // TODO: what about removing files??? what if depentands_ points to not existing file? - std::vector files_to_parse; + std::vector files_to_parse; // TODO: apparently just opening a file without changing it triggers reparse - if (auto this_file = file_manager_.find_processor_file(file_location); - file_content_status == open_file_result::changed_content - || file_content_status == open_file_result::changed_lsp && !(this_file && this_file->has_lsp_info())) + if (processor_file_compoments* this_file = nullptr; file_content_status == open_file_result::changed_content + || file_content_status == open_file_result::changed_lsp + && !((this_file = find_processor_file_impl(file_location)) != nullptr + && this_file->m_processor_file->has_lsp_info())) { if (trigger_reparse(file_location)) files_to_parse = collect_dependants(file_location); - if (files_to_parse.empty() && this_file) - files_to_parse.push_back(std::move(this_file)); + if (files_to_parse.empty()) + { + if (!this_file) + this_file = &add_processor_file_impl(file_location); + files_to_parse.push_back(this_file); + } - for (const auto& f : files_to_parse) + for (auto* component : files_to_parse) { - const auto& f_loc = f->get_location(); + const auto& f = component->m_processor_file; + const auto& f_loc = component->m_processor_file->get_location(); auto alt_cfg = m_configuration.load_alternative_config_if_needed(f_loc); if (auto opened_it = opened_files_.find(f_loc); opened_it != opened_files_.end()) opened_it->second.alternative_config = std::move(alt_cfg); - if (!f->parse(*this, get_asm_options(f_loc), get_preprocessor_options(f_loc), &fm_vfm_)) + workspace_parse_lib_provider ws_lib(*this, f_loc); + if (!f->parse(ws_lib, get_asm_options(f_loc), get_preprocessor_options(f_loc), &fm_vfm_)) continue; - ws_file_info = parse_successful(f); + ws_file_info = parse_successful(*component, std::move(ws_lib)); } // second check after all dependants are there to close all files that used to be dependencies - for (const auto& f : files_to_parse) - filter_and_close_dependencies_(f->files_to_close(), f); + for (const auto* component : files_to_parse) + filter_and_close_dependencies_(component->m_processor_file->files_to_close(), component->m_processor_file); } return ws_file_info; } -workspace_file_info workspace::parse_successful(const processor_file_ptr& f) +workspace_file_info workspace::parse_successful(processor_file_compoments& comp, workspace_parse_lib_provider libs) { workspace_file_info ws_file_info; + const auto& f = comp.m_processor_file; + if (!f->dependencies().empty()) dependants_.insert(f->get_location()); + f->store_used_files(std::move(libs.used_files)); const processor_group& grp = get_proc_grp_by_program(f->get_location()); f->collect_diags(); @@ -269,13 +347,13 @@ void workspace::did_close_file(const utils::resource::resource_location& file_lo auto fname = dependants_.find(file_location); if (fname != dependants_.end()) { - auto file = file_manager_.find_processor_file(*fname); + auto file = find_processor_file(*fname); // filter the dependencies that should not be closed filter_and_close_dependencies_(file->dependencies(), file); // Erase macros cached for this opencode from all its dependencies for (const auto& dep : file->dependencies()) { - auto proc_file = file_manager_.get_processor_file(dep); + auto proc_file = find_processor_file(dep); if (proc_file) proc_file->erase_cache_of_opencode(file_location); } @@ -284,6 +362,7 @@ void workspace::did_close_file(const utils::resource::resource_location& file_lo } // close the file itself + m_processor_files.erase(file_location); file_manager_.did_close_file(file_location); file_manager_.remove_file(file_location); } @@ -482,6 +561,17 @@ lsp::document_symbol_list_s workspace::document_symbol( return {}; } +std::vector workspace::semantic_tokens(const utils::resource::resource_location& document_loc) const +{ + auto comp = find_processor_file_impl(document_loc); + const auto& f = comp->m_processor_file; + + if (!f || !f->current_source()) + return {}; + + return f->get_hl_info(); +} + void workspace::open() { opened_ = true; @@ -628,21 +718,18 @@ std::vector> workspace::make_opcode_suggestion( } void workspace::filter_and_close_dependencies_( - const std::set& dependencies, processor_file_ptr file) + const std::set& dependencies, std::shared_ptr file) { std::set filtered; // filters out externally open files for (const auto& dependency : dependencies) - { - auto dependency_file = file_manager_.find_processor_file(dependency); - if (dependency_file && !dependency_file->get_lsp_editing()) + if (auto dep_file = file_manager_.find(dependency); dep_file && !dep_file->get_lsp_editing()) filtered.insert(dependency); - } // filters the files that are dependencies of other dependants and externally open files for (const auto& dependant : dependants_) { - auto fdependant = file_manager_.find_processor_file(dependant); + auto fdependant = find_processor_file(dependant); if (!fdependant) continue; for (auto& dependency : fdependant->dependencies()) @@ -655,16 +742,17 @@ void workspace::filter_and_close_dependencies_( // close all exclusive dependencies of file for (auto& dep : filtered) { + m_processor_files.erase(dep); file_manager_.did_close_file(dep); file_manager_.remove_file(dep); } } -bool workspace::is_dependency_(const utils::resource::resource_location& file_location) +bool workspace::is_dependency_(const utils::resource::resource_location& file_location) const { for (const auto& dependant : dependants_) { - auto fdependant = file_manager_.find_processor_file(dependant); + auto fdependant = find_processor_file(dependant); if (!fdependant) continue; for (auto& dependency : fdependant->dependencies()) @@ -676,49 +764,6 @@ bool workspace::is_dependency_(const utils::resource::resource_location& file_lo return false; } -parse_result workspace::parse_library(const std::string& library, analyzing_context ctx, library_data data) -{ - utils::resource::resource_location url; - auto& proc_grp = get_proc_grp_by_program(ctx.hlasm_ctx->opencode_location()); - for (auto&& lib : proc_grp.libraries()) - { - if (!lib->has_file(library, &url)) - continue; - - std::shared_ptr found = file_manager_.add_processor_file(url); - assert(found); - return found->parse_macro(*this, std::move(ctx), data); - } - - return false; -} - -bool workspace::has_library(const std::string& library, const utils::resource::resource_location& program) const -{ - const auto& libs = get_proc_grp_by_program(program).libraries(); - - return std::any_of(libs.begin(), libs.end(), [&library](const auto& lib) { return lib->has_file(library); }); -} - -std::optional> workspace::get_library( - const std::string& library, const utils::resource::resource_location& program) const -{ - utils::resource::resource_location url; - auto& proc_grp = get_proc_grp_by_program(program); - for (auto&& lib : proc_grp.libraries()) - { - if (!lib->has_file(library, &url)) - continue; - - auto content = file_manager_.get_file_content(url); - if (!content.has_value()) - return std::nullopt; - - return std::make_pair(std::move(content).value(), std::move(url)); - } - return std::nullopt; -} - std::vector> workspace::get_libraries( const utils::resource::resource_location& file_location) const { @@ -758,9 +803,61 @@ std::vector workspace::get_preprocessor_options( return get_proc_grp_by_program(file_location).preprocessors(); } -processor_file_ptr workspace::get_processor_file(const utils::resource::resource_location& file_location) +std::shared_ptr workspace::add_processor_file(const utils::resource::resource_location& file_location) { - return get_file_manager().get_processor_file(file_location); + return add_processor_file_impl(file_location).m_processor_file; +} + +workspace::processor_file_compoments& workspace::add_processor_file_impl( + const utils::resource::resource_location& file_location) +{ + if (auto p = find_processor_file_impl(file_location)) + return *p; + + processor_file_compoments pfc { + std::make_shared(file_manager_.add_file(file_location), file_manager_, cancel_), + }; + + return m_processor_files.insert_or_assign(file_location, std::move(pfc)).first->second; +} + +std::shared_ptr workspace::find_processor_file( + const utils::resource::resource_location& file_location) const +{ + auto p = find_processor_file_impl(file_location); + if (!p) + return {}; + return p->m_processor_file; +} + +void workspace::processor_file_compoments::update_source_if_needed() const +{ + if (!m_processor_file->current_version()) + { + m_processor_file->update_source(); + } +} + +workspace::processor_file_compoments* workspace::find_processor_file_impl( + const utils::resource::resource_location& file_location) +{ + if (auto it = m_processor_files.find(file_location); it != m_processor_files.end()) + { + it->second.update_source_if_needed(); + return &it->second; + } + return nullptr; +} + +const workspace::processor_file_compoments* workspace::find_processor_file_impl( + const utils::resource::resource_location& file_location) const +{ + if (auto it = m_processor_files.find(file_location); it != m_processor_files.end()) + { + it->second.update_source_if_needed(); + return &it->second; + } + return nullptr; } } // namespace hlasm_plugin::parser_library::workspaces diff --git a/parser_library/src/workspaces/workspace.h b/parser_library/src/workspaces/workspace.h index fcbbd2c8f..f232ce2d9 100644 --- a/parser_library/src/workspaces/workspace.h +++ b/parser_library/src/workspaces/workspace.h @@ -38,13 +38,14 @@ namespace hlasm_plugin::parser_library::workspaces { class file_manager; class library; +class processor_file_impl; using ws_uri = std::string; using ws_highlight_info = std::unordered_map; - +struct workspace_parse_lib_provider; // Represents a LSP workspace. It solves all dependencies between files - // implements parse lib provider and decides which files are to be parsed // when a particular file has been changed in the editor. -class workspace : public diagnosable_impl, public parse_lib_provider +class workspace : public diagnosable_impl { public: // Creates just a dummy workspace with no libraries - no dependencies @@ -75,7 +76,6 @@ class workspace : public diagnosable_impl, public parse_lib_provider workspace_file_info parse_file( const utils::resource::resource_location& file_location, open_file_result file_content_status); - workspace_file_info parse_successful(const processor_file_ptr& f); bool refresh_libraries(const std::vector& file_locations); workspace_file_info did_open_file(const utils::resource::resource_location& file_location, open_file_result file_content_status = open_file_result::changed_content); @@ -94,10 +94,8 @@ class workspace : public diagnosable_impl, public parse_lib_provider lsp::document_symbol_list_s document_symbol( const utils::resource::resource_location& document_loc, long long limit) const; - parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override; - bool has_library(const std::string& library, const utils::resource::resource_location& program) const override; - std::optional> get_library( - const std::string& library, const utils::resource::resource_location& program) const override; + std::vector semantic_tokens(const utils::resource::resource_location& document_loc) const; + virtual std::vector> get_libraries( const utils::resource::resource_location& file_location) const; virtual asm_option get_asm_options(const utils::resource::resource_location& file_location) const; @@ -110,7 +108,8 @@ class workspace : public diagnosable_impl, public parse_lib_provider void set_message_consumer(message_consumer* consumer); - processor_file_ptr get_processor_file(const utils::resource::resource_location& file_location); + std::shared_ptr add_processor_file(const utils::resource::resource_location& file); + std::shared_ptr find_processor_file(const utils::resource::resource_location& file) const; file_manager& get_file_manager() const; @@ -122,6 +121,8 @@ class workspace : public diagnosable_impl, public parse_lib_provider std::vector> make_opcode_suggestion( const utils::resource::resource_location& file, std::string_view opcode, bool extended); + void retrieve_fade_messages(std::vector& fms) const; + static lsp::completion_list_s generate_completion(const lsp::completion_list_source& cls, std::function(std::string_view)> instruction_suggestions = {}); @@ -157,12 +158,12 @@ class workspace : public diagnosable_impl, public parse_lib_provider opened_files_; void filter_and_close_dependencies_( - const std::set& dependencies, processor_file_ptr file); - bool is_dependency_(const utils::resource::resource_location& file_location); + const std::set& dependencies, std::shared_ptr file); + bool is_dependency_(const utils::resource::resource_location& file_location) const; - std::vector find_related_opencodes( + std::vector> find_related_opencodes( const utils::resource::resource_location& document_loc) const; - void delete_diags(processor_file_ptr file); + void delete_diags(std::shared_ptr file); void show_message(const std::string& message); @@ -174,6 +175,17 @@ class workspace : public diagnosable_impl, public parse_lib_provider workspace_configuration m_configuration; + struct processor_file_compoments + { + std::shared_ptr m_processor_file; + void update_source_if_needed() const; + }; + + std::unordered_map + m_processor_files; + static lsp::completion_list_s generate_completion( std::monostate, const std::function(std::string_view)>& instruction_suggestions); static lsp::completion_list_s generate_completion(const lsp::vardef_storage*, @@ -183,7 +195,13 @@ class workspace : public diagnosable_impl, public parse_lib_provider static lsp::completion_list_s generate_completion(const lsp::completion_list_instructions&, const std::function(std::string_view)>& instruction_suggestions); - std::vector collect_dependants(const utils::resource::resource_location& file_location) const; + std::vector collect_dependants(const utils::resource::resource_location& file_location); + + processor_file_compoments& add_processor_file_impl(const utils::resource::resource_location& file); + processor_file_compoments* find_processor_file_impl(const utils::resource::resource_location& file); + const processor_file_compoments* find_processor_file_impl(const utils::resource::resource_location& file) const; + friend struct workspace_parse_lib_provider; + workspace_file_info parse_successful(processor_file_compoments& comp, workspace_parse_lib_provider libs); }; } // namespace hlasm_plugin::parser_library::workspaces diff --git a/parser_library/test/debugging/debugger_test.cpp b/parser_library/test/debugging/debugger_test.cpp index 66a22274c..26f387593 100644 --- a/parser_library/test/debugging/debugger_test.cpp +++ b/parser_library/test/debugging/debugger_test.cpp @@ -389,13 +389,6 @@ class workspace_mock : public workspace : workspace(file_mngr, config, global_settings) {} - parse_result parse_library(const std::string&, analyzing_context, library_data) override - { - assert(false); - - return false; - } - std::vector> get_libraries(const resource_location&) const override { struct debugger_mock_library : library diff --git a/parser_library/test/workspace/CMakeLists.txt b/parser_library/test/workspace/CMakeLists.txt index 4d910f3cf..7802e24b7 100644 --- a/parser_library/test/workspace/CMakeLists.txt +++ b/parser_library/test/workspace/CMakeLists.txt @@ -18,7 +18,6 @@ target_sources(library_test PRIVATE extension_handling_test.cpp file_manager_impl_test.cpp file_manager_mock.h - file_with_text.h files_parse_lib_provider.h instruction_sets_test.cpp library_mock.h diff --git a/parser_library/test/workspace/b4g_integration_test.cpp b/parser_library/test/workspace/b4g_integration_test.cpp index 7c3a88911..eb486e74a 100644 --- a/parser_library/test/workspace/b4g_integration_test.cpp +++ b/parser_library/test/workspace/b4g_integration_test.cpp @@ -129,20 +129,16 @@ TEST(b4g_integration_test, basic_pgm_conf_retrieval) ws.did_open_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(ws.diags().empty()); - EXPECT_TRUE(matches_message_text(file_manager.diags(), { "SYS/SUB/ASMMACP1/MAC1", "ASMMACP1/MAC2" })); + EXPECT_TRUE(matches_message_text(ws.diags(), { "SYS/SUB/ASMMACP1/MAC1", "ASMMACP1/MAC2" })); + ws.diags().clear(); ws.did_close_file(resource_location("SYS/SUB/ASMPGM/A")); - file_manager.diags().clear(); ws.did_open_file(resource_location("SYS/SUB/ASMPGM/B")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(ws.diags().empty()); - EXPECT_TRUE(matches_message_text(file_manager.diags(), { "SYS/SUB/ASMMACP2/MAC1", "ASMMACP2/MAC2" })); + EXPECT_TRUE(matches_message_text(ws.diags(), { "SYS/SUB/ASMMACP2/MAC1", "ASMMACP2/MAC2" })); ws.did_close_file(resource_location("SYS/SUB/ASMPGM/B")); } @@ -162,9 +158,7 @@ TEST(b4g_integration_test, invalid_bridge_json) ws.did_open_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(file_manager.diags().empty()); EXPECT_TRUE(matches_message_codes(ws.diags(), { "B4G001" })); } @@ -185,9 +179,7 @@ TEST(b4g_integration_test, missing_pgroup) ws.did_open_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(file_manager.diags().empty()); EXPECT_TRUE(matches_message_codes(ws.diags(), { "B4G002", "B4G002" })); } @@ -210,9 +202,7 @@ TEST(b4g_integration_test, missing_pgroup_but_not_used) ws.did_close_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(file_manager.diags().empty()); EXPECT_TRUE(ws.diags().empty()); } @@ -240,13 +230,10 @@ TEST(b4g_integration_test, bridge_config_changed) ws.did_open_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(matches_message_codes(file_manager.diags(), { "E049" })); - EXPECT_TRUE(matches_message_codes(ws.diags(), { "B4G001" })); + EXPECT_TRUE(matches_message_codes(ws.diags(), { "E049", "B4G001" })); ws.diags().clear(); - file_manager.diags().clear(); std::string_view new_bridge_json = R"({"elements":{},"defaultProcessorGroup":"P1","fileExtension":""})"; document_change doc_change(new_bridge_json.data(), new_bridge_json.size()); @@ -254,10 +241,8 @@ TEST(b4g_integration_test, bridge_config_changed) ws.did_change_file(resource_location("SYS/SUB/ASMPGM/.bridge.json"), &doc_change, 1); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(matches_message_codes(file_manager.diags(), { "MNOTE" })); - EXPECT_TRUE(ws.diags().empty()); + EXPECT_TRUE(matches_message_codes(ws.diags(), { "MNOTE" })); } TEST(b4g_integration_test, proc_config_changed) @@ -284,13 +269,10 @@ TEST(b4g_integration_test, proc_config_changed) ws.did_open_file(resource_location("SYS/SUB/ASMPGM/A")); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(matches_message_codes(file_manager.diags(), { "E049" })); - EXPECT_TRUE(matches_message_codes(ws.diags(), { "B4G002" })); + EXPECT_TRUE(matches_message_codes(ws.diags(), { "E049", "B4G002" })); ws.diags().clear(); - file_manager.diags().clear(); std::string_view new_bridge_json = R"({"pgroups":[{"name":"P1","libs":[{"path":"ASMMAC","prefer_alternate_root":true}]}]})"; @@ -299,8 +281,6 @@ TEST(b4g_integration_test, proc_config_changed) ws.did_change_file(resource_location(".hlasmplugin/proc_grps.json"), &doc_change, 1); ws.collect_diags(); - file_manager.collect_diags(); - EXPECT_TRUE(matches_message_codes(file_manager.diags(), { "MNOTE" })); - EXPECT_TRUE(ws.diags().empty()); + EXPECT_TRUE(matches_message_codes(ws.diags(), { "MNOTE" })); } diff --git a/parser_library/test/workspace/diags_suppress_test.cpp b/parser_library/test/workspace/diags_suppress_test.cpp index 4554b81bb..fa89566c6 100644 --- a/parser_library/test/workspace/diags_suppress_test.cpp +++ b/parser_library/test/workspace/diags_suppress_test.cpp @@ -65,7 +65,7 @@ TEST(diags_suppress, no_suppress) ws.open(); ws.did_open_file(file_loc); - auto pfile = fm.find(file_loc); + auto pfile = ws.find_processor_file(file_loc); ASSERT_TRUE(pfile); pfile->collect_diags(); @@ -97,7 +97,7 @@ TEST(diags_suppress, do_suppress) ws.open(); ws.did_open_file(file_loc); - auto pfile = fm.find(file_loc); + auto pfile = ws.find_processor_file(file_loc); ASSERT_TRUE(pfile); pfile->collect_diags(); @@ -127,7 +127,7 @@ TEST(diags_suppress, pgm_supress_limit_changed) ws.open(); ws.did_open_file(file_loc); - auto pfile = fm.find(file_loc); + auto pfile = ws.find_processor_file(file_loc); ASSERT_TRUE(pfile); pfile->collect_diags(); @@ -142,7 +142,7 @@ TEST(diags_suppress, pgm_supress_limit_changed) ws.did_change_file(file_loc, &ch, 1); - pfile = fm.find(file_loc); + pfile = ws.find_processor_file(file_loc); ASSERT_TRUE(pfile); pfile->collect_diags(); EXPECT_TRUE(matches_message_codes(pfile->diags(), { "SUP" })); @@ -171,9 +171,9 @@ TEST(diags_suppress, cancel_token) ws.open(); ws.did_open_file(file_loc); - auto pfile = fm.find(file_loc); + auto pfile = ws.find_processor_file(file_loc); ASSERT_TRUE(pfile); pfile->collect_diags(); - EXPECT_TRUE(matches_message_codes(pfile->diags(), { "SUP" })); + EXPECT_TRUE(pfile->diags().empty()); } diff --git a/parser_library/test/workspace/file_manager_mock.h b/parser_library/test/workspace/file_manager_mock.h index 7ed558176..25e3be044 100644 --- a/parser_library/test/workspace/file_manager_mock.h +++ b/parser_library/test/workspace/file_manager_mock.h @@ -27,12 +27,9 @@ class file_manager_mock : public file_manager, public diagnosable_impl { // nothing to do } - MOCK_METHOD(file_ptr, add_file, (const file_location&), (override)); - MOCK_METHOD(processor_file_ptr, add_processor_file, (const file_location&), (override)); - MOCK_METHOD(processor_file_ptr, get_processor_file, (const file_location&), (override)); + MOCK_METHOD(std::shared_ptr, add_file, (const file_location&), (override)); MOCK_METHOD(void, remove_file, (const file_location&), (override)); - MOCK_METHOD(file_ptr, find, (const file_location& key), (const override)); - MOCK_METHOD(processor_file_ptr, find_processor_file, (const file_location& key), (override)); + MOCK_METHOD(std::shared_ptr, find, (const file_location& key), (const override)); MOCK_METHOD(list_directory_result, list_directory_files, (const hlasm_plugin::utils::resource::resource_location& path), @@ -79,7 +76,7 @@ class file_manager_mock : public file_manager, public diagnosable_impl MOCK_METHOD(std::optional, get_file_content, (const hlasm_plugin::utils::resource::resource_location&), - (override)); + (const override)); MOCK_METHOD(void, retrieve_fade_messages, (std::vector&), (const override)); }; diff --git a/parser_library/test/workspace/file_with_text.h b/parser_library/test/workspace/file_with_text.h deleted file mode 100644 index 1fc473db7..000000000 --- a/parser_library/test/workspace/file_with_text.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2021 Broadcom. - * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Broadcom, Inc. - initial API and implementation - */ -#ifndef TEST_WORKSPACE_WORKSPACE_FILE_WITH_TEXT_TEST_H -#define TEST_WORKSPACE_WORKSPACE_FILE_WITH_TEXT_TEST_H - -#include "utils/resource_location.h" -#include "workspaces/processor_file_impl.h" - -class file_with_text : public hlasm_plugin::parser_library::workspaces::processor_file_impl -{ -public: - file_with_text(const hlasm_plugin::utils::resource::resource_location& location, - const std::string& text, - const hlasm_plugin::parser_library::workspaces::file_manager& file_mngr) - : file_impl(location) - , processor_file_impl(location, file_mngr) - { - did_open(text, 1); - } - - const std::string& get_text() override { return get_text_ref(); } - - hlasm_plugin::parser_library::workspaces::update_file_result update_and_get_bad() override - { - return hlasm_plugin::parser_library::workspaces::update_file_result::changed; - } -}; - -#endif diff --git a/parser_library/test/workspace/files_parse_lib_provider.h b/parser_library/test/workspace/files_parse_lib_provider.h index 0a5898692..a021b2652 100644 --- a/parser_library/test/workspace/files_parse_lib_provider.h +++ b/parser_library/test/workspace/files_parse_lib_provider.h @@ -21,18 +21,21 @@ #include "analyzer.h" #include "workspaces/file_manager.h" +#include "workspaces/workspace.h" namespace hlasm_plugin::parser_library::workspaces { struct files_parse_lib_provider : public workspaces::parse_lib_provider { file_manager* file_mngr; - files_parse_lib_provider(file_manager& mngr) + workspace* ws; + files_parse_lib_provider(file_manager& mngr, workspace& ws) : file_mngr(&mngr) + , ws(&ws) {} parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override { - auto macro = file_mngr->add_processor_file(utils::resource::resource_location(library)); + auto macro = ws->add_processor_file(utils::resource::resource_location(library)); if (!macro) return false; return macro->parse_macro(*this, std::move(ctx), std::move(data)); @@ -44,7 +47,7 @@ struct files_parse_lib_provider : public workspaces::parse_lib_provider std::optional> get_library( const std::string& library, const utils::resource::resource_location&) const override { - auto macro = file_mngr->add_processor_file(utils::resource::resource_location(library)); + auto macro = file_mngr->find(utils::resource::resource_location(library)); if (!macro) return std::nullopt; return std::pair( diff --git a/parser_library/test/workspace/instruction_sets_test.cpp b/parser_library/test/workspace/instruction_sets_test.cpp index 4898307ee..5918741da 100644 --- a/parser_library/test/workspace/instruction_sets_test.cpp +++ b/parser_library/test/workspace/instruction_sets_test.cpp @@ -19,7 +19,6 @@ #include "../common_testing.h" #include "../workspace/empty_configs.h" -#include "file_with_text.h" #include "utils/path.h" #include "utils/platform.h" #include "utils/resource_location.h" @@ -36,11 +35,10 @@ class workspace_instruction_sets_test : public diagnosable_impl, public testing: { public: void collect_diags() const override {} - size_t collect_and_get_diags_size(workspace& ws, file_manager& file_mngr) + size_t collect_and_get_diags_size(workspace& ws) { diags().clear(); collect_diags_from_child(ws); - collect_diags_from_child(file_mngr); return diags().size(); } }; @@ -169,12 +167,12 @@ TEST_F(workspace_instruction_sets_test, changed_instr_set_370_Z10) ws.open(); ws.did_open_file(source_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)0); // Change instruction set change_instruction_set({ { 0, 0 }, { 12, 1 } }, pgroups_file_optable_Z10, file_manager, ws); - collect_and_get_diags_size(ws, file_manager); + collect_and_get_diags_size(ws); EXPECT_TRUE(matches_message_codes(diags(), { "E049" })); } @@ -187,11 +185,11 @@ TEST_F(workspace_instruction_sets_test, changed_instr_set_Z10_370) ws.open(); ws.did_open_file(source_loc); - collect_and_get_diags_size(ws, file_manager); + collect_and_get_diags_size(ws); EXPECT_TRUE(matches_message_codes(diags(), { "E049" })); // Change instruction set change_instruction_set({ { 0, 0 }, { 12, 1 } }, pgroups_file_optable_370, file_manager, ws); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); -} \ No newline at end of file + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)0); +} diff --git a/parser_library/test/workspace/load_config_test.cpp b/parser_library/test/workspace/load_config_test.cpp index e24d78ea5..b5a84a0d8 100644 --- a/parser_library/test/workspace/load_config_test.cpp +++ b/parser_library/test/workspace/load_config_test.cpp @@ -179,7 +179,7 @@ class file_pgm_conf : public file_impl class file_manager_proc_grps_test : public file_manager_impl { public: - std::optional get_file_content(const resource_location& location) override + std::optional get_file_content(const resource_location& location) const override { if (hlasm_plugin::utils::resource::filename(location) == "proc_grps.json") return proc_grps->get_text(); @@ -570,7 +570,7 @@ TEST(workspace, lsp_file_not_processed_yet) ws.open(); mngr.did_open_file(file_loc, 0, " LR 1,1"); - auto file = mngr.add_processor_file(file_loc); + auto file = ws.add_processor_file(file_loc); // Prior to parsing, it should return default values const auto* fp = file->get_lsp_context(); diff --git a/parser_library/test/workspace/macro_cache_test.cpp b/parser_library/test/workspace/macro_cache_test.cpp index 6cbe7c9b6..ef719190f 100644 --- a/parser_library/test/workspace/macro_cache_test.cpp +++ b/parser_library/test/workspace/macro_cache_test.cpp @@ -17,9 +17,9 @@ #include "gtest/gtest.h" +#include "../workspace/empty_configs.h" #include "analyzer.h" #include "context/id_storage.h" -#include "file_with_text.h" #include "files_parse_lib_provider.h" #include "utils/resource_location.h" #include "workspaces/file_manager_impl.h" @@ -36,8 +36,8 @@ struct file_manager_cache_test_mock : public file_manager_impl, public parse_lib { const static inline size_t lib_prefix_length = 4; - std::unordered_map, resource_location_hasher> files_by_location_; - std::unordered_map, macro_cache>> files_by_library_; + std::unordered_map, resource_location_hasher> files_by_location_; + std::unordered_map, macro_cache>> files_by_library_; std::shared_ptr hlasm_ctx; @@ -45,12 +45,11 @@ struct file_manager_cache_test_mock : public file_manager_impl, public parse_lib { auto file_loc = resource_location(file_name); - auto file = std::make_shared(file_loc, text, *this); + did_open_file(file_loc, {}, text); + auto f = file_manager_impl::find(file_loc); - auto [it, succ] = files_by_library_.emplace(file_name.substr(lib_prefix_length), - std::pair, macro_cache>( - std::piecewise_construct, std::forward_as_tuple(file), std::forward_as_tuple(*this, *file))); - files_by_location_.emplace(std::move(file_loc), file); + auto [it, succ] = files_by_library_.try_emplace(file_name.substr(lib_prefix_length), f, macro_cache(*this, *f)); + files_by_location_.emplace(std::move(file_loc), f); return it->second; } @@ -59,19 +58,20 @@ struct file_manager_cache_test_mock : public file_manager_impl, public parse_lib { auto file_loc = resource_location(file_name); - auto file = std::make_shared(file_loc, text, *this); - files_by_location_.emplace(std::move(file_loc), file); - return file; + did_open_file(file_loc, {}, text); + auto f = file_manager_impl::find(file_loc); + files_by_location_.emplace(std::move(file_loc), f); + return f; } - file_ptr find(const resource_location& key) const override + std::shared_ptr find(const resource_location& key) const override { auto it = files_by_location_.find(key); return it == files_by_location_.end() ? nullptr : it->second; }; - std::pair get_proc_file_from_library(const std::string& library) + std::pair, macro_cache*> get_proc_file_from_library(const std::string& library) { auto it = files_by_library_.find(library); if (it == files_by_library_.end()) @@ -149,11 +149,17 @@ TEST(macro_cache_test, copy_from_macro) )"; file_manager_cache_test_mock file_mngr; + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(file_mngr, config, global_settings); + ws.open(); - auto opencode = file_mngr.add_opencode(opencode_file_name, opencode_text); + file_mngr.add_opencode(opencode_file_name, opencode_text); auto& [macro, macro_c] = file_mngr.add_macro_or_copy(macro_file_name, macro_text); auto& [copyfile, copy_c] = file_mngr.add_macro_or_copy(copyfile_file_name, copyfile_text); + auto opencode = ws.add_processor_file(opencode_file_loc); + opencode->parse(file_mngr, {}, {}, nullptr); opencode->collect_diags(); @@ -215,9 +221,15 @@ SETA OPSYN LR )"; file_manager_cache_test_mock file_mngr; - auto opencode = file_mngr.add_opencode(opencode_file_name, opencode_text); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(file_mngr, config, global_settings); + ws.open(); + auto opencode_file = file_mngr.add_opencode(opencode_file_name, opencode_text); auto& [macro, macro_c] = file_mngr.add_macro_or_copy(macro_file_name, macro_text); + auto opencode = ws.add_processor_file(opencode_file_loc); + opencode->parse(file_mngr, {}, {}, nullptr); opencode->collect_diags(); EXPECT_EQ(opencode->diags().size(), 0U); @@ -242,7 +254,8 @@ SETA OPSYN LR - opencode->did_change({}, "L OPSYN SETB\n"); + opencode_file->did_change({}, "L OPSYN SETB\n"); + EXPECT_EQ(opencode, ws.add_processor_file(opencode_file_loc)); opencode->parse(file_mngr, {}, {}, nullptr); analyzing_context ctx_second_opsyn1 = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); @@ -273,8 +286,14 @@ TEST(macro_cache_test, empty_macro) std::string macro_text = ""; file_manager_cache_test_mock file_mngr; - auto opencode = file_mngr.add_opencode(opencode_file_name, opencode_text); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(file_mngr, config, global_settings); + ws.open(); + + file_mngr.add_opencode(opencode_file_name, opencode_text); auto& [macro, macro_c] = file_mngr.add_macro_or_copy(macro_file_name, macro_text); + auto opencode = ws.add_processor_file(opencode_file_loc); opencode->parse(file_mngr, {}, {}, nullptr); @@ -359,11 +378,15 @@ TEST(macro_cache_test, overwrite_by_inline) )"; file_manager_impl file_mngr; - files_parse_lib_provider lib_provider(file_mngr); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(file_mngr, config, global_settings); + ws.open(); + files_parse_lib_provider lib_provider(file_mngr, ws); file_mngr.did_open_file(opencode_file_loc, 0, opencode_text); file_mngr.did_open_file(macro_file_loc, 0, macro_text); - auto opencode = file_mngr.add_processor_file(opencode_file_loc); + auto opencode = ws.add_processor_file(opencode_file_loc); opencode->parse(lib_provider, {}, {}, nullptr); opencode->collect_diags(); @@ -398,8 +421,13 @@ TEST(macro_cache_test, inline_depends_on_copy) std::string copy_text = R"( LR 1,1 arbitrary instruction)"; file_manager_cache_test_mock file_mngr; - auto opencode = file_mngr.add_opencode(opencode_file_name, opencode_text); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(file_mngr, config, global_settings); + ws.open(); + file_mngr.add_opencode(opencode_file_name, opencode_text); auto& [copyfile, copy_c] = file_mngr.add_macro_or_copy(copy_file_name, copy_text); + auto opencode = ws.add_processor_file(opencode_file_loc); opencode->parse(file_mngr, {}, {}, nullptr); opencode->collect_diags(); diff --git a/parser_library/test/workspace/processor_file_test.cpp b/parser_library/test/workspace/processor_file_test.cpp index df30304e7..10d789dd3 100644 --- a/parser_library/test/workspace/processor_file_test.cpp +++ b/parser_library/test/workspace/processor_file_test.cpp @@ -15,10 +15,12 @@ #include "gtest/gtest.h" #include "../gtest_stringers.h" +#include "../workspace/empty_configs.h" #include "files_parse_lib_provider.h" #include "utils/resource_location.h" #include "workspaces/file_manager_impl.h" #include "workspaces/processor_file_impl.h" +#include "workspaces/workspace.h" using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::workspaces; @@ -29,7 +31,11 @@ TEST(processor_file, no_lsp_context) resource_location file_loc("filename"); file_manager_impl mngr; mngr.did_open_file(file_loc, 0, " LR 1,1"); - auto file = mngr.add_processor_file(file_loc); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(mngr, config, global_settings); + ws.open(); + auto file = ws.add_processor_file(file_loc); // Prior to parsing, there is no lsp_context available @@ -43,16 +49,20 @@ TEST(processor_file, parse_macro) resource_location macro_loc("MAC"); file_manager_impl mngr; - files_parse_lib_provider provider(mngr); + lib_config config; + shared_json global_settings = make_empty_shared_json(); + workspace ws(mngr, config, global_settings); + ws.open(); + files_parse_lib_provider provider(mngr, ws); mngr.did_open_file(opencode_loc, 0, " SAM31\n MAC"); - auto opencode = mngr.add_processor_file(opencode_loc); + auto opencode = ws.add_processor_file(opencode_loc); mngr.did_open_file(macro_loc, 0, R"( MACRO MAC SAM31 MEND)"); - auto macro = mngr.add_processor_file(macro_loc); + auto macro = ws.add_processor_file(macro_loc); opencode->parse(provider, {}, {}, nullptr); diff --git a/parser_library/test/workspace/workspace_test.cpp b/parser_library/test/workspace/workspace_test.cpp index 472c74688..7e9bbd935 100644 --- a/parser_library/test/workspace/workspace_test.cpp +++ b/parser_library/test/workspace/workspace_test.cpp @@ -18,7 +18,6 @@ #include "gtest/gtest.h" #include "empty_configs.h" -#include "file_with_text.h" #include "utils/path.h" #include "utils/platform.h" #include "utils/resource_location.h" @@ -40,11 +39,10 @@ class workspace_test : public diagnosable_impl, public testing::Test { public: void collect_diags() const override {} - size_t collect_and_get_diags_size(workspace& ws, file_manager& file_mngr) + size_t collect_and_get_diags_size(workspace& ws) { diags().clear(); collect_diags_from_child(ws); - collect_diags_from_child(file_mngr); return diags().size(); } @@ -65,54 +63,10 @@ class workspace_test : public diagnosable_impl, public testing::Test } return true; } -}; - -TEST_F(workspace_test, parse_lib_provider) -{ - using namespace hlasm_plugin::utils; lib_config config; shared_json global_settings = make_empty_shared_json(); - file_manager_impl file_mngr; - - std::string test_wks_path = path::join(path::join("test", "library"), "test_wks").string(); - - workspace ws(resource_location(test_wks_path), file_mngr, config, global_settings); - - ws.open(); - - collect_diags_from_child(ws); - collect_diags_from_child(file_mngr); - EXPECT_EQ(diags().size(), (size_t)0); - - file_mngr.add_processor_file(correct_loc); - - auto [ctx_1, ctx_2] = [&ws]() { - ws.did_open_file(correct_loc); - return std::make_pair(std::make_shared(correct_loc), - std::make_shared(correct_loc)); - }(); - - collect_diags_from_child(file_mngr); - EXPECT_EQ(diags().size(), (size_t)0); - - diags().clear(); - - auto macro1 = context::id_index("MACRO1"); - ws.parse_library("MACRO1", - analyzing_context { ctx_1, std::make_shared(ctx_1) }, - library_data { processing::processing_kind::MACRO, macro1 }); - - // test, that macro1 is parsed, once we are able to parse macros (mby in ctx) - - collect_diags_from_child(ws); - EXPECT_EQ(diags().size(), (size_t)0); - - auto not_existing = context::id_index("NOT_EXISTING"); - ws.parse_library("not_existing", - analyzing_context { ctx_2, std::make_shared(ctx_2) }, - library_data { processing::processing_kind::MACRO, not_existing }); -} +}; namespace { std::string pgroups_file = R"({ @@ -381,8 +335,6 @@ class file_manager_opt : public file_manager_impl TEST_F(workspace_test, did_close_file) { - lib_config config; - shared_json global_settings = make_empty_shared_json(); file_manager_extended file_manager; workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); @@ -393,18 +345,18 @@ TEST_F(workspace_test, did_close_file) // on first reparse, there should be 3 diagnostics from sources and lib/ERROR file ws.did_open_file(source1_loc); ws.did_open_file(source2_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)3); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)3); EXPECT_TRUE(match_strings({ faulty_macro_loc, source2_loc, source1_loc })); // when we close source1, only its diagnostics should disappear // macro's and source2's diagnostics should stay as it is still open ws.did_close_file(source1_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)2); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)2); EXPECT_TRUE(match_strings({ faulty_macro_loc, source2_loc })); // even though we close the ERROR macro, its diagnostics will still be there as it is a dependency of source2 ws.did_close_file(faulty_macro_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)2); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)2); EXPECT_TRUE(match_strings({ faulty_macro_loc, source2_loc })); // if we remove the line using ERROR macro in the source2. its diagnostics will be removed as it is no longer a @@ -414,30 +366,28 @@ TEST_F(workspace_test, did_close_file) changes.push_back(document_change({ { 0, 0 }, { 0, 6 } }, new_text.c_str(), new_text.size())); file_manager.did_change_file(source2_loc, 1, changes.data(), changes.size()); ws.did_change_file(source2_loc, changes.data(), changes.size()); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(match_strings({ source2_loc })); // finally if we close the last source2 file, its diagnostics will disappear as well ws.did_close_file(source2_loc); - ASSERT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); + ASSERT_EQ(collect_and_get_diags_size(ws), (size_t)0); } TEST_F(workspace_test, did_change_watched_files) { file_manager_extended file_manager; - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); // no diagnostics with no syntax errors ws.did_open_file(source3_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)0); // remove the macro, there should still be 1 diagnostic E049 that the ERROR was not found file_manager.insert_correct_macro = false; ws.did_change_watched_files({ correct_macro_loc }); - ASSERT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)1); + ASSERT_EQ(collect_and_get_diags_size(ws), (size_t)1); EXPECT_STREQ(diags()[0].code.c_str(), "E049"); // put it back and make some change in the source file, the diagnostic will disappear @@ -447,25 +397,23 @@ TEST_F(workspace_test, did_change_watched_files) std::string new_text = ""; changes.push_back(document_change({ { 0, 0 }, { 0, 0 } }, new_text.c_str(), new_text.size())); ws.did_change_file(source3_loc, changes.data(), changes.size()); - ASSERT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); + ASSERT_EQ(collect_and_get_diags_size(ws), (size_t)0); } TEST_F(workspace_test, diagnostics_recollection) { file_manager_opt file_manager(file_manager_opt_variant::required); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); ws.did_open_file(source1_loc); ws.collect_diags(); - size_t original_diags_size = collect_and_get_diags_size(ws, file_manager); + size_t original_diags_size = collect_and_get_diags_size(ws); EXPECT_GE(original_diags_size, (size_t)1); ws.collect_diags(); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), original_diags_size); + EXPECT_EQ(collect_and_get_diags_size(ws), original_diags_size); } TEST_F(workspace_test, missing_library_required) @@ -475,13 +423,11 @@ TEST_F(workspace_test, missing_library_required) file_manager_opt_variant::required }) { file_manager_opt file_manager(type); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); ws.did_open_file(source1_loc); - EXPECT_GE(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_GE(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(std::any_of(diags().begin(), diags().end(), [](const auto& d) { return d.code == "L0002"; })); } } @@ -489,48 +435,40 @@ TEST_F(workspace_test, missing_library_required) TEST_F(workspace_test, missing_library_optional) { file_manager_opt file_manager(file_manager_opt_variant::optional); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); ws.did_open_file(source1_loc); - EXPECT_EQ(collect_and_get_diags_size(ws, file_manager), (size_t)0); + EXPECT_EQ(collect_and_get_diags_size(ws), (size_t)0); } TEST_F(workspace_test, invalid_assembler_options) { file_manager_opt file_manager(file_manager_opt_variant::invalid_assembler_options); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); - EXPECT_GE(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_GE(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(std::any_of(diags().begin(), diags().end(), [](const auto& d) { return d.code == "W0005"; })); } TEST_F(workspace_test, invalid_assembler_options_in_pgm_conf) { file_manager_opt file_manager(file_manager_opt_variant::invalid_assembler_options_in_pgm_conf); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); - EXPECT_GE(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_GE(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(std::any_of(diags().begin(), diags().end(), [](const auto& d) { return d.code == "W0005"; })); } TEST_F(workspace_test, invalid_preprocessor_options) { file_manager_opt file_manager(file_manager_opt_variant::invalid_preprocessor_options); - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); - EXPECT_GE(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_GE(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(std::any_of(diags().begin(), diags().end(), [](const auto& d) { return d.code == "W0006"; })); } @@ -554,13 +492,11 @@ class file_manager_list_dir_failed : public file_manager_opt TEST_F(workspace_test, library_list_failure) { file_manager_list_dir_failed file_manager; - lib_config config; - shared_json global_settings = make_empty_shared_json(); workspace ws(empty_loc, "workspace_name", file_manager, config, global_settings); ws.open(); ws.did_open_file(source1_loc); - EXPECT_GE(collect_and_get_diags_size(ws, file_manager), (size_t)1); + EXPECT_GE(collect_and_get_diags_size(ws), (size_t)1); EXPECT_TRUE(std::any_of(diags().begin(), diags().end(), [](const auto& d) { return d.code == "L0001"; })); }