Browse Source

Improved Rename, Go to Usage, Go to Method, and Go to Implementation through broader similar cursor search. Function template definitions and spesializations, and overloaded functions, are now considered similar.

merge-requests/365/head
eidheim 9 years ago
parent
commit
e0fc075483
  1. 2
      libclangmm
  2. 83
      src/source_clang.cc
  3. 13
      src/source_clang.h
  4. 8
      tests/source_clang_test.cc
  5. 2
      tests/source_clang_test_files/main.cpp

2
libclangmm

@ -1 +1 @@
Subproject commit c79b2925ef5bf9677f447a05cf5a46bd24faf040 Subproject commit 7f5c657f52229bcfc194eadda08371013a3c1e77

83
src/source_clang.cc

@ -797,7 +797,7 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
similar_identifiers_tag->property_weight()=1000; //TODO: Replace 1000 with Pango::WEIGHT_ULTRAHEAVY when debian stable gets updated in 2017 similar_identifiers_tag->property_weight()=1000; //TODO: Replace 1000 with Pango::WEIGHT_ULTRAHEAVY when debian stable gets updated in 2017
get_buffer()->signal_changed().connect([this]() { get_buffer()->signal_changed().connect([this]() {
if(!renaming && last_tagged_identifier) { if(last_tagged_identifier) {
for(auto &mark: similar_identifiers_marks) { for(auto &mark: similar_identifiers_marks) {
get_buffer()->remove_tag(similar_identifiers_tag, mark.first->get_iter(), mark.second->get_iter()); get_buffer()->remove_tag(similar_identifiers_tag, mark.first->get_iter(), mark.second->get_iter());
get_buffer()->delete_mark(mark.first); get_buffer()->delete_mark(mark.first);
@ -837,32 +837,42 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
//If rename constructor or destructor, set token to class //If rename constructor or destructor, set token to class
if(identifier.kind==clangmm::Cursor::Kind::Constructor || identifier.kind==clangmm::Cursor::Kind::Destructor) { if(identifier.kind==clangmm::Cursor::Kind::Constructor || identifier.kind==clangmm::Cursor::Kind::Destructor) {
auto parent_cursor=identifier.cursor.get_semantic_parent(); auto parent_cursor=identifier.cursor.get_semantic_parent();
identifier=Identifier(parent_cursor.get_kind(), identifier.spelling, parent_cursor.get_usr(), parent_cursor); identifier=Identifier(identifier.spelling, parent_cursor);
}
//Special case for class with constructor template
else if(identifier.kind==clangmm::Cursor::Kind::FunctionTemplate) {
auto parent_cursor=identifier.cursor.get_semantic_parent();
auto kind=parent_cursor.get_kind();
if(identifier.spelling==parent_cursor.get_spelling() &&
(kind==clangmm::Cursor::Kind::ClassDecl || kind==clangmm::Cursor::Kind::ClassTemplate || kind==clangmm::Cursor::Kind::StructDecl))
identifier=Identifier(identifier.spelling, parent_cursor);
} }
std::vector<Source::View*> renamed_views; std::vector<Source::View*> renamed_views;
for(auto &view: views) { for(auto &view: views) {
if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) { if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) {
//If rename class, also rename constructors and destructor //If rename class, also rename constructors and destructor
std::set<Identifier> identifiers; std::set<Identifier> identifiers;
identifiers.emplace(identifier); identifiers.emplace(identifier);
auto identifier_cursor_kind=identifier.cursor.get_kind(); auto identifier_cursor_kind=identifier.cursor.get_kind();
if(identifier_cursor_kind==clangmm::Cursor::Kind::ClassDecl || identifier_cursor_kind==clangmm::Cursor::Kind::ClassTemplate) { if(identifier_cursor_kind==clangmm::Cursor::Kind::ClassDecl || identifier_cursor_kind==clangmm::Cursor::Kind::ClassTemplate ||
identifier_cursor_kind==clangmm::Cursor::Kind::StructDecl) {
for(auto &token: *clang_view->clang_tokens) { for(auto &token: *clang_view->clang_tokens) {
auto cursor=token.get_cursor(); auto cursor=token.get_cursor();
auto cursor_kind=cursor.get_kind(); auto kind=cursor.get_kind();
auto parent_cursor=cursor.get_semantic_parent(); if((kind==clangmm::Cursor::Kind::Constructor || kind==clangmm::Cursor::Kind::Destructor ||
if((cursor_kind==clangmm::Cursor::Kind::Constructor || cursor_kind==clangmm::Cursor::Kind::Destructor) && kind==clangmm::Cursor::Kind::FunctionTemplate) && token.is_identifier()) {
token.is_identifier() && parent_cursor.get_usr()==identifier.cursor.get_usr()) { auto parent_cursor=cursor.get_semantic_parent();
identifiers.emplace(cursor.get_kind(), token.get_spelling(), cursor.get_usr()); if(parent_cursor.get_kind()==identifier.kind && token.get_spelling()==identifier.spelling && parent_cursor.get_usr_extended()==identifier.usr_extended) {
identifiers.emplace(token.get_spelling(), cursor);
}
} }
} }
} }
std::vector<std::pair<clangmm::Offset, clangmm::Offset> > offsets; std::vector<std::pair<clangmm::Offset, clangmm::Offset> > offsets;
for(auto &identifier: identifiers) { for(auto &identifier: identifiers) {
auto token_offsets=clang_view->clang_tokens->get_similar_token_offsets(identifier.kind, identifier.spelling, identifier.usr); auto token_offsets=clang_view->clang_tokens->get_similar_token_offsets(identifier.spelling, identifier.usr_extended);
for(auto &token_offset: token_offsets) for(auto &token_offset: token_offsets)
offsets.emplace_back(token_offset); offsets.emplace_back(token_offset);
} }
@ -872,7 +882,6 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
clang_view->get_buffer()->create_mark(clang_view->get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1))); clang_view->get_buffer()->create_mark(clang_view->get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1)));
} }
if(!marks.empty()) { if(!marks.empty()) {
clang_view->renaming=true;
clang_view->get_buffer()->begin_user_action(); clang_view->get_buffer()->begin_user_action();
for(auto &mark: marks) { for(auto &mark: marks) {
clang_view->get_buffer()->erase(mark.first->get_iter(), mark.second->get_iter()); clang_view->get_buffer()->erase(mark.first->get_iter(), mark.second->get_iter());
@ -881,7 +890,6 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
clang_view->get_buffer()->delete_mark(mark.second); clang_view->get_buffer()->delete_mark(mark.second);
} }
clang_view->get_buffer()->end_user_action(); clang_view->get_buffer()->end_user_action();
clang_view->renaming=false;
clang_view->save(views); clang_view->save(views);
renamed_views.emplace_back(clang_view); renamed_views.emplace_back(clang_view);
renamed.emplace_back(clang_view->file_path, marks.size()); renamed.emplace_back(clang_view->file_path, marks.size());
@ -998,6 +1006,9 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
auto identifier=get_identifier(); auto identifier=get_identifier();
if(identifier) { if(identifier) {
wait_parsing(views); wait_parsing(views);
//First, look for a definition cursor that is equal
auto identifier_usr=identifier.cursor.get_usr();
for(auto &view: views) { for(auto &view: views) {
if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) { if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) {
for(auto &token: *clang_view->clang_tokens) { for(auto &token: *clang_view->clang_tokens) {
@ -1005,15 +1016,15 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
auto cursor_kind=cursor.get_kind(); auto cursor_kind=cursor.get_kind();
if((cursor_kind==clangmm::Cursor::Kind::FunctionDecl || cursor_kind==clangmm::Cursor::Kind::CXXMethod || if((cursor_kind==clangmm::Cursor::Kind::FunctionDecl || cursor_kind==clangmm::Cursor::Kind::CXXMethod ||
cursor_kind==clangmm::Cursor::Kind::Constructor || cursor_kind==clangmm::Cursor::Kind::Destructor || cursor_kind==clangmm::Cursor::Kind::Constructor || cursor_kind==clangmm::Cursor::Kind::Destructor ||
cursor_kind==clangmm::Cursor::Kind::ConversionFunction) && cursor_kind==clangmm::Cursor::Kind::FunctionTemplate || cursor_kind==clangmm::Cursor::Kind::ConversionFunction) &&
token.is_identifier()) { token.is_identifier()) {
auto referenced=cursor.get_referenced(); auto token_spelling=token.get_spelling();
if(referenced && identifier.kind==referenced.get_kind() && if(identifier.kind==cursor.get_kind() && identifier.spelling==token_spelling && identifier_usr==cursor.get_usr()) {
identifier.spelling==token.get_spelling() && identifier.usr==referenced.get_usr()) { if(clang_isCursorDefinition(cursor.cx_cursor)) {
if(clang_isCursorDefinition(referenced.cx_cursor)) {
Offset offset; Offset offset;
offset.file_path=cursor.get_source_location().get_path(); auto location=cursor.get_source_location();
auto clang_offset=cursor.get_source_location().get_offset(); auto clang_offset=location.get_offset();
offset.file_path=location.get_path();
offset.line=clang_offset.line-1; offset.line=clang_offset.line-1;
offset.index=clang_offset.index-1; offset.index=clang_offset.index-1;
offsets.emplace_back(offset); offsets.emplace_back(offset);
@ -1029,12 +1040,26 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
//If no implementation was found, try using clang_getCursorDefinition //If no implementation was found, try using clang_getCursorDefinition
auto definition=identifier.cursor.get_definition(); auto definition=identifier.cursor.get_definition();
if(definition) { if(definition) {
auto definition_location=definition.get_source_location(); auto location=definition.get_source_location();
Offset offset;
offset.file_path=location.get_path();
auto clang_offset=location.get_offset();
offset.line=clang_offset.line-1;
offset.index=clang_offset.index-1;
offsets.emplace_back(offset);
return offsets;
}
//If no implementation was found, use declaration if it is a function template
auto canonical=identifier.cursor.get_canonical();
auto cursor=clang_tu->get_cursor(canonical.get_source_location());
if(cursor && cursor.get_kind()==clangmm::Cursor::Kind::FunctionTemplate) {
auto location=cursor.get_source_location();
Offset offset; Offset offset;
offset.file_path=definition_location.get_path(); offset.file_path=location.get_path();
auto definition_offset=definition_location.get_offset(); auto clang_offset=location.get_offset();
offset.line=definition_offset.line-1; offset.line=clang_offset.line-1;
offset.index=definition_offset.index-1; offset.index=clang_offset.index-1;
offsets.emplace_back(offset); offsets.emplace_back(offset);
return offsets; return offsets;
} }
@ -1135,7 +1160,7 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
} }
for(auto &view: views_reordered) { for(auto &view: views_reordered) {
if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) { if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) {
auto offsets=clang_view->clang_tokens->get_similar_token_offsets(identifier.kind, identifier.spelling, identifier.usr); auto offsets=clang_view->clang_tokens->get_similar_token_offsets(identifier.spelling, identifier.usr_extended);
for(auto &offset: offsets) { for(auto &offset: offsets) {
size_t whitespaces_removed=0; size_t whitespaces_removed=0;
auto start_iter=clang_view->get_buffer()->get_iter_at_line(offset.first.line-1); auto start_iter=clang_view->get_buffer()->get_iter_at_line(offset.first.line-1);
@ -1253,14 +1278,14 @@ Source::ClangViewRefactor::ClangViewRefactor(const boost::filesystem::path &file
auto kind=cursor.get_kind(); auto kind=cursor.get_kind();
if(kind==clangmm::Cursor::Kind::FunctionDecl || kind==clangmm::Cursor::Kind::CXXMethod || if(kind==clangmm::Cursor::Kind::FunctionDecl || kind==clangmm::Cursor::Kind::CXXMethod ||
kind==clangmm::Cursor::Kind::Constructor || kind==clangmm::Cursor::Kind::Destructor || kind==clangmm::Cursor::Kind::Constructor || kind==clangmm::Cursor::Kind::Destructor ||
kind==clangmm::Cursor::Kind::ConversionFunction) { kind==clangmm::Cursor::Kind::FunctionTemplate || kind==clangmm::Cursor::Kind::ConversionFunction) {
auto offset=cursor.get_source_location().get_offset(); auto offset=cursor.get_source_location().get_offset();
if(offset==last_offset) if(offset==last_offset)
continue; continue;
last_offset=offset; last_offset=offset;
std::string method; std::string method;
if(kind==clangmm::Cursor::Kind::FunctionDecl || kind==clangmm::Cursor::Kind::CXXMethod) { if(kind!=clangmm::Cursor::Kind::Constructor && kind!=clangmm::Cursor::Kind::Destructor) {
method+=cursor.get_type().get_result().get_spelling(); method+=cursor.get_type().get_result().get_spelling();
auto pos=method.find(" "); auto pos=method.find(" ");
if(pos!=std::string::npos) if(pos!=std::string::npos)
@ -1488,7 +1513,7 @@ Source::ClangViewRefactor::Identifier Source::ClangViewRefactor::get_identifier(
if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) { if(line==token.offsets.first.line-1 && index>=token.offsets.first.index-1 && index <=token.offsets.second.index-1) {
auto referenced=token.get_cursor().get_referenced(); auto referenced=token.get_cursor().get_referenced();
if(referenced) if(referenced)
return Identifier(referenced.get_kind(), token.get_spelling(), referenced.get_usr(), referenced); return Identifier(token.get_spelling(), referenced);
} }
} }
} }
@ -1535,7 +1560,7 @@ void Source::ClangViewRefactor::tag_similar_identifiers(const Identifier &identi
get_buffer()->delete_mark(mark.second); get_buffer()->delete_mark(mark.second);
} }
similar_identifiers_marks.clear(); similar_identifiers_marks.clear();
auto offsets=clang_tokens->get_similar_token_offsets(identifier.kind, identifier.spelling, identifier.usr); auto offsets=clang_tokens->get_similar_token_offsets(identifier.spelling, identifier.usr_extended);
for(auto &offset: offsets) { for(auto &offset: offsets) {
auto start_iter=get_buffer()->get_iter_at_line_index(offset.first.line-1, offset.first.index-1); auto start_iter=get_buffer()->get_iter_at_line_index(offset.first.line-1, offset.first.index-1);
auto end_iter=get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1); auto end_iter=get_buffer()->get_iter_at_line_index(offset.second.line-1, offset.second.index-1);

13
src/source_clang.h

@ -78,17 +78,17 @@ namespace Source {
class ClangViewRefactor : public virtual ClangViewParse { class ClangViewRefactor : public virtual ClangViewParse {
class Identifier { class Identifier {
public: public:
Identifier(clangmm::Cursor::Kind kind, const std::string &spelling, const std::string &usr, const clangmm::Cursor &cursor=clangmm::Cursor()) : Identifier(const std::string &spelling, const clangmm::Cursor &cursor)
kind(kind), spelling(spelling), usr(usr), cursor(cursor) {} : kind(cursor.get_kind()), spelling(spelling), usr_extended(cursor.get_usr_extended()), cursor(cursor) {}
Identifier() : kind(static_cast<clangmm::Cursor::Kind>(0)) {} Identifier() : kind(static_cast<clangmm::Cursor::Kind>(0)) {}
operator bool() const { return static_cast<int>(kind)!=0; } operator bool() const { return static_cast<int>(kind)!=0; }
bool operator==(const Identifier &rhs) const { return (kind==rhs.kind && spelling==rhs.spelling && usr==rhs.usr); } bool operator==(const Identifier &rhs) const { return spelling==rhs.spelling && usr_extended==rhs.usr_extended; }
bool operator!=(const Identifier &rhs) const { return !(*this==rhs); } bool operator!=(const Identifier &rhs) const { return !(*this==rhs); }
bool operator<(const Identifier &rhs) const { return usr<rhs.usr; } bool operator<(const Identifier &rhs) const { return spelling<rhs.spelling || (spelling==rhs.spelling && usr_extended<rhs.usr_extended); }
clangmm::Cursor::Kind kind; clangmm::Cursor::Kind kind;
std::string spelling; std::string spelling;
std::string usr; std::string usr_extended;
clangmm::Cursor cursor; clangmm::Cursor cursor;
}; };
public: public:
@ -103,7 +103,6 @@ namespace Source {
void tag_similar_identifiers(const Identifier &identifier); void tag_similar_identifiers(const Identifier &identifier);
Glib::RefPtr<Gtk::TextTag> similar_identifiers_tag; Glib::RefPtr<Gtk::TextTag> similar_identifiers_tag;
Identifier last_tagged_identifier; Identifier last_tagged_identifier;
bool renaming=false;
}; };
class ClangView : public ClangViewAutocomplete, public ClangViewRefactor { class ClangView : public ClangViewAutocomplete, public ClangViewRefactor {

8
tests/source_clang_test.cc

@ -35,18 +35,18 @@ int main() {
g_assert_cmpuint(clang_view->clang_diagnostics.size(), ==, 0); g_assert_cmpuint(clang_view->clang_diagnostics.size(), ==, 0);
//test get_declaration and get_implementation //test get_declaration and get_implementation
clang_view->place_cursor_at_line_index(13, 7); clang_view->place_cursor_at_line_index(15, 7);
auto location=clang_view->get_declaration_location(); auto location=clang_view->get_declaration_location();
g_assert_cmpuint(location.line, ==, 4); g_assert_cmpuint(location.line, ==, 6);
clang_view->place_cursor_at_line_index(location.line, location.index); clang_view->place_cursor_at_line_index(location.line, location.index);
auto impl_locations=clang_view->get_implementation_locations({clang_view}); auto impl_locations=clang_view->get_implementation_locations({clang_view});
g_assert_cmpuint(impl_locations.size(), ==, 1); g_assert_cmpuint(impl_locations.size(), ==, 1);
g_assert_cmpuint(impl_locations[0].line, ==, 9); g_assert_cmpuint(impl_locations[0].line, ==, 11);
clang_view->place_cursor_at_line_index(location.line, location.index); clang_view->place_cursor_at_line_index(location.line, location.index);
location=clang_view->get_declaration_location(); location=clang_view->get_declaration_location();
g_assert_cmpuint(location.line, ==, 4); g_assert_cmpuint(location.line, ==, 6);
//test get_usages and get_methods //test get_usages and get_methods
auto locations=clang_view->get_usages({clang_view}); auto locations=clang_view->get_usages({clang_view});

2
tests/source_clang_test_files/main.cpp

@ -1,6 +1,8 @@
class TestClass { class TestClass {
public: public:
TestClass(); TestClass();
template<class T>
TestClass(T t) {++t;}
~TestClass() {} ~TestClass() {}
void function(); void function();
}; };

Loading…
Cancel
Save