From 30e0eace0184e43ad491adfd32d746dfced93bca Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 21 Feb 2017 07:47:36 +0100 Subject: [PATCH] Improvement of primary-right click: now goes to declaration if no implementation was found (related to #317) --- src/source.cc | 9 +- src/source.h | 2 +- src/source_clang.cc | 242 ++++++++++++++++++++++++-------------------- src/window.cc | 110 ++++++++++---------- 4 files changed, 197 insertions(+), 166 deletions(-) diff --git a/src/source.cc b/src/source.cc index a9fe2c6..6bfc3df 100644 --- a/src/source.cc +++ b/src/source.cc @@ -2246,13 +2246,8 @@ bool Source::View::on_button_press_event(GdkEventButton *event) { if(iter) get_buffer()->place_cursor(iter); - if(is_implementation_location) { - if(is_implementation_location()) - Menu::get().actions["source_goto_declaration"]->activate(); - else - Menu::get().actions["source_goto_implementation"]->activate(); - return true; - } + Menu::get().actions["source_goto_declaration_or_implementation"]->activate(); + return true; } } diff --git a/src/source.h b/src/source.h index ee966d9..0dd6366 100644 --- a/src/source.h +++ b/src/source.h @@ -68,8 +68,8 @@ namespace Source { std::function non_interactive_completion; std::function format_style; std::function get_declaration_location; - std::function is_implementation_location; std::function(const std::vector &views)> get_implementation_locations; + std::function(const std::vector &views)> get_declaration_or_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 e9d8fb4..775782b 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -1011,65 +1011,8 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file }, 100); } }); - - auto get_header_location=[this]() { - // If cursor is at an include line, return offset to included file - const static std::regex include_regex("^[ \t]*#[ \t]*include[ \t]*[<\"]([^<>\"]+)[>\"].*$"); - std::smatch sm; - auto line=get_line(); - if(std::regex_match(line, sm, include_regex)) { - struct ClientData { - boost::filesystem::path &file_path; - std::string found_include; - int line_nr; - std::string sm_str; - }; - ClientData client_data{this->file_path, std::string(), get_buffer()->get_insert()->get_iter().get_line(), sm[1].str()}; - - // Attempt to find the 100% correct include file first - clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { - auto client_data=static_cast(client_data_); - if(client_data->found_include.empty() && include_len>0) { - auto source_location=clang::SourceLocation(inclusion_stack[0]); - if(static_cast(source_location.get_offset().line)-1==client_data->line_nr && - filesystem::get_normal_path(source_location.get_path())==client_data->file_path) - client_data->found_include=clang::to_string(clang_getFileName(included_file)); - } - }, &client_data); - - if(!client_data.found_include.empty()) - return Offset(0, 0, client_data.found_include); - - // Find a matching include file if no include was found previously - clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { - auto client_data=static_cast(client_data_); - if(client_data->found_include.empty()) { - for(unsigned c=1;c(source_location.get_offset().line)-1<=client_data->line_nr && - filesystem::get_normal_path(source_location.get_path())==client_data->file_path) { - auto included_file_str=clang::to_string(clang_getFileName(included_file)); - if(included_file_str.size()>=client_data->sm_str.size() && - included_file_str.compare(included_file_str.size()-client_data->sm_str.size(), client_data->sm_str.size(), client_data->sm_str)==0) { - client_data->found_include=included_file_str; - break; - } - } - } - } - }, &client_data); - - if(!client_data.found_include.empty()) - return Offset(0, 0, client_data.found_include); - } - return Offset(); - }; - - get_declaration_location=[this, get_header_location](){ - if(!parsed) { - Info::get().print("Buffer is parsing"); - return Offset(); - } + + auto declaration_location=[this]() { auto identifier=get_identifier(); if(identifier) { auto source_location=identifier.cursor.get_canonical().get_source_location(); @@ -1077,35 +1020,72 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file return Offset(offset.line-1, offset.index-1, source_location.get_path()); } else { - auto location=get_header_location(); - if(location) - return location; - } - Info::get().print("No declaration found"); - return Offset(); - }; - - is_implementation_location=[this]() { - if(!parsed) - return false; - auto iter=get_buffer()->get_insert()->get_iter(); - auto line=static_cast(iter.get_line()); - auto index=static_cast(iter.get_line_index()); - for(auto &token: *clang_tokens) { - if(token.is_identifier()) { - if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) - return clang_isCursorDefinition(token.get_cursor().cx_cursor)>0; + // If cursor is at an include line, return offset to included file + const static std::regex include_regex("^[ \t]*#[ \t]*include[ \t]*[<\"]([^<>\"]+)[>\"].*$"); + std::smatch sm; + auto line=get_line(); + if(std::regex_match(line, sm, include_regex)) { + struct ClientData { + boost::filesystem::path &file_path; + std::string found_include; + int line_nr; + std::string sm_str; + }; + ClientData client_data{this->file_path, std::string(), get_buffer()->get_insert()->get_iter().get_line(), sm[1].str()}; + + // Attempt to find the 100% correct include file first + clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { + auto client_data=static_cast(client_data_); + if(client_data->found_include.empty() && include_len>0) { + auto source_location=clang::SourceLocation(inclusion_stack[0]); + if(static_cast(source_location.get_offset().line)-1==client_data->line_nr && + filesystem::get_normal_path(source_location.get_path())==client_data->file_path) + client_data->found_include=clang::to_string(clang_getFileName(included_file)); + } + }, &client_data); + + if(!client_data.found_include.empty()) + return Offset(0, 0, client_data.found_include); + + // Find a matching include file if no include was found previously + clang_getInclusions(clang_tu->cx_tu, [](CXFile included_file, CXSourceLocation *inclusion_stack, unsigned include_len, CXClientData client_data_) { + auto client_data=static_cast(client_data_); + if(client_data->found_include.empty()) { + for(unsigned c=1;c(source_location.get_offset().line)-1<=client_data->line_nr && + filesystem::get_normal_path(source_location.get_path())==client_data->file_path) { + auto included_file_str=clang::to_string(clang_getFileName(included_file)); + if(included_file_str.size()>=client_data->sm_str.size() && + included_file_str.compare(included_file_str.size()-client_data->sm_str.size(), client_data->sm_str.size(), client_data->sm_str)==0) { + client_data->found_include=included_file_str; + break; + } + } + } + } + }, &client_data); + + if(!client_data.found_include.empty()) + return Offset(0, 0, client_data.found_include); } } - return false; + return Offset(); }; - get_implementation_locations=[this, get_header_location](const std::vector &views){ - std::vector locations; + get_declaration_location=[this, declaration_location](){ if(!parsed) { Info::get().print("Buffer is parsing"); - return locations; + return Offset(); } + auto offset=declaration_location(); + if(!offset) + Info::get().print("No declaration found"); + return offset; + }; + + auto implementation_locations=[this](const std::vector &views) { + std::vector offsets; auto identifier=get_identifier(); if(identifier) { wait_parsing(views); @@ -1122,32 +1102,32 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file 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(); + Offset offset; + offset.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; - locations.emplace_back(location); + offset.line=clang_offset.line-1; + offset.index=clang_offset.index-1; + offsets.emplace_back(offset); } } } } } } - if(!locations.empty()) - return locations; + if(!offsets.empty()) + return offsets; //If no implementation was found, try using clang_getCursorDefinition auto definition=identifier.cursor.get_definition(); 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; - locations.emplace_back(location); - return locations; + Offset offset; + offset.file_path=definition_location.get_path(); + auto definition_offset=definition_location.get_offset(); + offset.line=definition_offset.line-1; + offset.index=definition_offset.index-1; + offsets.emplace_back(offset); + return offsets; } //If no implementation was found, try using Ctags @@ -1161,24 +1141,72 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file auto ctags_locations=Ctags::get_locations(this->file_path, name, identifier.cursor.get_type_description()); 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); + Offset offset; + offset.file_path=ctags_location.file_path; + offset.line=ctags_location.line; + offset.index=ctags_location.index; + offsets.emplace_back(offset); + } + return offsets; + } + } + return offsets; + }; + + get_implementation_locations=[this, implementation_locations](const std::vector &views){ + if(!parsed) { + Info::get().print("Buffer is parsing"); + return std::vector(); + } + auto offsets=implementation_locations(views); + if(offsets.empty()) + Info::get().print("No implementation found"); + return offsets; + }; + + get_declaration_or_implementation_locations=[this, declaration_location, implementation_locations](const std::vector &views) { + if(!parsed) { + Info::get().print("Buffer is parsing"); + return std::vector(); + } + + std::vector offsets; + + bool is_implementation=false; + auto iter=get_buffer()->get_insert()->get_iter(); + auto line=static_cast(iter.get_line()); + auto index=static_cast(iter.get_line_index()); + for(auto &token: *clang_tokens) { + if(token.is_identifier()) { + if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index<=token.offsets.second.index-1) { + if(clang_isCursorDefinition(token.get_cursor().cx_cursor)>0) + is_implementation=true; + break; } - return locations; } } + // If cursor is at implementation, return declaration_location + if(is_implementation) { + auto offset=declaration_location(); + if(offset) + offsets.emplace_back(offset); + } else { - auto location=get_header_location(); - if(location) { - locations.emplace_back(location); - return locations; + auto implementation_offsets=implementation_locations(views); + if(!implementation_offsets.empty()) { + offsets=std::move(implementation_offsets); + } + else { + auto offset=declaration_location(); + if(offset) + offsets.emplace_back(offset); } } - Info::get().print("No implementation found"); - return locations; + + if(offsets.empty()) + Info::get().print("No declaration or implementation found"); + + return offsets; }; get_usages=[this](const std::vector &views) { diff --git a/src/window.cc b/src/window.cc index afc06c8..8644d4e 100644 --- a/src/window.cc +++ b/src/window.cc @@ -741,58 +741,65 @@ void Window::set_menu_actions() { } } }); - menu.add_action("source_goto_implementation", [this]() { - if(auto view=Notebook::get().get_current_view()) { - 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(); - SelectionDialog::create(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) { - auto path=filesystem::get_relative_path(filesystem::get_normal_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; - SelectionDialog::get()->add_row(row); - } - - if(rows->size()==0) - return; - else if(rows->size()==1) { - auto location=*rows->begin(); - if(!boost::filesystem::is_regular_file(location.second.file_path)) - return; - 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; - } - SelectionDialog::get()->on_select=[this, rows](const std::string &selected, bool hide_window) { - auto location=rows->at(selected); - if(!boost::filesystem::is_regular_file(location.file_path)) - return; - 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(); - SelectionDialog::get()->show(); - } + auto goto_selected_location=[](Source::View *view, const std::vector &locations) { + if(!locations.empty()) { + auto dialog_iter=view->get_iter_for_dialog(); + SelectionDialog::create(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) { + auto path=filesystem::get_relative_path(filesystem::get_normal_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; + SelectionDialog::get()->add_row(row); + } + + if(rows->size()==0) + return; + else if(rows->size()==1) { + auto location=*rows->begin(); + if(!boost::filesystem::is_regular_file(location.second.file_path)) + return; + 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; } + SelectionDialog::get()->on_select=[rows](const std::string &selected, bool hide_window) { + auto location=rows->at(selected); + if(!boost::filesystem::is_regular_file(location.file_path)) + return; + 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(); + SelectionDialog::get()->show(); + } + }; + menu.add_action("source_goto_implementation", [this, goto_selected_location]() { + if(auto view=Notebook::get().get_current_view()) { + if(view->get_implementation_locations) + goto_selected_location(view, view->get_implementation_locations(Notebook::get().get_views())); + } + }); + menu.add_action("source_goto_declaration_or_implementation", [this, goto_selected_location]() { + if(auto view=Notebook::get().get_current_view()) { + if(view->get_declaration_or_implementation_locations) + goto_selected_location(view, view->get_declaration_or_implementation_locations(Notebook::get().get_views())); } }); @@ -1202,6 +1209,7 @@ void Window::activate_menu_items() { 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_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); menu.actions["source_goto_method"]->set_enabled(view && view->get_methods); menu.actions["source_rename"]->set_enabled(view && view->rename_similar_tokens);