cursor.cc 8.53 KB
Newer Older
1 2
#include "cursor.h"
#include "utility.h"
3
#include <algorithm>
Jørgen Lien Sellæg's avatar
Jørgen Lien Sellæg committed
4

5
std::string clangmm::Cursor::Type::get_spelling() const {
6 7 8
  return to_string(clang_getTypeSpelling(cx_type));
}

9
clangmm::Cursor::Type clangmm::Cursor::Type::get_result() const {
10 11 12
  return Type(clang_getResultType(cx_type));
}

13 14 15 16
clangmm::Cursor clangmm::Cursor::Type::get_cursor() const {
  return Cursor(clang_getTypeDeclaration(cx_type));
}

17
bool clangmm::Cursor::Type::operator==(const Cursor::Type& rhs) const {
18 19 20
  return clang_equalTypes(cx_type, rhs.cx_type);
}

21
clangmm::Cursor::Kind clangmm::Cursor::get_kind() const {
22 23 24
  return static_cast<Kind>(clang_getCursorKind(cx_cursor));
}

Florian Jung's avatar
Florian Jung committed
25 26 27 28
std::string clangmm::Cursor::get_kind_spelling() const {
  return to_string(clang_getCursorKindSpelling(clang_getCursorKind(cx_cursor)));
}

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
bool clangmm::Cursor::is_similar_kind(Kind kind, Kind other_kind) {
  auto is_function_or_method=[](Kind kind) {
    if(kind==Kind::FunctionDecl || kind==Kind::CXXMethod || kind==Kind::FunctionTemplate)
      return true;
    return false;
  };
  auto is_class_or_struct=[](Kind kind) {
    if(kind==Kind::ClassDecl || kind==Kind::StructDecl || kind==Kind::ClassTemplate ||
       kind==Cursor::Kind::Constructor || kind==Cursor::Kind::Destructor || kind==Cursor::Kind::FunctionTemplate)
      return true;
    return false;
  };
  if(kind==Kind::FunctionTemplate)
    return is_function_or_method(other_kind) || is_class_or_struct(other_kind);
  if(is_function_or_method(kind))
    return is_function_or_method(other_kind);
  if(is_class_or_struct(kind))
    return is_class_or_struct(other_kind);
  return kind==other_kind;
}

50
clangmm::Cursor::Type clangmm::Cursor::get_type() const {
51
  return Type(clang_getCursorType(cx_cursor));
Jørgen Lien Sellæg's avatar
Jørgen Lien Sellæg committed
52 53
}

54
clangmm::SourceLocation clangmm::Cursor::get_source_location() const {
55 56 57
  return SourceLocation(clang_getCursorLocation(cx_cursor));
}

58
clangmm::SourceRange clangmm::Cursor::get_source_range() const {
59 60 61
  return SourceRange(clang_getCursorExtent(cx_cursor));
}

62
std::string clangmm::Cursor::get_spelling() const {
63
  return to_string(clang_getCursorSpelling(cx_cursor));
64 65
}

66
std::string clangmm::Cursor::get_display_name() const {
67 68 69
  return to_string(clang_getCursorDisplayName(cx_cursor));
}

70 71 72 73 74 75 76 77 78 79 80 81 82 83
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;
}

84
std::string clangmm::Cursor::get_usr() const {
85
  return to_string(clang_getCursorUSR(cx_cursor));
86 87
}

88 89 90 91
std::string clangmm::Cursor::get_usr_extended() const {
  if(!is_valid_kind())
    return std::string();
  
92 93 94
  auto cursor=*this;
  auto kind=cursor.get_kind();
  // If constructor, destructor or function template, and the token spelling is equal, set cursor to parent
95 96
  if(kind==Cursor::Kind::Constructor || kind==Cursor::Kind::Destructor ||
     kind==Cursor::Kind::FunctionTemplate) {
97
    auto parent=cursor.get_semantic_parent();
98 99
    auto parent_kind=parent.get_kind();
    if((parent_kind==Cursor::Kind::ClassDecl || parent_kind==Cursor::Kind::StructDecl || parent_kind==Cursor::Kind::ClassTemplate) &&
100
       cursor.get_token_spelling()==parent.get_token_spelling())
101
      cursor=parent;
102 103
  }
  
104
  std::string usr=cursor.get_token_spelling();
105 106
  auto parent=cursor.get_semantic_parent();
  while((kind=parent.get_kind())!=Kind::TranslationUnit && parent.is_valid_kind()) {
107 108
    if(kind==Kind::CXXMethod || kind==Kind::FunctionDecl || kind==Kind::FunctionTemplate ||
       kind==Kind::Constructor || kind==Kind::Destructor) {
109
      auto canonical=cursor.get_canonical();
110 111 112 113
      auto location=canonical.get_source_location();
      auto offset=location.get_offset();
      return std::to_string(offset.line)+':'+std::to_string(offset.index)+':'+location.get_path();
    }
114
    usr+=':'+parent.get_token_spelling();
115
    parent=parent.get_semantic_parent();
116 117 118 119
  }
  return usr;
}

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
std::unordered_set<std::string> clangmm::Cursor::get_all_usr_extended() const {
  std::unordered_set<std::string> usrs;
  if(get_kind()==Kind::CXXMethod) {
    class Recursive {
    public:
      static void overridden(std::unordered_set<std::string> &usrs, const Cursor &cursor) {
        usrs.emplace(cursor.get_usr_extended());
        CXCursor *cursors;
        unsigned size;
        clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
        for(unsigned c=0;c<size;++c)
          overridden(usrs, cursors[c]);
        clang_disposeOverriddenCursors(cursors);
      }
    };
    Recursive::overridden(usrs, *this);
    return usrs;
  }
  else {
    usrs.emplace(get_usr_extended());
    return usrs;
  }
}

144
clangmm::Cursor clangmm::Cursor::get_referenced() const {
145 146 147
  return Cursor(clang_getCursorReferenced(cx_cursor));
}

148
clangmm::Cursor clangmm::Cursor::get_canonical() const {
149 150 151
  return Cursor(clang_getCanonicalCursor(cx_cursor));
}

152
clangmm::Cursor clangmm::Cursor::get_definition() const {
153 154 155
  return Cursor(clang_getCursorDefinition(cx_cursor));
}

156
clangmm::Cursor clangmm::Cursor::get_semantic_parent() const {
157 158 159
  return Cursor(clang_getCursorSemanticParent(cx_cursor));
}

160 161 162 163 164 165 166 167 168 169 170 171
std::vector<clangmm::Cursor> clangmm::Cursor::get_children() const {
  std::vector<Cursor> result;
  clang_visitChildren(cx_cursor,
    [](CXCursor cur, CXCursor /*parent*/, CXClientData data) {
      static_cast<std::vector<Cursor>*>(data)->emplace_back(cur);
      return CXChildVisit_Continue;
    },
    &result
  );
  return result;
}

172
std::vector<clangmm::Cursor> clangmm::Cursor::get_arguments() const {
173 174 175 176 177
  std::vector<Cursor> cursors;
  auto size=clang_Cursor_getNumArguments(cx_cursor);
  for(int c=0;c<size;++c)
    cursors.emplace_back(clang_Cursor_getArgument(cx_cursor, c));
  return cursors;
178 179
}

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
std::vector<clangmm::Cursor> clangmm::Cursor::get_all_overridden_cursors() const {
  std::vector<Cursor> result;
  if(get_kind()!=Kind::CXXMethod)
    return result;
  
  class Recursive {
  public:
    static void overridden(std::vector<Cursor> &result, const Cursor &cursor, int depth) {
      if(depth>0)
        result.emplace_back(cursor);
      CXCursor *cursors;
      unsigned size;
      clang_getOverriddenCursors(cursor.cx_cursor, &cursors, &size);
      for(unsigned c=0;c<size;++c)
        overridden(result, cursors[c], depth+1);
      clang_disposeOverriddenCursors(cursors);
    }
  };
  Recursive::overridden(result, *this, 0);
  return result;
}

202
clangmm::Cursor::operator bool() const {
203
  return !clang_Cursor_isNull(cx_cursor);
204 205
}

206
bool clangmm::Cursor::operator==(const Cursor& rhs) const {
207
  return clang_equalCursors(cx_cursor, rhs.cx_cursor);
208
}
209

210
bool clangmm::Cursor::is_valid_kind() const {
211 212 213
  auto referenced=clang_getCursorReferenced(cx_cursor);
  if(clang_Cursor_isNull(referenced))
    return false;
214 215
  auto kind=get_kind();
  return kind>Kind::UnexposedDecl && (kind<Kind::FirstInvalid || kind>Kind::LastInvalid);
216 217
}

218
std::string clangmm::Cursor::get_type_description() const {
219 220 221 222
  std::string spelling;
  auto referenced=clang_getCursorReferenced(cx_cursor);
  if(!clang_Cursor_isNull(referenced)) {
    auto type=clang_getCursorType(referenced);
223
    spelling=to_string(clang_getTypeSpelling(type));
224
    
225
#if CINDEX_VERSION_MAJOR==0 && CINDEX_VERSION_MINOR<32
226 227 228
    const std::string auto_str="auto";
    if(spelling.size()>=4 && std::equal(auto_str.begin(), auto_str.end(), spelling.begin())) {
      auto canonical_type=clang_getCanonicalType(clang_getCursorType(cx_cursor));
229
      auto canonical_spelling=to_string(clang_getTypeSpelling(canonical_type));
Ole Christian Eidheim's avatar
Ole Christian Eidheim committed
230 231
      if(spelling.size()>5 && spelling[4]==' ' && spelling[5]=='&' && spelling!=canonical_spelling)
        return canonical_spelling+" &";
232 233 234 235 236 237 238
      else
        return canonical_spelling;
    }
    
    const std::string const_auto_str="const auto";
    if(spelling.size()>=10 && std::equal(const_auto_str.begin(), const_auto_str.end(), spelling.begin())) {
      auto canonical_type=clang_getCanonicalType(clang_getCursorType(cx_cursor));
239
      auto canonical_spelling=to_string(clang_getTypeSpelling(canonical_type));
Ole Christian Eidheim's avatar
Ole Christian Eidheim committed
240 241
      if(spelling.size()>11 && spelling[10]==' ' && spelling[11]=='&' && spelling!=canonical_spelling)
        return canonical_spelling+" &";
242 243
      else
        return canonical_spelling;
244
    }
245
#endif
Ole Christian Eidheim's avatar
Ole Christian Eidheim committed
246
  }
247
  
248 249 250
  if(spelling.empty())
    return get_spelling();
  
251 252 253
  return spelling;
}

254
std::string clangmm::Cursor::get_brief_comments() const {
255 256 257
  std::string comment_string;
  auto referenced=get_referenced();
  if(referenced) {
258
    comment_string=to_string(clang_Cursor_getBriefCommentText(referenced.cx_cursor));
259 260 261
  }
  return comment_string;
}