diff --git a/src/ctags.cc b/src/ctags.cc index ce09cc8..f0b4fc0 100644 --- a/src/ctags.cc +++ b/src/ctags.cc @@ -103,7 +103,7 @@ Ctags::Location Ctags::get_location(const std::string &line, bool markup) { return location; } -Ctags::Location Ctags::get_location(const boost::filesystem::path &path, const std::string &name, const std::string &type) { +std::vector Ctags::get_locations(const boost::filesystem::path &path, const std::string &name, const std::string &type) { //insert name into type size_t c=0; size_t bracket_count=0; @@ -139,12 +139,12 @@ Ctags::Location Ctags::get_location(const boost::filesystem::path &path, const s auto result=get_result(path); result.second->seekg(0, std::ios::end); if(result.second->tellg()==0) - return Location(); + return std::vector(); result.second->seekg(0, std::ios::beg); std::string line; size_t best_score=0; - Location best_location; + std::vector best_locations; while(std::getline(*result.second, line)) { if(line.find(name)==std::string::npos) continue; @@ -163,9 +163,12 @@ Ctags::Location Ctags::get_location(const boost::filesystem::path &path, const s } if(score>best_score) { best_score=score; - best_location=location; + best_locations.clear(); + best_locations.emplace_back(location); } + else if(score==best_score) + best_locations.emplace_back(location); } - return best_location; + return best_locations; } diff --git a/src/ctags.h b/src/ctags.h index 7119af5..c3c821f 100644 --- a/src/ctags.h +++ b/src/ctags.h @@ -20,7 +20,7 @@ public: static Location get_location(const std::string &line, bool markup); - static Location get_location(const boost::filesystem::path &path, const std::string &name, const std::string &type); + static std::vector get_locations(const boost::filesystem::path &path, const std::string &name, const std::string &type); }; #endif //JUCI_CTAGS_H_ diff --git a/src/source.h b/src/source.h index 6e6519d..7129170 100644 --- a/src/source.h +++ b/src/source.h @@ -60,7 +60,7 @@ namespace Source { std::function auto_indent; std::function get_declaration_location; - std::function &views)> get_implementation_location; + std::function(const std::vector &views)> get_implementation_locations; std::function >(const std::vector &views)> get_usages; std::function get_method; std::function >()> get_methods; diff --git a/src/source_clang.cc b/src/source_clang.cc index 6475391..c05f75e 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -923,47 +923,53 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return Offset(); }; - get_implementation_location=[this](const std::vector &views){ - Offset location; + get_implementation_locations=[this](const std::vector &views){ + std::vector locations; if(!parsed) { Info::get().print("Buffer is parsing"); - return location; + return locations; } auto identifier=get_identifier(); if(identifier) { wait_parsing(views); for(auto &view: views) { if(auto clang_view=dynamic_cast(view)) { - if(clang_view->language && clang_view->language->get_id()!="chdr" && clang_view->language->get_id()!="cpphdr") { - for(auto token_it=clang_view->clang_tokens->rbegin();token_it!=clang_view->clang_tokens->rend();++token_it) { - auto cursor=token_it->get_cursor(); - auto kind=cursor.get_kind(); - if((kind==clang::CursorKind::FunctionDecl || kind==clang::CursorKind::CXXMethod || - kind==clang::CursorKind::Constructor || kind==clang::CursorKind::Destructor) && - token_it->get_kind()==clang::TokenKind::Token_Identifier && cursor.has_type()) { - auto referenced=cursor.get_referenced(); - if(referenced && identifier.kind==referenced.get_kind() && - identifier.spelling==token_it->get_spelling() && identifier.usr==referenced.get_usr()) { + for(auto &token: *clang_view->clang_tokens) { + auto cursor=token.get_cursor(); + auto kind=cursor.get_kind(); + if((kind==clang::CursorKind::FunctionDecl || kind==clang::CursorKind::CXXMethod || + kind==clang::CursorKind::Constructor || kind==clang::CursorKind::Destructor) && + token.get_kind()==clang::TokenKind::Token_Identifier && cursor.has_type()) { + auto referenced=cursor.get_referenced(); + if(referenced && identifier.kind==referenced.get_kind() && + identifier.spelling==token.get_spelling() && identifier.usr==referenced.get_usr()) { + if(clang_isCursorDefinition(referenced.cx_cursor)) { + Offset location; location.file_path=cursor.get_source_location().get_path(); auto clang_offset=cursor.get_source_location().get_offset(); location.line=clang_offset.line-1; location.index=clang_offset.index-1; - return location; + locations.emplace_back(location); } } } } } } + if(!locations.empty()) + return locations; + //If no implementation was found, try using clang_getCursorDefinition auto definition=clang::Cursor(clang_getCursorDefinition(identifier.cursor.cx_cursor)); if(definition) { auto definition_location=definition.get_source_location(); + Offset location; location.file_path=definition_location.get_path(); auto offset=definition_location.get_offset(); location.line=offset.line-1; location.index=offset.index-1; - return location; + locations.emplace_back(location); + return locations; } //If no implementation was found, try using Ctags @@ -974,17 +980,21 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file name.insert(0, spelling); parent=parent.get_semantic_parent(); } - auto ctags_location=Ctags::get_location(this->file_path, name, identifier.cursor.get_type()); - if(ctags_location) { - location.file_path=ctags_location.file_path; - location.line=ctags_location.line; - location.index=ctags_location.index; - return location; + auto ctags_locations=Ctags::get_locations(this->file_path, name, identifier.cursor.get_type()); + if(!ctags_locations.empty()) { + for(auto &ctags_location: ctags_locations) { + Offset location; + location.file_path=ctags_location.file_path; + location.line=ctags_location.line; + location.index=ctags_location.index; + locations.emplace_back(location); + } + return locations; } Info::get().print("Could not find implementation"); } - return location; + return locations; }; get_usages=[this](const std::vector &views) { diff --git a/src/window.cc b/src/window.cc index 7bc947f..c76af17 100644 --- a/src/window.cc +++ b/src/window.cc @@ -547,21 +547,56 @@ void Window::set_menu_actions() { }); menu.add_action("source_goto_implementation", [this]() { if(auto view=Notebook::get().get_current_view()) { - if(view->get_implementation_location) { - auto location=view->get_implementation_location(Notebook::get().get_views()); - if(location) { - boost::filesystem::path implementation_path; - boost::system::error_code ec; - implementation_path=boost::filesystem::canonical(location.file_path, ec); - if(ec) + if(view->get_implementation_locations) { + auto locations=view->get_implementation_locations(Notebook::get().get_views()); + if(!locations.empty()) { + auto dialog_iter=view->get_iter_for_dialog(); + view->selection_dialog=std::unique_ptr(new SelectionDialog(*view, view->get_buffer()->create_mark(dialog_iter), true, true)); + auto rows=std::make_shared >(); + auto project_path=Project::Build::create(view->file_path)->project_path; + if(project_path.empty()) { + if(!Directories::get().path.empty()) + project_path=Directories::get().path; + else + project_path=view->file_path.parent_path(); + } + for(auto &location: locations) { + boost::filesystem::path implementation_path; + boost::system::error_code ec; + implementation_path=boost::filesystem::canonical(location.file_path, ec); + if(!ec) { + location.file_path=implementation_path; + auto path=filesystem::get_relative_path(location.file_path, project_path); + if(path.empty()) + path=location.file_path.filename(); + auto row=path.string()+":"+std::to_string(location.line+1); + (*rows)[row]=location; + view->selection_dialog->add_row(row); + } + } + + if(rows->size()==0) return; - Notebook::get().open(implementation_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_index(line, index); - view->scroll_to_cursor_delayed(view, true, false); - return; + else if(rows->size()==1) { + auto location=*rows->begin(); + Notebook::get().open(location.second.file_path); + auto view=Notebook::get().get_current_view(); + auto line=static_cast(location.second.line); + auto index=static_cast(location.second.index); + view->place_cursor_at_line_index(line, index); + view->scroll_to_cursor_delayed(view, true, false); + return; + } + view->selection_dialog->on_select=[this, rows](const std::string &selected, bool hide_window) { + auto location=rows->at(selected); + Notebook::get().open(location.file_path); + auto view=Notebook::get().get_current_view(); + view->place_cursor_at_line_index(location.line, location.index); + view->scroll_to_cursor_delayed(view, true, false); + view->hide_tooltips(); + }; + view->hide_tooltips(); + view->selection_dialog->show(); } } } @@ -969,7 +1004,7 @@ void Window::activate_menu_items(bool activate) { menu.actions["source_find_symbol_ctags"]->set_enabled(activate); menu.actions["source_find_documentation"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_token_data) : false); menu.actions["source_goto_declaration"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_declaration_location) : false); - menu.actions["source_goto_implementation"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_implementation_location) : false); + menu.actions["source_goto_implementation"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_implementation_locations) : false); menu.actions["source_goto_usage"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_usages) : false); menu.actions["source_goto_method"]->set_enabled(activate ? static_cast(notebook.get_current_view()->get_methods) : false); menu.actions["source_rename"]->set_enabled(activate ? static_cast(notebook.get_current_view()->rename_similar_tokens) : false); diff --git a/tests/source_clang_test.cc b/tests/source_clang_test.cc index b6e5ccc..3216068 100644 --- a/tests/source_clang_test.cc +++ b/tests/source_clang_test.cc @@ -40,8 +40,9 @@ int main() { g_assert_cmpuint(location.line, ==, 4); clang_view->place_cursor_at_line_index(location.line, location.index); - location=clang_view->get_implementation_location({clang_view}); - g_assert_cmpuint(location.line, ==, 9); + auto impl_locations=clang_view->get_implementation_locations({clang_view}); + g_assert_cmpuint(impl_locations.size(), ==, 1); + g_assert_cmpuint(impl_locations[0].line, ==, 9); clang_view->place_cursor_at_line_index(location.line, location.index); location=clang_view->get_declaration_location();