diff --git a/src/completion_string.cc b/src/completion_string.cc index 3a4f4d4..148d686 100644 --- a/src/completion_string.cc +++ b/src/completion_string.cc @@ -4,6 +4,14 @@ clangmm::CompletionChunk::CompletionChunk(std::string text, CompletionChunkKind kind) : text(std::move(text)), kind(kind) {} +std::vector clangmm::CompletionString::get_chunks() const { + std::vector chunks; + for(unsigned i = 0; i < get_num_chunks(); ++i) + chunks.emplace_back(to_string(clang_getCompletionChunkText(cx_completion_string, i)), + static_cast(clang_getCompletionChunkKind(cx_completion_string, i))); + return chunks; +} + clangmm::CompletionString::CompletionString(const CXCompletionString &cx_completion_string) : cx_completion_string(cx_completion_string) {} @@ -15,14 +23,112 @@ unsigned clangmm::CompletionString::get_num_chunks() const { return clang_getNumCompletionChunks(cx_completion_string); } -std::vector clangmm::CompletionString::get_chunks() const { - std::vector chunks; - for(unsigned i = 0; i < get_num_chunks(); ++i) - chunks.emplace_back(to_string(clang_getCompletionChunkText(cx_completion_string, i)), - static_cast(clang_getCompletionChunkKind(cx_completion_string, i))); - return chunks; -} - std::string clangmm::CompletionString::get_brief_comment() const { return to_string(clang_getCompletionBriefComment(cx_completion_string)); } + +// Several workarounds has been added due to clang_getCursorCompletionString result being different from normal completion strings +clangmm::Cursor clangmm::CompletionString::get_cursor(CXTranslationUnit &tu) const { + class VisitorData { + public: + std::vector &completion_chunks; + std::vector parent_parts; + clangmm::Cursor found_cursor; + }; + class ChunkString { + public: + static void remove_template_argument_and_namespace(std::string &chunk) { + size_t pos1, pos2; + if((pos1=chunk.find('<'))!=std::string::npos && (pos2=chunk.rfind('>'))!=std::string::npos) + chunk=chunk.substr(0, pos1)+chunk.substr(pos2+1); + if((pos2=chunk.rfind("::"))!=std::string::npos) { + pos1=pos2-1; + while(pos1!=std::string::npos && ((chunk[pos1]>='a' && chunk[pos1]<='z') || (chunk[pos1]>='A' && chunk[pos1]<='Z') || + (chunk[pos1]>='0' && chunk[pos1]<='9') || chunk[pos1]==':' || chunk[pos1]=='_')) + --pos1; + chunk=chunk.substr(0, pos1+1)+chunk.substr(pos2+2); + } + } + }; + std::vector chunks; + for(unsigned i=0;i parent_parts; + if(!parent.empty()) { + size_t pos=0; + size_t last_pos=0; + while((pos=parent.find("::", pos))!=std::string::npos) { + parent_parts.emplace_back(parent.substr(last_pos, pos-last_pos)); + pos+=2; + last_pos=pos; + } + parent_parts.emplace_back(parent.substr(last_pos)); + } + + VisitorData visitor_data{chunks, parent_parts, clangmm::Cursor()}; + + clang_visitChildren(clang_getTranslationUnitCursor(tu), [](CXCursor cx_cursor, CXCursor cx_parent, CXClientData cx_data) { + auto data = static_cast(cx_data); + + bool equal=true; + auto cx_tmp_cursor=cx_parent; + if(clang_getCursorKind(cx_tmp_cursor)!=CXCursorKind::CXCursor_TranslationUnit) { + int c=0; + auto it=data->parent_parts.rbegin(); + for(;it!=data->parent_parts.rend();++it) { + auto name=clangmm::to_string(clang_getCursorDisplayName(cx_tmp_cursor)); + size_t pos; + if((pos=name.find('<'))!=std::string::npos) + name=name.substr(0, pos); + if(name!=*it) { + equal=false; + break; + } + cx_tmp_cursor=clang_getCursorSemanticParent(cx_tmp_cursor); + if(clang_getCursorKind(cx_tmp_cursor)==CXCursorKind::CXCursor_TranslationUnit) { + ++it; + break; + } + ++c; + } + if(it!=data->parent_parts.rend()) + equal=false; + } + else if(!data->parent_parts.empty()) + return CXChildVisit_Recurse; + + if(equal) { + auto completion_string = clang_getCursorCompletionString(cx_cursor); + auto num_completion_chunks=clang_getNumCompletionChunks(completion_string); + if(num_completion_chunks>=data->completion_chunks.size()) { + bool equal=true; + for(unsigned i=0;icompletion_chunks.size() && icompletion_chunks[i]!=chunk) { + equal=false; + break; + } + } + } + if(equal) { + data->found_cursor=cx_cursor; + return CXChildVisit_Break; + } + } + } + + return CXChildVisit_Recurse; + }, &visitor_data); + + return Cursor(visitor_data.found_cursor); +} diff --git a/src/completion_string.h b/src/completion_string.h index 03456b3..0aa327c 100644 --- a/src/completion_string.h +++ b/src/completion_string.h @@ -3,6 +3,7 @@ #include #include #include +#include "cursor.h" namespace clangmm { enum CompletionChunkKind { @@ -31,8 +32,11 @@ namespace clangmm { explicit CompletionString(const CXCompletionString &cx_completion_string); bool available() const; std::vector get_chunks() const; - std::string get_brief_comment() const; unsigned get_num_chunks() const; + std::string get_brief_comment() const; + + /// Search for the corresponding cursor + Cursor get_cursor(CXTranslationUnit &tu) const; CXCompletionString cx_completion_string; }; diff --git a/src/cursor.cc b/src/cursor.cc index 790d4c4..c8ccd98 100644 --- a/src/cursor.cc +++ b/src/cursor.cc @@ -59,6 +59,20 @@ std::string clangmm::Cursor::get_display_name() const { return to_string(clang_getCursorDisplayName(cx_cursor)); } +std::string clangmm::Cursor::get_token_spelling() const { + auto spelling=get_spelling(); + for(size_t i=0;i0 && spelling[0]=='~') + return spelling.substr(1, i-1); + return spelling.substr(0, i); + } + } + if(!spelling.empty() && spelling[0]=='~') + return spelling.substr(1); + return spelling; +} + std::string clangmm::Cursor::get_usr() const { return to_string(clang_getCursorUSR(cx_cursor)); } @@ -67,19 +81,6 @@ std::string clangmm::Cursor::get_usr_extended() const { if(!is_valid_kind()) return std::string(); - const auto token_spelling=[](const std::string &spelling) -> std::string { - for(size_t i=0;i0 && spelling[0]=='~') - return spelling.substr(1, i-1); - return spelling.substr(0, i); - } - } - if(!spelling.empty() && spelling[0]=='~') - return spelling.substr(1); - return spelling; - }; - auto cursor=*this; auto kind=cursor.get_kind(); // If constructor, destructor or function template, and the token spelling is equal, set cursor to parent @@ -88,11 +89,11 @@ std::string clangmm::Cursor::get_usr_extended() const { auto parent=cursor.get_semantic_parent(); auto parent_kind=parent.get_kind(); if((parent_kind==Cursor::Kind::ClassDecl || parent_kind==Cursor::Kind::StructDecl || parent_kind==Cursor::Kind::ClassTemplate) && - token_spelling(cursor.get_spelling())==token_spelling(parent.get_spelling())) + cursor.get_token_spelling()==parent.get_token_spelling()) cursor=parent; } - std::string usr=token_spelling(cursor.get_spelling()); + std::string usr=cursor.get_token_spelling(); auto parent=cursor.get_semantic_parent(); while((kind=parent.get_kind())!=Kind::TranslationUnit && parent.is_valid_kind()) { if(kind==Kind::CXXMethod || kind==Kind::FunctionDecl || kind==Kind::FunctionTemplate || @@ -102,7 +103,7 @@ std::string clangmm::Cursor::get_usr_extended() const { auto offset=location.get_offset(); return std::to_string(offset.line)+':'+std::to_string(offset.index)+':'+location.get_path(); } - usr+=':'+token_spelling(parent.get_spelling()); + usr+=':'+parent.get_token_spelling(); parent=parent.get_semantic_parent(); } return usr; diff --git a/src/cursor.h b/src/cursor.h index badf7d2..bdb229d 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -196,6 +196,7 @@ namespace clangmm { SourceRange get_source_range() const; std::string get_spelling() const; std::string get_display_name() const; + std::string get_token_spelling() const; std::string get_usr() const; /// Improved usr that is also template and argument invariant std::string get_usr_extended() const;