1 #include "cursor.hpp"
2 #include "utility.hpp"
3 
get_spelling() const4 std::string clangmm::Cursor::Type::get_spelling() const {
5   return to_string(clang_getTypeSpelling(cx_type));
6 }
7 
get_result() const8 clangmm::Cursor::Type clangmm::Cursor::Type::get_result() const {
9   return Type(clang_getResultType(cx_type));
10 }
11 
get_cursor() const12 clangmm::Cursor clangmm::Cursor::Type::get_cursor() const {
13   return Cursor(clang_getTypeDeclaration(cx_type));
14 }
15 
operator ==(const Cursor::Type & rhs) const16 bool clangmm::Cursor::Type::operator==(const Cursor::Type &rhs) const {
17   return clang_equalTypes(cx_type, rhs.cx_type);
18 }
19 
get_kind() const20 clangmm::Cursor::Kind clangmm::Cursor::get_kind() const {
21   return static_cast<Kind>(clang_getCursorKind(cx_cursor));
22 }
23 
get_kind_spelling() const24 std::string clangmm::Cursor::get_kind_spelling() const {
25   return to_string(clang_getCursorKindSpelling(clang_getCursorKind(cx_cursor)));
26 }
27 
is_similar_kind(Kind kind,Kind other_kind)28 bool clangmm::Cursor::is_similar_kind(Kind kind, Kind other_kind) {
29   auto is_function_or_method = [](Kind kind) {
30     if(kind == Kind::FunctionDecl || kind == Kind::CXXMethod || kind == Kind::FunctionTemplate)
31       return true;
32     return false;
33   };
34   auto is_class_or_struct = [](Kind kind) {
35     if(kind == Kind::ClassDecl || kind == Kind::StructDecl || kind == Kind::ClassTemplate ||
36        kind == Cursor::Kind::Constructor || kind == Cursor::Kind::Destructor || kind == Cursor::Kind::FunctionTemplate)
37       return true;
38     return false;
39   };
40   if(kind == Kind::FunctionTemplate)
41     return is_function_or_method(other_kind) || is_class_or_struct(other_kind);
42   if(is_function_or_method(kind))
43     return is_function_or_method(other_kind);
44   if(is_class_or_struct(kind))
45     return is_class_or_struct(other_kind);
46   return kind == other_kind;
47 }
48 
get_type() const49 clangmm::Cursor::Type clangmm::Cursor::get_type() const {
50   return Type(clang_getCursorType(cx_cursor));
51 }
52 
get_source_location() const53 clangmm::SourceLocation clangmm::Cursor::get_source_location() const {
54   return SourceLocation(clang_getCursorLocation(cx_cursor));
55 }
56 
get_source_range() const57 clangmm::SourceRange clangmm::Cursor::get_source_range() const {
58   return SourceRange(clang_getCursorExtent(cx_cursor));
59 }
60 
get_spelling() const61 std::string clangmm::Cursor::get_spelling() const {
62   return to_string(clang_getCursorSpelling(cx_cursor));
63 }
64 
get_display_name() const65 std::string clangmm::Cursor::get_display_name() const {
66   return to_string(clang_getCursorDisplayName(cx_cursor));
67 }
68 
get_token_spelling() const69 std::string clangmm::Cursor::get_token_spelling() const {
70   auto spelling = get_spelling();
71   for(size_t i = 0; i < spelling.size(); ++i) {
72     if(spelling[i] == '<' || spelling[i] == '(') {
73       if(i > 0 && spelling[0] == '~')
74         return spelling.substr(1, i - 1);
75       return spelling.substr(0, i);
76     }
77   }
78   if(!spelling.empty() && spelling[0] == '~')
79     return spelling.substr(1);
80   return spelling;
81 }
82 
get_usr() const83 std::string clangmm::Cursor::get_usr() const {
84   return to_string(clang_getCursorUSR(cx_cursor));
85 }
86 
get_usr_extended() const87 std::string clangmm::Cursor::get_usr_extended() const {
88   if(!is_valid_kind())
89     return std::string();
90 
91   auto cursor = *this;
92   auto kind = cursor.get_kind();
93   // If constructor, destructor or function template, and the token spelling is equal, set cursor to parent
94   if(kind == Cursor::Kind::Constructor || kind == Cursor::Kind::Destructor ||
95      kind == Cursor::Kind::FunctionTemplate) {
96     auto parent = cursor.get_semantic_parent();
97     auto parent_kind = parent.get_kind();
98     if((parent_kind == Cursor::Kind::ClassDecl || parent_kind == Cursor::Kind::StructDecl || parent_kind == Cursor::Kind::ClassTemplate) &&
99        cursor.get_token_spelling() == parent.get_token_spelling())
100       cursor = parent;
101   }
102 
103   std::string usr = cursor.get_token_spelling();
104   auto parent = cursor.get_semantic_parent();
105   while((kind = parent.get_kind()) != Kind::TranslationUnit && parent.is_valid_kind()) {
106     if(kind == Kind::CXXMethod || kind == Kind::FunctionDecl || kind == Kind::FunctionTemplate ||
107        kind == Kind::Constructor || kind == Kind::Destructor) {
108       auto canonical = cursor.get_canonical();
109       auto location = canonical.get_source_location();
110       auto offset = location.get_offset();
111       return std::to_string(offset.line) + ':' + std::to_string(offset.index) + ':' + location.get_path();
112     }
113     usr += ':' + parent.get_token_spelling();
114     parent = parent.get_semantic_parent();
115   }
116   return usr;
117 }
118 
get_all_usr_extended() const119 std::unordered_set<std::string> clangmm::Cursor::get_all_usr_extended() const {
120   std::unordered_set<std::string> usrs;
121   if(get_kind() == Kind::CXXMethod) {
122     class Recursive {
123     public:
124       static void overridden(std::unordered_set<std::string> &usrs, const Cursor &cursor) {
125         usrs.emplace(cursor.get_usr_extended());
126         CXCursor *cursors;
127         unsigned size;
128         clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
129         for(unsigned c = 0; c < size; ++c)
130           overridden(usrs, cursors[c]);
131         clang_disposeOverriddenCursors(cursors);
132       }
133     };
134     Recursive::overridden(usrs, *this);
135     return usrs;
136   }
137   else {
138     usrs.emplace(get_usr_extended());
139     return usrs;
140   }
141 }
142 
get_referenced() const143 clangmm::Cursor clangmm::Cursor::get_referenced() const {
144   return Cursor(clang_getCursorReferenced(cx_cursor));
145 }
146 
get_canonical() const147 clangmm::Cursor clangmm::Cursor::get_canonical() const {
148   return Cursor(clang_getCanonicalCursor(cx_cursor));
149 }
150 
get_definition() const151 clangmm::Cursor clangmm::Cursor::get_definition() const {
152   return Cursor(clang_getCursorDefinition(cx_cursor));
153 }
154 
get_semantic_parent() const155 clangmm::Cursor clangmm::Cursor::get_semantic_parent() const {
156   return Cursor(clang_getCursorSemanticParent(cx_cursor));
157 }
158 
get_children() const159 std::vector<clangmm::Cursor> clangmm::Cursor::get_children() const {
160   std::vector<Cursor> result;
161   clang_visitChildren(cx_cursor, [](CXCursor cur, CXCursor /*parent*/, CXClientData data) {
162     static_cast<std::vector<Cursor> *>(data)->emplace_back(cur);
163     return CXChildVisit_Continue;
164   }, &result);
165   return result;
166 }
167 
get_arguments() const168 std::vector<clangmm::Cursor> clangmm::Cursor::get_arguments() const {
169   std::vector<Cursor> cursors;
170   auto size = clang_Cursor_getNumArguments(cx_cursor);
171   for(int c = 0; c < size; ++c)
172     cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c));
173   return cursors;
174 }
175 
get_all_overridden_cursors() const176 std::vector<clangmm::Cursor> clangmm::Cursor::get_all_overridden_cursors() const {
177   std::vector<Cursor> result;
178   if(get_kind() != Kind::CXXMethod)
179     return result;
180 
181   class Recursive {
182   public:
183     static void overridden(std::vector<Cursor> &result, const Cursor &cursor, int depth) {
184       if(depth > 0)
185         result.emplace_back(cursor);
186       CXCursor *cursors;
187       unsigned size;
188       clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
189       for(unsigned c = 0; c < size; ++c)
190         overridden(result, cursors[c], depth + 1);
191       clang_disposeOverriddenCursors(cursors);
192     }
193   };
194   Recursive::overridden(result, *this, 0);
195   return result;
196 }
197 
operator bool() const198 clangmm::Cursor::operator bool() const {
199   return !clang_Cursor_isNull(cx_cursor);
200 }
201 
operator ==(const Cursor & rhs) const202 bool clangmm::Cursor::operator==(const Cursor &rhs) const {
203   return clang_equalCursors(cx_cursor, rhs.cx_cursor);
204 }
205 
hash() const206 unsigned clangmm::Cursor::hash() const {
207   return clang_hashCursor(cx_cursor);
208 }
209 
is_valid_kind() const210 bool clangmm::Cursor::is_valid_kind() const {
211   auto referenced = clang_getCursorReferenced(cx_cursor);
212   if(clang_Cursor_isNull(referenced))
213     return false;
214   auto kind = get_kind();
215   return kind > Kind::UnexposedDecl && (kind < Kind::FirstInvalid || kind > Kind::LastInvalid);
216 }
217 
get_type_description() const218 std::string clangmm::Cursor::get_type_description() const {
219   auto type = clang_getCursorType(cx_cursor);
220   if(type.kind != CXTypeKind::CXType_Invalid && type.kind != CXTypeKind::CXType_Unexposed)
221     return to_string(clang_getTypeSpelling(type));
222 
223   auto referenced = clang_getCursorReferenced(cx_cursor);
224   if(!clang_Cursor_isNull(referenced)) {
225     auto type = clang_getCursorType(referenced);
226     if(type.kind != CXTypeKind::CXType_Invalid)
227       return to_string(clang_getTypeSpelling(type));
228   }
229 
230   return get_spelling();
231 }
232 
get_brief_comments() const233 std::string clangmm::Cursor::get_brief_comments() const {
234   std::string comment_string;
235   auto referenced = get_referenced();
236   if(referenced) {
237     comment_string = to_string(clang_Cursor_getBriefCommentText(referenced.cx_cursor));
238   }
239   return comment_string;
240 }
241