Commit 8c3f78eb authored by Ole Christian Eidheim's avatar Ole Christian Eidheim
Browse files

Added CompletionString::get_cursor and Cursor::get_token_spelling

parent 88e05677
......@@ -4,6 +4,14 @@
clangmm::CompletionChunk::CompletionChunk(std::string text, CompletionChunkKind kind)
: text(std::move(text)), kind(kind) {}
std::vector<clangmm::CompletionChunk> clangmm::CompletionString::get_chunks() const {
std::vector<CompletionChunk> chunks;
for(unsigned i = 0; i < get_num_chunks(); ++i)
chunks.emplace_back(to_string(clang_getCompletionChunkText(cx_completion_string, i)),
static_cast<CompletionChunkKind>(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::CompletionChunk> clangmm::CompletionString::get_chunks() const {
std::vector<CompletionChunk> chunks;
for(unsigned i = 0; i < get_num_chunks(); ++i)
chunks.emplace_back(to_string(clang_getCompletionChunkText(cx_completion_string, i)),
static_cast<CompletionChunkKind>(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<std::string> &completion_chunks;
std::vector<std::string> 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<std::string> chunks;
for(unsigned i=0;i<clang_getNumCompletionChunks(cx_completion_string);++i) {
auto kind = clang_getCompletionChunkKind(cx_completion_string, i);
if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) {
auto chunk=clangmm::to_string(clang_getCompletionChunkText(cx_completion_string, i));
ChunkString::remove_template_argument_and_namespace(chunk);
chunks.emplace_back(chunk);
}
}
auto parent=clangmm::to_string(clang_getCompletionParent(cx_completion_string, nullptr));
std::vector<std::string> 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<VisitorData *>(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;i<data->completion_chunks.size() && i<num_completion_chunks;++i) {
auto kind = clang_getCompletionChunkKind(completion_string, i);
if(kind != CXCompletionChunk_Optional && kind != CXCompletionChunk_Informative) {
auto chunk=clangmm::to_string(clang_getCompletionChunkText(completion_string, i));
ChunkString::remove_template_argument_and_namespace(chunk);
if(data->completion_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);
}
......@@ -3,6 +3,7 @@
#include <clang-c/Index.h>
#include <string>
#include <vector>
#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<CompletionChunk> 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;
};
......
......@@ -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;i<spelling.size();++i) {
if(spelling[i]=='<' || spelling[i]=='(') {
if(i>0 && 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;i<spelling.size();++i) {
if(spelling[i]=='<' || spelling[i]=='(') {
if(i>0 && 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;
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment