diff --git a/src/source.hpp b/src/source.hpp index 2b75caf..2a76e7a 100644 --- a/src/source.hpp +++ b/src/source.hpp @@ -85,8 +85,8 @@ namespace Source { std::function non_interactive_completion; std::function format_style; - std::function get_declaration_location; - std::function get_type_declaration_location; + std::function()> get_declaration_locations; + std::function()> get_type_declaration_locations; std::function()> get_implementation_locations; std::function()> get_declaration_or_implementation_locations; std::function>()> get_usages; diff --git a/src/source_clang.cpp b/src/source_clang.cpp index df434eb..7ee0d72 100644 --- a/src/source_clang.cpp +++ b/src/source_clang.cpp @@ -1421,7 +1421,7 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return Offset(); }; - get_declaration_location = [this, declaration_location]() { + get_declaration_locations = [this, declaration_location]() -> std::vector { if(!parsed) { if(selected_completion_string) { auto completion_cursor = clangmm::CompletionString(selected_completion_string).get_cursor(clang_tu->cx_tu); @@ -1439,16 +1439,16 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file if(!boost::filesystem::exists(include_path, ec)) offset.file_path = "/usr/include" / include_path; - return offset; + return {offset}; } else { Info::get().print("No declaration found"); - return Offset(); + return {}; } } Info::get().print("Buffer is parsing"); - return Offset(); + return {}; } auto offset = declaration_location(); if(!offset) @@ -1461,13 +1461,13 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file if(!boost::filesystem::exists(include_path, ec)) offset.file_path = "/usr/include" / include_path; - return offset; + return {offset}; }; - get_type_declaration_location = [this]() { + get_type_declaration_locations = [this]() -> std::vector { if(!parsed) { Info::get().print("Buffer is parsing"); - return Offset(); + return {}; } auto identifier = get_identifier(); if(identifier) { @@ -1486,12 +1486,12 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file if(!boost::filesystem::exists(include_path, ec)) offset.file_path = "/usr/include" / include_path; - return offset; + return {offset}; } } } Info::get().print("No type declaration found"); - return Offset(); + return {}; }; auto implementation_locations = [this](const Identifier &identifier) { @@ -1658,9 +1658,8 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file } else { auto implementation_offsets = implementation_locations(get_identifier()); - if(!implementation_offsets.empty()) { + if(!implementation_offsets.empty()) offsets = std::move(implementation_offsets); - } else { auto offset = declaration_location(); if(offset) diff --git a/src/source_language_protocol.cpp b/src/source_language_protocol.cpp index 0d20521..3a4c997 100644 --- a/src/source_language_protocol.cpp +++ b/src/source_language_protocol.cpp @@ -927,11 +927,11 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { } if(capabilities.definition) { - get_declaration_location = [this]() { - auto offset = get_declaration(get_buffer()->get_insert()->get_iter()); - if(!offset) + get_declaration_locations = [this]() { + auto offsets = get_declarations(get_buffer()->get_insert()->get_iter()); + if(offsets.empty()) Info::get().print("No declaration found"); - return offset; + return offsets; }; // Assumes that capabilities.definition is available when capabilities.implementation is supported @@ -949,27 +949,25 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { } } if(offsets.empty() || is_implementation) { - if(auto offset = get_declaration_location()) - return std::vector({std::move(offset)}); + auto offsets = get_declaration_locations(); + if(!offsets.empty()) + return offsets; } return offsets; }; } else { get_declaration_or_implementation_locations = [this]() { - std::vector offsets; - if(auto offset = get_declaration_location()) - offsets.emplace_back(std::move(offset)); - return offsets; + return get_declaration_locations(); }; } } if(capabilities.type_definition) { - get_type_declaration_location = [this]() { - auto offset = get_type_declaration(get_buffer()->get_insert()->get_iter()); - if(!offset) + get_type_declaration_locations = [this]() { + auto offsets = get_type_declarations(get_buffer()->get_insert()->get_iter()); + if(offsets.empty()) Info::get().print("No type declaration found"); - return offset; + return offsets; }; } if(capabilities.implementation) { @@ -2249,10 +2247,12 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect Glib::ustring value_type = "Value"; auto token_iters = get_token_iters(get_buffer()->get_iter_at_offset(offset)); - auto offset = get_declaration(token_iters.first); auto variable = get_buffer()->get_text(token_iters.first, token_iters.second); - Glib::ustring debug_value = Debug::LLDB::get().get_value(variable, offset.file_path, offset.line + 1, offset.index + 1); + Glib::ustring debug_value; + auto offsets = get_declarations(token_iters.first); + for(size_t i = 0; i < offsets.size() && debug_value.empty(); ++i) + debug_value = Debug::LLDB::get().get_value(variable, offsets[i].file_path, offsets[i].line + 1, offsets[i].index + 1); if(debug_value.empty()) { debug_value = Debug::LLDB::get().get_return_value(file_path, token_iters.first.get_line() + 1, token_iters.first.get_line_index() + 1); if(!debug_value.empty()) @@ -2353,10 +2353,10 @@ void Source::LanguageProtocolView::apply_clickable_tag(const Gtk::TextIter &iter }); } -Source::Offset Source::LanguageProtocolView::get_declaration(const Gtk::TextIter &iter) { - auto offset = std::make_shared(); +std::vector Source::LanguageProtocolView::get_declarations(const Gtk::TextIter &iter) { + auto offsets = std::make_shared>(); std::promise result_processed; - write_request("textDocument/definition", to_string({make_position(iter.get_line(), get_line_pos(iter))}), [offset, &result_processed](JSON &&result, bool error) { + write_request("textDocument/definition", to_string({make_position(iter.get_line(), get_line_pos(iter))}), [offsets, &result_processed](JSON &&result, bool error) { if(!error) { auto locations = result.array_or_empty(); if(locations.empty()) { @@ -2366,10 +2366,7 @@ Source::Offset Source::LanguageProtocolView::get_declaration(const Gtk::TextIter for(auto &location_object : locations) { try { LanguageProtocol::Location location(location_object); - offset->file_path = std::move(location.file); - offset->line = location.range.start.line; - offset->index = location.range.start.character; - break; // TODO: can a language server return several definitions? + offsets->emplace_back(location.range.start.line, location.range.start.character, std::move(location.file)); } catch(...) { } @@ -2378,13 +2375,13 @@ Source::Offset Source::LanguageProtocolView::get_declaration(const Gtk::TextIter result_processed.set_value(); }); result_processed.get_future().get(); - return *offset; + return *offsets; } -Source::Offset Source::LanguageProtocolView::get_type_declaration(const Gtk::TextIter &iter) { - auto offset = std::make_shared(); +std::vector Source::LanguageProtocolView::get_type_declarations(const Gtk::TextIter &iter) { + auto offsets = std::make_shared>(); std::promise result_processed; - write_request("textDocument/typeDefinition", to_string({make_position(iter.get_line(), get_line_pos(iter))}), [offset, &result_processed](JSON &&result, bool error) { + write_request("textDocument/typeDefinition", to_string({make_position(iter.get_line(), get_line_pos(iter))}), [offsets, &result_processed](JSON &&result, bool error) { if(!error) { auto locations = result.array_or_empty(); if(locations.empty()) { @@ -2394,10 +2391,7 @@ Source::Offset Source::LanguageProtocolView::get_type_declaration(const Gtk::Tex for(auto &location_object : locations) { try { LanguageProtocol::Location location(location_object); - offset->file_path = std::move(location.file); - offset->line = location.range.start.line; - offset->index = location.range.start.character; - break; // TODO: can a language server return several type definitions? + offsets->emplace_back(location.range.start.line, location.range.start.character, std::move(location.file)); } catch(...) { } @@ -2406,7 +2400,7 @@ Source::Offset Source::LanguageProtocolView::get_type_declaration(const Gtk::Tex result_processed.set_value(); }); result_processed.get_future().get(); - return *offset; + return *offsets; } std::vector Source::LanguageProtocolView::get_implementations(const Gtk::TextIter &iter) { @@ -2422,7 +2416,7 @@ std::vector Source::LanguageProtocolView::get_implementations(co for(auto &location_object : locations) { try { LanguageProtocol::Location location(location_object); - offsets->emplace_back(location.range.start.line, location.range.start.character, location.file); + offsets->emplace_back(location.range.start.line, location.range.start.character, std::move(location.file)); } catch(...) { } diff --git a/src/source_language_protocol.hpp b/src/source_language_protocol.hpp index f2ad596..f379f9f 100644 --- a/src/source_language_protocol.hpp +++ b/src/source_language_protocol.hpp @@ -267,8 +267,8 @@ namespace Source { void tag_similar_symbols(); - Offset get_declaration(const Gtk::TextIter &iter); - Offset get_type_declaration(const Gtk::TextIter &iter); + std::vector get_declarations(const Gtk::TextIter &iter); + std::vector get_type_declarations(const Gtk::TextIter &iter); std::vector get_implementations(const Gtk::TextIter &iter); std::unique_ptr autocomplete; diff --git a/src/window.cpp b/src/window.cpp index abb2409..1db4eef 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1128,44 +1128,6 @@ void Window::set_menu_actions() { } }); - menu.add_action("source_goto_declaration", []() { - if(auto view = Notebook::get().get_current_view()) { - if(view->get_declaration_location) { - auto location = view->get_declaration_location(); - if(location) { - boost::system::error_code ec; - if(!boost::filesystem::is_regular_file(location.file_path, ec)) - return; - if(Notebook::get().open(location.file_path)) { - auto view = Notebook::get().get_current_view(); - auto line = static_cast(location.line); - auto index = static_cast(location.index); - view->place_cursor_at_line_pos(line, index); - view->scroll_to_cursor_delayed(true, false); - } - } - } - } - }); - menu.add_action("source_goto_type_declaration", []() { - if(auto view = Notebook::get().get_current_view()) { - if(view->get_type_declaration_location) { - auto location = view->get_type_declaration_location(); - if(location) { - boost::system::error_code ec; - if(!boost::filesystem::is_regular_file(location.file_path, ec)) - return; - if(Notebook::get().open(location.file_path)) { - auto view = Notebook::get().get_current_view(); - auto line = static_cast(location.line); - auto index = static_cast(location.index); - view->place_cursor_at_line_pos(line, index); - view->scroll_to_cursor_delayed(true, false); - } - } - } - } - }); auto goto_selected_location = [](Source::View *view, const std::vector &locations) { if(!locations.empty()) { SelectionDialog::create(view, true, true); @@ -1215,6 +1177,18 @@ void Window::set_menu_actions() { SelectionDialog::get()->show(); } }; + menu.add_action("source_goto_declaration", [goto_selected_location]() { + if(auto view = Notebook::get().get_current_view()) { + if(view->get_declaration_locations) + goto_selected_location(view, view->get_declaration_locations()); + } + }); + menu.add_action("source_goto_type_declaration", [goto_selected_location]() { + if(auto view = Notebook::get().get_current_view()) { + if(view->get_type_declaration_locations) + goto_selected_location(view, view->get_type_declaration_locations()); + } + }); menu.add_action("source_goto_implementation", [goto_selected_location]() { if(auto view = Notebook::get().get_current_view()) { if(view->get_implementation_locations) @@ -1812,8 +1786,8 @@ void Window::set_menu_actions() { menu.actions["source_comments_toggle"]->set_enabled(view && view->toggle_comments); menu.actions["source_comments_add_documentation"]->set_enabled(view && view->get_documentation_template); menu.actions["source_find_documentation"]->set_enabled(view && view->get_token_data); - menu.actions["source_goto_declaration"]->set_enabled(view && view->get_declaration_location); - menu.actions["source_goto_type_declaration"]->set_enabled(view && view->get_type_declaration_location); + menu.actions["source_goto_declaration"]->set_enabled(view && view->get_declaration_locations); + menu.actions["source_goto_type_declaration"]->set_enabled(view && view->get_type_declaration_locations); menu.actions["source_goto_implementation"]->set_enabled(view && view->get_implementation_locations); menu.actions["source_goto_declaration_or_implementation"]->set_enabled(view && view->get_declaration_or_implementation_locations); menu.actions["source_goto_usage"]->set_enabled(view && view->get_usages); diff --git a/tests/language_protocol_client_test.cpp b/tests/language_protocol_client_test.cpp index 34416f6..32ad3cc 100644 --- a/tests/language_protocol_client_test.cpp +++ b/tests/language_protocol_client_test.cpp @@ -42,22 +42,24 @@ int main() { } )"); - g_assert(view->get_declaration_location); - auto location = view->get_declaration_location(); - g_assert(location); - g_assert(location.file_path == "main.rs"); - g_assert_cmpuint(location.line, ==, 0); - g_assert_cmpuint(location.index, ==, 3); - - g_assert(view->get_type_declaration_location); - location = view->get_type_declaration_location(); - g_assert(location); - g_assert(location.file_path == "main.rs"); - g_assert_cmpuint(location.line, ==, 0); - g_assert_cmpuint(location.index, ==, 4); + g_assert(view->get_declaration_locations); + auto locations = view->get_declaration_locations(); + g_assert(locations.size() == 1); + g_assert(locations[0]); + g_assert(locations[0].file_path == "main.rs"); + g_assert_cmpuint(locations[0].line, ==, 0); + g_assert_cmpuint(locations[0].index, ==, 3); + + g_assert(view->get_type_declaration_locations); + locations = view->get_type_declaration_locations(); + g_assert(locations.size() == 1); + g_assert(locations[0]); + g_assert(locations[0].file_path == "main.rs"); + g_assert_cmpuint(locations[0].line, ==, 0); + g_assert_cmpuint(locations[0].index, ==, 4); g_assert(view->get_implementation_locations); - auto locations = view->get_implementation_locations(); + locations = view->get_implementation_locations(); g_assert(locations.size() == 2); g_assert(locations[0].file_path == "main.rs"); g_assert(locations[1].file_path == "main.rs"); diff --git a/tests/source_clang_test.cpp b/tests/source_clang_test.cpp index 32e23fb..db159a9 100644 --- a/tests/source_clang_test.cpp +++ b/tests/source_clang_test.cpp @@ -42,32 +42,37 @@ int main() { //test get_declaration and get_implementation clang_view->place_cursor_at_line_index(15, 7); - auto location = clang_view->get_declaration_location(); - g_assert_cmpuint(location.line, ==, 6); + auto locations = clang_view->get_declaration_locations(); + g_assert(locations.size() == 1); + g_assert_cmpuint(locations[0].line, ==, 6); - clang_view->place_cursor_at_line_index(location.line, location.index); + clang_view->place_cursor_at_line_index(locations[0].line, locations[0].index); auto impl_locations = clang_view->get_implementation_locations(); g_assert_cmpuint(impl_locations.size(), ==, 1); g_assert_cmpuint(impl_locations[0].line, ==, 11); - clang_view->place_cursor_at_line_index(location.line, location.index); - location = clang_view->get_declaration_location(); - g_assert_cmpuint(location.line, ==, 6); + clang_view->place_cursor_at_line_index(locations[0].line, locations[0].index); + locations = clang_view->get_declaration_locations(); + g_assert(locations.size() == 1); + g_assert_cmpuint(locations[0].line, ==, 6); //test get_usages and get_methods - auto locations = clang_view->get_usages(); - g_assert_cmpuint(locations.size(), >, 0); + { + auto locations = clang_view->get_usages(); + g_assert_cmpuint(locations.size(), >, 0); - locations = clang_view->get_methods(); - g_assert_cmpuint(locations.size(), >, 0); + locations = clang_view->get_methods(); + g_assert_cmpuint(locations.size(), >, 0); + } //Test rename class (error if not constructor and destructor is renamed as well) auto saved_main = clang_view->get_buffer()->get_text(); clang_view->place_cursor_at_line_index(0, 6); auto token = clang_view->get_token(clang_view->get_buffer()->get_insert()->get_iter()); g_assert_cmpstr(token.c_str(), ==, "TestClass"); - location = clang_view->get_declaration_location(); - g_assert_cmpuint(location.line, ==, 0); + locations = clang_view->get_declaration_locations(); + g_assert(locations.size() == 1); + g_assert_cmpuint(locations[0].line, ==, 0); clang_view->rename_similar_tokens("RenamedTestClass"); while(!clang_view->parsed) flush_events();