From 4ba42b17f407fdcc039185e5607f8e7b3c30d4f7 Mon Sep 17 00:00:00 2001 From: slavek-kucera <53339291+slavek-kucera@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:16:24 +0100 Subject: [PATCH] Resolve lifetime issues related to macro dependencies (part 2) --- parser_library/fuzzer/fuzzer.cpp | 11 +- parser_library/src/analyzer.cpp | 4 +- parser_library/src/analyzing_context.h | 10 +- .../src/checking/asm_instr_check.cpp | 3 +- .../src/config/assembler_options.cpp | 11 +- parser_library/src/context/common_types.cpp | 14 - parser_library/src/context/common_types.h | 4 - parser_library/src/context/id_storage.cpp | 7 +- .../src/debugging/debug_lib_provider.cpp | 6 +- .../src/debugging/debug_lib_provider.h | 6 +- .../src/library_info_transitional.cpp | 3 +- .../src/library_info_transitional.h | 9 +- parser_library/src/lsp/CMakeLists.txt | 1 + .../src/lsp/completion_list_source.h | 54 +++ parser_library/src/lsp/item_convertors.cpp | 110 ++++- parser_library/src/lsp/item_convertors.h | 17 +- parser_library/src/lsp/lsp_context.cpp | 3 + parser_library/src/lsp/lsp_context.h | 14 +- .../grammar/assembler_operand_rules.g4 | 4 +- .../parsing/grammar/hlasmparser_multiline.g4 | 1 + .../parsing/grammar/hlasmparser_singleline.g4 | 1 + parser_library/src/parsing/parser_impl.cpp | 3 +- .../instruction_sets/asm_processor.cpp | 3 +- .../instruction_sets/instruction_processor.h | 2 +- .../src/processing/opencode_provider.cpp | 8 +- .../preprocessors/cics_preprocessor.cpp | 7 +- .../preprocessors/db2_preprocessor.cpp | 2 +- .../preprocessors/endevor_preprocessor.cpp | 3 +- .../src/processing/processing_manager.cpp | 2 + .../lookahead_processor.cpp | 6 +- .../ordinary_processor.cpp | 2 +- .../members_statement_provider.cpp | 7 +- parser_library/src/protocol.cpp | 1 + parser_library/src/workspace_manager_impl.h | 2 + .../src/workspaces/library_local.cpp | 3 +- parser_library/src/workspaces/macro_cache.cpp | 16 +- parser_library/src/workspaces/macro_cache.h | 8 +- .../src/workspaces/parse_lib_provider.h | 14 +- .../src/workspaces/processor_file_impl.cpp | 70 ++-- .../src/workspaces/processor_file_impl.h | 2 - parser_library/src/workspaces/workspace.cpp | 127 +----- parser_library/src/workspaces/workspace.h | 20 +- .../workspaces/workspace_configuration.cpp | 1 + parser_library/test/CMakeLists.txt | 1 + .../debugging/debug_lib_provider_test.cpp | 8 +- parser_library/test/gtest_stringers.cpp | 70 ++++ parser_library/test/gtest_stringers.h | 59 +-- parser_library/test/lsp/CMakeLists.txt | 1 + parser_library/test/lsp/lsp_completion.cpp | 80 ++++ .../lsp/lsp_context_copy_in_macro_test.cpp | 1 + .../lsp_context_document_symbol_ord_test.cpp | 2 + ...p_context_document_symbol_var_seq_test.cpp | 2 + .../test/lsp/lsp_context_instr_test.cpp | 6 +- .../lsp_context_macro_documentation_test.cpp | 2 + .../lsp_context_macro_in_opencode_test.cpp | 2 +- .../lsp/lsp_context_nested_macro_test.cpp | 1 + .../test/lsp/lsp_context_ord_sym_test.cpp | 2 + .../lsp/lsp_context_preprocessor_test.cpp | 1 + .../test/lsp/lsp_context_seq_sym_test.cpp | 2 + .../test/lsp/lsp_context_var_sym_test.cpp | 1 + parser_library/test/lsp/lsp_features_test.cpp | 1 + parser_library/test/mock_parse_lib_provider.h | 16 +- .../test/parsing/deferred_statement_test.cpp | 1 + .../test/processing/lookahead_test.cpp | 1 + parser_library/test/workspace/CMakeLists.txt | 1 - .../test/workspace/files_parse_lib_provider.h | 60 --- .../test/workspace/load_config_test.cpp | 25 +- .../test/workspace/macro_cache_test.cpp | 390 ++++++++---------- .../test/workspace/processor_file_test.cpp | 57 ++- .../test/workspace/workspace_test.cpp | 58 --- utils/include/utils/string_operations.h | 4 + utils/src/string_operations.cpp | 14 + 72 files changed, 763 insertions(+), 708 deletions(-) create mode 100644 parser_library/src/lsp/completion_list_source.h create mode 100644 parser_library/test/gtest_stringers.cpp create mode 100644 parser_library/test/lsp/lsp_completion.cpp delete mode 100644 parser_library/test/workspace/files_parse_lib_provider.h diff --git a/parser_library/fuzzer/fuzzer.cpp b/parser_library/fuzzer/fuzzer.cpp index 35f5562b4..3bbf472f6 100644 --- a/parser_library/fuzzer/fuzzer.cpp +++ b/parser_library/fuzzer/fuzzer.cpp @@ -35,7 +35,7 @@ using namespace hlasm_plugin::parser_library::workspaces; class fuzzer_lib_provider : public parse_lib_provider { - std::optional read_library_name(const std::string& library) const + std::optional read_library_name(std::string_view library) const { if (library.size() < 2 || library.size() > 8 || library[0] != '@' || std::any_of(library.begin() + 1, library.end(), [](unsigned char c) { return !isdigit(c); })) @@ -50,7 +50,7 @@ class fuzzer_lib_provider : public parse_lib_provider } public: - parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override + parse_result parse_library(std::string_view library, analyzing_context ctx, library_data data) override { auto lib = read_library_name(library); if (!lib.has_value()) @@ -63,13 +63,10 @@ class fuzzer_lib_provider : public parse_lib_provider return true; } - bool has_library(const std::string& library, const hlasm_plugin::utils::resource::resource_location&) const override - { - return read_library_name(library).has_value(); - } + bool has_library(std::string_view library) const override { return read_library_name(library).has_value(); } std::optional> get_library( - const std::string& library, const hlasm_plugin::utils::resource::resource_location&) const override + std::string_view library) const override { auto lib = read_library_name(library); if (!lib.has_value()) diff --git a/parser_library/src/analyzer.cpp b/parser_library/src/analyzer.cpp index f02dc5e96..288f664a1 100644 --- a/parser_library/src/analyzer.cpp +++ b/parser_library/src/analyzer.cpp @@ -15,6 +15,7 @@ #include "analyzer.h" #include "hlasmparser_multiline.h" +#include "lsp/lsp_context.h" #include "processing/opencode_provider.h" #include "processing/preprocessor.h" @@ -114,8 +115,7 @@ analyzer::analyzer(std::string_view text, analyzer_options opts) src_proc_, *this, opts.get_preprocessor( - [libs = &opts.get_lib_provider(), program = opts.file_loc]( - std::string_view library) { return libs->get_library(std::string(library), program); }, + [libs = &opts.get_lib_provider()](std::string_view library) { return libs->get_library(library); }, *this, src_proc_), opts.parsing_opencode == file_is_opencode::yes ? processing::opencode_provider_options { true, 10 } diff --git a/parser_library/src/analyzing_context.h b/parser_library/src/analyzing_context.h index 039b63c8e..990d20739 100644 --- a/parser_library/src/analyzing_context.h +++ b/parser_library/src/analyzing_context.h @@ -15,11 +15,15 @@ #ifndef HLASMPARSER_PARSERLIBRARY_ANALYZING_CONTEXT_H #define HLASMPARSER_PARSERLIBRARY_ANALYZING_CONTEXT_H -#include "context/hlasm_context.h" -#include "lsp/lsp_context.h" +#include namespace hlasm_plugin::parser_library { - +namespace context { +class hlasm_context; +} // namespace context +namespace lsp { +class lsp_context; +} // namespace lsp struct analyzing_context { diff --git a/parser_library/src/checking/asm_instr_check.cpp b/parser_library/src/checking/asm_instr_check.cpp index fafdc7ca9..7a9ce789c 100644 --- a/parser_library/src/checking/asm_instr_check.cpp +++ b/parser_library/src/checking/asm_instr_check.cpp @@ -21,6 +21,7 @@ #include "context/common_types.h" #include "diagnostic_collector.h" #include "lexing/tools.h" +#include "utils/string_operations.h" namespace { const std::vector rmode_options = { "24", "31", "64", "ANY" }; @@ -662,7 +663,7 @@ bool external::check(const std::vector& to_check, if (auto complex_op = get_complex_operand(operand); complex_op) { // check PART operand - if (context::to_upper_copy(complex_op->operand_identifier) != "PART") + if (utils::to_upper_copy(complex_op->operand_identifier) != "PART") { add_diagnostic(diagnostic_op::error_A129_EXTRN_format(operand->operand_range)); return false; diff --git a/parser_library/src/config/assembler_options.cpp b/parser_library/src/config/assembler_options.cpp index 13b070935..4c73c224e 100644 --- a/parser_library/src/config/assembler_options.cpp +++ b/parser_library/src/config/assembler_options.cpp @@ -18,6 +18,7 @@ #include "compiler_options.h" #include "nlohmann/json.hpp" +#include "utils/string_operations.h" namespace hlasm_plugin::parser_library::config { @@ -129,16 +130,10 @@ static_assert(std::is_sorted(std::begin(instr_set_machine_equivalents), [](const auto& l, const auto& r) { return l.first < r.first; })); #endif -void to_upper(std::string& s) -{ - for (auto& c : s) - c = static_cast(std::toupper((unsigned char)c)); -} - bool instr_set_equivalent_valid( std::string instr_set_name, std::span equivalents) noexcept { - to_upper(instr_set_name); + utils::to_upper(instr_set_name); #ifdef __cpp_lib_ranges return instr_set_name.size() == 0 @@ -169,7 +164,7 @@ namespace { std::optional find_instruction_set( std::string instr_set_name, const std::span equivalents) { - to_upper(instr_set_name); + utils::to_upper(instr_set_name); #ifdef __cpp_lib_ranges auto it = std::ranges::lower_bound(equivalents, instr_set_name, {}, [](const auto& instr) { return instr.first; }); diff --git a/parser_library/src/context/common_types.cpp b/parser_library/src/context/common_types.cpp index d2b80bcc1..31d870585 100644 --- a/parser_library/src/context/common_types.cpp +++ b/parser_library/src/context/common_types.cpp @@ -19,20 +19,6 @@ namespace hlasm_plugin::parser_library::context { -std::string& to_upper(std::string& s) -{ - for (auto& c : s) - c = static_cast(std::toupper((unsigned char)c)); - return s; -} - -std::string to_upper_copy(std::string s) -{ - for (auto& c : s) - c = static_cast(std::toupper((unsigned char)c)); - return s; -} - SET_t::SET_t(context::A_t value) : a_value(value) , b_value(value) diff --git a/parser_library/src/context/common_types.h b/parser_library/src/context/common_types.h index 1f18ee57f..9a8f01f7c 100644 --- a/parser_library/src/context/common_types.h +++ b/parser_library/src/context/common_types.h @@ -119,9 +119,5 @@ struct SET_t bool operator==(const SET_t& r) const noexcept; }; -// just mock method for now, will be implemented later with respect to UTF/EBCDIC -std::string& to_upper(std::string& s); -std::string to_upper_copy(std::string s); - } // namespace hlasm_plugin::parser_library::context #endif diff --git a/parser_library/src/context/id_storage.cpp b/parser_library/src/context/id_storage.cpp index 731dd5c85..7589702f0 100644 --- a/parser_library/src/context/id_storage.cpp +++ b/parser_library/src/context/id_storage.cpp @@ -17,6 +17,7 @@ #include #include "common_types.h" +#include "utils/string_operations.h" using namespace hlasm_plugin::parser_library::context; @@ -36,7 +37,7 @@ std::optional id_storage::find(std::string_view value) const if (value.size() < id_index::buffer_size) return small_id(value); - if (auto tmp = lit_.find(to_upper_copy(std::string(value))); tmp != lit_.end()) + if (auto tmp = lit_.find(utils::to_upper_copy(std::string(value))); tmp != lit_.end()) return id_index(std::to_address(tmp)); else return std::nullopt; @@ -47,7 +48,7 @@ id_index id_storage::add(std::string_view value) if (value.size() < id_index::buffer_size) return small_id(value); - return id_index(std::to_address(lit_.insert(to_upper_copy(std::string(value))).first)); + return id_index(std::to_address(lit_.insert(utils::to_upper_copy(std::string(value))).first)); } id_index id_storage::add(std::string&& value) @@ -55,7 +56,7 @@ id_index id_storage::add(std::string&& value) if (value.size() < id_index::buffer_size) return small_id(value); - to_upper(value); + utils::to_upper(value); return id_index(std::to_address(lit_.insert(std::move(value)).first)); } diff --git a/parser_library/src/debugging/debug_lib_provider.cpp b/parser_library/src/debugging/debug_lib_provider.cpp index 11262ab22..1d53759d0 100644 --- a/parser_library/src/debugging/debug_lib_provider.cpp +++ b/parser_library/src/debugging/debug_lib_provider.cpp @@ -30,7 +30,7 @@ debug_lib_provider::debug_lib_provider(std::vectorhas_file(library)) @@ -67,7 +67,7 @@ bool debug_lib_provider::has_library(const std::string& library, const utils::re } std::optional> debug_lib_provider::get_library( - const std::string& library, const utils::resource::resource_location&) const + std::string_view library) const { utils::resource::resource_location url; for (const auto& lib : m_libraries) diff --git a/parser_library/src/debugging/debug_lib_provider.h b/parser_library/src/debugging/debug_lib_provider.h index 0ae4a1a52..2d3541020 100644 --- a/parser_library/src/debugging/debug_lib_provider.h +++ b/parser_library/src/debugging/debug_lib_provider.h @@ -51,12 +51,12 @@ class debug_lib_provider final : public workspaces::parse_lib_provider std::atomic* cancel); workspaces::parse_result parse_library( - const std::string& library, analyzing_context ctx, workspaces::library_data data) override; + std::string_view library, analyzing_context ctx, workspaces::library_data data) override; - bool has_library(const std::string& library, const utils::resource::resource_location& program) const override; + bool has_library(std::string_view library) const override; std::optional> get_library( - const std::string& library, const utils::resource::resource_location& program) const override; + std::string_view library) const override; }; } // namespace hlasm_plugin::parser_library::debugging diff --git a/parser_library/src/library_info_transitional.cpp b/parser_library/src/library_info_transitional.cpp index bec594aa2..5d05cbb13 100644 --- a/parser_library/src/library_info_transitional.cpp +++ b/parser_library/src/library_info_transitional.cpp @@ -25,8 +25,7 @@ namespace hlasm_plugin::parser_library { bool library_info_transitional::has_library(std::string_view member) const { - return m_lib_provider->has_library( - std::string(member), m_hlasm_ctx ? m_hlasm_ctx->opencode_location() : empty_location); + return m_lib_provider->has_library(member); } const library_info_transitional library_info_transitional::empty(workspaces::empty_parse_lib_provider::instance); diff --git a/parser_library/src/library_info_transitional.h b/parser_library/src/library_info_transitional.h index 0bbb77f49..363420a77 100644 --- a/parser_library/src/library_info_transitional.h +++ b/parser_library/src/library_info_transitional.h @@ -28,19 +28,12 @@ class parse_lib_provider; class library_info_transitional final : public library_info { workspaces::parse_lib_provider* m_lib_provider; - const context::hlasm_context* m_hlasm_ctx = nullptr; - - explicit library_info_transitional(workspaces::parse_lib_provider& lib_provider) - : m_lib_provider(&lib_provider) - {} public: bool has_library(std::string_view member) const override; - explicit library_info_transitional( - workspaces::parse_lib_provider& lib_provider, const context::hlasm_context& hlasm_ctx) + explicit library_info_transitional(workspaces::parse_lib_provider& lib_provider) : m_lib_provider(&lib_provider) - , m_hlasm_ctx(&hlasm_ctx) {} static const library_info_transitional empty; diff --git a/parser_library/src/lsp/CMakeLists.txt b/parser_library/src/lsp/CMakeLists.txt index fad34d10d..90253c8ab 100644 --- a/parser_library/src/lsp/CMakeLists.txt +++ b/parser_library/src/lsp/CMakeLists.txt @@ -13,6 +13,7 @@ target_sources(parser_library PRIVATE completion_item.cpp completion_item.h + completion_list_source.h document_symbol_item.cpp document_symbol_item.h file_info.cpp diff --git a/parser_library/src/lsp/completion_list_source.h b/parser_library/src/lsp/completion_list_source.h new file mode 100644 index 000000000..57dc15922 --- /dev/null +++ b/parser_library/src/lsp/completion_list_source.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 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 HLASMPLUGIN_PARSERLIBRARY_LSP_COMPLETION_LIST_SOURCE_H +#define HLASMPLUGIN_PARSERLIBRARY_LSP_COMPLETION_LIST_SOURCE_H + +#include +#include +#include +#include +#include + +namespace hlasm_plugin::parser_library { +namespace context { +class id_index; +class macro_definition; +struct sequence_symbol; +class symbol; +} // namespace context +} // namespace hlasm_plugin::parser_library + +namespace hlasm_plugin::parser_library::lsp { + +class lsp_context; +struct macro_info; +struct variable_symbol_definition; + +struct completion_list_instructions +{ + std::string_view completed_text; + size_t completed_text_start_column; + const std::unordered_map, std::shared_ptr>* macros; + const lsp_context* lsp_ctx; +}; + +using completion_list_source = std::variant*, + const std::unordered_map>*, + completion_list_instructions>; + +} // namespace hlasm_plugin::parser_library::lsp + +#endif diff --git a/parser_library/src/lsp/item_convertors.cpp b/parser_library/src/lsp/item_convertors.cpp index ff988ef82..0a123d96f 100644 --- a/parser_library/src/lsp/item_convertors.cpp +++ b/parser_library/src/lsp/item_convertors.cpp @@ -21,7 +21,8 @@ #include "context/sequence_symbol.h" #include "ebcdic_encoding.h" #include "file_info.h" -#include "macro_info.h" +#include "lsp/lsp_context.h" +#include "lsp/macro_info.h" #include "text_data_view.h" #include "utils/concat.h" #include "utils/string_operations.h" @@ -225,10 +226,115 @@ completion_item_s generate_completion_item(const macro_info& sym, const file_inf const context::macro_definition& m = *sym.macro_definition; return completion_item_s(m.id.to_string(), - lsp::get_macro_signature(m), + get_macro_signature(m), m.id.to_string(), info ? get_macro_documentation(info->data, sym.definition_location.pos.line) : "", completion_item_kind::macro); } + +completion_list_s generate_completion(const completion_list_source& cls, + const std::function(std::string_view)>& instruction_suggestions) +{ + return std::visit( + [&instruction_suggestions](auto v) { return generate_completion(v, instruction_suggestions); }, cls); +} + +completion_list_s generate_completion(std::monostate, const std::function(std::string_view)>&) +{ + return completion_list_s(); +} + +completion_list_s generate_completion( + const vardef_storage* var_defs, const std::function(std::string_view)>&) +{ + completion_list_s items; + for (const auto& vardef : *var_defs) + { + items.emplace_back(generate_completion_item(vardef)); + } + + return items; +} + +completion_list_s generate_completion( + const context::label_storage* seq_syms, const std::function(std::string_view)>&) +{ + completion_list_s items; + items.reserve(seq_syms->size()); + for (const auto& [_, sym] : *seq_syms) + { + items.emplace_back(generate_completion_item(*sym)); + } + return items; +} + +completion_list_s generate_completion(const completion_list_instructions& cli, + const std::function(std::string_view)>& instruction_suggestions) +{ + assert(cli.lsp_ctx); + + const auto& hlasm_ctx = cli.lsp_ctx->get_related_hlasm_context(); + + auto suggestions = [&instruction_suggestions](std::string_view ct) { + std::vector> result; + if (ct.empty() || !instruction_suggestions) + return result; + auto raw_suggestions = instruction_suggestions(ct); + result.reserve(raw_suggestions.size()); + for (auto&& s : raw_suggestions) + result.emplace_back(std::move(s), false); + return result; + }(cli.completed_text); + const auto locate_suggestion = [&s = suggestions](std::string_view text) { + auto it = std::find_if(s.begin(), s.end(), [text](const auto& e) { return e.first == text; }); + return it == s.end() ? nullptr : std::to_address(it); + }; + + completion_list_s result; + + // Store only instructions from the currently active instruction set + for (const auto& instr : completion_item_s::m_instruction_completion_items) + { + auto id = hlasm_ctx.ids().find(instr.label); + // TODO: we could provide more precise results here if actual generation is provided + if (id.has_value() && hlasm_ctx.find_opcode_mnemo(id.value(), context::opcode_generation::zero)) + { + auto& i = result.emplace_back(instr); + if (auto space = i.insert_text.find(' '); space != std::string::npos) + { + if (auto col_pos = cli.completed_text_start_column + space; col_pos < 15) + i.insert_text.insert(i.insert_text.begin() + space, 15 - col_pos, ' '); + } + if (auto* suggestion = locate_suggestion(i.label)) + { + i.suggestion_for = cli.completed_text; + suggestion->second = true; + } + } + } + + for (const auto& [_, macro_i] : *cli.macros) + { + auto& i = result.emplace_back( + generate_completion_item(*macro_i, cli.lsp_ctx->get_file_info(macro_i->definition_location.resource_loc))); + if (auto* suggestion = locate_suggestion(i.label)) + { + i.suggestion_for = cli.completed_text; + suggestion->second = true; + } + } + + for (const auto& [suggestion, used] : suggestions) + { + if (used) + continue; + result.emplace_back( + suggestion, "", suggestion, "", completion_item_kind::macro, false, std::string(cli.completed_text)); + } + + return result; +} + + } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/src/lsp/item_convertors.h b/parser_library/src/lsp/item_convertors.h index 52ec495fe..7e77b8784 100644 --- a/parser_library/src/lsp/item_convertors.h +++ b/parser_library/src/lsp/item_convertors.h @@ -15,9 +15,12 @@ #ifndef HLASMPLUGIN_PARSERLIBRARY_LSP_ITEM_CONVERTORS_H #define HLASMPLUGIN_PARSERLIBRARY_LSP_ITEM_CONVERTORS_H +#include #include #include +#include +#include "completion_list_source.h" namespace hlasm_plugin::parser_library { namespace context { @@ -45,6 +48,18 @@ completion_item_s generate_completion_item(const context::sequence_symbol& sym); completion_item_s generate_completion_item(const variable_symbol_definition& sym); completion_item_s generate_completion_item(const macro_info& sym, const file_info* info); +std::vector generate_completion(const completion_list_source& cls, + const std::function(std::string_view)>& instruction_suggestions = {}); +std::vector generate_completion( + std::monostate, const std::function(std::string_view)>& instruction_suggestions); +std::vector generate_completion(const std::vector*, + const std::function(std::string_view)>& instruction_suggestions); +std::vector generate_completion( + const std::unordered_map>*, + const std::function(std::string_view)>& instruction_suggestions); +std::vector generate_completion(const completion_list_instructions&, + const std::function(std::string_view)>& instruction_suggestions); + } // namespace hlasm_plugin::parser_library::lsp -#endif \ No newline at end of file +#endif diff --git a/parser_library/src/lsp/lsp_context.cpp b/parser_library/src/lsp/lsp_context.cpp index 4a1db233f..e65c73520 100644 --- a/parser_library/src/lsp/lsp_context.cpp +++ b/parser_library/src/lsp/lsp_context.cpp @@ -21,10 +21,13 @@ #include #include #include +#include #include "context/instruction.h" +#include "context/macro.h" #include "ebcdic_encoding.h" #include "item_convertors.h" +#include "lsp/macro_info.h" #include "utils/similar.h" namespace hlasm_plugin::parser_library::lsp { diff --git a/parser_library/src/lsp/lsp_context.h b/parser_library/src/lsp/lsp_context.h index a65c52b32..2fbc8bb4c 100644 --- a/parser_library/src/lsp/lsp_context.h +++ b/parser_library/src/lsp/lsp_context.h @@ -25,6 +25,7 @@ #include #include "completion_item.h" +#include "completion_list_source.h" #include "context/id_storage.h" #include "context/macro.h" #include "document_symbol_item.h" @@ -36,19 +37,6 @@ namespace hlasm_plugin::parser_library::lsp { -class lsp_context; - -struct completion_list_instructions -{ - std::string_view completed_text; - size_t completed_text_start_column; - const std::unordered_map* macros; - const lsp_context* lsp_ctx; -}; - -using completion_list_source = - std::variant; - class lsp_context final { opencode_info_ptr m_opencode; diff --git a/parser_library/src/parsing/grammar/assembler_operand_rules.g4 b/parser_library/src/parsing/grammar/assembler_operand_rules.g4 index 268674c27..98f1775d2 100644 --- a/parser_library/src/parsing/grammar/assembler_operand_rules.g4 +++ b/parser_library/src/parsing/grammar/assembler_operand_rules.g4 @@ -62,9 +62,7 @@ asm_op returns [operand_ptr op] } | { !ALIAS() }? mach_expr { - std::string upper_case = $mach_expr.ctx->getText(); - context::to_upper(upper_case); - $op = std::make_unique(std::move($mach_expr.m_e),upper_case,provider.get_range($mach_expr.ctx)); + $op = std::make_unique(std::move($mach_expr.m_e),utils::to_upper_copy($mach_expr.ctx->getText()),provider.get_range($mach_expr.ctx)); } | string { diff --git a/parser_library/src/parsing/grammar/hlasmparser_multiline.g4 b/parser_library/src/parsing/grammar/hlasmparser_multiline.g4 index f25aed6fc..396cdb024 100644 --- a/parser_library/src/parsing/grammar/hlasmparser_multiline.g4 +++ b/parser_library/src/parsing/grammar/hlasmparser_multiline.g4 @@ -47,6 +47,7 @@ deferred_operand_rules; #include "expressions/mach_operator.h" #include "expressions/data_definition.h" #include "semantics/operand_impls.h" + #include "utils/string_operations.h" namespace hlasm_plugin::parser_library::parsing { diff --git a/parser_library/src/parsing/grammar/hlasmparser_singleline.g4 b/parser_library/src/parsing/grammar/hlasmparser_singleline.g4 index 64e2cf089..beb1bd1ca 100644 --- a/parser_library/src/parsing/grammar/hlasmparser_singleline.g4 +++ b/parser_library/src/parsing/grammar/hlasmparser_singleline.g4 @@ -47,6 +47,7 @@ deferred_operand_rules; #include "expressions/mach_operator.h" #include "expressions/data_definition.h" #include "semantics/operand_impls.h" + #include "utils/string_operations.h" namespace hlasm_plugin::parser_library::parsing { diff --git a/parser_library/src/parsing/parser_impl.cpp b/parser_library/src/parsing/parser_impl.cpp index 2e1816d69..be3c29bec 100644 --- a/parser_library/src/parsing/parser_impl.cpp +++ b/parser_library/src/parsing/parser_impl.cpp @@ -27,6 +27,7 @@ #include "lexing/input_source.h" #include "lexing/token_stream.h" #include "processing/op_code.h" +#include "utils/string_operations.h" namespace hlasm_plugin::parser_library::parsing { @@ -135,7 +136,7 @@ void parser_impl::disable_continuation() { input.disable_continuation(); } bool parser_impl::is_self_def() { std::string tmp(_input->LT(1)->getText()); - context::to_upper(tmp); + utils::to_upper(tmp); return tmp == "B" || tmp == "X" || tmp == "C" || tmp == "G"; } diff --git a/parser_library/src/processing/instruction_sets/asm_processor.cpp b/parser_library/src/processing/instruction_sets/asm_processor.cpp index 352c41fa4..f63b4678e 100644 --- a/parser_library/src/processing/instruction_sets/asm_processor.cpp +++ b/parser_library/src/processing/instruction_sets/asm_processor.cpp @@ -36,6 +36,7 @@ #include "processing/statement_fields_parser.h" #include "range.h" #include "semantics/operand_impls.h" +#include "utils/string_operations.h" #include "utils/unicode_text.h" #include "workspaces/parse_lib_provider.h" @@ -502,7 +503,7 @@ void asm_processor::process_external(rebuilt_statement stmt, external_type t) } else if (auto complex = op_asm->access_complex()) { - if (context::to_upper_copy(complex->value.identifier) != "PART") + if (utils::to_upper_copy(complex->value.identifier) != "PART") continue; for (const auto& nested : complex->value.values) { diff --git a/parser_library/src/processing/instruction_sets/instruction_processor.h b/parser_library/src/processing/instruction_sets/instruction_processor.h index 3de2bb7db..3ff696919 100644 --- a/parser_library/src/processing/instruction_sets/instruction_processor.h +++ b/parser_library/src/processing/instruction_sets/instruction_processor.h @@ -50,7 +50,7 @@ class instruction_processor : public diagnosable_ctx , hlasm_ctx(*ctx.hlasm_ctx) , branch_provider(branch_provider) , lib_provider(lib_provider) - , lib_info(lib_provider, *ctx.hlasm_ctx) + , lib_info(lib_provider) , eval_ctx { *ctx.hlasm_ctx, lib_info, *this } {} diff --git a/parser_library/src/processing/opencode_provider.cpp b/parser_library/src/processing/opencode_provider.cpp index 92fd0d11b..89b64d73d 100644 --- a/parser_library/src/processing/opencode_provider.cpp +++ b/parser_library/src/processing/opencode_provider.cpp @@ -19,6 +19,7 @@ #include "lexing/input_source.h" #include "lexing/token_stream.h" #include "library_info_transitional.h" +#include "lsp/lsp_context.h" #include "parsing/error_strategy.h" #include "parsing/parser_impl.h" #include "processing/error_statement.h" @@ -267,7 +268,7 @@ std::shared_ptr opencode_provider::process_ordin if (proc.kind == processing_kind::ORDINARY && try_trigger_attribute_lookahead(collector.current_instruction(), - { *m_ctx->hlasm_ctx, library_info_transitional(*m_lib_provider, *m_ctx->hlasm_ctx), drop_diags }, + { *m_ctx->hlasm_ctx, library_info_transitional(*m_lib_provider), drop_diags }, *m_state_listener)) return nullptr; @@ -364,9 +365,8 @@ std::shared_ptr opencode_provider::process_ordin auto result = collector.extract_statement(proc_status, statement_range); if (proc.kind == processing_kind::ORDINARY - && try_trigger_attribute_lookahead(*result, - { *m_ctx->hlasm_ctx, library_info_transitional(*m_lib_provider, *m_ctx->hlasm_ctx), drop_diags }, - *m_state_listener)) + && try_trigger_attribute_lookahead( + *result, { *m_ctx->hlasm_ctx, library_info_transitional(*m_lib_provider), drop_diags }, *m_state_listener)) return nullptr; if (m_current_logical_line.segments.size() > 1) diff --git a/parser_library/src/processing/preprocessors/cics_preprocessor.cpp b/parser_library/src/processing/preprocessors/cics_preprocessor.cpp index b0f647431..93171a2f9 100644 --- a/parser_library/src/processing/preprocessors/cics_preprocessor.cpp +++ b/parser_library/src/processing/preprocessors/cics_preprocessor.cpp @@ -37,6 +37,7 @@ #include "semantics/source_info_processor.h" #include "semantics/statement.h" #include "utils/concat.h" +#include "utils/string_operations.h" #include "utils/text_matchers.h" #include "utils/unicode_text.h" #include "workspaces/parse_lib_provider.h" @@ -765,12 +766,12 @@ class mini_parser if (m_matches[1].length() != 0) m_substituted_operands.append("=F'") .append( - std::to_string(DFHRESP_operands.at(context::to_upper_copy(m_matches[1].str())))) + std::to_string(DFHRESP_operands.at(utils::to_upper_copy(m_matches[1].str())))) .append("'"); else if (m_matches[2].length() != 0) m_substituted_operands.append("=F'") - .append(std::to_string( - DFHVALUE_operands.at(context::to_upper_copy(m_matches[2].str())))) + .append( + std::to_string(DFHVALUE_operands.at(utils::to_upper_copy(m_matches[2].str())))) .append("'"); else { diff --git a/parser_library/src/processing/preprocessors/db2_preprocessor.cpp b/parser_library/src/processing/preprocessors/db2_preprocessor.cpp index 66267b4cb..c64717aec 100644 --- a/parser_library/src/processing/preprocessors/db2_preprocessor.cpp +++ b/parser_library/src/processing/preprocessors/db2_preprocessor.cpp @@ -543,7 +543,7 @@ class db2_preprocessor final : public preprocessor // TODO Take DBCS into accoun std::pair process_include_member( line_type instruction_type, std::string member, size_t lineno) { - auto member_upper = context::to_upper_copy(member); + auto member_upper = utils::to_upper_copy(member); if (member_upper == "SQLCA") { diff --git a/parser_library/src/processing/preprocessors/endevor_preprocessor.cpp b/parser_library/src/processing/preprocessors/endevor_preprocessor.cpp index c74af2d3d..37c494494 100644 --- a/parser_library/src/processing/preprocessors/endevor_preprocessor.cpp +++ b/parser_library/src/processing/preprocessors/endevor_preprocessor.cpp @@ -29,6 +29,7 @@ #include "range.h" #include "semantics/source_info_processor.h" #include "utils/resource_location.h" +#include "utils/string_operations.h" namespace hlasm_plugin::parser_library::processing { @@ -66,7 +67,7 @@ class endevor_preprocessor final : public preprocessor bool process_member(std::string_view member, std::vector& stack) { - std::string member_upper = context::to_upper_copy(std::string(member)); + std::string member_upper = utils::to_upper_copy(std::string(member)); if (std::any_of(stack.begin(), stack.end(), [member = std::string_view(member_upper)](const auto& e) { return e.name == member; diff --git a/parser_library/src/processing/processing_manager.cpp b/parser_library/src/processing/processing_manager.cpp index f9eff5bdf..4c74357c7 100644 --- a/parser_library/src/processing/processing_manager.cpp +++ b/parser_library/src/processing/processing_manager.cpp @@ -17,6 +17,8 @@ #include #include +#include "lsp/lsp_context.h" +#include "lsp/text_data_view.h" #include "parsing/parser_impl.h" #include "statement_analyzers/lsp_analyzer.h" #include "statement_processors/copy_processor.h" diff --git a/parser_library/src/processing/statement_processors/lookahead_processor.cpp b/parser_library/src/processing/statement_processors/lookahead_processor.cpp index f3cdfd87b..4c0c9503c 100644 --- a/parser_library/src/processing/statement_processors/lookahead_processor.cpp +++ b/parser_library/src/processing/statement_processors/lookahead_processor.cpp @@ -152,7 +152,7 @@ lookahead_processor::process_table_t lookahead_processor::create_table() void lookahead_processor::assign_EQU_attributes(context::id_index symbol_name, const resolved_statement& statement) { diagnostic_consumer_transform drop_diags([](diagnostic_op) {}); - library_info_transitional li(lib_provider_, *ctx.hlasm_ctx); + library_info_transitional li(lib_provider_); context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, li); // type attribute operand context::symbol_attributes::type_attr t_attr = context::symbol_attributes::undef_type; @@ -237,7 +237,7 @@ void lookahead_processor::assign_data_def_attributes(context::id_index symbol_na context::symbol_attributes::len_attr len = context::symbol_attributes::undef_length; context::symbol_attributes::scale_attr scale = context::symbol_attributes::undef_scale; - library_info_transitional li(lib_provider_, *ctx.hlasm_ctx); + library_info_transitional li(lib_provider_); context::ordinary_assembly_dependency_solver dep_solver(hlasm_ctx.ord_ctx, li); diagnostic_consumer_transform drop_diags([](diagnostic_op) {}); @@ -346,7 +346,7 @@ void lookahead_processor::find_ord(const resolved_statement& statement) void lookahead_processor::register_attr_ref(context::id_index name, context::symbol_attributes attributes) { - library_info_transitional li(lib_provider_, *ctx.hlasm_ctx); + library_info_transitional li(lib_provider_); hlasm_ctx.ord_ctx.add_symbol_reference( context::symbol(name, context::symbol_value(), attributes, location(), {}), li); } diff --git a/parser_library/src/processing/statement_processors/ordinary_processor.cpp b/parser_library/src/processing/statement_processors/ordinary_processor.cpp index 2bf5ac800..0a117560e 100644 --- a/parser_library/src/processing/statement_processors/ordinary_processor.cpp +++ b/parser_library/src/processing/statement_processors/ordinary_processor.cpp @@ -35,7 +35,7 @@ ordinary_processor::ordinary_processor(analyzing_context ctx, const processing_manager& proc_mgr) : statement_processor(processing_kind::ORDINARY, ctx) , lib_provider(lib_provider) - , lib_info(lib_provider, *ctx.hlasm_ctx) + , lib_info(lib_provider) , eval_ctx { *ctx.hlasm_ctx, lib_info, *this } , ca_proc_(ctx, branch_provider, lib_provider, state_listener, open_code) , mac_proc_(ctx, branch_provider, lib_provider) diff --git a/parser_library/src/processing/statement_providers/members_statement_provider.cpp b/parser_library/src/processing/statement_providers/members_statement_provider.cpp index 92c2ee2be..781929267 100644 --- a/parser_library/src/processing/statement_providers/members_statement_provider.cpp +++ b/parser_library/src/processing/statement_providers/members_statement_provider.cpp @@ -48,9 +48,8 @@ context::shared_stmt_ptr members_statement_provider::get_next(const statement_pr { if (const auto* instr = retrieve_instruction(*cache)) { - if (try_trigger_attribute_lookahead(*instr, - { *ctx.hlasm_ctx, library_info_transitional(lib_provider, *ctx.hlasm_ctx), drop_diags }, - listener)) + if (try_trigger_attribute_lookahead( + *instr, { *ctx.hlasm_ctx, library_info_transitional(lib_provider), drop_diags }, listener)) return nullptr; } } @@ -74,7 +73,7 @@ context::shared_stmt_ptr members_statement_provider::get_next(const statement_pr if (processor.kind == processing_kind::ORDINARY && try_trigger_attribute_lookahead( - *stmt, { *ctx.hlasm_ctx, library_info_transitional(lib_provider, *ctx.hlasm_ctx), drop_diags }, listener)) + *stmt, { *ctx.hlasm_ctx, library_info_transitional(lib_provider), drop_diags }, listener)) return nullptr; return stmt; diff --git a/parser_library/src/protocol.cpp b/parser_library/src/protocol.cpp index 10db34b5f..d209657a6 100644 --- a/parser_library/src/protocol.cpp +++ b/parser_library/src/protocol.cpp @@ -19,6 +19,7 @@ #include "fade_messages.h" #include "location.h" #include "lsp/completion_item.h" +#include "lsp/document_symbol_item.h" #include "semantics/highlighting_info.h" #include "workspaces/processor.h" diff --git a/parser_library/src/workspace_manager_impl.h b/parser_library/src/workspace_manager_impl.h index d1286d88e..b1215e67a 100644 --- a/parser_library/src/workspace_manager_impl.h +++ b/parser_library/src/workspace_manager_impl.h @@ -24,6 +24,8 @@ #include #include +#include "lsp/completion_item.h" +#include "lsp/document_symbol_item.h" #include "protocol.h" #include "workspace_manager.h" #include "workspaces/file_manager_impl.h" diff --git a/parser_library/src/workspaces/library_local.cpp b/parser_library/src/workspaces/library_local.cpp index 3657c9cba..bd34a975d 100644 --- a/parser_library/src/workspaces/library_local.cpp +++ b/parser_library/src/workspaces/library_local.cpp @@ -20,6 +20,7 @@ #include "utils/path.h" #include "utils/platform.h" +#include "utils/string_operations.h" #include "wildcard.h" namespace hlasm_plugin::parser_library::workspaces { @@ -159,7 +160,7 @@ library_local::files_collection_t library_local::load_files() else continue; - context::to_upper(file); + utils::to_upper(file); if (auto [it, inserted] = new_files.try_emplace(std::move(file), std::move(rl)); !inserted) { diff --git a/parser_library/src/workspaces/macro_cache.cpp b/parser_library/src/workspaces/macro_cache.cpp index 381bc8b2e..0d4162e43 100644 --- a/parser_library/src/workspaces/macro_cache.cpp +++ b/parser_library/src/workspaces/macro_cache.cpp @@ -17,6 +17,7 @@ #include #include "file_manager.h" +#include "lsp/lsp_context.h" namespace hlasm_plugin::parser_library::workspaces { @@ -25,9 +26,9 @@ void macro_cache::collect_diags() const // No collectible children } -macro_cache::macro_cache(const file_manager& file_mngr, file& macro_file) +macro_cache::macro_cache(const file_manager& file_mngr, std::shared_ptr macro_file) : file_mngr_(&file_mngr) - , macro_file_(¯o_file) + , macro_file_(std::move(macro_file)) {} std::vector macro_cache_key::get_opsyn_state(context::hlasm_context& ctx) @@ -115,7 +116,7 @@ const macro_cache_data* macro_cache::find_cached_data(const macro_cache_key& key return &cached_data; } -bool macro_cache::load_from_cache(const macro_cache_key& key, const analyzing_context& ctx) +bool macro_cache::load_from_cache(const macro_cache_key& key, const analyzing_context& ctx) const { if (auto cached_data = find_cached_data(key)) { @@ -186,14 +187,7 @@ void macro_cache::save_macro(const macro_cache_key& key, const analyzer& analyze void macro_cache::erase_cache_of_opencode(const utils::resource::resource_location& opencode_file_location) { - auto it = cache_.begin(); - while (it != cache_.end()) - { - if (it->first.opencode_file_location == opencode_file_location) - it = cache_.erase(it); - else - ++it; - } + std::erase_if(cache_, [&l = opencode_file_location](const auto& e) { return e.first.opencode_file_location == l; }); } } // namespace hlasm_plugin::parser_library::workspaces diff --git a/parser_library/src/workspaces/macro_cache.h b/parser_library/src/workspaces/macro_cache.h index 3d8a09117..10983c2e8 100644 --- a/parser_library/src/workspaces/macro_cache.h +++ b/parser_library/src/workspaces/macro_cache.h @@ -15,6 +15,8 @@ #ifndef HLASMPLUGIN_PARSERLIBRARY_MACRO_CACHE_H #define HLASMPLUGIN_PARSERLIBRARY_MACRO_CACHE_H +#include + #include "analyzer.h" namespace hlasm_plugin::parser_library::workspaces { @@ -78,13 +80,13 @@ class macro_cache final : public diagnosable_impl { std::map cache_; const file_manager* file_mngr_; - file* macro_file_; + std::shared_ptr macro_file_; public: - macro_cache(const file_manager& file_mngr, file& macro_file); + macro_cache(const file_manager& file_mngr, std::shared_ptr macro_file); // Checks whether any dependencies with specified macro cache key (macro context) have changed. If not, loads the // cached macro to the specified context. Returns true, if the macro was loaded. - bool load_from_cache(const macro_cache_key& key, const analyzing_context& ctx); + bool load_from_cache(const macro_cache_key& key, const analyzing_context& ctx) const; void save_macro(const macro_cache_key& key, const analyzer& analyzer); void erase_cache_of_opencode(const utils::resource::resource_location& opencode_file_location); diff --git a/parser_library/src/workspaces/parse_lib_provider.h b/parser_library/src/workspaces/parse_lib_provider.h index 552e80d0b..9169944da 100644 --- a/parser_library/src/workspaces/parse_lib_provider.h +++ b/parser_library/src/workspaces/parse_lib_provider.h @@ -21,6 +21,8 @@ #include #include "analyzing_context.h" +#include "context/id_storage.h" +#include "processing/processing_format.h" #include "utils/resource_location.h" namespace hlasm_plugin::parser_library::workspaces { @@ -38,12 +40,12 @@ class parse_lib_provider public: // Parses library with specified name and saves it into context. // Library data passes information whether COPY or macro is going to be parsed. - virtual parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) = 0; + virtual parse_result parse_library(std::string_view library, analyzing_context ctx, library_data data) = 0; - virtual bool has_library(const std::string& library, const utils::resource::resource_location& program) const = 0; + virtual bool has_library(std::string_view library) const = 0; virtual std::optional> get_library( - const std::string& library, const utils::resource::resource_location& program) const = 0; + std::string_view library) const = 0; protected: ~parse_lib_provider() = default; @@ -53,10 +55,10 @@ class parse_lib_provider class empty_parse_lib_provider final : public parse_lib_provider { public: - parse_result parse_library(const std::string&, analyzing_context, library_data) override { return false; }; - bool has_library(const std::string&, const utils::resource::resource_location&) const override { return false; }; + parse_result parse_library(std::string_view, analyzing_context, library_data) override { return false; }; + bool has_library(std::string_view) const override { return false; }; std::optional> get_library( - const std::string&, const utils::resource::resource_location&) const override + std::string_view) const override { return std::nullopt; } diff --git a/parser_library/src/workspaces/processor_file_impl.cpp b/parser_library/src/workspaces/processor_file_impl.cpp index 4092b16d5..7d62af060 100644 --- a/parser_library/src/workspaces/processor_file_impl.cpp +++ b/parser_library/src/workspaces/processor_file_impl.cpp @@ -28,7 +28,7 @@ processor_file_impl::processor_file_impl(std::shared_ptr file, file_manage : file_mngr_(file_mngr) , file_(std::move(file)) , cancel_(cancel) - , macro_cache_(file_mngr, *file_) + , macro_cache_(file_mngr, file_) {} void processor_file_impl::collect_diags() const {} @@ -60,31 +60,34 @@ parse_result processor_file_impl::parse(parse_lib_provider& lib_provider, auto old_dep = dependencies_; - auto res = parse_inner(*new_analyzer); + new_analyzer->analyze(cancel_); - if (!cancel_ || !*cancel_) + if (cancel_ && *cancel_) + return false; + + diags().clear(); + collect_diags_from_child(*new_analyzer); + + last_analyzer_ = std::move(new_analyzer); + last_analyzer_opencode_ = true; + last_analyzer_with_lsp = collect_hl; + + dependencies_.clear(); + for (auto& file : last_analyzer_->hlasm_ctx().get_visited_files()) + if (file != file_->get_location()) + dependencies_.insert(file); + + files_to_close_.clear(); + // files that used to be dependencies but are not anymore should be closed internally + for (const auto& file : old_dep) { - last_analyzer_ = std::move(new_analyzer); - last_analyzer_opencode_ = true; - last_analyzer_with_lsp = collect_hl; - - dependencies_.clear(); - for (auto& file : last_analyzer_->hlasm_ctx().get_visited_files()) - if (file != file_->get_location()) - dependencies_.insert(file); - - files_to_close_.clear(); - // files that used to be dependencies but are not anymore should be closed internally - for (const auto& file : old_dep) - { - if (dependencies_.find(file) == dependencies_.end()) - files_to_close_.insert(file); - } - - fade_messages_ = std::move(fms); + if (dependencies_.find(file) == dependencies_.end()) + files_to_close_.insert(file); } - return res; + fade_messages_ = std::move(fms); + + return true; } parse_result processor_file_impl::parse_macro( @@ -107,11 +110,14 @@ parse_result processor_file_impl::parse_macro( fms, }); - auto ret = parse_inner(*a); + a->analyze(cancel_); - if (!ret) // Parsing was interrupted by cancellation token, do not save the result into cache + if (cancel_ && *cancel_) return false; + diags().clear(); + collect_diags_from_child(*a); + macro_cache_.save_macro(cache_key, *a); last_analyzer_ = std::move(a); last_analyzer_opencode_ = false; @@ -119,7 +125,7 @@ parse_result processor_file_impl::parse_macro( fade_messages_ = std::move(fms); - return ret; + return true; } const std::set& processor_file_impl::dependencies() { return dependencies_; } @@ -156,18 +162,6 @@ void processor_file_impl::erase_cache_of_opencode(const utils::resource::resourc macro_cache_.erase_cache_of_opencode(opencode_file_location); } -bool processor_file_impl::parse_inner(analyzer& new_analyzer) -{ - new_analyzer.analyze(cancel_); - - if (cancel_ && *cancel_) - return false; - - diags().clear(); - collect_diags_from_child(new_analyzer); - return true; -} - bool processor_file_impl::should_collect_hl(context::hlasm_context* ctx) const { // collect highlighting information in any of the following cases: @@ -197,6 +191,8 @@ void processor_file_impl::update_source() last_analyzer_.reset(); used_files.clear(); file_ = file_mngr_.add_file(get_location()); + macro_cache_ = macro_cache(file_mngr_, file_); + diags().clear(); } void processor_file_impl::store_used_files(std::unordered_map* cancel_; std::set dependencies_; diff --git a/parser_library/src/workspaces/workspace.cpp b/parser_library/src/workspaces/workspace.cpp index babaec891..919014736 100644 --- a/parser_library/src/workspaces/workspace.cpp +++ b/parser_library/src/workspaces/workspace.cpp @@ -20,7 +20,9 @@ #include "context/instruction.h" #include "file_impl.h" #include "file_manager.h" +#include "lsp/document_symbol_item.h" #include "lsp/item_convertors.h" +#include "lsp/lsp_context.h" #include "processor_file_impl.h" #include "utils/bk_tree.h" #include "utils/levenshtein_distance.h" @@ -43,10 +45,10 @@ struct workspace_parse_lib_provider final : public parse_lib_provider {} // Inherited via parse_lib_provider - parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override + parse_result parse_library(std::string_view library, analyzing_context ctx, library_data data) override { utils::resource::resource_location url; - for (auto&& lib : libraries) + for (const auto& lib : libraries) { if (!lib->has_file(library, &url)) continue; @@ -61,16 +63,16 @@ struct workspace_parse_lib_provider final : public parse_lib_provider return false; } - bool has_library(const std::string& library, const utils::resource::resource_location&) const override + bool has_library(std::string_view library) 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 + std::string_view library) const override { utils::resource::resource_location url; - for (auto&& lib : libraries) + for (const auto& lib : libraries) { if (!lib->has_file(library, &url)) continue; @@ -432,7 +434,7 @@ lsp::completion_list_s workspace::completion(const utils::resource::resource_loc if (!lsp_context) return {}; - return generate_completion(lsp_context->completion(document_loc, pos, trigger_char, trigger_kind), + return lsp::generate_completion(lsp_context->completion(document_loc, pos, trigger_char, trigger_kind), [&document_loc, this](std::string_view opcode) { auto suggestions = make_opcode_suggestion(document_loc, opcode, true); std::vector result; @@ -443,111 +445,6 @@ lsp::completion_list_s workspace::completion(const utils::resource::resource_loc }); } -lsp::completion_list_s workspace::generate_completion(const lsp::completion_list_source& cls, - std::function(std::string_view)> instruction_suggestions) -{ - return std::visit( - [&instruction_suggestions](auto v) { return generate_completion(v, instruction_suggestions); }, cls); -} - -lsp::completion_list_s workspace::generate_completion( - std::monostate, const std::function(std::string_view)>&) -{ - return lsp::completion_list_s(); -} - -lsp::completion_list_s workspace::generate_completion( - const lsp::vardef_storage* var_defs, const std::function(std::string_view)>&) -{ - lsp::completion_list_s items; - for (const auto& vardef : *var_defs) - { - items.emplace_back(lsp::generate_completion_item(vardef)); - } - - return items; -} - -lsp::completion_list_s workspace::generate_completion( - const context::label_storage* seq_syms, const std::function(std::string_view)>&) -{ - lsp::completion_list_s items; - items.reserve(seq_syms->size()); - for (const auto& [_, sym] : *seq_syms) - { - items.emplace_back(lsp::generate_completion_item(*sym)); - } - return items; -} - -lsp::completion_list_s workspace::generate_completion(const lsp::completion_list_instructions& cli, - const std::function(std::string_view)>& instruction_suggestions) -{ - lsp::completion_list_s result; - - assert(cli.lsp_ctx); - - const auto& hlasm_ctx = cli.lsp_ctx->get_related_hlasm_context(); - - auto suggestions = [&instruction_suggestions](std::string_view ct) { - std::vector> result; - if (ct.empty() || !instruction_suggestions) - return result; - auto raw_suggestions = instruction_suggestions(ct); - result.reserve(raw_suggestions.size()); - for (auto&& s : raw_suggestions) - result.emplace_back(std::move(s), false); - return result; - }(cli.completed_text); - const auto locate_suggestion = [&s = suggestions](std::string_view text) { - auto it = std::find_if(s.begin(), s.end(), [text](const auto& e) { return e.first == text; }); - return it == s.end() ? nullptr : std::to_address(it); - }; - - - // Store only instructions from the currently active instruction set - for (const auto& instr : lsp::completion_item_s::m_instruction_completion_items) - { - auto id = hlasm_ctx.ids().find(instr.label); - // TODO: we could provide more precise results here if actual generation is provided - if (id.has_value() && hlasm_ctx.find_opcode_mnemo(id.value(), context::opcode_generation::zero)) - { - auto& i = result.emplace_back(instr); - if (auto space = i.insert_text.find(' '); space != std::string::npos) - { - if (auto col_pos = cli.completed_text_start_column + space; col_pos < 15) - i.insert_text.insert(i.insert_text.begin() + space, 15 - col_pos, ' '); - } - if (auto* suggestion = locate_suggestion(i.label)) - { - i.suggestion_for = cli.completed_text; - suggestion->second = true; - } - } - } - - for (const auto& [_, macro_i] : *cli.macros) - { - auto& i = result.emplace_back(lsp::generate_completion_item( - *macro_i, cli.lsp_ctx->get_file_info(macro_i->definition_location.resource_loc))); - if (auto* suggestion = locate_suggestion(i.label)) - { - i.suggestion_for = cli.completed_text; - suggestion->second = true; - } - } - - for (const auto& [suggestion, used] : suggestions) - { - if (used) - continue; - result.emplace_back( - suggestion, "", suggestion, "", completion_item_kind::macro, false, std::string(cli.completed_text)); - } - - return result; -} - lsp::document_symbol_list_s workspace::document_symbol( const utils::resource::resource_location& document_loc, long long limit) const { @@ -564,6 +461,9 @@ lsp::document_symbol_list_s workspace::document_symbol( std::vector workspace::semantic_tokens(const utils::resource::resource_location& document_loc) const { auto comp = find_processor_file_impl(document_loc); + if (!comp) + return {}; + const auto& f = comp->m_processor_file; if (!f || !f->current_source()) @@ -803,11 +703,6 @@ std::vector workspace::get_preprocessor_options( return get_proc_grp_by_program(file_location).preprocessors(); } -std::shared_ptr workspace::add_processor_file(const utils::resource::resource_location& 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) { diff --git a/parser_library/src/workspaces/workspace.h b/parser_library/src/workspaces/workspace.h index f232ce2d9..b28987d7c 100644 --- a/parser_library/src/workspaces/workspace.h +++ b/parser_library/src/workspaces/workspace.h @@ -16,7 +16,6 @@ #define HLASMPLUGIN_PARSERLIBRARY_WORKSPACE_H #include -#include #include #include #include @@ -85,13 +84,13 @@ class workspace : public diagnosable_impl void did_change_watched_files(const std::vector& file_locations); location definition(const utils::resource::resource_location& document_loc, position pos) const; - location_list references(const utils::resource::resource_location& document_loc, position pos) const; + std::vector references(const utils::resource::resource_location& document_loc, position pos) const; std::string hover(const utils::resource::resource_location& document_loc, position pos) const; - lsp::completion_list_s completion(const utils::resource::resource_location& document_loc, + std::vector completion(const utils::resource::resource_location& document_loc, position pos, char trigger_char, completion_trigger_kind trigger_kind); - lsp::document_symbol_list_s document_symbol( + std::vector document_symbol( const utils::resource::resource_location& document_loc, long long limit) const; std::vector semantic_tokens(const utils::resource::resource_location& document_loc) const; @@ -108,7 +107,6 @@ class workspace : public diagnosable_impl void set_message_consumer(message_consumer* consumer); - 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; @@ -123,9 +121,6 @@ class workspace : public diagnosable_impl 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 = {}); - private: std::atomic* cancel_; @@ -186,15 +181,6 @@ class workspace : public diagnosable_impl utils::resource::resource_location_hasher> 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*, - const std::function(std::string_view)>& instruction_suggestions); - static lsp::completion_list_s generate_completion(const context::label_storage*, - const std::function(std::string_view)>& instruction_suggestions); - 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); processor_file_compoments& add_processor_file_impl(const utils::resource::resource_location& file); diff --git a/parser_library/src/workspaces/workspace_configuration.cpp b/parser_library/src/workspaces/workspace_configuration.cpp index d55de3005..45212f187 100644 --- a/parser_library/src/workspaces/workspace_configuration.cpp +++ b/parser_library/src/workspaces/workspace_configuration.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/parser_library/test/CMakeLists.txt b/parser_library/test/CMakeLists.txt index 458071e34..85ddf77fe 100644 --- a/parser_library/test/CMakeLists.txt +++ b/parser_library/test/CMakeLists.txt @@ -19,6 +19,7 @@ target_sources(library_test PRIVATE diagnosable_ctx_test.cpp diagnostics_check_test.cpp diagnostics_sysvar_test.cpp + gtest_stringers.cpp gtest_stringers.h message_consumer_mock.h metrics_test.cpp diff --git a/parser_library/test/debugging/debug_lib_provider_test.cpp b/parser_library/test/debugging/debug_lib_provider_test.cpp index 18b242a86..d88048c53 100644 --- a/parser_library/test/debugging/debug_lib_provider_test.cpp +++ b/parser_library/test/debugging/debug_lib_provider_test.cpp @@ -62,8 +62,8 @@ TEST_F(debug_lib_provider_test, has_library) EXPECT_CALL(*mock_lib, has_file(Eq("AAA"), _)).WillOnce(Return(true)); EXPECT_CALL(*mock_lib, has_file(Eq("BBB"), _)).WillOnce(Return(false)); - EXPECT_TRUE(lib.has_library("AAA", resource_location())); - EXPECT_FALSE(lib.has_library("BBB", resource_location())); + EXPECT_TRUE(lib.has_library("AAA")); + EXPECT_FALSE(lib.has_library("BBB")); } TEST_F(debug_lib_provider_test, get_library) @@ -75,7 +75,7 @@ TEST_F(debug_lib_provider_test, get_library) EXPECT_CALL(*mock_lib, has_file(Eq("AAA"), _)).WillOnce(DoAll(SetArgPointee<1>(aaa_location), Return(true))); EXPECT_CALL(*mock_lib, has_file(Eq("BBB"), _)).WillOnce(Return(false)); - EXPECT_EQ(lib.get_library("AAA", resource_location()), std::pair(aaa_content, aaa_location)); + EXPECT_EQ(lib.get_library("AAA"), std::pair(aaa_content, aaa_location)); - EXPECT_EQ(lib.get_library("BBB", resource_location()), std::nullopt); + EXPECT_EQ(lib.get_library("BBB"), std::nullopt); } diff --git a/parser_library/test/gtest_stringers.cpp b/parser_library/test/gtest_stringers.cpp new file mode 100644 index 000000000..4fe57a4f5 --- /dev/null +++ b/parser_library/test/gtest_stringers.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023 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 + */ + +#include "gtest_stringers.h" + +#include + +#include "location.h" +#include "lsp/completion_item.h" +#include "lsp/symbol_occurence.h" +#include "protocol.h" + +namespace hlasm_plugin::parser_library { + +std::ostream& operator<<(std::ostream& stream, const position& item) +{ + return stream << "{ " << item.line << ", " << item.column << " }"; +} + +std::ostream& operator<<(std::ostream& stream, range item) +{ + return stream << "{ " << item.start << ", " << item.end << " }"; +} + +std::ostream& operator<<(std::ostream& stream, const location& item) +{ + return stream << "{ file: " << item.get_uri() << "\n position: " << item.pos << " }"; +} + +std::ostream& operator<<(std::ostream& stream, const performance_metrics& item) +{ + return stream << "continued statements: " << item.continued_statements + << "\n copy def statements: " << item.copy_def_statements + << "\n copy statements: " << item.copy_statements << "\n files: " << item.files + << "\n lines: " << item.lines << "\n lookahead statements: " << item.lookahead_statements + << "\n macro def statements: " << item.macro_def_statements + << "\n macro statements: " << item.macro_statements + << "\n non continued statements: " << item.non_continued_statements + << "\n open code statements: " << item.open_code_statements + << "\n reparsed statements: " << item.reparsed_statements << "\n"; +} + +} // namespace hlasm_plugin::parser_library + +namespace hlasm_plugin::parser_library::lsp { + +std::ostream& operator<<(std::ostream& stream, const symbol_occurence& item) +{ + return stream << "{ kind: " << (int)item.kind << "\n name: " << item.name.to_string_view() + << "\n range: " << item.occurence_range << " }"; +} + +std::ostream& operator<<(std::ostream& stream, const lsp::completion_item_s& item) +{ + return stream << "{ label: " << item.label << "\n detail: " << item.detail << "\n insert text: " << item.insert_text + << "\n documentation: " << item.documentation << "\n kind: " << (int)item.kind << " }"; +} + +} // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/test/gtest_stringers.h b/parser_library/test/gtest_stringers.h index 597306bb6..c2908fbf1 100644 --- a/parser_library/test/gtest_stringers.h +++ b/parser_library/test/gtest_stringers.h @@ -15,58 +15,33 @@ #ifndef HLASMPLUGIN_PARSERLIBRARY_TEST_GTEST_STRINGERS_H #define HLASMPLUGIN_PARSERLIBRARY_TEST_GTEST_STRINGERS_H -#include "gtest/gtest.h" +#include -#include "analyzer.h" +namespace hlasm_plugin::parser_library { -// This file contains ostream operator<< overloads to improve GTest error reporting. +struct position; +struct range; +struct location; +struct performance_metrics; +std::ostream& operator<<(std::ostream& stream, const position& item); -namespace hlasm_plugin::parser_library { +std::ostream& operator<<(std::ostream& stream, range item); + +std::ostream& operator<<(std::ostream& stream, const location& item); -inline std::ostream& operator<<(std::ostream& stream, const position& item) -{ - return stream << "{ " << item.line << ", " << item.column << " }"; -} - -inline std::ostream& operator<<(std::ostream& stream, range item) -{ - return stream << "{ " << item.start << ", " << item.end << " }"; -} - -inline std::ostream& operator<<(std::ostream& stream, const location& item) -{ - return stream << "{ file: " << item.get_uri() << "\n position: " << item.pos << " }"; -} - -inline std::ostream& operator<<(std::ostream& stream, const performance_metrics& item) -{ - return stream << "continued statements: " << item.continued_statements - << "\n copy def statements: " << item.copy_def_statements - << "\n copy statements: " << item.copy_statements << "\n files: " << item.files - << "\n lines: " << item.lines << "\n lookahead statements: " << item.lookahead_statements - << "\n macro def statements: " << item.macro_def_statements - << "\n macro statements: " << item.macro_statements - << "\n non continued statements: " << item.non_continued_statements - << "\n open code statements: " << item.open_code_statements - << "\n reparsed statements: " << item.reparsed_statements << "\n"; -} +std::ostream& operator<<(std::ostream& stream, const performance_metrics& item); } // namespace hlasm_plugin::parser_library namespace hlasm_plugin::parser_library::lsp { -inline std::ostream& operator<<(std::ostream& stream, const symbol_occurence& item) -{ - return stream << "{ kind: " << (int)item.kind << "\n name: " << item.name.to_string_view() - << "\n range: " << item.occurence_range << " }"; -} - -inline std::ostream& operator<<(std::ostream& stream, const lsp::completion_item_s& item) -{ - return stream << "{ label: " << item.label << "\n detail: " << item.detail << "\n insert text: " << item.insert_text - << "\n documentation: " << item.documentation << "\n kind: " << (int)item.kind << " }"; -} +struct symbol_occurence; +struct completion_item_s; + +std::ostream& operator<<(std::ostream& stream, const symbol_occurence& item); + +std::ostream& operator<<(std::ostream& stream, const completion_item_s& item); } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/test/lsp/CMakeLists.txt b/parser_library/test/lsp/CMakeLists.txt index 619f1ffe0..f4afe110a 100644 --- a/parser_library/test/lsp/CMakeLists.txt +++ b/parser_library/test/lsp/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(library_test PRIVATE analyzer_fixture.h instruction_hints_test.cpp item_convertors_test.cpp + lsp_completion.cpp lsp_context_copy_in_macro_test.cpp lsp_context_document_symbol_ord_test.cpp lsp_context_document_symbol_var_seq_test.cpp diff --git a/parser_library/test/lsp/lsp_completion.cpp b/parser_library/test/lsp/lsp_completion.cpp new file mode 100644 index 000000000..e5cf18214 --- /dev/null +++ b/parser_library/test/lsp/lsp_completion.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023 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 + */ + +#include + +#include "gtest/gtest.h" + +#include "../common_testing.h" +#include "lsp/completion_item.h" +#include "lsp/item_convertors.h" +#include "lsp/lsp_context.h" + +TEST(lsp_completion, completion_list_instr) +{ + const std::string input = R"( + MACRO + AAAA + MEND +)"; + analyzer a(input); + a.analyze(); + + auto aaaa = a.context().lsp_ctx->get_macro_info(context::id_index("AAAA")); + ASSERT_TRUE(aaaa); + std::unordered_map m; + m.try_emplace(aaaa->macro_definition, aaaa); + + auto result = lsp::generate_completion( + lsp::completion_list_source(lsp::completion_list_instructions { "AAAAA", 1, &m, a.context().lsp_ctx.get() }), + [](std::string_view v) -> std::vector { + if (v == "AAAAA") + return { "AAAA", "ADATA" }; + return {}; + }); + + EXPECT_TRUE(std::any_of( + result.begin(), result.end(), [](const auto& e) { return e.label == "ADATA" && e.suggestion_for == "AAAAA"; })); + EXPECT_TRUE(std::any_of( + result.begin(), result.end(), [](const auto& e) { return e.label == "AAAA" && e.suggestion_for == "AAAAA"; })); +} + +TEST(lsp_completion, completion_list_vars) +{ + lsp::vardef_storage vars(1, lsp::variable_symbol_definition(context::id_index("VARNAME"), 0, {})); + + auto result = lsp::generate_completion(&vars); + + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(std::count_if(result.begin(), result.end(), [](const auto& e) { return e.label == "&VARNAME"; }), 1); +} + +TEST(lsp_completion, completion_list_labels) +{ + context::label_storage labels; + labels.try_emplace(context::id_index("LABEL"), + std::make_unique(context::id_index("LABEL"), location(), 0)); + + auto result = lsp::generate_completion(&labels); + + EXPECT_EQ(result.size(), 1); + EXPECT_EQ(std::count_if(result.begin(), result.end(), [](const auto& e) { return e.label == ".LABEL"; }), 1); +} + +TEST(lsp_completion, completion_list_empty) +{ + auto result = lsp::generate_completion({}); + + EXPECT_TRUE(result.empty()); +} diff --git a/parser_library/test/lsp/lsp_context_copy_in_macro_test.cpp b/parser_library/test/lsp/lsp_context_copy_in_macro_test.cpp index 417fb1437..67d00d0be 100644 --- a/parser_library/test/lsp/lsp_context_copy_in_macro_test.cpp +++ b/parser_library/test/lsp/lsp_context_copy_in_macro_test.cpp @@ -16,6 +16,7 @@ #include "../mock_parse_lib_provider.h" #include "analyzer_fixture.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" using namespace hlasm_plugin::parser_library; diff --git a/parser_library/test/lsp/lsp_context_document_symbol_ord_test.cpp b/parser_library/test/lsp/lsp_context_document_symbol_ord_test.cpp index 4f606b1a8..fe4461fe2 100644 --- a/parser_library/test/lsp/lsp_context_document_symbol_ord_test.cpp +++ b/parser_library/test/lsp/lsp_context_document_symbol_ord_test.cpp @@ -15,6 +15,8 @@ #include "gtest/gtest.h" #include "../mock_parse_lib_provider.h" +#include "lsp/document_symbol_item.h" +#include "lsp/lsp_context.h" using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::lsp; diff --git a/parser_library/test/lsp/lsp_context_document_symbol_var_seq_test.cpp b/parser_library/test/lsp/lsp_context_document_symbol_var_seq_test.cpp index 26b9f4423..150e322a4 100644 --- a/parser_library/test/lsp/lsp_context_document_symbol_var_seq_test.cpp +++ b/parser_library/test/lsp/lsp_context_document_symbol_var_seq_test.cpp @@ -16,6 +16,8 @@ #include "../mock_parse_lib_provider.h" #include "analyzer_fixture.h" +#include "lsp/document_symbol_item.h" +#include "lsp/lsp_context.h" using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::lsp; diff --git a/parser_library/test/lsp/lsp_context_instr_test.cpp b/parser_library/test/lsp/lsp_context_instr_test.cpp index 366f5c063..94a2126b2 100644 --- a/parser_library/test/lsp/lsp_context_instr_test.cpp +++ b/parser_library/test/lsp/lsp_context_instr_test.cpp @@ -16,7 +16,9 @@ #include "analyzer_fixture.h" #include "instruction_set_version.h" -#include "workspaces/workspace.h" +#include "lsp/completion_item.h" +#include "lsp/item_convertors.h" +#include "lsp/lsp_context.h" using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::lsp; @@ -53,7 +55,7 @@ struct lsp_context_instr : public ::testing::Test a.analyze(); - return workspaces::workspace::generate_completion(a.context().lsp_ctx->completion( + return generate_completion(a.context().lsp_ctx->completion( opencode_file_loc, { 2, 3 }, 'R', completion_trigger_kind::trigger_character)); } }; diff --git a/parser_library/test/lsp/lsp_context_macro_documentation_test.cpp b/parser_library/test/lsp/lsp_context_macro_documentation_test.cpp index 4a3d44395..12720b927 100644 --- a/parser_library/test/lsp/lsp_context_macro_documentation_test.cpp +++ b/parser_library/test/lsp/lsp_context_macro_documentation_test.cpp @@ -15,6 +15,8 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/item_convertors.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" #include "workspaces/workspace.h" diff --git a/parser_library/test/lsp/lsp_context_macro_in_opencode_test.cpp b/parser_library/test/lsp/lsp_context_macro_in_opencode_test.cpp index 319d77ba4..96dc204d3 100644 --- a/parser_library/test/lsp/lsp_context_macro_in_opencode_test.cpp +++ b/parser_library/test/lsp/lsp_context_macro_in_opencode_test.cpp @@ -15,10 +15,10 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" #include "workspaces/workspace.h" - using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::lsp; diff --git a/parser_library/test/lsp/lsp_context_nested_macro_test.cpp b/parser_library/test/lsp/lsp_context_nested_macro_test.cpp index f05247a47..891c06ce9 100644 --- a/parser_library/test/lsp/lsp_context_nested_macro_test.cpp +++ b/parser_library/test/lsp/lsp_context_nested_macro_test.cpp @@ -15,6 +15,7 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" using namespace hlasm_plugin::parser_library; diff --git a/parser_library/test/lsp/lsp_context_ord_sym_test.cpp b/parser_library/test/lsp/lsp_context_ord_sym_test.cpp index 91d00faba..ccce165b5 100644 --- a/parser_library/test/lsp/lsp_context_ord_sym_test.cpp +++ b/parser_library/test/lsp/lsp_context_ord_sym_test.cpp @@ -15,6 +15,8 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/document_symbol_item.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" using namespace hlasm_plugin::parser_library; diff --git a/parser_library/test/lsp/lsp_context_preprocessor_test.cpp b/parser_library/test/lsp/lsp_context_preprocessor_test.cpp index 8672ecfdf..70721f8b8 100644 --- a/parser_library/test/lsp/lsp_context_preprocessor_test.cpp +++ b/parser_library/test/lsp/lsp_context_preprocessor_test.cpp @@ -22,6 +22,7 @@ #include "analyzer.h" #include "context/instruction.h" #include "location.h" +#include "lsp/lsp_context.h" #include "range.h" #include "utils/resource_location.h" #include "workspaces/parse_lib_provider.h" diff --git a/parser_library/test/lsp/lsp_context_seq_sym_test.cpp b/parser_library/test/lsp/lsp_context_seq_sym_test.cpp index cd212ed58..852ff927f 100644 --- a/parser_library/test/lsp/lsp_context_seq_sym_test.cpp +++ b/parser_library/test/lsp/lsp_context_seq_sym_test.cpp @@ -15,6 +15,8 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/item_convertors.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" #include "workspaces/workspace.h" diff --git a/parser_library/test/lsp/lsp_context_var_sym_test.cpp b/parser_library/test/lsp/lsp_context_var_sym_test.cpp index bbcf1b920..cb1da4d04 100644 --- a/parser_library/test/lsp/lsp_context_var_sym_test.cpp +++ b/parser_library/test/lsp/lsp_context_var_sym_test.cpp @@ -15,6 +15,7 @@ #include "gtest/gtest.h" #include "analyzer_fixture.h" +#include "lsp/lsp_context.h" #include "lsp_context_test_helper.h" #include "workspaces/workspace.h" diff --git a/parser_library/test/lsp/lsp_features_test.cpp b/parser_library/test/lsp/lsp_features_test.cpp index bbce9a421..7089efa22 100644 --- a/parser_library/test/lsp/lsp_features_test.cpp +++ b/parser_library/test/lsp/lsp_features_test.cpp @@ -17,6 +17,7 @@ #include "../mock_parse_lib_provider.h" #include "analyzer.h" #include "context/instruction.h" +#include "lsp/lsp_context.h" #include "utils/resource_location.h" #include "workspaces/parse_lib_provider.h" diff --git a/parser_library/test/mock_parse_lib_provider.h b/parser_library/test/mock_parse_lib_provider.h index 6c3b16535..ed2cc1f39 100644 --- a/parser_library/test/mock_parse_lib_provider.h +++ b/parser_library/test/mock_parse_lib_provider.h @@ -23,10 +23,11 @@ namespace hlasm_plugin::parser_library { class mock_parse_lib_provider : public workspaces::parse_lib_provider { - std::unordered_map m_files; + std::unordered_map> m_files; public: - std::unordered_map> analyzers; + std::unordered_map, utils::hashers::string_hasher, std::equal_to<>> + analyzers; mock_parse_lib_provider() = default; mock_parse_lib_provider(std::initializer_list> entries) @@ -38,7 +39,7 @@ class mock_parse_lib_provider : public workspaces::parse_lib_provider {} workspaces::parse_result parse_library( - const std::string& library, analyzing_context ctx, workspaces::library_data data) override + std::string_view library, analyzing_context ctx, workspaces::library_data data) override { auto it = m_files.find(library); if (it == m_files.end()) @@ -48,18 +49,15 @@ class mock_parse_lib_provider : public workspaces::parse_lib_provider analyzer_options { hlasm_plugin::utils::resource::resource_location(library), this, std::move(ctx), data }); a->analyze(); a->collect_diags(); - analyzers[library] = std::move(a); + analyzers.insert_or_assign(std::string(library), std::move(a)); return true; } - bool has_library(const std::string& library, const utils::resource::resource_location&) const override - { - return m_files.count(library); - } + bool has_library(std::string_view library) const override { return m_files.count(library); } std::optional> get_library( - const std::string& library, const utils::resource::resource_location&) const override + std::string_view library) const override { auto it = m_files.find(library); if (it == m_files.end()) diff --git a/parser_library/test/parsing/deferred_statement_test.cpp b/parser_library/test/parsing/deferred_statement_test.cpp index 8c079bf76..21bd15c23 100644 --- a/parser_library/test/parsing/deferred_statement_test.cpp +++ b/parser_library/test/parsing/deferred_statement_test.cpp @@ -15,6 +15,7 @@ #include "gtest/gtest.h" #include "../common_testing.h" +#include "lsp/lsp_context.h" using namespace hlasm_plugin::utils::resource; TEST(deferred_statement, split_var) diff --git a/parser_library/test/processing/lookahead_test.cpp b/parser_library/test/processing/lookahead_test.cpp index 304a61c42..247748582 100644 --- a/parser_library/test/processing/lookahead_test.cpp +++ b/parser_library/test/processing/lookahead_test.cpp @@ -18,6 +18,7 @@ #include "../mock_parse_lib_provider.h" #include "hlasmparser_multiline.h" #include "library_info_transitional.h" +#include "lsp/lsp_context.h" // tests for lookahead feature: // forward/backward jums diff --git a/parser_library/test/workspace/CMakeLists.txt b/parser_library/test/workspace/CMakeLists.txt index 7802e24b7..b47eb16ee 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 - files_parse_lib_provider.h instruction_sets_test.cpp library_mock.h load_config_test.cpp diff --git a/parser_library/test/workspace/files_parse_lib_provider.h b/parser_library/test/workspace/files_parse_lib_provider.h deleted file mode 100644 index a021b2652..000000000 --- a/parser_library/test/workspace/files_parse_lib_provider.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2019 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 HLASMPLUGIN_PARSERLIBRARY_TEST_FILES_PARSE_LIB_PROVIDER_H -#define HLASMPLUGIN_PARSERLIBRARY_TEST_FILES_PARSE_LIB_PROVIDER_H - -#include -#include -#include -#include - -#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; - 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 = ws->add_processor_file(utils::resource::resource_location(library)); - if (!macro) - return false; - return macro->parse_macro(*this, std::move(ctx), std::move(data)); - } - bool has_library(const std::string& library, const utils::resource::resource_location&) const override - { - return file_mngr->find(utils::resource::resource_location(library)) != nullptr; - } - std::optional> get_library( - const std::string& library, const utils::resource::resource_location&) const override - { - auto macro = file_mngr->find(utils::resource::resource_location(library)); - if (!macro) - return std::nullopt; - return std::pair( - macro->get_text(), macro->get_location()); - } -}; - -} // namespace hlasm_plugin::parser_library::workspaces - -#endif diff --git a/parser_library/test/workspace/load_config_test.cpp b/parser_library/test/workspace/load_config_test.cpp index b5a84a0d8..16c4d4d0c 100644 --- a/parser_library/test/workspace/load_config_test.cpp +++ b/parser_library/test/workspace/load_config_test.cpp @@ -19,6 +19,7 @@ #include "../common_testing.h" #include "empty_configs.h" +#include "lsp/completion_item.h" #include "nlohmann/json.hpp" #include "utils/content_loader.h" #include "utils/platform.h" @@ -566,21 +567,35 @@ TEST(workspace, lsp_file_not_processed_yet) file_manager_impl mngr; lib_config config; shared_json global_settings = make_empty_shared_json(); - workspace ws(mngr, config, global_settings); + std::atomic cancel; + workspace ws(mngr, config, global_settings, &cancel); ws.open(); mngr.did_open_file(file_loc, 0, " LR 1,1"); - auto file = ws.add_processor_file(file_loc); - // Prior to parsing, it should return default values - const auto* fp = file->get_lsp_context(); - ASSERT_FALSE(fp); + auto file = ws.find_processor_file(file_loc); + EXPECT_FALSE(file); + + EXPECT_EQ(ws.definition(file_loc, { 0, 5 }), location({ 0, 5 }, file_loc)); + EXPECT_EQ(ws.references(file_loc, { 0, 5 }), location_list()); + EXPECT_EQ(ws.hover(file_loc, { 0, 5 }), ""); + EXPECT_EQ(ws.completion(file_loc, { 0, 5 }, '\0', completion_trigger_kind::invoked), lsp::completion_list_s()); + + cancel = true; + ws.did_open_file(file_loc); EXPECT_EQ(ws.definition(file_loc, { 0, 5 }), location({ 0, 5 }, file_loc)); EXPECT_EQ(ws.references(file_loc, { 0, 5 }), location_list()); EXPECT_EQ(ws.hover(file_loc, { 0, 5 }), ""); EXPECT_EQ(ws.completion(file_loc, { 0, 5 }, '\0', completion_trigger_kind::invoked), lsp::completion_list_s()); + file = ws.find_processor_file(file_loc); + + ASSERT_TRUE(file); + + // Prior to parsing, it should return default values + const auto* fp = file->get_lsp_context(); + ASSERT_FALSE(fp); EXPECT_EQ(file->get_hl_info(), semantics::lines_info()); EXPECT_EQ(file->get_metrics(), performance_metrics()); } diff --git a/parser_library/test/workspace/macro_cache_test.cpp b/parser_library/test/workspace/macro_cache_test.cpp index ef719190f..99a11d532 100644 --- a/parser_library/test/workspace/macro_cache_test.cpp +++ b/parser_library/test/workspace/macro_cache_test.cpp @@ -20,7 +20,9 @@ #include "../workspace/empty_configs.h" #include "analyzer.h" #include "context/id_storage.h" -#include "files_parse_lib_provider.h" +#include "lsp/lsp_context.h" +#include "lsp/opencode_info.h" +#include "lsp/text_data_view.h" #include "utils/resource_location.h" #include "workspaces/file_manager_impl.h" #include "workspaces/processor_file_impl.h" @@ -28,98 +30,51 @@ using namespace hlasm_plugin::parser_library; using namespace hlasm_plugin::parser_library::workspaces; +using namespace hlasm_plugin::utils::hashers; using namespace hlasm_plugin::utils::resource; namespace { -struct file_manager_cache_test_mock : public file_manager_impl, public parse_lib_provider +analyzing_context create_analyzing_context(std::string file_name, std::shared_ptr ids) { - 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::shared_ptr hlasm_ctx; - - auto& add_macro_or_copy(std::string file_name, std::string text) - { - auto file_loc = resource_location(file_name); - - did_open_file(file_loc, {}, text); - auto f = file_manager_impl::find(file_loc); - - 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; - } - - auto add_opencode(std::string file_name, std::string text) - { - auto file_loc = resource_location(file_name); - - 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; - } - - - 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; + auto hlasm_ctx = + std::make_shared(resource_location(file_name), asm_option(), std::move(ids)); + return analyzing_context { + hlasm_ctx, + std::make_shared(hlasm_ctx), }; +} - 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()) - return { nullptr, nullptr }; - else - return { it->second.first, &it->second.second }; +auto parse_dependency(std::shared_ptr f, analyzing_context ctx, processing::processing_kind proc_kind) +{ + workspaces::library_data lib_data { proc_kind, ctx.hlasm_ctx->ids().add(f->get_location().filename()) }; + + std::pair result { + std::make_unique(f->get_text(), + analyzer_options { + f->get_location(), + ctx, + lib_data, + }), + lib_data, }; - workspaces::parse_result parse_library( - const std::string& library, analyzing_context ctx, const workspaces::library_data data) override - { - auto [m, cache] = get_proc_file_from_library(library); - auto a = std::make_unique(m->get_text(), analyzer_options { m->get_location(), ctx, this, data }); - a->analyze(); - auto key = macro_cache_key::create_from_context(*ctx.hlasm_ctx, data); - cache->save_macro(key, *a); - hlasm_ctx = ctx.hlasm_ctx; - return true; - } + result.first->analyze(); - bool has_library(const std::string& library, const resource_location&) const override - { - return files_by_library_.count(library) > 0; - }; - - std::optional> get_library( - const std::string& library, const resource_location&) const override - { - auto it = files_by_library_.find(library); - if (it == files_by_library_.end()) - return std::nullopt; - return std::pair( - it->second.first->get_text(), it->second.first->get_location()); - } -}; + return result; +} -analyzing_context create_analyzing_context(std::string file_name, std::shared_ptr ids) +void save_dependency(macro_cache& cache, std::pair, workspaces::library_data> input) { - auto hlasm_ctx = - std::make_shared(resource_location(file_name), asm_option(), std::move(ids)); - analyzing_context new_ctx { - hlasm_ctx, - std::make_shared(hlasm_ctx), - }; - lsp::opencode_info_ptr oip = std::make_unique(lsp::vardef_storage(), lsp::file_occurences_t {}); - new_ctx.lsp_ctx->add_opencode(std::move(oip), lsp::text_data_view("")); + auto key = macro_cache_key::create_from_context(*input.first->context().hlasm_ctx, input.second); + + cache.save_macro(key, *input.first); +} - return new_ctx; +auto open_file(resource_location file, std::string text, file_manager& fm) +{ + fm.did_open_file(file, 0, text); + return fm.find(file); } } // namespace @@ -127,14 +82,10 @@ analyzing_context create_analyzing_context(std::string file_name, std::shared_pt TEST(macro_cache_test, copy_from_macro) { std::string opencode_file_name = "opencode"; - auto opencode_file_loc = resource_location(opencode_file_name); - std::string opencode_text = - R"( - MAC 1 + resource_location opencode_file_loc(opencode_file_name); -)"; std::string macro_file_name = "lib/MAC"; - auto macro_file_loc = resource_location(macro_file_name); + resource_location macro_file_loc(macro_file_name); std::string macro_text = R"( MACRO MAC &PARAM @@ -142,64 +93,57 @@ TEST(macro_cache_test, copy_from_macro) MEND )"; std::string copyfile_file_name = "lib/COPYFILE"; - auto copyfile_file_loc = resource_location(copyfile_file_name); + resource_location copyfile_file_loc(copyfile_file_name); std::string copyfile_text = R"( LR 15,1 )"; - 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(); - - 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); - + file_manager_impl file_mngr; - opencode->parse(file_mngr, {}, {}, nullptr); - opencode->collect_diags(); - EXPECT_EQ(opencode->diags().size(), 0U); + auto macro_file = open_file(macro_file_loc, macro_text, file_mngr); + auto copy_file = open_file(copyfile_file_loc, copyfile_text, file_mngr); - auto macro_id = context::id_index("MAC"); - auto copy_id = context::id_index("COPYFILE"); + macro_cache macro_c(file_mngr, macro_file); + macro_cache copy_c(file_mngr, copy_file); - analyzing_context new_ctx = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); + auto ids = std::make_shared(); + // parse everything and cache results + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + save_dependency(copy_c, parse_dependency(copy_file, ctx, processing::processing_kind::COPY)); + save_dependency(macro_c, parse_dependency(macro_file, ctx, processing::processing_kind::MACRO)); + constexpr context::id_index macro_id("MAC"); + constexpr context::id_index copy_id("COPYFILE"); macro_cache_key macro_key { opencode_file_loc, { processing::processing_kind::MACRO, macro_id }, {} }; + macro_cache_key copy_key { opencode_file_loc, { processing::processing_kind::COPY, copy_id }, {} }; - + // try recalling the cached results + analyzing_context new_ctx = create_analyzing_context(opencode_file_name, ids); EXPECT_TRUE(macro_c.load_from_cache(macro_key, new_ctx)); - EXPECT_NE(new_ctx.hlasm_ctx->get_macro_definition(macro_id), nullptr); EXPECT_NE(new_ctx.lsp_ctx->get_macro_info(macro_id), nullptr); EXPECT_NE(new_ctx.hlasm_ctx->get_copy_member(copy_id), nullptr); + // introduce macro change + macro_file->did_change({}, " "); - macro->did_change({}, " "); - - analyzing_context ctx_macro_changed = create_analyzing_context(opencode_file_name, new_ctx.hlasm_ctx->ids_ptr()); - - macro_cache_key copy_key { opencode_file_loc, { processing::processing_kind::COPY, copy_id }, {} }; // After macro change, copy should still be cached + analyzing_context ctx_macro_changed = create_analyzing_context(opencode_file_name, new_ctx.hlasm_ctx->ids_ptr()); EXPECT_TRUE(copy_c.load_from_cache(copy_key, ctx_macro_changed)); EXPECT_NE(ctx_macro_changed.hlasm_ctx->get_copy_member(copy_id), nullptr); EXPECT_FALSE(macro_c.load_from_cache(macro_key, ctx_macro_changed)); // Reparse the change so everything is cached again - opencode->parse(file_mngr, {}, {}, nullptr); - - copyfile->did_change({}, " "); + save_dependency(macro_c, parse_dependency(macro_file, ctx, processing::processing_kind::MACRO)); - analyzing_context ctx_copy_changed = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); + // introduce change into copy + copy_file->did_change({}, " "); // Macro depends on the copyfile, so none should be cached. + analyzing_context ctx_copy_changed = create_analyzing_context(opencode_file_name, ids); EXPECT_FALSE(macro_c.load_from_cache(macro_key, ctx_copy_changed)); EXPECT_FALSE(copy_c.load_from_cache(copy_key, ctx_copy_changed)); } @@ -207,99 +151,97 @@ TEST(macro_cache_test, copy_from_macro) TEST(macro_cache_test, opsyn_change) { std::string opencode_file_name = "opencode"; - auto opencode_file_loc = resource_location("opencode"); - std::string opencode_text = - R"( -SETA OPSYN LR - MAC 1 -)"; + resource_location opencode_file_loc(opencode_file_name); + ///* Simulates the following code + /// SETA OPSYN LR + /// MAC 1 std::string macro_file_name = "lib/MAC"; + resource_location macro_file_loc(macro_file_name); std::string macro_text = R"( MACRO MAC &PARAM MEND )"; + file_manager_impl file_mngr; + auto macro_file = open_file(macro_file_loc, macro_text, file_mngr); + macro_cache macro_c(file_mngr, macro_file); + constexpr context::id_index macro_id("MAC"); - 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 = 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); - - - auto macro_id = context::id_index("MAC"); - auto ids = file_mngr.hlasm_ctx->ids_ptr(); - + auto ids = std::make_shared(); + constexpr context::id_index L("L"); constexpr context::id_index LR("LR"); + constexpr context::id_index SETA("SETA"); + constexpr context::id_index SETB("SETB"); + + // generate OPSYN condition and parse macro + { + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + ctx.hlasm_ctx->add_mnemonic(SETA, LR); + save_dependency(macro_c, parse_dependency(macro_file, ctx, processing::processing_kind::MACRO)); + } + // try loading with and without OPSYN change + macro_cache_key macro_key { opencode_file_loc, { processing::processing_kind::MACRO, macro_id }, {} }; macro_cache_key macro_key_one_opsyn { opencode_file_loc, { processing::processing_kind::MACRO, macro_id }, { cached_opsyn_mnemo { context::id_storage::well_known::SETA, LR, false } } }; + { + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + EXPECT_FALSE(macro_c.load_from_cache(macro_key, ctx)); + EXPECT_TRUE(macro_c.load_from_cache(macro_key_one_opsyn, ctx)); + } + // parse macro with extra opsyn + { + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + ctx.hlasm_ctx->add_mnemonic(L, SETB); + ctx.hlasm_ctx->add_mnemonic(SETA, LR); + save_dependency(macro_c, parse_dependency(macro_file, ctx, processing::processing_kind::MACRO)); + } - analyzing_context new_ctx = create_analyzing_context(opencode_file_name, ids); - - - macro_cache_key macro_key { opencode_file_loc, { processing::processing_kind::MACRO, macro_id }, {} }; - EXPECT_FALSE(macro_c.load_from_cache(macro_key, new_ctx)); - EXPECT_TRUE(macro_c.load_from_cache(macro_key_one_opsyn, new_ctx)); - - - - 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()); - EXPECT_TRUE(macro_c.load_from_cache(macro_key_one_opsyn, ctx_second_opsyn1)); - - constexpr context::id_index L("L"); - - macro_cache_key macro_key_two_opsyns = macro_key_one_opsyn; - macro_key_two_opsyns.opsyn_state.push_back(cached_opsyn_mnemo { L, context::id_storage::well_known::SETB, false }); + // original cache entry is still present + { + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + EXPECT_TRUE(macro_c.load_from_cache(macro_key_one_opsyn, ctx)); + } - macro_cache_key::sort_opsyn_state(macro_key_two_opsyns.opsyn_state); + // new cache entry is present as well + { + macro_cache_key macro_key_two_opsyns = macro_key_one_opsyn; + macro_key_two_opsyns.opsyn_state.push_back({ L, context::id_storage::well_known::SETB, false }); + macro_cache_key::sort_opsyn_state(macro_key_two_opsyns.opsyn_state); - analyzing_context ctx_second_opsyn2 = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); - EXPECT_TRUE(macro_c.load_from_cache(macro_key_two_opsyns, ctx_second_opsyn2)); + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + EXPECT_TRUE(macro_c.load_from_cache(macro_key_two_opsyns, ctx)); + } } TEST(macro_cache_test, empty_macro) { std::string opencode_file_name = "opencode"; - auto opencode_file_loc = resource_location("opencode"); - - // This tests a caveat where parse_library is called twice for the same macro, if the macro is not defined in its - // file. + resource_location opencode_file_loc("opencode"); std::string opencode_text = R"( MAC MAC)"; + + // This tests a caveat where parse_library is called twice for the same macro, if the macro is not defined in its + // file. std::string macro_file_name = "lib/MAC"; + resource_location macro_file_loc(macro_file_name); std::string macro_text = ""; - 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(); + file_manager_impl file_mngr; + auto macro_file = open_file(macro_file_loc, macro_text, file_mngr); + macro_cache macro_c(file_mngr, macro_file); + constexpr context::id_index macro_id("MAC"); - 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); + auto ids = std::make_shared(); - opencode->parse(file_mngr, {}, {}, nullptr); - auto macro_id = context::id_index("MAC"); + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + save_dependency(macro_c, parse_dependency(macro_file, ctx, processing::processing_kind::MACRO)); - analyzing_context new_ctx = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); + analyzing_context new_ctx = create_analyzing_context(opencode_file_name, ids); macro_cache_key macro_key { opencode_file_loc, { processing::processing_kind::MACRO, macro_id }, {} }; EXPECT_TRUE(macro_c.load_from_cache(macro_key, new_ctx)); @@ -378,36 +320,55 @@ TEST(macro_cache_test, overwrite_by_inline) )"; file_manager_impl 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 = ws.add_processor_file(opencode_file_loc); - opencode->parse(lib_provider, {}, {}, nullptr); - opencode->collect_diags(); + processor_file_impl opencode(open_file(opencode_file_loc, opencode_text, file_mngr), file_mngr); + processor_file_impl macro(open_file(macro_file_loc, macro_text, file_mngr), file_mngr); + + struct simple_provider : parse_lib_provider + { + processor_file_impl& macro_ref; + + parse_result parse_library(std::string_view lib, analyzing_context ac, library_data ld) override + { + EXPECT_EQ(lib, "MAC"); + + return macro_ref.parse_macro(*this, ac, ld); + } + bool has_library(std::string_view) const override { return false; } + std::optional> get_library(std::string_view) const override + { + return std::nullopt; + } + + simple_provider(processor_file_impl& macro_ref) + : macro_ref(macro_ref) + {} - EXPECT_EQ(opencode->diags().size(), 2U); - EXPECT_TRUE(find_diag_with_filename(opencode->diags(), macro_file_loc)); - EXPECT_TRUE(find_diag_with_filename(opencode->diags(), opencode_file_loc)); + } provider(macro); - opencode->diags().clear(); + opencode.parse(provider, {}, {}, nullptr); + opencode.collect_diags(); - opencode->parse(lib_provider, {}, {}, nullptr); - opencode->collect_diags(); - EXPECT_EQ(opencode->diags().size(), 2U); - EXPECT_TRUE(find_diag_with_filename(opencode->diags(), macro_file_loc)); - EXPECT_TRUE(find_diag_with_filename(opencode->diags(), opencode_file_loc)); + EXPECT_EQ(opencode.diags().size(), 2U); + EXPECT_TRUE(find_diag_with_filename(opencode.diags(), macro_file_loc)); + EXPECT_TRUE(find_diag_with_filename(opencode.diags(), opencode_file_loc)); + + opencode.diags().clear(); + + opencode.parse(provider, {}, {}, nullptr); + opencode.collect_diags(); + EXPECT_EQ(opencode.diags().size(), 2U); + EXPECT_TRUE(find_diag_with_filename(opencode.diags(), macro_file_loc)); + EXPECT_TRUE(find_diag_with_filename(opencode.diags(), opencode_file_loc)); } TEST(macro_cache_test, inline_depends_on_copy) { std::string opencode_file_name = "opencode"; - auto opencode_file_loc = resource_location("opencode"); + resource_location opencode_file_loc(opencode_file_name); std::string opencode_text = R"( MACRO @@ -418,33 +379,32 @@ TEST(macro_cache_test, inline_depends_on_copy) MAC )"; std::string copy_file_name = "lib/COPYFILE"; + resource_location copy_file_loc(copy_file_name); std::string copy_text = R"( LR 1,1 arbitrary instruction)"; - 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(); - 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(); - EXPECT_EQ(opencode->diags().size(), 0U); + file_manager_impl file_mngr; + auto copy_file = open_file(copy_file_loc, copy_text, file_mngr); + macro_cache copy_c(file_mngr, copy_file); + constexpr context::id_index copy_id("COPYFILE"); - auto copy_id = context::id_index("COPYFILE"); + auto ids = std::make_shared(); - analyzing_context new_ctx = create_analyzing_context(opencode_file_name, file_mngr.hlasm_ctx->ids_ptr()); + analyzing_context ctx = create_analyzing_context(opencode_file_name, ids); + save_dependency(copy_c, parse_dependency(copy_file, ctx, processing::processing_kind::COPY)); + // try parsing the opencode now + analyzer opencode(opencode_text, analyzer_options { opencode_file_loc, ctx }); + opencode.analyze(); + opencode.collect_diags(); + EXPECT_TRUE(opencode.diags().empty()); macro_cache_key copy_key { opencode_file_loc, { processing::processing_kind::COPY, copy_id }, {} }; + + analyzing_context new_ctx = create_analyzing_context(opencode_file_name, ids); EXPECT_TRUE(copy_c.load_from_cache(copy_key, new_ctx)); - copyfile->did_change({ { 0, 4 }, { 0, 5 } }, "16"); - opencode->parse(file_mngr, {}, {}, nullptr); - opencode->collect_diags(); - ASSERT_EQ(opencode->diags().size(), 1U); - EXPECT_EQ(opencode->diags()[0].code, "M120"); + analyzing_context new_ctx_2 = create_analyzing_context(opencode_file_name, ids); + copy_file->did_change({ { 0, 4 }, { 0, 5 } }, "16"); + EXPECT_FALSE(copy_c.load_from_cache(copy_key, new_ctx_2)); } diff --git a/parser_library/test/workspace/processor_file_test.cpp b/parser_library/test/workspace/processor_file_test.cpp index 10d789dd3..e709b7c03 100644 --- a/parser_library/test/workspace/processor_file_test.cpp +++ b/parser_library/test/workspace/processor_file_test.cpp @@ -16,7 +16,7 @@ #include "../gtest_stringers.h" #include "../workspace/empty_configs.h" -#include "files_parse_lib_provider.h" +#include "lsp/lsp_context.h" #include "utils/resource_location.h" #include "workspaces/file_manager_impl.h" #include "workspaces/processor_file_impl.h" @@ -31,15 +31,12 @@ 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"); - 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); + + processor_file_impl file(mngr.find(file_loc), mngr); // Prior to parsing, there is no lsp_context available - const auto* fp = file->get_lsp_context(); + const auto* fp = file.get_lsp_context(); ASSERT_FALSE(fp); } @@ -49,25 +46,43 @@ TEST(processor_file, parse_macro) resource_location macro_loc("MAC"); file_manager_impl 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 = ws.add_processor_file(opencode_loc); mngr.did_open_file(macro_loc, 0, R"( MACRO MAC SAM31 MEND)"); - auto macro = ws.add_processor_file(macro_loc); - opencode->parse(provider, {}, {}, nullptr); + processor_file_impl opencode(mngr.find(opencode_loc), mngr); + processor_file_impl macro(mngr.find(macro_loc), mngr); + + struct simple_provider : parse_lib_provider + { + processor_file_impl& macro_ref; + + parse_result parse_library(std::string_view lib, analyzing_context ac, library_data ld) override + { + EXPECT_EQ(lib, "MAC"); + + return macro_ref.parse_macro(*this, ac, ld); + } + bool has_library(std::string_view) const override { return false; } + std::optional> get_library(std::string_view) const override + { + return std::nullopt; + } + + simple_provider(processor_file_impl& macro_ref) + : macro_ref(macro_ref) + {} + + } provider(macro); + + opencode.parse(provider, {}, {}, nullptr); // Opencode file tests - const auto* open_fp = opencode->get_lsp_context(); + const auto* open_fp = opencode.get_lsp_context(); ASSERT_TRUE(open_fp); EXPECT_EQ(open_fp->definition(opencode_loc, { 1, 2 }), location({ 1, 1 }, macro_loc)); @@ -84,7 +99,7 @@ TEST(processor_file, parse_macro) { 1, 1, 1, 4, semantics::hl_scopes::instruction }, }; - EXPECT_EQ(opencode->get_hl_info(), open_expected_hl); + EXPECT_EQ(opencode.get_hl_info(), open_expected_hl); performance_metrics expected_metrics; expected_metrics.files = 2; @@ -93,11 +108,11 @@ TEST(processor_file, parse_macro) expected_metrics.macro_statements = 2; expected_metrics.non_continued_statements = 6; expected_metrics.open_code_statements = 2; - EXPECT_EQ(opencode->get_metrics(), expected_metrics); + EXPECT_EQ(opencode.get_metrics(), expected_metrics); // Macro file tests - const auto* macro_fp = macro->get_lsp_context(); + const auto* macro_fp = macro.get_lsp_context(); ASSERT_TRUE(macro_fp); EXPECT_EQ(macro_fp->definition(opencode_loc, { 1, 2 }), location({ 1, 1 }, macro_loc)); EXPECT_EQ(macro_fp->hover(opencode_loc, { 0, 2 }), sam31_hover_message); @@ -110,6 +125,6 @@ TEST(processor_file, parse_macro) { 3, 1, 3, 5, semantics::hl_scopes::instruction }, }; - EXPECT_EQ(macro->get_hl_info(), macro_expected_hl); - EXPECT_EQ(macro->get_metrics(), expected_metrics); + EXPECT_EQ(macro.get_hl_info(), macro_expected_hl); + EXPECT_EQ(macro.get_metrics(), expected_metrics); } diff --git a/parser_library/test/workspace/workspace_test.cpp b/parser_library/test/workspace/workspace_test.cpp index 7e9bbd935..0c6b2e234 100644 --- a/parser_library/test/workspace/workspace_test.cpp +++ b/parser_library/test/workspace/workspace_test.cpp @@ -499,61 +499,3 @@ TEST_F(workspace_test, library_list_failure) 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"; })); } - -TEST(workspace, completion_list_instr) -{ - const std::string input = R"( - MACRO - AAAA - MEND -)"; - analyzer a(input); - a.analyze(); - - auto aaaa = a.context().lsp_ctx->get_macro_info(context::id_index("AAAA")); - ASSERT_TRUE(aaaa); - std::unordered_map m; - m.try_emplace(aaaa->macro_definition, aaaa); - - auto result = workspace::generate_completion( - lsp::completion_list_source(lsp::completion_list_instructions { "AAAAA", 1, &m, a.context().lsp_ctx.get() }), - [](std::string_view v) -> std::vector { - if (v == "AAAAA") - return { "AAAA", "ADATA" }; - return {}; - }); - - EXPECT_TRUE(std::any_of( - result.begin(), result.end(), [](const auto& e) { return e.label == "ADATA" && e.suggestion_for == "AAAAA"; })); - EXPECT_TRUE(std::any_of( - result.begin(), result.end(), [](const auto& e) { return e.label == "AAAA" && e.suggestion_for == "AAAAA"; })); -} - -TEST(workspace, completion_list_vars) -{ - lsp::vardef_storage vars(1, lsp::variable_symbol_definition(context::id_index("VARNAME"), 0, {})); - - auto result = workspace::generate_completion(&vars); - - EXPECT_EQ(result.size(), 1); - EXPECT_EQ(std::count_if(result.begin(), result.end(), [](const auto& e) { return e.label == "&VARNAME"; }), 1); -} - -TEST(workspace, completion_list_labels) -{ - context::label_storage labels; - labels.try_emplace(context::id_index("LABEL"), - std::make_unique(context::id_index("LABEL"), location(), 0)); - - auto result = workspace::generate_completion(&labels); - - EXPECT_EQ(result.size(), 1); - EXPECT_EQ(std::count_if(result.begin(), result.end(), [](const auto& e) { return e.label == ".LABEL"; }), 1); -} - -TEST(workspace, completion_list_empty) -{ - auto result = workspace::generate_completion({}); - - EXPECT_TRUE(result.empty()); -} diff --git a/utils/include/utils/string_operations.h b/utils/include/utils/string_operations.h index b82b3c9ee..0b94a04b4 100644 --- a/utils/include/utils/string_operations.h +++ b/utils/include/utils/string_operations.h @@ -16,6 +16,7 @@ #define HLASMPLUGIN_UTILS_STRING_OPERATIONS_H #include +#include #include #include @@ -67,6 +68,9 @@ size_t trim_left(T& b, const T& e, std::initializer_list to_tr return result; } +std::string& to_upper(std::string& s); +std::string to_upper_copy(std::string s); + } // namespace hlasm_plugin::utils #endif diff --git a/utils/src/string_operations.cpp b/utils/src/string_operations.cpp index 6750295ef..8697b003d 100644 --- a/utils/src/string_operations.cpp +++ b/utils/src/string_operations.cpp @@ -65,4 +65,18 @@ std::string_view next_nonblank_sequence(std::string_view s) return s.substr(0, space); } +std::string& to_upper(std::string& s) +{ + for (auto& c : s) + c = static_cast(std::toupper((unsigned char)c)); + return s; +} + +std::string to_upper_copy(std::string s) +{ + for (auto& c : s) + c = static_cast(std::toupper((unsigned char)c)); + return s; +} + } // namespace hlasm_plugin::utils