diff --git a/.github/workflows/Sonarcloud-build.yml b/.github/workflows/Sonarcloud-build.yml index ac2a4de58..8f5a885f0 100644 --- a/.github/workflows/Sonarcloud-build.yml +++ b/.github/workflows/Sonarcloud-build.yml @@ -82,6 +82,7 @@ jobs: run: | mkdir pr-info echo ${{ github.event.ref }} > pr-info/ref.txt + echo -Dsonar.branch.name=${{ github.ref_name }} > pr-info/head-branch-arg.txt - uses: actions/upload-artifact@v3 with: diff --git a/clients/vscode-hlasmplugin/CHANGELOG.md b/clients/vscode-hlasmplugin/CHANGELOG.md index 9f0314a30..d8a8fd48a 100644 --- a/clients/vscode-hlasmplugin/CHANGELOG.md +++ b/clients/vscode-hlasmplugin/CHANGELOG.md @@ -18,6 +18,7 @@ #### Changed - Macro label is the preferred go to definition target unless the request is made from the label itself +- Library contents are now shared between processor groups ## [1.5.0](https://github.com/eclipse/che-che4z-lsp-for-hlasm/compare/1.4.0...1.5.0) (2022-11-02) diff --git a/parser_library/src/context/source_context.h b/parser_library/src/context/source_context.h index 6a5cae0be..a2720baf1 100644 --- a/parser_library/src/context/source_context.h +++ b/parser_library/src/context/source_context.h @@ -22,6 +22,7 @@ #include "copy_member.h" #include "processing/processing_format.h" #include "source_snapshot.h" +#include "utils/general_hashers.h" namespace hlasm_plugin::parser_library::context { @@ -103,11 +104,8 @@ class processing_frame_tree size_t operator()(const processing_frame_node& n) const { constexpr auto hash = [](const T&... v) { - constexpr auto hash_combine = [](size_t old, size_t next) { - return old ^ (next + 0x9e3779b9 + (old << 6) + (old >> 2)); - }; size_t result = 0; - ((result = hash_combine(result, std::hash()(v))), ...); + ((result = utils::hashers::hash_combine(result, std::hash()(v))), ...); return result; }; return hash(n.m_parent, n.frame.member_name, n.frame.resource_loc, n.frame.pos.column, n.frame.pos.line); diff --git a/parser_library/src/expressions/data_definition.cpp b/parser_library/src/expressions/data_definition.cpp index 15406d9dc..c9308908e 100644 --- a/parser_library/src/expressions/data_definition.cpp +++ b/parser_library/src/expressions/data_definition.cpp @@ -28,9 +28,11 @@ #include "mach_expr_term.h" #include "mach_expr_visitor.h" #include "semantics/collector.h" +#include "utils/general_hashers.h" #include "utils/similar.h" namespace hlasm_plugin::parser_library::expressions { +using utils::hashers::hash_combine; constexpr char V_type = 'V'; diff --git a/parser_library/src/expressions/mach_expr_term.cpp b/parser_library/src/expressions/mach_expr_term.cpp index af77ed1d4..22efad2a0 100644 --- a/parser_library/src/expressions/mach_expr_term.cpp +++ b/parser_library/src/expressions/mach_expr_term.cpp @@ -23,9 +23,11 @@ #include "context/ordinary_assembly/symbol_value.h" #include "ebcdic_encoding.h" #include "mach_expr_visitor.h" +#include "utils/general_hashers.h" #include "utils/similar.h" namespace hlasm_plugin::parser_library::expressions { +using utils::hashers::hash_combine; //*********** mach_expr_constant ************ bool mach_expr_constant::do_is_similar(const mach_expression& expr) const diff --git a/parser_library/src/expressions/mach_expression.h b/parser_library/src/expressions/mach_expression.h index 165cf7c37..c984d7c81 100644 --- a/parser_library/src/expressions/mach_expression.h +++ b/parser_library/src/expressions/mach_expression.h @@ -70,11 +70,6 @@ class mach_expression : public context::resolvable range expr_range_; }; -inline size_t hash_combine(std::size_t old, std::size_t next) -{ - return old ^ (next + 0x9e3779b9 + (old << 6) + (old >> 2)); -} - } // namespace hlasm_plugin::parser_library::expressions #endif diff --git a/parser_library/src/expressions/mach_operator.cpp b/parser_library/src/expressions/mach_operator.cpp index b573a2da6..8df94efe8 100644 --- a/parser_library/src/expressions/mach_operator.cpp +++ b/parser_library/src/expressions/mach_operator.cpp @@ -17,9 +17,11 @@ #include #include "context/ordinary_assembly/symbol_value.h" +#include "utils/general_hashers.h" #include "utils/similar.h" namespace hlasm_plugin::parser_library::expressions { +using utils::hashers::hash_combine; template bool mach_expr_binary::do_is_similar(const mach_expression& expr) const diff --git a/parser_library/src/expressions/nominal_value.cpp b/parser_library/src/expressions/nominal_value.cpp index 01261632b..5c5ab148f 100644 --- a/parser_library/src/expressions/nominal_value.cpp +++ b/parser_library/src/expressions/nominal_value.cpp @@ -16,11 +16,14 @@ #include +#include "utils/general_hashers.h" #include "utils/similar.h" using namespace hlasm_plugin::parser_library::expressions; using namespace hlasm_plugin::parser_library::context; +using hlasm_plugin::utils::hashers::hash_combine; + nominal_value_string* nominal_value_t::access_string() { return dynamic_cast(this); } nominal_value_exprs* nominal_value_t::access_exprs() { return dynamic_cast(this); } diff --git a/parser_library/src/workspaces/library_local.h b/parser_library/src/workspaces/library_local.h index 4d1645958..00727311a 100644 --- a/parser_library/src/workspaces/library_local.h +++ b/parser_library/src/workspaces/library_local.h @@ -16,6 +16,7 @@ #define HLASMPLUGIN_PARSERLIBRARY_LOCAL_LIBRARY_H #include +#include #include #include #include @@ -37,6 +38,26 @@ struct library_local_options std::vector extensions; bool extensions_from_deprecated_source = false; bool optional_library = false; + +#ifdef __cpp_lib_three_way_comparison + auto operator<=>(const library_local_options&) const = default; +#else + // libc++ (not even in main!!!) + bool operator<(const library_local_options& o) const + { + if (extensions < o.extensions) + return true; + if (extensions > o.extensions) + return false; + if (extensions_from_deprecated_source < o.extensions_from_deprecated_source) + return true; + if (extensions_from_deprecated_source > o.extensions_from_deprecated_source) + return false; + if (optional_library < o.optional_library) + return true; + return false; + } +#endif }; // library holds absolute path to a directory and finds macro files in it diff --git a/parser_library/src/workspaces/processor_group.cpp b/parser_library/src/workspaces/processor_group.cpp index d3ce22922..c84852d8f 100644 --- a/parser_library/src/workspaces/processor_group.cpp +++ b/parser_library/src/workspaces/processor_group.cpp @@ -78,6 +78,8 @@ void processor_group::generate_suggestions(bool force) } } +void processor_group::invalidate_suggestions() { m_suggestions.reset(); } + std::vector> processor_group::suggest(std::string_view opcode, bool extended) { generate_suggestions(false); @@ -125,7 +127,7 @@ void processor_group::collect_diags() const } } -void processor_group::add_library(std::unique_ptr library) +void processor_group::add_library(std::shared_ptr library) { const auto& lib = m_libs.emplace_back(std::move(library)); m_refresh_prefix.emplace(lib->refresh_url_prefix()); diff --git a/parser_library/src/workspaces/processor_group.h b/parser_library/src/workspaces/processor_group.h index e7f5ca58b..e904e3793 100644 --- a/parser_library/src/workspaces/processor_group.h +++ b/parser_library/src/workspaces/processor_group.h @@ -45,7 +45,7 @@ class processor_group : public diagnosable_impl void collect_diags() const override; - void add_library(std::unique_ptr library); + void add_library(std::shared_ptr library); const std::string& name() const { return m_pg_name; } @@ -56,6 +56,7 @@ class processor_group : public diagnosable_impl const std::vector& preprocessors() const { return m_prep_opts; } void generate_suggestions(bool force = true); + void invalidate_suggestions(); std::vector> suggest(std::string_view s, bool extended); diff --git a/parser_library/src/workspaces/workspace_configuration.cpp b/parser_library/src/workspaces/workspace_configuration.cpp index 4f7cedf8f..e3911d03a 100644 --- a/parser_library/src/workspaces/workspace_configuration.cpp +++ b/parser_library/src/workspaces/workspace_configuration.cpp @@ -15,6 +15,8 @@ #include "workspace_configuration.h" #include +#include +#include #include "file_manager.h" #include "library_local.h" @@ -254,6 +256,37 @@ bool workspace_configuration::is_configuration_file(const utils::resource::resou { return is_config_file(file) || is_b4g_config_file(file); } + +template +inline bool operator<(const std::pair& l, + const std::tuple& r) noexcept +{ + const auto& [lx, ly] = l; + return std::tie(lx, ly) < r; +} + +template +inline bool operator<(const std::tuple& l, + const std::pair& r) noexcept +{ + const auto& [rx, ry] = r; + return l < std::tie(rx, ry); +} + +std::shared_ptr workspace_configuration::get_local_library( + const utils::resource::resource_location& url, const library_local_options& opts) +{ + if (auto it = m_libraries.find(std::tie(url, opts)); it != m_libraries.end()) + { + it->second.second = true; + return it->second.first; + } + + auto result = std::make_shared(m_file_manager, url, opts, m_proc_grps_loc); + m_libraries.try_emplace(std::make_pair(url, library_options(opts)), result, true); + return result; +} + void workspace_configuration::process_processor_group(const config::processor_group& pg, std::span fallback_macro_extensions, std::span always_recognize, @@ -281,8 +314,7 @@ void workspace_configuration::process_processor_group(const config::processor_gr rl.join(""); // Ensure that this is a directory if (auto first_wild_card = rl.get_uri().find_first_of("*?"); first_wild_card == std::string::npos) - prc_grp.add_library(std::make_unique( - m_file_manager, std::move(rl), std::move(lib_local_opts), m_proc_grps_loc)); + prc_grp.add_library(get_local_library(rl, lib_local_opts)); else find_and_add_libs(utils::resource::resource_location( rl.get_uri().substr(0, rl.get_uri().find_last_of("/", first_wild_card) + 1)), @@ -294,6 +326,22 @@ void workspace_configuration::process_processor_group(const config::processor_gr m_proc_grps.try_emplace(std::make_pair(prc_grp.name(), alternative_root), std::move(prc_grp)); } +void workspace_configuration::process_processor_group_and_cleanup_libraries( + std::span pgs, + std::span fallback_macro_extensions, + std::span always_recognize, + const utils::resource::resource_location& alternative_root, + std::vector& diags) +{ + for (auto& [_, l] : m_libraries) + l.second = false; // mark + + for (const auto& pg : pgs) + process_processor_group(pg, fallback_macro_extensions, always_recognize, alternative_root, diags); + + std::erase_if(m_libraries, [](const auto& kv) { return !kv.second.second; }); // sweep +} + bool workspace_configuration::process_program(const config::program_mapping& pgm, std::vector& diags) { const auto key = std::make_pair(pgm.pgroup, utils::resource::resource_location()); @@ -348,12 +396,11 @@ parse_config_file_result workspace_configuration::load_and_process_config(std::v file_ptr pgm_conf_file; const auto pgm_conf_loaded = load_pgm_config(pgm_config, pgm_conf_file, utilized_settings_values, diags); - // process processor groups - for (const auto& pg : proc_groups.pgroups) - { - process_processor_group( - pg, proc_groups.macro_extensions, pgm_config.always_recognize, utils::resource::resource_location(), diags); - } + process_processor_group_and_cleanup_libraries(proc_groups.pgroups, + proc_groups.macro_extensions, + pgm_config.always_recognize, + utils::resource::resource_location(), + diags); if (pgm_conf_loaded != parse_config_file_result::parsed) { @@ -502,8 +549,8 @@ parse_config_file_result workspace_configuration::parse_b4g_config_file( return parse_config_file_result::error; } - for (const auto& pg_def : m_proc_grps_source.pgroups) - process_processor_group(pg_def, m_proc_grps_source.macro_extensions, {}, alternative_root, conf.diags); + process_processor_group_and_cleanup_libraries( + m_proc_grps_source.pgroups, m_proc_grps_source.macro_extensions, {}, alternative_root, conf.diags); for (const auto& [name, details] : conf.config.value().files) { @@ -589,7 +636,7 @@ void workspace_configuration::find_and_add_libs(const utils::resource::resource_ continue; if (std::regex_match(dir.get_uri(), path_validator)) - prc_grp.add_library(std::make_unique(m_file_manager, dir, opts, m_proc_grps_loc)); + prc_grp.add_library(get_local_library(dir, opts)); auto [subdir_list, return_code] = m_file_manager.list_directory_subdirs_and_symlinks(dir); if (return_code != utils::path::list_directory_rc::done) @@ -648,16 +695,20 @@ parse_config_file_result workspace_configuration::parse_configuration_file( bool workspace_configuration::refresh_libraries(const std::vector& file_locations) { bool refreshed = false; + + std::unordered_set refreshed_libs; for (auto& [_, proc_grp] : m_proc_grps) { if (!proc_grp.refresh_needed(file_locations)) continue; refreshed = true; - for (auto& lib : proc_grp.libraries()) + for (const auto& lib : proc_grp.libraries()) { + if (!refreshed_libs.emplace(std::to_address(lib)).second) + continue; lib->refresh(); } - proc_grp.generate_suggestions(); + proc_grp.invalidate_suggestions(); } return refreshed; } diff --git a/parser_library/src/workspaces/workspace_configuration.h b/parser_library/src/workspaces/workspace_configuration.h index f6a55b6e6..c4bba86e2 100644 --- a/parser_library/src/workspaces/workspace_configuration.h +++ b/parser_library/src/workspaces/workspace_configuration.h @@ -84,6 +84,83 @@ class shared_json }; #endif + +class library_options +{ + template + struct impl_t + { + static void deleter(const void* p) noexcept { delete static_cast(p); } + static bool comparer_lt(const void* l, const void* r) noexcept + { + return *static_cast(l) < *static_cast(r); + } + }; + struct impl + { + void (*deleter)(const void* p) noexcept; + bool (*comparer_lt)(const void* l, const void* r) noexcept; + template + static const impl* get() + { + static constexpr const impl i { &impl_t::deleter, &impl_t::comparer_lt }; + return &i; + } + }; + const impl* m_impl; + const void* m_data; + +public: + template + explicit library_options(T value) + : m_impl(impl::get()) + , m_data(new T(std::move(value))) + {} + library_options(library_options&& o) noexcept + : m_impl(std::exchange(o.m_impl, nullptr)) + , m_data(std::exchange(o.m_data, nullptr)) + {} + library_options& operator=(library_options&& o) noexcept + { + library_options tmp(std::move(o)); + swap(tmp); + return *this; + } + void swap(library_options& o) noexcept + { + std::swap(m_impl, o.m_impl); + std::swap(m_data, o.m_data); + } + ~library_options() + { + if (m_impl) + m_impl->deleter(m_data); + } + + friend bool operator<(const library_options& l, const library_options& r) noexcept + { + if (auto c = l.m_impl <=> r.m_impl; c != 0) + return c < 0; + + return l.m_impl && l.m_impl->comparer_lt(l.m_data, r.m_data); + } + + template + friend bool operator<(const library_options& l, const T& r) noexcept + { + if (auto c = l.m_impl <=> impl::template get(); c != 0) + return c < 0; + return impl_t::comparer_lt(l.m_data, &r); + } + template + friend bool operator<(const T& l, const library_options& r) noexcept + { + if (auto c = impl::template get() <=> r.m_impl; c != 0) + return c < 0; + return impl_t::comparer_lt(&l, r.m_data); + } +}; + class workspace_configuration { static constexpr const char FILENAME_PROC_GRPS[] = "proc_grps.json"; @@ -133,12 +210,26 @@ class workspace_configuration std::vector m_config_diags; + std::map, + std::pair, bool>, + std::less<>> + m_libraries; + + std::shared_ptr get_local_library( + const utils::resource::resource_location& url, const library_local_options& opts); + void process_processor_group(const config::processor_group& pg, std::span fallback_macro_extensions, std::span always_recognize, const utils::resource::resource_location& alternative_root, std::vector& diags); + void process_processor_group_and_cleanup_libraries(std::span pgs, + std::span fallback_macro_extensions, + std::span always_recognize, + const utils::resource::resource_location& alternative_root, + std::vector& diags); + bool process_program(const config::program_mapping& pgm, std::vector& diags); bool is_config_file(const utils::resource::resource_location& file_location) const; diff --git a/parser_library/test/workspace/CMakeLists.txt b/parser_library/test/workspace/CMakeLists.txt index f404a7eb5..7038f22ba 100644 --- a/parser_library/test/workspace/CMakeLists.txt +++ b/parser_library/test/workspace/CMakeLists.txt @@ -29,6 +29,7 @@ target_sources(library_test PRIVATE text_synchronization_test.cpp virtual_files_test.cpp wildcard2regex_test.cpp + workspace_configuration_test.cpp workspace_pattern_test.cpp workspace_test.cpp ) diff --git a/parser_library/test/workspace/processor_group_test.cpp b/parser_library/test/workspace/processor_group_test.cpp index 4e05f3a9f..2c55502d4 100644 --- a/parser_library/test/workspace/processor_group_test.cpp +++ b/parser_library/test/workspace/processor_group_test.cpp @@ -238,7 +238,7 @@ TEST(processor_group, opcode_suggestions) std::string refresh_url_prefix() const override { return {}; } }; processor_group grp("", {}, {}); - grp.add_library(std::make_unique()); + grp.add_library(std::make_shared()); auto mac_false = grp.suggest("MAC", false); std::vector> expected_mac_false { { "MAC1", 1 }, { "MAC2", 1 } }; diff --git a/parser_library/test/workspace/workspace_configuration_test.cpp b/parser_library/test/workspace/workspace_configuration_test.cpp new file mode 100644 index 000000000..f34edf435 --- /dev/null +++ b/parser_library/test/workspace/workspace_configuration_test.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 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 "workspaces/workspace_configuration.h" + +using namespace hlasm_plugin::parser_library; +using namespace hlasm_plugin::parser_library::workspaces; + +namespace { +template +struct X +{ + char a; + + auto operator<=>(const X&) const = default; +}; +} // namespace + +TEST(workspace_configuration, library_options) +{ + static_assert(!std::is_copy_constructible_v); + + constexpr auto eq = [](auto&& l, auto&& r) { return !(l < r || r < l); }; + + X<0> x0_0 { 0 }; + library_options lx0_1(X<0> { 0 }); + EXPECT_TRUE(eq(lx0_1, x0_0)); + + library_options lx0_2(X<0> { 0 }); + EXPECT_TRUE(eq(lx0_1, lx0_2)); + + library_options lx0_moved_1(std::move(lx0_1)); + library_options lx0_moved_2(std::move(lx0_2)); + EXPECT_TRUE(eq(lx0_moved_1, lx0_moved_2)); + EXPECT_TRUE(eq(lx0_1, lx0_2)); + EXPECT_FALSE(eq(lx0_1, lx0_moved_1)); + + X<0> x0_1 { 1 }; + EXPECT_TRUE(lx0_moved_1 < x0_1); + EXPECT_TRUE(lx0_moved_1 < library_options(x0_1)); + + X<1> x1_0 { 0 }; + EXPECT_FALSE(eq(lx0_moved_1, x1_0)); + EXPECT_FALSE(eq(lx0_moved_1, library_options(x1_0))); + + library_options lx1_1(x1_0); + library_options lx1_2(x1_0); + library_options lx1_3(x0_0); + + EXPECT_TRUE(eq(lx1_1, lx1_2)); + EXPECT_FALSE(eq(lx1_2, lx1_3)); + + lx1_3 = library_options(x1_0); + EXPECT_TRUE(eq(lx1_1, lx1_3)); + + EXPECT_TRUE(library_options(X<2> { 1 }) < X<2> { 2 }); + EXPECT_TRUE(library_options(X<2> { 1 }) < library_options(X<2> { 2 })); +} diff --git a/utils/include/utils/general_hashers.h b/utils/include/utils/general_hashers.h index 0a74c11ff..6cb30978d 100644 --- a/utils/include/utils/general_hashers.h +++ b/utils/include/utils/general_hashers.h @@ -26,6 +26,12 @@ struct string_hasher return hasher(s); } }; + +constexpr size_t hash_combine(std::size_t old, std::size_t next) +{ + return old ^ (next + 0x9e3779b9 + (old << 6) + (old >> 2)); +} + } // namespace hlasm_plugin::utils::hashers -#endif \ No newline at end of file +#endif