void Tokenizer::getMethodNameAtLocation(size_t origOffset, OovString &className, OovString &methodName) { CLangAutoLock lock(mCLangLock, __LINE__, this); CXCursor startCursor = getCursorAtOffset(mTransUnit, mSourceFile, origOffset); std::string method = getDisposedString(clang_getCursorDisplayName(startCursor)); size_t pos = method.find('('); if(pos != std::string::npos) { method.erase(pos); } methodName = method; // Attempt to go to the definition from the following places: // A header file method declaration or inline definition. // A source file where the method is defined. // A call to a method through a pointer, or directly (self) // Attempt to go directly to the definition, it will work if it is in this // translation unit. CXCursor methodDefCursor = clang_getCursorDefinition(startCursor); CXCursor classCursor = startCursor; // Just default to something. // Method call can return invalid file when the definition is not in this // translation unit. if(clang_getCursorKind(methodDefCursor) != CXCursor_InvalidFile) { // In this translation unit (either header or source) // At this point, the semantic parent of the method definition is // the class. classCursor = clang_getCursorSemanticParent(methodDefCursor); } else { // In a file that isn't in this translation unit if(startCursor.kind == CXCursor_CXXMethod) { classCursor = clang_getCursorSemanticParent(startCursor); } else // Handle a call - The cursor is usually a compound statement? { // The definition was not available, so instead, look for the // declaration and class from through the referenced cursor. CXCursor refCursor = clang_getCursorReferenced(startCursor); classCursor = clang_getCursorSemanticParent(refCursor); } } std::string classCursorStr = getDisposedString(clang_getCursorDisplayName(classCursor)); className = classCursorStr; }
std::string TranslationUnit::GetEnclosingFunctionAtLocation( const std::string &filename, int line, int column, const std::vector< UnsavedFile > &unsaved_files, bool reparse ) { if ( reparse ) { Reparse( unsaved_files ); } unique_lock< mutex > lock( clang_access_mutex_ ); if ( !clang_translation_unit_ ) { return "Internal error: no translation unit"; } CXCursor cursor = GetCursor( filename, line, column ); if ( !CursorIsValid( cursor ) ) { return "Internal error: cursor not valid"; } CXCursor parent = clang_getCursorSemanticParent( cursor ); std::string parent_str = CXStringToString( clang_getCursorDisplayName( parent ) ); if ( parent_str.empty() ) { return "Unknown semantic parent"; } return parent_str; }
CXChildVisitResult visitor( CXCursor cursor, CXCursor parent, CXClientData client_data) { ClangTools::TranslationUnit::AstWalker * astWalker = reinterpret_cast<ClangTools::TranslationUnit::AstWalker *>(client_data); std::vector<std::string> & funcNames = *(reinterpret_cast<std::vector<std::string> *>(astWalker->getClientData())); auto sourceLocation = clang_getCursorLocation(cursor); CXFile file; clang_getFileLocation(sourceLocation, &file, 0, 0, 0); auto fileName = clang_getFileName(file); auto fileNameStr = ClangTools::String(fileName); if (fileNameStr != astWalker->getFileName()) { return CXChildVisit_Recurse; } auto func = std::string{}; auto def = bool{false}; if (clang_isCursorDefinition(cursor)) { def = true; } switch (clang_getCursorKind(cursor)) { case CXCursor_FunctionDecl: func = "Function "; break; case CXCursor_FunctionTemplate: func = "FunctionTemplate "; break; case CXCursor_CXXMethod: func = "CXXMethod "; break; default: return CXChildVisit_Recurse; break; } func += clang_isCursorDefinition(cursor) ? "definition: " : "declaration: "; auto semanticParent = clang_getCursorSemanticParent(cursor); auto semanticParentSpelling = clang_getCursorSpelling(semanticParent); func += ClangTools::String(semanticParentSpelling) + "::"; auto cursorSpelling = clang_getCursorSpelling(cursor); func += ClangTools::String(cursorSpelling); auto lexicalParent = clang_getCursorLexicalParent(cursor); auto lexicalParentSpelling = clang_getCursorSpelling(lexicalParent); func += " found in: " + ClangTools::String(lexicalParentSpelling); funcNames.push_back(func); return CXChildVisit_Recurse; }
int main(int argc, char *argv[]) { auto index = clang_createIndex(0, 0); auto options = clang_defaultEditingTranslationUnitOptions(); char const *args[] = { "-x", "c++", "-std=c++11" }; auto arg_count = sizeof( args ) / sizeof( *args ); filename = argv[1]; CXUnsavedFile *unsaved_files = NULL; auto unsaved_file_count = 0; tu = clang_parseTranslationUnit(index, filename.c_str(), args, arg_count, unsaved_files, unsaved_file_count, options ); if ( !tu ) { std::cout << "Translation Unit Parse Failed!\n"; return -1; } std::stringstream ss( argv[2] ); int line, col; ss >> line; ss.get(); ss >> col; std::cout << "Hello " << line << ":" << col << "\n"; auto file = clang_getFile( tu, filename.c_str() ); auto location = clang_getLocation( tu, file, line, col ); clang_visitChildren( clang_getTranslationUnitCursor( tu ), visitor, reinterpret_cast<CXClientData>(0) ); auto cursor = clang_getCursor( tu, location ); auto refcursor = clang_getCursorReferenced( cursor ); auto rrefcursor = clang_getCursorReferenced( refcursor ); auto arf = clang_getTypeKindSpelling( clang_getCursorType( cursor ).kind ); auto foo = clang_getCanonicalCursor( cursor ); auto semparent = clang_getCursorSemanticParent( cursor ); auto lexparent = clang_getCursorLexicalParent( cursor ); std::cout << cursor << "\n"; std::cout << refcursor << "\n"; std::cout << rrefcursor << "\n"; std::cout << clang_getCString(arf) << "\n"; std::cout << foo << "\n"; std::cout << "Parent: " << semparent << "\n"; std::cout << "LexParent: " << lexparent << "\n"; //clang_visitChildren( semparent, visitor, reinterpret_cast<CXClientData>(0) ); clang_disposeString( arf ); return 0; }
Cursor Cursor::semantic_parent() const { if ( !m_semantic_parent ) { CXCursor cx_cursor(clang_getCursorSemanticParent(m_cx_cursor)); if ( is_null(cx_cursor) ) { CLANGXX_THROW_LogicError("Error determining the semantic parent of this cursor."); } m_semantic_parent.reset(new Cursor(std::move(cx_cursor), m_translation_unit)); } return *m_semantic_parent; }
SEXP R_clang_getCursorSemanticParent(SEXP r_cursor) { SEXP r_ans = R_NilValue; CXCursor cursor = * GET_REF(r_cursor, CXCursor); CXCursor ans; ans = clang_getCursorSemanticParent(cursor); r_ans = R_makeCXCursor(ans) ; return(r_ans); }
std::string libclang_vim::stringize_parent(CXCursor const& cursor, CXCursor const& parent) { auto const semantic_parent = clang_getCursorSemanticParent(cursor); auto const lexical_parent = clang_getCursorLexicalParent(cursor); cxstring_ptr parent_name = clang_getCursorSpelling(parent); cxstring_ptr semantic_parent_name = clang_getCursorSpelling(semantic_parent); cxstring_ptr lexical_parent_name = clang_getCursorSpelling(lexical_parent); return stringize_key_value("parent", parent_name) + stringize_key_value("semantic_parent", semantic_parent_name) + stringize_key_value("lexical_parent", lexical_parent_name); }
bool IndexerJob::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { CursorInfo &info = mData->symbols[location]; if (!info.symbolLength || !RTags::isCursor(info.kind)) { CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info.symbolLength = cstr ? strlen(cstr) : 0; info.type = clang_getCursorType(cursor).kind; if (!info.symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info.symbolLength = 5; info.symbolName = "class"; break; case CXCursor_UnionDecl: info.symbolLength = 5; info.symbolName = "union"; break; case CXCursor_StructDecl: info.symbolLength = 6; info.symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info.symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; if (kind == CXCursor_EnumConstantDecl) { #if CLANG_VERSION_MINOR > 1 info.enumValue = clang_getEnumConstantDeclValue(cursor); #else info.definition = clang_isCursorDefinition(cursor); #endif } else{ info.definition = clang_isCursorDefinition(cursor); } info.kind = kind; const String usr = RTags::eatString(clang_getCursorUSR(cursor)); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info.kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { CursorInfo &parent = mData->symbols[parentLocation]; parent.references.insert(location); info.references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(&info); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
String IndexerJob::addNamePermutations(const CXCursor &cursor, const Location &location) { CXCursorKind kind = clang_getCursorKind(cursor); const CXCursorKind originalKind = kind; char buf[1024]; int pos = sizeof(buf) - 1; buf[pos] = '\0'; int cutoff = -1; CXCursor c = cursor; bool hasTemplates = false; do { CXStringScope displayName(clang_getCursorDisplayName(c)); const char *name = displayName.data(); if (!name) break; const int len = strlen(name); if (!len) break; if (kind == CXCursor_ClassTemplate) hasTemplates = true; if (pos != sizeof(buf) - 1 && (pos -= 2) >= 0) { memset(buf + pos, ':', 2); } pos -= len; if (pos < 0) { error("SymbolName too long. Giving up"); return String(); } memcpy(buf + pos, name, len); c = clang_getCursorSemanticParent(c); kind = clang_getCursorKind(c); if (cutoff == -1) { switch (kind) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_StructDecl: break; case CXCursor_Namespace: // namespaces can include all namespaces in their symbolname if (originalKind == CXCursor_Namespace) break; default: cutoff = pos; break; } } } while (RTags::needsQualifiers(kind)); String type; switch (originalKind) { case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: break; default: type = typeName(cursor); break; } if (cutoff == -1) cutoff = pos; String ret; for (int i=0; i<2; ++i) { char *ch = buf + pos; while (true) { const String name(ch, sizeof(buf) - (ch - buf) - 1); mData->symbolNames[name].insert(location); if (!type.isEmpty()) { mData->symbolNames[type + name].insert(location); } ch = strstr(ch + 1, "::"); if (ch) { ch += 2; } else { break; } } if (i == 0) { ret.assign(buf + cutoff, sizeof(buf) - cutoff - 1); if (!type.isEmpty()) ret.prepend(type); } if (!hasTemplates) { break; } else if (i == 0) { char *start = strchr(buf + pos, '<'); assert(start); char *end = strchr(start, '>'); const int templateSize = (end - start) + 1; assert(end); memmove(buf + pos + templateSize, buf + pos, start - (buf + pos)); pos += templateSize; } } return ret; }
static inline bool isImplicit(const CXCursor &cursor) { return clang_equalLocations(clang_getCursorLocation(cursor), clang_getCursorLocation(clang_getCursorSemanticParent(cursor))); }
cursor cursor::semanticParent() const { return { clang_getCursorSemanticParent(cur) }; }
Cursor Cursor::GetSemanticParent() const { return clang_getCursorSemanticParent(cursor_); }
bool ClangIndexer::handleCursor(const CXCursor &cursor, CXCursorKind kind, const Location &location) { // error() << "Got a cursor" << cursor; std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); if (!info->symbolLength) { // if (mLogFile) { // String out; // Log(&out) << cursor << a; // fwrite(out.constData(), 1, out.size(), mLogFile); // fwrite("\n", 1, 1, mLogFile); // } CXStringScope name = clang_getCursorSpelling(cursor); const char *cstr = name.data(); info->symbolLength = cstr ? strlen(cstr) : 0; info->type = clang_getCursorType(cursor).kind; if (!info->symbolLength) { // this is for these constructs: // typedef struct { // int a; // } foobar; // // We end up not getting a spelling for the cursor switch (kind) { case CXCursor_ClassDecl: info->symbolLength = 5; info->symbolName = "class"; break; case CXCursor_UnionDecl: info->symbolLength = 5; info->symbolName = "union"; break; case CXCursor_StructDecl: info->symbolLength = 6; info->symbolName = "struct"; break; default: mData->symbols.remove(location); return false; } } else { info->symbolName = addNamePermutations(cursor, location); } CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; if (kind == CXCursor_EnumConstantDecl) { #if CINDEX_VERSION_MINOR > 1 info->enumValue = clang_getEnumConstantDeclValue(cursor); #else info->definition = 1; #endif } else { info->definition = clang_isCursorDefinition(cursor); } info->kind = kind; // apparently some function decls will give a different usr for // their definition and their declaration. Using the canonical // cursor's usr allows us to join them. Check JSClassRelease in // JavaScriptCore for an example. const String usr = RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(cursor))); if (!usr.isEmpty()) mData->usrMap[usr].insert(location); switch (info->kind) { case CXCursor_Constructor: case CXCursor_Destructor: { Location parentLocation = createLocation(clang_getCursorSemanticParent(cursor)); // consider doing this for only declaration/inline definition since // declaration and definition should know of one another if (parentLocation.isValid()) { std::shared_ptr<CursorInfo> &parent = mData->symbols[parentLocation]; if (!parent) parent = std::make_shared<CursorInfo>(); parent->references.insert(location); info->references.insert(parentLocation); } break; } case CXCursor_CXXMethod: { List<CursorInfo*> infos; infos.append(info.get()); addOverriddenCursors(cursor, location, infos); break; } default: break; } } return true; }
String ClangIndexer::addNamePermutations(const CXCursor &cursor, const Location &location) { CXCursorKind kind = clang_getCursorKind(cursor); const CXCursorKind originalKind = kind; char buf[32768]; int pos = sizeof(buf) - 1; buf[pos] = '\0'; int cutoff = -1; CXCursor c = cursor; do { CXStringScope displayName(clang_getCursorDisplayName(c)); const char *name = displayName.data(); if (!name) break; const int len = strlen(name); if (!len) break; if (pos != sizeof(buf) - 1 && (pos -= 2) >= 0) { memset(buf + pos, ':', 2); } pos -= len; if (pos < 0) { error("SymbolName too long. Giving up"); return String(); } memcpy(buf + pos, name, len); c = clang_getCursorSemanticParent(c); kind = clang_getCursorKind(c); if (cutoff == -1) { switch (kind) { case CXCursor_ClassDecl: case CXCursor_ClassTemplate: case CXCursor_StructDecl: break; case CXCursor_Namespace: // namespaces can include all namespaces in their symbolname if (originalKind == CXCursor_Namespace) break; default: cutoff = pos; break; } } } while (RTags::needsQualifiers(kind)); String type; switch (originalKind) { case CXCursor_ClassDecl: case CXCursor_StructDecl: case CXCursor_ClassTemplate: break; default: type = RTags::typeName(cursor); break; } if (cutoff == -1) cutoff = pos; String ret; int templateStart, templateEnd, colonColonCount; int colonColons[512]; ::tokenize(buf, pos, &templateStart, &templateEnd, &colonColonCount, colonColons); // i == 0 --> with templates, // i == 1 without templates or without EnumConstantDecl part for (int i=0; i<2; ++i) { for (int j=0; j<colonColonCount; ++j) { const char *ch = buf + colonColons[j]; const String name(ch, sizeof(buf) - (ch - buf) - 1); mData->symbolNames[name].insert(location); if (!type.isEmpty() && (originalKind != CXCursor_ParmDecl || !strchr(ch, '('))) { // We only want to add the type to the final declaration for ParmDecls // e.g. // void foo(int)::bar // and // int bar // // not // int void foo(int)::bar // or // void foo(int)::int bar mData->symbolNames[type + name].insert(location); } } if (i == 0) { // create actual symbol name that will go into CursorInfo. This doesn't include namespaces etc if (!type.isEmpty()) { ret = type; ret.append(buf + cutoff, sizeof(buf) - cutoff - 1); } else { ret.assign(buf + cutoff, sizeof(buf) - cutoff - 1); } } if (i == 1 || (templateStart == -1 && originalKind != CXCursor_EnumConstantDecl)) { // nothing more to do break; } if (originalKind == CXCursor_EnumConstantDecl) { // remove CXCursor_EnumDecl // struct A { enum B { C } }; // Will by default generate a A::B::C symbolname. // This code removes the B:: part from it if (colonColonCount > 2) { const char *last = buf + colonColons[colonColonCount - 1]; const char *secondLast = buf + colonColons[colonColonCount - 2]; const int len = (last - secondLast); memmove(buf + pos + len, buf + pos, secondLast - (buf + pos)); pos += len; // ### We could/should just move the colon colon values but this // should be pretty quick and I don't want to write the code to // do it. ::tokenize(buf, pos, &templateStart, &templateEnd, &colonColonCount, colonColons); } } else { // remove templates assert(templateStart != -1); assert(templateEnd != -1); const int templateSize = (templateEnd - templateStart) + 1; memmove(buf + pos + templateSize, buf + pos, (buf + templateStart) - (buf + pos)); pos += templateSize; } } return ret; }
Cursor Cursor::semanticParent() const { return clang_getCursorSemanticParent(cxCursor); }