From 5724f79514e104bb7903e7414e964e75a1fc2ada Mon Sep 17 00:00:00 2001 From: slavek-kucera <53339291+slavek-kucera@users.noreply.github.com> Date: Tue, 19 Oct 2021 17:02:34 +0200 Subject: [PATCH] Introduce a limit to outline tree size (#194) --- .../src/lsp/feature_language_features.cpp | 3 +- parser_library/include/workspace_manager.h | 2 +- .../src/lsp/document_symbol_item.cpp | 52 +- parser_library/src/lsp/document_symbol_item.h | 8 +- parser_library/src/lsp/feature_provider.h | 2 +- parser_library/src/lsp/file_info.cpp | 27 +- parser_library/src/lsp/file_info.h | 2 + parser_library/src/lsp/lsp_context.cpp | 445 +++++++++--------- parser_library/src/lsp/lsp_context.h | 38 +- parser_library/src/workspace_manager.cpp | 4 +- parser_library/src/workspace_manager_impl.h | 4 +- .../src/workspaces/processor_file_impl.cpp | 2 +- parser_library/src/workspaces/workspace.cpp | 4 +- parser_library/src/workspaces/workspace.h | 2 +- .../lsp_context_document_symbol_ord_test.cpp | 122 +++-- ...p_context_document_symbol_var_seq_test.cpp | 72 +-- .../test/lsp/lsp_context_ord_sym_test.cpp | 4 +- utils/include/utils/CMakeLists.txt | 1 + utils/include/utils/similar.h | 80 ++++ 19 files changed, 503 insertions(+), 371 deletions(-) create mode 100644 utils/include/utils/similar.h diff --git a/language_server/src/lsp/feature_language_features.cpp b/language_server/src/lsp/feature_language_features.cpp index f98dcdeec..1d502299f 100644 --- a/language_server/src/lsp/feature_language_features.cpp +++ b/language_server/src/lsp/feature_language_features.cpp @@ -320,7 +320,8 @@ void feature_language_features::document_symbol(const json& id, const json& para { auto document_uri = params["textDocument"]["uri"].get(); - auto symbol_list = ws_mngr_.document_symbol(uri_to_path(document_uri).c_str()); + const auto limit = 5000LL; + auto symbol_list = ws_mngr_.document_symbol(uri_to_path(document_uri).c_str(), limit); response_->respond(id, "", document_symbol_list_json(symbol_list)); } diff --git a/parser_library/include/workspace_manager.h b/parser_library/include/workspace_manager.h index ee49d64e9..781134b5e 100644 --- a/parser_library/include/workspace_manager.h +++ b/parser_library/include/workspace_manager.h @@ -101,7 +101,7 @@ class PARSER_LIBRARY_EXPORT workspace_manager const char* document_uri, position pos, char trigger_char, completion_trigger_kind trigger_kind); virtual const std::vector& semantic_tokens(const char* document_uri); - virtual document_symbol_list document_symbol(const char* document_uri); + virtual document_symbol_list document_symbol(const char* document_uri, long long limit); virtual void configuration_changed(const lib_config& new_config); diff --git a/parser_library/src/lsp/document_symbol_item.cpp b/parser_library/src/lsp/document_symbol_item.cpp index f8ac1e618..5bc60cfd7 100644 --- a/parser_library/src/lsp/document_symbol_item.cpp +++ b/parser_library/src/lsp/document_symbol_item.cpp @@ -14,6 +14,8 @@ #include "document_symbol_item.h" +#include "utils/similar.h" + namespace hlasm_plugin::parser_library::lsp { document_symbol_item_s::document_symbol_item_s(std::string name, document_symbol_kind kind, range symbol_range) @@ -31,55 +33,15 @@ document_symbol_item_s::document_symbol_item_s( , children(children) {} -bool is_permutation_with_permutations(const document_symbol_list_s& lhs, const document_symbol_list_s& rhs) -{ - if (lhs.size() != rhs.size()) - { - return false; - } - for (auto& item : lhs) - { - auto i = std::find(rhs.begin(), rhs.end(), item); - if (i == rhs.end()) - { - return false; - } - if (!is_permutation_with_permutations(item.children, i->children)) - { - return false; - } - } - return true; -} - -document_symbol_list_s::iterator document_symbol_no_children_find( - document_symbol_list_s::iterator begin, document_symbol_list_s::iterator end, const document_symbol_item_s& item) -{ - while (begin != end) - { - if (item.name == begin->name && item.kind == begin->kind && item.symbol_range == begin->symbol_range - && item.symbol_selection_range == begin->symbol_selection_range) - { - return begin; - } - begin++; - } - return end; -} - -bool operator==(const document_symbol_item_s& lhs, const document_symbol_item_s& rhs) +bool is_similar(const document_symbol_list_s& l, const document_symbol_list_s& r) { - return lhs.name == rhs.name && lhs.kind == rhs.kind && lhs.symbol_range == rhs.symbol_range - && lhs.symbol_selection_range == rhs.symbol_selection_range - && is_permutation_with_permutations(lhs.children, rhs.children); + return l.size() == r.size() && std::is_permutation(l.begin(), l.end(), r.begin(), utils::is_similar); } -void operator+=(document_symbol_list_s& lhs, const document_symbol_list_s& rhs) +bool is_similar(const document_symbol_item_s& l, const document_symbol_item_s& r) { - for (const auto& item : rhs) - { - lhs.push_back(item); - } + return l.name == r.name && l.kind == r.kind && l.symbol_range == r.symbol_range + && l.symbol_selection_range == r.symbol_selection_range && is_similar(l.children, r.children); } } // namespace hlasm_plugin::parser_library::lsp \ No newline at end of file diff --git a/parser_library/src/lsp/document_symbol_item.h b/parser_library/src/lsp/document_symbol_item.h index a0586d202..8c9d8dba0 100644 --- a/parser_library/src/lsp/document_symbol_item.h +++ b/parser_library/src/lsp/document_symbol_item.h @@ -42,12 +42,8 @@ struct document_symbol_item_s std::vector scope; }; - -bool operator==(const document_symbol_item_s& lhs, const document_symbol_item_s& rhs); -bool is_permutation_with_permutations(const document_symbol_list_s& lhs, const document_symbol_list_s& rhs); -document_symbol_list_s::iterator document_symbol_no_children_find( - document_symbol_list_s::iterator begin, document_symbol_list_s::iterator end, const document_symbol_item_s& item); -void operator+=(document_symbol_list_s& lhs, const document_symbol_list_s& rhs); +bool is_similar(const document_symbol_list_s& l, const document_symbol_list_s& r); +bool is_similar(const document_symbol_item_s& l, const document_symbol_item_s& r); } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/src/lsp/feature_provider.h b/parser_library/src/lsp/feature_provider.h index 6bde29bf4..1e6a8b040 100644 --- a/parser_library/src/lsp/feature_provider.h +++ b/parser_library/src/lsp/feature_provider.h @@ -34,7 +34,7 @@ struct feature_provider position pos, char trigger_char, completion_trigger_kind trigger_kind) const = 0; - virtual document_symbol_list_s document_symbol(const std::string& document_uri) const = 0; + virtual document_symbol_list_s document_symbol(const std::string& document_uri, long long limit) const = 0; protected: ~feature_provider() = default; diff --git a/parser_library/src/lsp/file_info.cpp b/parser_library/src/lsp/file_info.cpp index fc5cfe13a..09bfaa5e5 100644 --- a/parser_library/src/lsp/file_info.cpp +++ b/parser_library/src/lsp/file_info.cpp @@ -56,13 +56,20 @@ occurence_scope_t file_info::find_occurence_with_scope(position pos) const { const symbol_occurence* found = nullptr; + auto l = std::lower_bound(occurences.begin(), occurences.end(), pos, [](const auto& occ, const auto& p) { + return occ.occurence_range.end.line < p.line; + }); + auto it_limit = occurences_start_limit.begin() + std::distance(occurences.begin(), l); // find in occurences - for (const auto& occ : occurences) + for (auto it = l; it != occurences.end() && *it_limit <= pos.line; ++it, ++it_limit) + { + const auto& occ = *it; if (is_in_range(pos, occ.occurence_range)) { found = &occ; break; } + } // if not found, return if (!found) @@ -93,8 +100,7 @@ std::vector file_info::find_references( void file_info::update_occurences(const occurence_storage& occurences_upd) { - for (const auto& occ : occurences_upd) - occurences.emplace_back(occ); + occurences.insert(occurences.end(), occurences_upd.begin(), occurences_upd.end()); } void file_info::update_slices(const std::vector& slices_upd) @@ -145,4 +151,19 @@ std::vector file_slice_t::transform_slices( const std::vector& file_info::get_occurences() const { return occurences; } +void file_info::process_occurrences() +{ + std::sort(occurences.begin(), occurences.end(), [](const auto& l, const auto& r) { + return std::tie(l.occurence_range.end.line, l.occurence_range.start.line) + < std::tie(r.occurence_range.end.line, r.occurence_range.start.line); + }); + + occurences_start_limit.resize(occurences.size()); + + std::transform(occurences.rbegin(), + occurences.rend(), + occurences_start_limit.rbegin(), + [min = (size_t)-1](const auto& occ) mutable { return min = std::min(min, occ.occurence_range.start.line); }); +} + } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/src/lsp/file_info.h b/parser_library/src/lsp/file_info.h index 9a6e2fd21..8d9bd9f25 100644 --- a/parser_library/src/lsp/file_info.h +++ b/parser_library/src/lsp/file_info.h @@ -96,10 +96,12 @@ class file_info void update_occurences(const occurence_storage& occurences_upd); void update_slices(const std::vector& slices); const std::vector& get_occurences() const; + void process_occurrences(); private: std::map slices; std::vector occurences; + std::vector occurences_start_limit; }; } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/src/lsp/lsp_context.cpp b/parser_library/src/lsp/lsp_context.cpp index 0778e74a6..d81d4c9e6 100644 --- a/parser_library/src/lsp/lsp_context.cpp +++ b/parser_library/src/lsp/lsp_context.cpp @@ -22,6 +22,7 @@ #include "context/instruction.h" #include "ebcdic_encoding.h" +#include "utils/similar.h" namespace hlasm_plugin::parser_library::lsp { namespace { @@ -104,115 +105,77 @@ std::string lsp_context::find_macro_copy_id(const context::processing_stack_t& s return stack[i].member_name == context::id_storage::empty_id ? stack[i].proc_location.file : *stack[i].member_name; } -document_symbol_list_s lsp_context::document_symbol_macro(const std::string& document_uri) const +void lsp_context::document_symbol_macro( + document_symbol_list_s& result, const std::string& document_uri, std::optional r, long long& limit) const { + auto m = std::find_if(macros_.begin(), macros_.end(), [&document_uri](const auto& mac) { + return mac.first->definition_location.file == document_uri; + }); + if (m == macros_.end()) + return; + + const auto& [def, info] = *m; + auto copy_occs = copy_occurences(document_uri); - document_symbol_list_s result; - for (const auto& [def, info] : macros_) + + for (const auto& var : info->var_definitions) { - if (info->definition_location.file == document_uri) + if (limit <= 0) + break; + if (!belongs_to_copyfile(document_uri, var.def_position, var.name)) { - for (const auto& var : info->var_definitions) - { - if (belongs_to_copyfile(document_uri, var.def_position, var.name)) - { - modify_with_copy(result, var.name, copy_occs, document_symbol_kind::VAR); - } - else - { - result.emplace_back(document_symbol_item_s { - *var.name, document_symbol_kind::VAR, { var.def_position, var.def_position } }); - } - } - for (const auto& [name, seq] : def->labels) - { - if (belongs_to_copyfile(document_uri, seq->symbol_location.pos, name)) - { - modify_with_copy(result, name, copy_occs, document_symbol_kind::SEQ); - } - else - { - result.emplace_back(document_symbol_item_s { - *name, document_symbol_kind::SEQ, { seq->symbol_location.pos, seq->symbol_location.pos } }); - } - } - return result; + result.emplace_back(*var.name, document_symbol_kind::VAR, r.value_or(range(var.def_position))); + --limit; } + else if (!r.has_value()) + modify_with_copy(result, var.name, copy_occs, document_symbol_kind::VAR, limit); } - return result; -} - -document_symbol_list_s lsp_context::document_symbol_macro(const std::string& document_uri, const range& r) const -{ - auto copy_occs = copy_occurences(document_uri); - document_symbol_list_s result; - for (const auto& [def, info] : macros_) + for (const auto& [name, seq] : def->labels) { - if (def->definition_location.file == document_uri) + if (limit <= 0) + break; + if (!belongs_to_copyfile(document_uri, seq->symbol_location.pos, name)) { - for (const auto& var : info->var_definitions) - { - if (!belongs_to_copyfile(document_uri, var.def_position, var.name)) - { - result.emplace_back(document_symbol_item_s { - *var.name, document_symbol_kind::VAR, { var.def_position, var.def_position } }); - result.back().symbol_range = r; - result.back().symbol_selection_range = r; - } - } - for (const auto& [name, seq] : def->labels) - { - if (!belongs_to_copyfile(document_uri, seq->symbol_location.pos, name)) - { - result.emplace_back(document_symbol_item_s { - *name, document_symbol_kind::SEQ, { seq->symbol_location.pos, seq->symbol_location.pos } }); - result.back().symbol_range = r; - result.back().symbol_selection_range = r; - } - } - return result; + result.emplace_back(*name, document_symbol_kind::SEQ, r.value_or(range(seq->symbol_location.pos))); + --limit; } + else if (!r.has_value()) + modify_with_copy(result, name, copy_occs, document_symbol_kind::SEQ, limit); } - return result; } -bool lsp_context::belongs_to_copyfile(const std::string& document_uri, position pos, const context::id_index& id) const +bool lsp_context::belongs_to_copyfile(const std::string& document_uri, position pos, context::id_index id) const { - const auto& aux = find_occurence_with_scope(document_uri, pos).first; + const auto* aux = find_occurence_with_scope(document_uri, pos).first; return aux == nullptr || *aux->name != *id; } -document_symbol_list_s lsp_context::document_symbol_copy( - const std::vector& occurence_list, const std::string& document_uri) const +void lsp_context::document_symbol_copy(document_symbol_list_s& result, + const std::vector& occurence_list, + const std::string& document_uri, + std::optional r, + long long& limit) const { - document_symbol_list_s result; for (const auto& occ : occurence_list) { + if (limit <= 0) + return; if (occ.kind == occurence_kind::VAR || occ.kind == occurence_kind::SEQ) { position aux = definition(document_uri, occ.occurence_range.start).pos; - document_symbol_item_s item = { *occ.name, + document_symbol_item_s item = { + *occ.name, document_symbol_item_kind_mapping_macro.at(occ.kind), - { aux, { aux.line, aux.column + occ.occurence_range.end.column - occ.occurence_range.start.column } } }; - if (std::find(result.begin(), result.end(), item) == result.end()) + r.value_or(range(aux, + position(aux.line, aux.column + occ.occurence_range.end.column - occ.occurence_range.start.column))) + }; + if (std::none_of(result.begin(), result.end(), utils::is_similar_to(item))) { result.push_back(item); + --limit; } } } - return result; -} - -document_symbol_list_s lsp_context::document_symbol_copy( - const std::vector& occurence_list, const std::string& document_uri, const range& r) const -{ - document_symbol_list_s result = document_symbol_copy(occurence_list, document_uri); - for (auto& item : result) - { - item.symbol_range = r; - item.symbol_selection_range = r; - } - return result; } std::vector>> lsp_context::copy_occurences( @@ -222,63 +185,66 @@ std::vector>> lsp_con std::vector>> copy_occurences; for (const auto& [uri, info] : files_) { - if (info->type == file_type::COPY) + if (info->type != file_type::COPY) + continue; + + const context::id_index name = std::get(info->owner)->name; + for (const auto& occ : file->second->get_occurences()) { - const context::id_index name = std::get(info->owner)->name; - for (const auto& occ : file->second->get_occurences()) + if (occ.name != name) + continue; + + std::vector occurences; + for (const auto& new_occ : info->get_occurences()) { - if (occ.name == name) + if (new_occ.kind == occurence_kind::VAR + || new_occ.kind == occurence_kind::SEQ + && std::none_of( + occurences.begin(), occurences.end(), [id = new_occ.name](auto e) { return id == e; })) { - std::vector occurences; - for (const auto& new_occ : info->get_occurences()) - { - if (new_occ.kind == occurence_kind::VAR - || new_occ.kind == occurence_kind::SEQ - && std::find(occurences.begin(), occurences.end(), new_occ.name) == occurences.end()) - { - occurences.push_back(new_occ.name); - } - } - copy_occurences.emplace_back(std::pair { occ, occurences }); + occurences.push_back(new_occ.name); } } + copy_occurences.emplace_back(occ, std::move(occurences)); } } return copy_occurences; } void lsp_context::modify_with_copy(document_symbol_list_s& modified, - const context::id_index& sym_name, + context::id_index sym_name, const std::vector>>& copy_occs, - const document_symbol_kind kind) const + const document_symbol_kind kind, + long long& limit) const { - if (!copy_occs.empty()) + for (const auto& [copy_occ, occs] : copy_occs) { - for (const auto& [copy_occ, occs] : copy_occs) + if (limit <= 0) + return; + if (std::none_of(occs.begin(), occs.end(), [sym_name](auto e) { return e == sym_name; })) + continue; + + bool have_already = false; + document_symbol_item_s sym_item(*sym_name, kind, copy_occ.occurence_range); + for (auto& item : modified) { - if (std::find(occs.begin(), occs.end(), sym_name) != occs.end()) + if (item.name == *copy_occ.name + && std::none_of(item.children.begin(), item.children.end(), utils::is_similar_to(sym_item))) { - bool have_already = false; - auto sym_item = document_symbol_item_s { *sym_name, kind, copy_occ.occurence_range }; - for (auto& item : modified) - { - if (item.name == *copy_occ.name - && std::find(item.children.begin(), item.children.end(), sym_item) == item.children.end()) - { - item.children.push_back(sym_item); - have_already = true; - break; - } - } - if (!have_already) - { - modified.emplace_back(document_symbol_item_s { *copy_occ.name, - document_symbol_kind::MACRO, - copy_occ.occurence_range, - document_symbol_list_s { sym_item } }); - } + item.children.push_back(sym_item); + have_already = true; + --limit; + break; } } + if (!have_already) + { + modified.emplace_back(*copy_occ.name, + document_symbol_kind::MACRO, + copy_occ.occurence_range, + document_symbol_list_s { std::move(sym_item) }); + --limit; + } } } @@ -311,19 +277,27 @@ bool do_not_need_nodes( } void lsp_context::document_symbol_symbol(document_symbol_list_s& modified, - const document_symbol_list_s& children, - const context::id_index& id, + document_symbol_list_s children, + context::id_index id, const context::symbol& sym, document_symbol_kind kind, - unsigned long i) const + unsigned long i, + long long& limit) const { - document_symbol_item_s aux = { find_macro_copy_id(sym.proc_stack(), i), + document_symbol_item_s aux(find_macro_copy_id(sym.proc_stack(), i), document_symbol_kind::MACRO, - { sym.proc_stack()[0].proc_location.pos, sym.proc_stack()[0].proc_location.pos } }; - auto i_find = document_symbol_no_children_find(modified.begin(), modified.end(), aux); + range(sym.proc_stack()[0].proc_location.pos)); + + const auto comp_aux = [&aux](const auto& e) { + return aux.name == e.name && aux.kind == e.kind && aux.symbol_range == e.symbol_range + && aux.symbol_selection_range == e.symbol_selection_range; + }; + + auto i_find = std::find_if(modified.begin(), modified.end(), comp_aux); if (i_find == modified.end()) { modified.push_back(aux); + --limit; i_find = modified.end() - 1; } i++; @@ -331,175 +305,183 @@ void lsp_context::document_symbol_symbol(document_symbol_list_s& modified, { aux.name = find_macro_copy_id(sym.proc_stack(), i); document_symbol_list_s* aux_list = &i_find->children; - i_find = document_symbol_no_children_find(aux_list->begin(), aux_list->end(), aux); + i_find = std::find_if(aux_list->begin(), aux_list->end(), comp_aux); if (i_find == aux_list->end()) { aux_list->push_back(aux); + --limit; i_find = aux_list->end() - 1; } i++; } - document_symbol_list_s* aux_list = &i_find->children; - aux_list->emplace_back(document_symbol_item_s { *id, kind, i_find->symbol_range, children }); + i_find->children.emplace_back(*id, kind, i_find->symbol_range, std::move(children)); + --limit; } -document_symbol_list_s lsp_context::document_symbol_opencode_ord_symbol() const +void lsp_context::document_symbol_opencode_ord_symbol(document_symbol_list_s& result, long long& limit) const { - document_symbol_list_s result; const auto& symbol_list = hlasm_ctx_->ord_ctx.symbols(); std::map children_of_sects; for (const auto& [id, sym] : symbol_list) { if (sym.attributes().origin == context::symbol_origin::SECT) { - auto sect = hlasm_ctx_->ord_ctx.get_section(id); - if (sect == nullptr) - continue; - children_of_sects.try_emplace(sect, document_symbol_list_s {}); + if (auto sect = hlasm_ctx_->ord_ctx.get_section(id)) + { + children_of_sects.try_emplace(sect, document_symbol_list_s {}); + --limit; + } } } for (const auto& [id, sym] : symbol_list) { - if (sym.attributes().origin != context::symbol_origin::SECT) + if (limit <= 0) + break; + if (sym.attributes().origin == context::symbol_origin::SECT) + continue; + + const auto* sect = + sym.value().value_kind() == context::symbol_value_kind::RELOC && sym.value().get_reloc().bases().size() == 1 + ? sym.value().get_reloc().bases().front().first.owner + : nullptr; + if (sect == nullptr || children_of_sects.find(sect) == children_of_sects.end()) { - const auto& sect = sym.value().value_kind() == context::symbol_value_kind::RELOC - ? sym.value().get_reloc().bases()[0].first.owner - : nullptr; - if (children_of_sects.find(sect) == children_of_sects.end()) + if (sym.proc_stack().size() == 1) + { + result.emplace_back(*id, + document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), + range(sym.symbol_location.pos)); + --limit; + } + else { - if (sym.proc_stack().size() == 1) - { - result.emplace_back(document_symbol_item_s { *id, - document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), - { sym.symbol_location.pos, sym.symbol_location.pos } }); - continue; - } document_symbol_symbol(result, document_symbol_list_s {}, id, sym, document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), - 1); - continue; + 1, + limit); } - - const auto& sect_sym = hlasm_ctx_->ord_ctx.get_symbol(sect->name); + } + else + { + const auto* sect_sym = hlasm_ctx_->ord_ctx.get_symbol(sect->name); auto& children = children_of_sects.find(sect)->second; unsigned long i = 1; if (do_not_need_nodes(sym.proc_stack(), sect_sym->proc_stack(), i)) { - children.emplace_back(document_symbol_item_s { *id, + children.emplace_back(*id, document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), - { sym.proc_stack()[0].proc_location.pos, sym.proc_stack()[0].proc_location.pos } }); - continue; + range(sym.proc_stack()[0].proc_location.pos)); + --limit; + } + else + { + document_symbol_symbol(children, + document_symbol_list_s {}, + id, + sym, + document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), + i, + limit); } - document_symbol_symbol(children, - document_symbol_list_s {}, - id, - sym, - document_symbol_item_kind_mapping_symbol.at(sym.attributes().origin), - i); } } - for (const auto& [sect, children] : children_of_sects) + for (auto&& [sect, children] : children_of_sects) { const auto& sym = *hlasm_ctx_->ord_ctx.get_symbol(sect->name); if (sym.proc_stack().size() == 1) { - result.emplace_back(document_symbol_item_s { *sect->name, + result.emplace_back(*sect->name, document_symbol_item_kind_mapping_section.at(sect->kind), - { sym.symbol_location.pos, sym.symbol_location.pos }, - children }); - continue; + range(sym.symbol_location.pos), + std::move(children)); + } + else + { + ++limit; // already counted + document_symbol_symbol(result, + std::move(children), + sect->name, + sym, + document_symbol_item_kind_mapping_section.at(sect->kind), + 1, + limit); } - document_symbol_symbol( - result, children, sect->name, sym, document_symbol_item_kind_mapping_section.at(sect->kind), 1); } - - return result; } -void lsp_context::document_symbol_opencode_var_seq_symbol_aux(document_symbol_list_s& result) const +void lsp_context::document_symbol_opencode_var_seq_symbol_aux(document_symbol_list_s& result, + const std::unordered_map& name_to_uri_cache, + long long& limit) const { for (auto& item : result) { - if (item.kind == document_symbol_kind::MACRO) - { - std::string document_uri = ""; - for (const auto& [def, info] : macros_) - { - if (*def->id == item.name) - { - document_uri = info->definition_location.file; - break; - } - } - for (const auto& [def, info] : hlasm_ctx_->copy_members()) - { - if (*info->name == item.name) - { - document_uri = info->definition_location.file; - break; - } - } - if (document_uri == "") - { - return; - } - const auto& file = files_.find(document_uri); - if (file != files_.end()) - { - if (file->second->type == file_type::MACRO) - { - item.children += document_symbol_macro(file->first, item.symbol_range); - } - if (file->second->type == file_type::COPY) - { - item.children += - document_symbol_copy(file->second->get_occurences(), file->first, item.symbol_range); - } - } - } - document_symbol_opencode_var_seq_symbol_aux(item.children); - } -} + if (item.kind != document_symbol_kind::MACRO) + continue; -void lsp_context::document_symbol_opencode_var_seq_symbol( - const std::string& document_uri, document_symbol_list_s& result) const -{ - document_symbol_opencode_var_seq_symbol_aux(result); + auto uri = name_to_uri_cache.find(item.name); + if (uri == name_to_uri_cache.end() || uri->second.empty()) + return; - auto copy_occs = copy_occurences(document_uri); - for (const auto& sym : opencode_->variable_definitions) - { - if (!belongs_to_copyfile(document_uri, sym.def_position, sym.name)) + if (const auto& file = files_.find(std::string(uri->second)); file != files_.end()) { - result.emplace_back(document_symbol_item_s { - *sym.name, document_symbol_kind::VAR, { sym.def_position, sym.def_position } }); + if (file->second->type == file_type::MACRO) + document_symbol_macro(item.children, file->first, item.symbol_range, limit); + else if (file->second->type == file_type::COPY) + document_symbol_copy( + item.children, file->second->get_occurences(), file->first, item.symbol_range, limit); } + document_symbol_opencode_var_seq_symbol_aux(item.children, name_to_uri_cache, limit); } } -document_symbol_list_s lsp_context::document_symbol(const std::string& document_uri) const +document_symbol_list_s lsp_context::document_symbol(const std::string& document_uri, long long limit) const { + document_symbol_list_s result; const auto& file = files_.find(document_uri); - if (file == files_.end()) - { - return document_symbol_list_s {}; - } + if (file == files_.end() || limit <= 0) + return result; + + std::unordered_map name_to_uri; + for (const auto& [def, info] : macros_) + name_to_uri.insert_or_assign(*def->id, info->definition_location.file); + for (const auto& [def, info] : hlasm_ctx_->copy_members()) + name_to_uri.insert_or_assign(*info->name, info->definition_location.file); + switch (file->second->type) { case file_type::MACRO: - return document_symbol_macro(document_uri); + document_symbol_macro(result, document_uri, std::nullopt, limit); + break; + case file_type::COPY: - return document_symbol_copy(file->second->get_occurences(), document_uri); + document_symbol_copy(result, file->second->get_occurences(), document_uri, std::nullopt, limit); + break; + default: - document_symbol_list_s result = document_symbol_opencode_ord_symbol(); - document_symbol_opencode_var_seq_symbol(document_uri, result); - return result; + document_symbol_opencode_ord_symbol(result, limit); + document_symbol_opencode_var_seq_symbol_aux(result, name_to_uri, limit); + + for (const auto& sym : opencode_->variable_definitions) + { + if (limit <= 0) + break; + if (!belongs_to_copyfile(document_uri, sym.def_position, sym.name)) + { + result.emplace_back(*sym.name, document_symbol_kind::VAR, range(sym.def_position)); + --limit; + } + } + break; } + if (limit <= 0) + result.emplace(result.begin(), "Outline may be truncated", document_symbol_kind::DUMMY, range()); + + return result; } @@ -537,6 +519,9 @@ void lsp_context::add_opencode(opencode_info_ptr opencode_i, text_data_ref_t tex distribute_macro_i(m); distribute_file_occurences(opencode_->file_occurences); + + for (const auto& [name, file] : files_) + file->process_occurrences(); } macro_info_ptr lsp_context::get_macro_info(context::id_index macro_name) const diff --git a/parser_library/src/lsp/lsp_context.h b/parser_library/src/lsp/lsp_context.h index cc070eee4..95ffa8ebc 100644 --- a/parser_library/src/lsp/lsp_context.h +++ b/parser_library/src/lsp/lsp_context.h @@ -49,7 +49,7 @@ class lsp_context final : public feature_provider position pos, char trigger_char, completion_trigger_kind trigger_kind) const override; - document_symbol_list_s document_symbol(const std::string& document_uri) const override; + document_symbol_list_s document_symbol(const std::string& document_uri, long long limit) const override; private: void add_file(file_info file_i); @@ -69,29 +69,35 @@ class lsp_context final : public feature_provider bool should_complete_instr(const text_data_ref_t& text, const position pos) const; std::string get_macro_documentation(const macro_info& m) const; - document_symbol_list_s document_symbol_macro(const std::string& document_uri) const; - document_symbol_list_s document_symbol_macro(const std::string& document_uri, const range& r) const; - document_symbol_list_s document_symbol_copy( - const std::vector& occurence_list, const std::string& document_uri) const; - document_symbol_list_s document_symbol_copy( - const std::vector& occurence_list, const std::string& document_uri, const range& r) const; + void document_symbol_macro(document_symbol_list_s& result, + const std::string& document_uri, + std::optional r, + long long& limit) const; + void document_symbol_copy(document_symbol_list_s& result, + const std::vector& occurence_list, + const std::string& document_uri, + std::optional r, + long long& limit) const; std::vector>> copy_occurences( const std::string& document_uri) const; void modify_with_copy(document_symbol_list_s& modified, - const context::id_index& sym_name, + context::id_index sym_name, const std::vector>>& copy_occs, - const document_symbol_kind kind) const; + const document_symbol_kind kind, + long long& limit) const; std::string find_macro_copy_id(const context::processing_stack_t& stack, unsigned long i) const; void document_symbol_symbol(document_symbol_list_s& modified, - const document_symbol_list_s& children, - const context::id_index& id, + document_symbol_list_s children, + context::id_index id, const context::symbol& sym, const document_symbol_kind kind, - unsigned long i) const; - document_symbol_list_s document_symbol_opencode_ord_symbol() const; - void document_symbol_opencode_var_seq_symbol(const std::string& document_uri, document_symbol_list_s& result) const; - void document_symbol_opencode_var_seq_symbol_aux(document_symbol_list_s& result) const; - bool belongs_to_copyfile(const std::string& document_uri, position pos, const context::id_index& id) const; + unsigned long i, + long long& limit) const; + void document_symbol_opencode_ord_symbol(document_symbol_list_s& result, long long& limit) const; + void document_symbol_opencode_var_seq_symbol_aux(document_symbol_list_s& result, + const std::unordered_map& name_to_uri_cache, + long long& limit) const; + bool belongs_to_copyfile(const std::string& document_uri, position pos, context::id_index id) const; }; } // namespace hlasm_plugin::parser_library::lsp diff --git a/parser_library/src/workspace_manager.cpp b/parser_library/src/workspace_manager.cpp index d1e0e13d4..dceb31a72 100644 --- a/parser_library/src/workspace_manager.cpp +++ b/parser_library/src/workspace_manager.cpp @@ -121,9 +121,9 @@ const std::vector& workspace_manager::semantic_tokens(const char* do return impl_->semantic_tokens(document_uri); } -document_symbol_list workspace_manager::document_symbol(const char* document_uri) +document_symbol_list workspace_manager::document_symbol(const char* document_uri, long long limit) { - return impl_->document_symbol(document_uri); + return impl_->document_symbol(document_uri, limit); } } // namespace hlasm_plugin::parser_library diff --git a/parser_library/src/workspace_manager_impl.h b/parser_library/src/workspace_manager_impl.h index 660d61bf2..6be7b05bb 100644 --- a/parser_library/src/workspace_manager_impl.h +++ b/parser_library/src/workspace_manager_impl.h @@ -183,12 +183,12 @@ class workspace_manager::impl final : public diagnosable_impl } lsp::document_symbol_list_s document_symbol_result; - document_symbol_list document_symbol(const std::string& document_uri) + document_symbol_list document_symbol(const std::string& document_uri, long long limit) { if (cancel_ && *cancel_) return document_symbol_list { nullptr, 0 }; - document_symbol_result = ws_path_match(document_uri).document_symbol(document_uri); + document_symbol_result = ws_path_match(document_uri).document_symbol(document_uri, limit); return document_symbol_list(document_symbol_result.data(), document_symbol_result.size()); } diff --git a/parser_library/src/workspaces/processor_file_impl.cpp b/parser_library/src/workspaces/processor_file_impl.cpp index d012f1dbb..6fe695f3f 100644 --- a/parser_library/src/workspaces/processor_file_impl.cpp +++ b/parser_library/src/workspaces/processor_file_impl.cpp @@ -157,7 +157,7 @@ class empty_feature_provider final : public lsp::feature_provider { return {}; } - lsp::document_symbol_list_s document_symbol(const std::string&) const override { return {}; } + lsp::document_symbol_list_s document_symbol(const std::string&, long long limit) const override { return {}; } }; } // namespace diff --git a/parser_library/src/workspaces/workspace.cpp b/parser_library/src/workspaces/workspace.cpp index 929e79010..219cb1a26 100644 --- a/parser_library/src/workspaces/workspace.cpp +++ b/parser_library/src/workspaces/workspace.cpp @@ -315,13 +315,13 @@ lsp::completion_list_s workspace::completion(const std::string& document_uri, return opencodes.back()->get_lsp_feature_provider().completion(document_uri, pos, trigger_char, trigger_kind); } -lsp::document_symbol_list_s workspace::document_symbol(const std::string& document_uri) const +lsp::document_symbol_list_s workspace::document_symbol(const std::string& document_uri, long long limit) const { auto opencodes = find_related_opencodes(document_uri); if (opencodes.empty()) return {}; // for now take last opencode - return opencodes.back()->get_lsp_feature_provider().document_symbol(document_uri); + return opencodes.back()->get_lsp_feature_provider().document_symbol(document_uri, limit); } void workspace::open() { load_and_process_config(); } diff --git a/parser_library/src/workspaces/workspace.h b/parser_library/src/workspaces/workspace.h index 73b52991f..367917d53 100644 --- a/parser_library/src/workspaces/workspace.h +++ b/parser_library/src/workspaces/workspace.h @@ -102,7 +102,7 @@ class workspace : public diagnosable_impl, public parse_lib_provider, public lsp position pos, char trigger_char, completion_trigger_kind trigger_kind) const override; - lsp::document_symbol_list_s document_symbol(const std::string& document_uri) const override; + lsp::document_symbol_list_s document_symbol(const std::string& document_uri, long long limit) const override; parse_result parse_library(const std::string& library, analyzing_context ctx, library_data data) override; bool has_library(const std::string& library, const std::string& program) const override; 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 781bcc75c..3eb2941af 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 @@ -29,7 +29,9 @@ SEC1 DSECT )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string SEC0 = "SEC0", SEC1 = "SEC1", AUX = "AUX", E = "E"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -55,7 +57,7 @@ SEC1 DSECT }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_sect_2) @@ -73,7 +75,9 @@ AUX3 LR 1,1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string SEC0 = "SEC0", SEC1 = "SEC1", AUX0 = "AUX0", AUX1 = "AUX1", AUX2 = "AUX2", AUX3 = "AUX3", E = "E"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -116,7 +120,7 @@ AUX3 LR 1,1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_1) @@ -129,9 +133,11 @@ E EQU 1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); document_symbol_list_s expected = {}; - EXPECT_EQ(outline, expected); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_2) @@ -146,7 +152,9 @@ E EQU 1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC = "MAC", E = "E", AUX = "AUX"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -167,7 +175,7 @@ E EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_3) @@ -190,7 +198,9 @@ AUX2 LR 1,1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC1 = "MAC1", MAC2 = "MAC2", E1 = "E1", E2 = "E2", AUX1 = "AUX1", AUX2 = "AUX2"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -228,7 +238,7 @@ AUX2 LR 1,1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_4) @@ -253,7 +263,9 @@ AUX3 LR 1,1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC1 = "MAC1", E1 = "E1", MAC2 = "MAC2", E2 = "E2", AUX1 = "AUX1", AUX2 = "AUX2", AUX3 = "AUX3", SEC = "SEC"; document_symbol_list_s expected = document_symbol_list_s { @@ -318,7 +330,7 @@ AUX3 LR 1,1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_5) @@ -346,7 +358,9 @@ E3 EQU 1 )"; analyzer a(input); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC1 = "MAC1", MAC2 = "MAC2", E1 = "E1", E2 = "E2", E3 = "E3", AUX1 = "AUX1", AUX2 = "AUX2", AUX3 = "AUX3", AUX4 = "AUX4", SEC1 = "SEC1", SEC2 = "SEC2"; document_symbol_list_s expected = document_symbol_list_s { @@ -428,7 +442,7 @@ E3 EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_6) @@ -446,7 +460,9 @@ AUX LR 1,1 }); analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC1 = "MAC1", AUX = "AUX", E = "E"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -467,7 +483,7 @@ AUX LR 1,1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_7) @@ -501,7 +517,9 @@ E2 EQU 1 }); analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC0 = "MAC0", AUX0 = "AUX0", MAC1 = "MAC1", AUX1 = "AUX1", MAC2 = "MAC2", AUX2 = "AUX2", SEC0 = "SEC0", SEC1 = "SEC1", E0 = "E0", E1 = "E1", E2 = "E2"; document_symbol_list_s expected = document_symbol_list_s { @@ -592,7 +610,7 @@ E2 EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_8) @@ -627,7 +645,9 @@ E2 EQU 1 }); analyzer a(opencode, analyzer_options(&mock)); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC0 = "MAC0", AUX0 = "AUX0", MAC1 = "MAC1", AUX1 = "AUX1", MAC2 = "MAC2", AUX2 = "AUX2", SEC0 = "SEC0", SEC1 = "SEC1", E0 = "E0", E1 = "E1", E2 = "E2"; document_symbol_list_s expected = document_symbol_list_s { @@ -718,7 +738,7 @@ E2 EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_macro_9) @@ -767,7 +787,9 @@ E4 EQU 1 }); analyzer a(opencode, analyzer_options(&mock)); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string MAC0 = "MAC0", AUX0 = "AUX0", MAC1 = "MAC1", AUX1 = "AUX1", MAC2 = "MAC2", AUX2 = "AUX2", SEC0 = "SEC0", SEC1 = "SEC1", E0 = "E0", E1 = "E1", E2 = "E2", MAC3 = "MAC3", AUX3 = "AUX3", E3 = "E3", MAC4 = "MAC4", AUX4 = "AUX4", E4 = "E4"; @@ -869,7 +891,7 @@ E4 EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_copy) @@ -881,9 +903,11 @@ TEST(lsp_context_document_symbol, ord_copy) mock_parse_lib_provider mock({ { "COPYFILE1", "" } }); analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); document_symbol_list_s expected = document_symbol_list_s {}; - EXPECT_EQ(outline, expected); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_copy_2) @@ -900,7 +924,9 @@ AUX1 LR 1,1 }); analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string E0 = "E0", AUX0 = "AUX0", E1 = "E1", AUX1 = "AUX1", COPYFILE1 = "COPYFILE1"; document_symbol_list_s expected = document_symbol_list_s { document_symbol_item_s { @@ -931,7 +957,7 @@ AUX1 LR 1,1 range { { 0, 0 }, { 0, 0 } }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } TEST(lsp_context_document_symbol, ord_copy_3) @@ -969,7 +995,9 @@ EM1 EQU 1 }); analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); std::string EM0 = "EM0", AM0 = "AM0", EM1 = "EM1", AM1 = "AM1", EC0 = "EC0", AC0 = "AC0", EC1 = "EC1", AC1 = "AC1", EC2 = "EC2", AC2 = "AC2", EC3 = "EC3", AC3 = "AC3", COPYFILE1 = "COPYFILE1", COPYFILE2 = "COPYFILE2", COPYFILE3 = "COPYFILE3", MAC0 = "MAC0", MAC1 = "MAC1", SEC1 = "SEC1", SEC2 = "SEC2"; @@ -1081,5 +1109,43 @@ EM1 EQU 1 }, }, }; - EXPECT_TRUE(is_permutation_with_permutations(outline, expected)); + EXPECT_TRUE(is_similar(outline, expected)); } + +size_t recursive_counter(const document_symbol_list_s& x) +{ + size_t result = x.size(); + for (const auto& c : x) + result += recursive_counter(c.children); + return result; +} + +TEST(lsp_context_document_symbol, limit) +{ + std::string input = + R"( + MACRO + MAC &I + ACTR 999999 + LCLA &A + +.NEXT ANOP +LABEL_&A DS A +&A SETA &A+1 + AIF (&A LT &I).NEXT + + MEND + +SECT DSECT + MAC 1000 +)"; + analyzer a(input); + a.analyze(); + + const auto limit = 10LL; + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol("", limit); + + EXPECT_LE(recursive_counter(outline), 100); + ASSERT_FALSE(outline.empty()); + EXPECT_EQ(outline.front().name, "Outline may be truncated"); +} \ No newline at end of file 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 4954edea3..99aa79581 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 @@ -28,13 +28,15 @@ TEST(lsp_context_document_symbol_var_seq, 1) analyzer a(opencode, analyzer_options {}); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "V1", document_symbol_kind::VAR, range { { 0, 0 }, { 0, 0 } } }, document_symbol_item_s { "V2", document_symbol_kind::VAR, range { { 1, 0 }, { 1, 0 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); } TEST(lsp_context_document_symbol_var_seq, 2) @@ -57,8 +59,10 @@ EM1 EQU 1 analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); - document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1"); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); + document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "MAC1", document_symbol_kind::MACRO, @@ -77,8 +81,8 @@ EM1 EQU 1 document_symbol_item_s { "SM1", document_symbol_kind::SEQ, range { { 5, 0 }, { 5, 0 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac1, expected_mac1)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_mac1, expected_mac1)); } TEST(lsp_context_document_symbol_var_seq, 3) @@ -110,9 +114,11 @@ EM2 EQU 1 analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); - document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1"); - document_symbol_list_s outline_mac2 = a.context().lsp_ctx->document_symbol("MAC2"); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); + document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1", limit); + document_symbol_list_s outline_mac2 = a.context().lsp_ctx->document_symbol("MAC2", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "MAC1", document_symbol_kind::MACRO, @@ -144,9 +150,9 @@ EM2 EQU 1 document_symbol_item_s { "SM2", document_symbol_kind::SEQ, range { { 5, 0 }, { 5, 0 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac1, expected_mac1)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac2, expected_mac2)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_mac1, expected_mac1)); + EXPECT_TRUE(is_similar(outline_mac2, expected_mac2)); } TEST(lsp_context_document_symbol_var_seq, 4) @@ -175,9 +181,11 @@ EC1 EQU 1)" }, analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); - document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1"); - document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1"); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); + document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1", limit); + document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "COPYFILE1", document_symbol_kind::MACRO, @@ -209,9 +217,9 @@ EC1 EQU 1)" }, document_symbol_item_s { "SC1", document_symbol_kind::SEQ, range { { 3, 0 }, { 3, 4 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac1, expected_mac1)); - EXPECT_TRUE(is_permutation_with_permutations(outline_copyfile1, expected_copyfile1)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_mac1, expected_mac1)); + EXPECT_TRUE(is_similar(outline_copyfile1, expected_copyfile1)); } TEST(lsp_context_document_symbol_var_seq, 5) @@ -240,9 +248,11 @@ EC1 EQU 1 analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); - document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1"); - document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1"); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); + document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1", limit); + document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "COPYFILE1", document_symbol_kind::MACRO, @@ -274,9 +284,9 @@ EC1 EQU 1 document_symbol_item_s { "SC1", document_symbol_kind::SEQ, range { { 3, 0 }, { 3, 4 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac1, expected_mac1)); - EXPECT_TRUE(is_permutation_with_permutations(outline_copyfile1, expected_copyfile1)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_mac1, expected_mac1)); + EXPECT_TRUE(is_similar(outline_copyfile1, expected_copyfile1)); } TEST(lsp_context_document_symbol_var_seq, 6) @@ -306,9 +316,11 @@ EC1 EQU 1 analyzer a(opencode, analyzer_options { &mock }); a.analyze(); - document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol(""); - document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1"); - document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1"); + + const auto limit = 1000LL; + document_symbol_list_s outline_opencode = a.context().lsp_ctx->document_symbol("", limit); + document_symbol_list_s outline_mac1 = a.context().lsp_ctx->document_symbol("MAC1", limit); + document_symbol_list_s outline_copyfile1 = a.context().lsp_ctx->document_symbol("COPYFILE1", limit); document_symbol_list_s expected_opencode = document_symbol_list_s { document_symbol_item_s { "MAC1", document_symbol_kind::MACRO, @@ -347,7 +359,7 @@ EC1 EQU 1 document_symbol_item_s { "SC1", document_symbol_kind::SEQ, range { { 3, 0 }, { 3, 4 } } } }; - EXPECT_TRUE(is_permutation_with_permutations(outline_opencode, expected_opencode)); - EXPECT_TRUE(is_permutation_with_permutations(outline_mac1, expected_mac1)); - EXPECT_TRUE(is_permutation_with_permutations(outline_copyfile1, expected_copyfile1)); + EXPECT_TRUE(is_similar(outline_opencode, expected_opencode)); + EXPECT_TRUE(is_similar(outline_mac1, expected_mac1)); + EXPECT_TRUE(is_similar(outline_copyfile1, expected_copyfile1)); } 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 c640c5755..de3b0a302 100644 --- a/parser_library/test/lsp/lsp_context_ord_sym_test.cpp +++ b/parser_library/test/lsp/lsp_context_ord_sym_test.cpp @@ -35,11 +35,11 @@ R1 EQU 1 TEST_F(lsp_context_ord_symbol, document_symbol) { - document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(opencode_file_name); + document_symbol_list_s outline = a.context().lsp_ctx->document_symbol(opencode_file_name, 1000); std::string R1 = "R1"; document_symbol_list_s expected = { document_symbol_item_s { R1, document_symbol_kind::EQU, range { { 2, 0 }, { 2, 0 } } } }; - EXPECT_EQ(outline, expected); + EXPECT_TRUE(is_similar(outline, expected)); } TEST_F(lsp_context_ord_symbol, definition) diff --git a/utils/include/utils/CMakeLists.txt b/utils/include/utils/CMakeLists.txt index 17ee9a6ae..0b384c4ef 100644 --- a/utils/include/utils/CMakeLists.txt +++ b/utils/include/utils/CMakeLists.txt @@ -14,4 +14,5 @@ target_sources(hlasm_utils PUBLIC list_directory_rc.h path.h platform.h + similar.h ) diff --git a/utils/include/utils/similar.h b/utils/include/utils/similar.h new file mode 100644 index 000000000..747994428 --- /dev/null +++ b/utils/include/utils/similar.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ + +#ifndef HLASMPLUGIN_UTILS_SIMILAR_H +#define HLASMPLUGIN_UTILS_SIMILAR_H + +#include +#include + +namespace hlasm_plugin::utils { + +namespace detail { +template +void is_similar(const T&, const T&); // dummy if ADL fails + +class is_similar_t +{ + template + static auto use_standalone(const T& t) + -> std::enable_if_t, std::true_type>; + static std::false_type use_standalone(...); + + template + static auto use_member(const T& t) + -> std::enable_if_t, std::true_type>; + static std::false_type use_member(...); + + template + static auto use_equal(const T& t) -> std::enable_if_t, std::true_type>; + static std::false_type use_equal(...); + +public: + template + bool operator()(const T& l, const T& r) const + { + constexpr bool standalone = decltype(use_standalone(l))::value; + constexpr bool member = decltype(use_member(l))::value; + constexpr bool equal = decltype(use_equal(l))::value; + static_assert(standalone || member || equal, "is_similar or equal to operator not available"); + + if constexpr (standalone) + return is_similar(l, r); + else if constexpr (member) + return l.is_similar(r); + else if constexpr (equal) + return l == r; // if things are the same then they are also similar + } +}; +} // namespace detail + +constexpr detail::is_similar_t is_similar; + +template +class is_similar_to +{ + const T& value; + +public: + is_similar_to(const T& t) + : value(t) + {} + is_similar_to(T&&) = delete; + + bool operator()(const T& r) const { return is_similar(value, r); } +}; + +} // namespace hlasm_plugin::utils + +#endif