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; }
static inline CXCursor findDestructorForDelete(const CXCursor &deleteStatement) { const CXCursor child = RTags::findFirstChild(deleteStatement); CXCursorKind kind = clang_getCursorKind(child); switch (kind) { case CXCursor_UnexposedExpr: case CXCursor_CallExpr: break; default: return nullCursor; } const CXCursor var = clang_getCursorReferenced(child); kind = clang_getCursorKind(var); switch (kind) { case CXCursor_VarDecl: case CXCursor_FieldDecl: case CXCursor_ParmDecl: case CXCursor_CXXMethod: case CXCursor_FunctionDecl: break; default: if (!clang_isInvalid(kind)) { error() << "Got unexpected cursor" << deleteStatement << var; // assert(0); } return nullCursor; } CXCursor ref = RTags::findChild(var, CXCursor_TypeRef); if (ref != CXCursor_TypeRef) ref = RTags::findChild(var, CXCursor_TemplateRef); kind = clang_getCursorKind(ref); switch (kind) { case CXCursor_TypeRef: case CXCursor_TemplateRef: break; default: return nullCursor; } const CXCursor referenced = clang_getCursorReferenced(ref); kind = clang_getCursorKind(referenced); switch (kind) { case CXCursor_StructDecl: case CXCursor_ClassDecl: case CXCursor_ClassTemplate: break; default: return nullCursor; } const CXCursor destructor = RTags::findChild(referenced, CXCursor_Destructor); return destructor; }
Location TranslationUnit::GetDeclarationLocation( 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 Location(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return Location(); CXCursor referenced_cursor = clang_getCursorReferenced( cursor ); if ( !CursorIsValid( referenced_cursor ) ) return Location(); CXCursor canonical_cursor = clang_getCanonicalCursor( referenced_cursor ); if ( !CursorIsValid( canonical_cursor ) ) return Location( clang_getCursorLocation( referenced_cursor ) ); return Location( clang_getCursorLocation( canonical_cursor ) ); }
static void PrintCursor(CXCursor Cursor) { if (clang_isInvalid(Cursor.kind)) { CXString ks = clang_getCursorKindSpelling(Cursor.kind); printf("Invalid Cursor => %s", clang_getCString(ks)); clang_disposeString(ks); } else { CXString string, ks; CXCursor Referenced; unsigned line, column; ks = clang_getCursorKindSpelling(Cursor.kind); string = clang_getCursorSpelling(Cursor); printf("%s=%s", clang_getCString(ks), clang_getCString(string)); clang_disposeString(ks); clang_disposeString(string); Referenced = clang_getCursorReferenced(Cursor); if (!clang_equalCursors(Referenced, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(Referenced); clang_getInstantiationLocation(Loc, 0, &line, &column, 0); printf(":%d:%d", line, column); } if (clang_isCursorDefinition(Cursor)) printf(" (Definition)"); } }
virtual enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent) { CXFile file; unsigned int line, column, offset; clang_getInstantiationLocation( clang_getCursorLocation(cursor), &file, &line, &column, &offset); CXCursorKind kind = clang_getCursorKind(cursor); const char* cursorFilename = clang_getCString(clang_getFileName(file)); if (!clang_getFileName(file).data || strcmp(cursorFilename, translationUnitFilename) != 0) { return CXChildVisit_Continue; } CXCursor refCursor = clang_getCursorReferenced(cursor); if (!clang_equalCursors(refCursor, clang_getNullCursor())) { CXFile refFile; unsigned int refLine, refColumn, refOffset; clang_getInstantiationLocation( clang_getCursorLocation(refCursor), &refFile, &refLine, &refColumn, &refOffset); if (clang_getFileName(refFile).data) { std::string referencedUsr(clang_getCString(clang_getCursorUSR(refCursor))); if (!referencedUsr.empty()) { std::stringstream ss; ss << cursorFilename << ":" << line << ":" << column << ":" << kind; std::string location(ss.str()); usrToReferences[referencedUsr].insert(location); } } } return CXChildVisit_Recurse; }
bool ClangUtils::GetCursorAt(CXTranslationUnit &unit, const wxString &filename, int line, int col, CXCursor &cur) { CXFile file1; CXCursor cursor; CXSourceLocation loc; file1 = clang_getFile (unit, filename.mb_str(wxConvUTF8).data()); loc = clang_getLocation(unit, file1, line, col); cursor = clang_getCursor (unit, loc); if(clang_isInvalid(cursor.kind)) return false; if(cursor.kind == CXCursor_MemberRef || cursor.kind == CXCursor_MemberRefExpr || cursor.kind == CXCursor_TypeRef || cursor.kind == CXCursor_DeclRefExpr || cursor.kind == CXCursor_TemplateRef || cursor.kind == CXCursor_NamespaceRef ) { cursor = clang_getCursorReferenced(cursor); } cur = cursor; return true; }
DocumentationData TranslationUnit::GetDocsForLocationInFile( 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 DocumentationData(); CXCursor cursor = GetCursor( line, column ); if ( !CursorIsValid( cursor ) ) return DocumentationData(); // If the original cursor is a reference, then we return the documentation // for the type/method/etc. that is referenced CXCursor referenced_cursor = clang_getCursorReferenced( cursor ); if ( CursorIsValid( referenced_cursor ) ) cursor = referenced_cursor; // We always want the documentation associated with the canonical declaration CXCursor canonical_cursor = clang_getCanonicalCursor( cursor ); if ( !CursorIsValid( canonical_cursor ) ) return DocumentationData(); return DocumentationData( canonical_cursor ); }
CXChildVisitResult DumpThread::visitor(CXCursor cursor, CXCursor, CXClientData userData) { DumpThread *that = reinterpret_cast<DumpThread*>(userData); assert(that); CXSourceLocation location = clang_getCursorLocation(cursor); if (!clang_equalLocations(location, nullLocation)) { CXString file; unsigned line, col; clang_getPresumedLocation(location, &file, &line, &col); Path path = RTags::eatString(file); if (!path.isEmpty()) { uint32_t &fileId = that->mFiles[path]; if (!fileId) { const Path resolved = path.resolved(); fileId = Location::insertFile(resolved); that->mFiles[path] = that->mFiles[resolved] = fileId; } if (that->mQueryFlags & QueryMessage::DumpIncludeHeaders || fileId == that->mSource.fileId) { const Location loc(fileId, line, col); String message; message.reserve(256); if (!(that->mQueryFlags & QueryMessage::NoContext)) message += loc.context(); CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned endLine, endColumn; clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); if (endLine == line) { message += String::format<32>(" // %d-%d, %d: ", col, endColumn, that->mIndentLevel); } else { message += String::format<32>(" // %d-%d:%d, %d: ", col, endLine, endColumn, that->mIndentLevel); } message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); message.append(" " + RTags::typeName(cursor) + " "); CXCursor ref = clang_getCursorReferenced(cursor); if (clang_equalCursors(ref, cursor)) { message.append("refs self"); } else if (!clang_equalCursors(ref, nullCursor)) { message.append("refs "); message.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); } CXCursor canonical = clang_getCanonicalCursor(cursor); if (!clang_equalCursors(canonical, cursor) && !clang_equalCursors(canonical, nullCursor)) { message.append("canonical "); message.append(RTags::cursorToString(canonical, RTags::AllCursorToStringFlags)); } that->writeToConnetion(message); } } } ++that->mIndentLevel; clang_visitChildren(cursor, DumpThread::visitor, userData); --that->mIndentLevel; return CXChildVisit_Continue; }
void ClangIndexer::superclassTemplateMemberFunctionUgleHack(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { // This is for references to superclass template functions. Awful awful // shit. See https://github.com/Andersbakken/rtags/issues/62 and commit // for details. I really should report this as a bug. if (kind == CXCursor_MemberRefExpr && clang_getCursorKind(parent) == CXCursor_CallExpr) { const CXCursor templateRef = RTags::findChild(cursor, CXCursor_TemplateRef); if (templateRef == CXCursor_TemplateRef) { const CXCursor classTemplate = clang_getCursorReferenced(templateRef); if (classTemplate == CXCursor_ClassTemplate) { FILE *f = fopen(location.path().constData(), "r"); if (f) { const CXSourceRange range = clang_getCursorExtent(cursor); const CXSourceLocation end = clang_getRangeEnd(range); unsigned offset; clang_getSpellingLocation(end, 0, 0, 0, &offset); String name; while (offset > 0) { fseek(f, --offset, SEEK_SET); char ch = static_cast<char>(fgetc(f)); if (isalnum(ch) || ch == '_' || ch == '~') { name.prepend(ch); } else { break; } } fclose(f); if (!name.isEmpty()) { RTags::Filter out; out.kinds.insert(CXCursor_MemberRefExpr); const int argCount = RTags::children(parent, RTags::Filter(), out).size(); RTags::Filter in(RTags::Filter::And); in.names.insert(name); in.argumentCount = argCount; const List<CXCursor> alternatives = RTags::children(classTemplate, in); switch (alternatives.size()) { case 1: // ### not sure this is correct with line/col handleReference(cursor, kind, Location(location.fileId(), location.line(), location.column() + 1), alternatives.first(), parent); break; case 0: break; default: warning() << "Can't decide which of these cursors are right for me" << cursor << alternatives << "Need to parse types"; break; } } } } } } }
void DumpThread::checkIncludes(const Location &location, const CXCursor &cursor) { if (clang_getCursorKind(cursor) == CXCursor_InclusionDirective) { handleInclude(location, cursor); } else { const CXCursor ref = clang_getCursorReferenced(cursor); if (!clang_equalCursors(cursor, nullCursor) && !clang_equalCursors(cursor, ref)) { handleReference(location, ref); } } }
std::string AdvancedCallExprHandler( CXCursor cursor ) { auto newcursor = clang_getCursorReferenced( cursor ); std::string result = "Function"; if ( newcursor.kind == CXCursor_Constructor ) result = "Identifier"; else clang_visitChildren( cursor, CallExprVisitor, reinterpret_cast<std::string *>(&result) ); return result; }
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; }
Location TranslationUnit::GetDeclarationLocationForCursor( CXCursor cursor ) { CXCursor referenced_cursor = clang_getCursorReferenced( cursor ); if ( !CursorIsValid( referenced_cursor ) ) { return Location(); } CXCursor canonical_cursor = clang_getCanonicalCursor( referenced_cursor ); if ( !CursorIsValid( canonical_cursor ) ) { return Location( clang_getCursorLocation( referenced_cursor ) ); } return Location( clang_getCursorLocation( canonical_cursor ) ); }
location translation_unit::declaration_location_at(uint32_t row, uint32_t col) { CXCursor cursor = get_cursor_at(row, col); CXCursor ref = clang_getCursorReferenced( cursor ); if (clang_Cursor_isNull(ref) || clang_isInvalid(clang_getCursorKind(ref))) return {"", 0, 0}; CXSourceLocation loc = clang_getCursorLocation(ref); CXFile file; uint32_t nrow, ncol, offset = 0; clang_getExpansionLocation( loc, &file, &nrow, &ncol, &offset ); return { cx2std(clang_getFileName(file)), nrow, ncol }; }
Cursor Cursor::referenced() const { if ( !m_referenced ) { CXCursor cx_cursor(clang_getCursorReferenced(m_cx_cursor)); if ( is_null(cx_cursor) ) { if ( is_null(m_cx_cursor) ) { CLANGXX_THROW_LogicError("Error retrieving a cursor representing the entity that this cursor references."); } m_referenced.reset(new Cursor()); } else { m_referenced.reset(new Cursor(std::move(cx_cursor), m_translation_unit)); } } return *m_referenced; }
void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text,int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; CXCursor r = clang_getCursorReferenced(c); if (!clang_equalCursors(r, c)) { c=r; // link to referenced location } CXCursor t = clang_getSpecializedCursorTemplate(c); if (!clang_Cursor_isNull(t) && !clang_equalCursors(t,c)) { c=t; // link to template } CXString usr = clang_getCursorUSR(c); const char *usrStr = clang_getCString(usr); Definition *d = usrStr ? Doxygen::clangUsrMap->find(usrStr) : 0; //CXCursorKind kind = clang_getCursorKind(c); //if (d==0) //{ // printf("didn't find definition for '%s' usr='******' kind=%d\n", // text,usrStr,kind); //} //else //{ // printf("found definition for '%s' usr='******' name='%s'\n", // text,usrStr,d->name().data()); //} if (d && d->isLinkable()) { if (g_insideBody && g_currentMemberDef && d->definitionType()==Definition::TypeMember && (g_currentMemberDef!=d || g_currentLine<line)) // avoid self-reference { addDocCrossReference(g_currentMemberDef,(MemberDef*)d); } writeMultiLineCodeLink(ol,fd,line,column,d,text); } else { codifyLines(ol,fd,text,line,column); } clang_disposeString(usr); }
std::ostream& operator<<( std::ostream &os, CXCursor cursor ) { auto spelling = clang_getCursorKindSpelling( cursor.kind ); auto morespell = clang_getCursorSpelling( cursor ); os << clang_getCString( spelling ) << ":" << clang_getCString( morespell ) << " "; clang_disposeString( spelling ); clang_disposeString( morespell ); auto refcursor = clang_getCursorReferenced( cursor ); if ( clang_equalCursors( refcursor, clang_getNullCursor() )|| clang_equalCursors( refcursor, cursor ) ) return os; return os << " [ " << refcursor << " ] "; }
void ClangParser::linkIdentifier(CodeOutputInterface &ol, QSharedPointer<FileDef> fd, uint &line, uint &column, const QString &text, int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; CXCursor r = clang_getCursorReferenced(c); if (! clang_equalCursors(r, c)) { // link to referenced location c = r; } CXCursor t = clang_getSpecializedCursorTemplate(c); if (! clang_Cursor_isNull(t) && !clang_equalCursors(t, c)) { // link to template c = t; } CXString usr = clang_getCursorUSR(c); const char *usrStr = clang_getCString(usr); QSharedPointer<Definition> d; if (usrStr) { d = Doxy_Globals::clangUsrMap.value(usrStr); } if (d && d->isLinkable()) { if (g_insideBody && g_currentMemberDef && d->definitionType() == Definition::TypeMember && (g_currentMemberDef != d || g_currentLine < line)) { // avoid self-reference addDocCrossReference(g_currentMemberDef, d.dynamicCast<MemberDef>()); } writeMultiLineCodeLink(ol, fd, line, column, d, text); } else { codifyLines(ol, fd, text, line, column, ""); } clang_disposeString(usr); }
static CXChildVisitResult resolveAutoTypeRefVisitor(CXCursor cursor, CXCursor, CXClientData data) { ResolveAutoTypeRefUserData *userData = reinterpret_cast<ResolveAutoTypeRefUserData*>(data); const CXCursorKind kind = clang_getCursorKind(cursor); // userData->chain.append(kind); // error() << "Got here" << cursor << userData->chain; ++userData->index; switch (kind) { case CXCursor_TypeRef: case CXCursor_TemplateRef: // error() << "Found typeRef" << cursor; userData->ref = cursor; return CXChildVisit_Break; case CXCursor_UnexposedExpr: { CXCursor ref = clang_getCursorReferenced(cursor); // error() << "got unexposed expr ref" << ref; switch (clang_getCursorKind(ref)) { case CXCursor_VarDecl: case CXCursor_FunctionDecl: case CXCursor_CXXMethod: { ResolveAutoTypeRefUserData u = { nullCursor, 0 }; clang_visitChildren(ref, resolveAutoTypeRefVisitor, &u); // error() << "Visited for typeRef" << u.ref // << clang_isInvalid(clang_getCursorKind(u.ref)) // << u.chain; if (!clang_equalCursors(u.ref, nullCursor)) { userData->ref = u.ref; return CXChildVisit_Break; } break; } default: break; } break; } case CXCursor_ParmDecl: // nothing to find here return CXChildVisit_Break; default: break; } return CXChildVisit_Recurse; }
static enum CXChildVisitResult visit(CXCursor cursor, CXCursor parent, CXClientData userData) { (void)parent; int indent = *(int*)userData; int i; for (i=0; i<indent; ++i) { printf(" "); } printCursor(cursor); CXCursor ref = clang_getCursorReferenced(cursor); if (!clang_isInvalid(clang_getCursorKind(ref)) && !clang_equalCursors(ref, cursor)) { for (i=0; i<indent; ++i) { printf(" "); } printf("-> "); printCursor(ref); } ++indent; clang_visitChildren(cursor, visit, &indent); return CXChildVisit_Continue; }
std::string CursorKindSpelling( CXCursor cursor ) { auto kind = cursor.kind; CXCursor newcursor; switch( kind ) { case CXCursor_DeclRefExpr: case CXCursor_MemberRefExpr: newcursor = clang_getCursorReferenced( cursor ); std::cout << "NEW CURSOR: " << newcursor << "\n"; return CursorKindSpelling( newcursor ); case CXCursor_CallExpr: return AdvancedCallExprHandler( cursor ); case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_Constructor: case CXCursor_Destructor: case CXCursor_OverloadedDeclRef: return "Function"; case CXCursor_ParmDecl: case CXCursor_VarDecl: case CXCursor_FieldDecl: case CXCursor_MemberRef: case CXCursor_VariableRef: case CXCursor_NonTypeTemplateParameter: return "Variable"; case CXCursor_NamespaceRef: return "Namespace"; default: return "Identifier"; } return {}; }
CXChildVisitResult IndexerJob::verboseVisitor(CXCursor cursor, CXCursor, CXClientData userData) { VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData); Location loc = u->job->createLocation(cursor); if (loc.fileId()) { CXCursor ref = clang_getCursorReferenced(cursor); VerboseVisitorUserData *u = reinterpret_cast<VerboseVisitorUserData*>(userData); if (u->indent >= 0) u->out += String(u->indent, ' '); u->out += RTags::cursorToString(cursor); if (clang_equalCursors(ref, cursor)) { u->out += " refs self"; } else if (!clang_equalCursors(ref, nullCursor)) { u->out += " refs " + RTags::cursorToString(ref); } if (loc.fileId() && u->job->mVisitedFiles.contains(loc.fileId())) { if (u->job->mData->references.contains(loc)) { u->out += " used as reference\n"; } else if (u->job->mData->symbols.contains(loc)) { u->out += " used as cursor\n"; } else { u->out += " not used\n"; } } else { u->out += " not indexed\n"; } } if (u->indent >= 0) { u->indent += 2; clang_visitChildren(cursor, IndexerJob::verboseVisitor, userData); u->indent -= 2; return CXChildVisit_Continue; } else { return CXChildVisit_Recurse; } }
CXChildVisitResult IndexerJob::dumpVisitor(CXCursor cursor, CXCursor, CXClientData userData) { DumpUserData *dump = reinterpret_cast<DumpUserData*>(userData); assert(dump); assert(dump->job); Location loc = dump->job->createLocation(cursor); if (loc.fileId()) { CXCursor ref = clang_getCursorReferenced(cursor); String out; out.reserve(256); int col = -1; if (dump->showContext) { out.append(loc.context(&col)); if (col != -1) { out.append(String::format<32>(" // %d, %d: ", col, dump->indentLevel)); } else { out.append(String::format<32>(" // %d: ", dump->indentLevel)); } } else { out.append(String(dump->indentLevel * 2, ' ')); } out.append(RTags::cursorToString(cursor, RTags::AllCursorToStringFlags)); out.append(" " + typeName(cursor) + " "); if (clang_equalCursors(ref, cursor)) { out.append("refs self"); } else if (!clang_equalCursors(ref, nullCursor)) { out.append("refs "); out.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); } dump->job->write(out); } ++dump->indentLevel; clang_visitChildren(cursor, IndexerJob::dumpVisitor, userData); --dump->indentLevel; return CXChildVisit_Continue; }
CXChildVisitResult DumpThread::visit(const CXCursor &cursor) { if (isAborted()) return CXChildVisit_Break; const Location location = createLocation(cursor); if (!location.isNull()) { if (mQueryFlags & QueryMessage::DumpCheckIncludes) { checkIncludes(location, cursor); return CXChildVisit_Recurse; } else { Flags<Location::ToStringFlag> locationFlags; if (mQueryFlags & QueryMessage::NoColor) locationFlags |= Location::NoColor; CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned int endLine, endColumn; clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); if (!(mQueryFlags & QueryMessage::DumpIncludeHeaders) && location.fileId() != mSource.fileId) { return CXChildVisit_Continue; } String message; message.reserve(256); if (!(mQueryFlags & QueryMessage::NoContext)) { message = location.context(locationFlags); } if (endLine == location.line()) { message += String::format<32>(" // %d-%d, %d: ", location.column(), endColumn, mIndentLevel); } else { message += String::format<32>(" // %d-%d:%d, %d: ", location.column(), endLine, endColumn, mIndentLevel); } message += RTags::cursorToString(cursor, RTags::AllCursorToStringFlags); message.append(" " + RTags::typeName(cursor));; if (clang_getCursorKind(cursor) == CXCursor_VarDecl) { const std::shared_ptr<RTags::Auto> autoResolved = RTags::resolveAuto(cursor); if (autoResolved && !clang_equalCursors(autoResolved->cursor, nullCursor)) { message += "auto resolves to " + RTags::cursorToString(autoResolved->cursor, RTags::AllCursorToStringFlags); } } CXCursor ref = clang_getCursorReferenced(cursor); if (clang_equalCursors(ref, cursor)) { message.append("refs self"); } else if (!clang_equalCursors(ref, nullCursor)) { message.append("refs "); message.append(RTags::cursorToString(ref, RTags::AllCursorToStringFlags)); } CXCursor canonical = clang_getCanonicalCursor(cursor); if (!clang_equalCursors(canonical, cursor) && !clang_equalCursors(canonical, nullCursor)) { message.append("canonical "); message.append(RTags::cursorToString(canonical, RTags::AllCursorToStringFlags)); } CXCursor specialized = clang_getSpecializedCursorTemplate(cursor); if (!clang_equalCursors(specialized, cursor) && !clang_equalCursors(specialized, nullCursor)) { message.append("specialized "); message.append(RTags::cursorToString(specialized, RTags::AllCursorToStringFlags)); } writeToConnetion(message); } } ++mIndentLevel; clang_visitChildren(cursor, DumpThread::visitor, this); if (isAborted()) return CXChildVisit_Break; --mIndentLevel; return CXChildVisit_Continue; }
CXChildVisitResult IndexerJob::indexVisitor(CXCursor cursor, CXCursor parent, CXClientData data) { IndexerJob *job = static_cast<IndexerJob*>(data); { MutexLocker lock(&job->mMutex); if (job->mAborted) return CXChildVisit_Break; } const LastCursorUpdater updater(job->mLastCursor, cursor); const CXCursorKind kind = clang_getCursorKind(cursor); const RTags::CursorType type = RTags::cursorType(kind); if (type == RTags::Other) return CXChildVisit_Recurse; bool blocked = false; Location loc = job->createLocation(cursor, &blocked); if (blocked) { return CXChildVisit_Continue; } else if (loc.isNull()) { return CXChildVisit_Recurse; } if (testLog(VerboseDebug)) { Log log(VerboseDebug); log << cursor; CXCursor ref = clang_getCursorReferenced(cursor); if (!clang_isInvalid(clang_getCursorKind(ref)) && !clang_equalCursors(ref, cursor)) { log << "refs" << ref; } } switch (type) { case RTags::Cursor: job->handleCursor(cursor, kind, loc); break; case RTags::Include: job->handleInclude(cursor, kind, loc); break; case RTags::Reference: switch (kind) { case CXCursor_OverloadedDeclRef: { const int count = clang_getNumOverloadedDecls(cursor); for (int i=0; i<count; ++i) { const CXCursor ref = clang_getOverloadedDecl(cursor, i); job->handleReference(cursor, kind, loc, ref, parent); } break; } case CXCursor_CXXDeleteExpr: job->handleReference(cursor, kind, loc, findDestructorForDelete(cursor), parent); break; default: job->handleReference(cursor, kind, loc, clang_getCursorReferenced(cursor), parent); break; } break; case RTags::Other: assert(0); break; } return CXChildVisit_Recurse; }
static void PrintCursor(CXCursor Cursor) { if (clang_isInvalid(Cursor.kind)) { CXString ks = clang_getCursorKindSpelling(Cursor.kind); printf("Invalid Cursor => %s", clang_getCString(ks)); clang_disposeString(ks); } else { CXString string, ks; CXCursor Referenced; unsigned line, column; CXCursor SpecializationOf; ks = clang_getCursorKindSpelling(Cursor.kind); string = clang_getCursorSpelling(Cursor); printf("%s=%s", clang_getCString(ks), clang_getCString(string)); clang_disposeString(ks); clang_disposeString(string); Referenced = clang_getCursorReferenced(Cursor); if (!clang_equalCursors(Referenced, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(Referenced); clang_getInstantiationLocation(Loc, 0, &line, &column, 0); printf(":%d:%d", line, column); } if (clang_isCursorDefinition(Cursor)) printf(" (Definition)"); switch (clang_getCursorAvailability(Cursor)) { case CXAvailability_Available: break; case CXAvailability_Deprecated: printf(" (deprecated)"); break; case CXAvailability_NotAvailable: printf(" (unavailable)"); break; } if (Cursor.kind == CXCursor_IBOutletCollectionAttr) { CXType T = clang_getCanonicalType(clang_getIBOutletCollectionType(Cursor)); CXString S = clang_getTypeKindSpelling(T.kind); printf(" [IBOutletCollection=%s]", clang_getCString(S)); clang_disposeString(S); } if (Cursor.kind == CXCursor_CXXBaseSpecifier) { enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor); unsigned isVirtual = clang_isVirtualBase(Cursor); const char *accessStr = 0; switch (access) { case CX_CXXInvalidAccessSpecifier: accessStr = "invalid"; break; case CX_CXXPublic: accessStr = "public"; break; case CX_CXXProtected: accessStr = "protected"; break; case CX_CXXPrivate: accessStr = "private"; break; } printf(" [access=%s isVirtual=%s]", accessStr, isVirtual ? "true" : "false"); } SpecializationOf = clang_getSpecializedCursorTemplate(Cursor); if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf); CXString Name = clang_getCursorSpelling(SpecializationOf); clang_getInstantiationLocation(Loc, 0, &line, &column, 0); printf(" [Specialization of %s:%d:%d]", clang_getCString(Name), line, column); clang_disposeString(Name); } } }
void Html_File::write_token(FILE* f, CXFile file, CXToken tok, const char* str, unsigned line, unsigned column) { static bool preprocessor = false; static bool include = false; CXSourceLocation tloc = clang_getTokenLocation(tu_file_->tu(), tok); CXCursor c = clang_getCursor(tu_file_->tu(), tloc); if (cur_line_ <= line) cur_column_ = 1; for (; cur_line_ <= line; ++cur_line_) fprintf (f, "\n<a name=\"l%05i\"></a>%05i", cur_line_, cur_line_); for (; cur_column_ <= column; ++cur_column_) fprintf (f , " "); switch (clang_getTokenKind(tok)) { case (CXToken_Punctuation): if (str[0] == '#') preprocessor = true; fprintf(f, "%s", str); break; case (CXToken_Keyword): fprintf(f, "<span class=\"keyword\">%s</span>", str); break; case (CXToken_Comment): fprintf(f, "<span class=\"comment\">%s</span>", str); break; case (CXToken_Literal): { //include = false; // disable include links for now if (include) { include = false; // found an include file std::string t; const char* p = str; while (*p) { if (*p != '"') t += *p; ++p; } // first, use this file's path, then all the include paths bool found_include = false; char path[PATH_MAX]; std::string includefile = realpath(dirname(tu_file_->source_filename()), path); includefile += "/" + t; struct stat st; if (stat(includefile.c_str(), &st) == 0) { found_include = true; } else { for (std::vector<std::string>::const_iterator i = includes_.begin(), e = includes_.end(); i != e; ++i) { includefile = realpath((*i).c_str(), path); includefile += "/" + t; if (stat(includefile.c_str(), &st) == 0) { found_include = true; break; } } } if (found_include) { if (files_.find(includefile) != files_.end()) { t = make_filename(includefile, html_dir_, prefix_, ".html", false); fprintf(f, "<a class=\"code\" href=\"%s\" title="">%s</a>", t.c_str(), str); break; } std::map<std::string, Definition>::iterator i = defmap_.find(includefile); if (i != defmap_.end()) { t = i->second.file.c_str(); fprintf(f, "<a class=\"code\" href=\"%s\" title="">%s</a>", t.c_str(), str); break; } } } // not an include or include not found std::string s = fix(str); fprintf(f, "%s", s.c_str() ); break; } case (CXToken_Identifier): { if (preprocessor) { preprocessor = false; if (strcmp(str, "include") == 0) include = true; fprintf(f, "<span class=\"code\">%s</span>", str); break; } if (clang_isUnexposed(c.kind)) { fprintf(f, "<span class=\"code\">%s</span>", str); fprintf(f, "<!-- origin line: %i : %s : kind = %i -->", __LINE__, str, c.kind); break; } // Calling clang_getCursorDefinition() does not work properly // for template classes, i.e., it will find the method // declaration, not the definition, if they differ. However, // once you have the declaration's location, you can use it // get that cursor, and find the definition that way. CXSourceLocation decloc = clang_getCursorLocation(clang_getCursorDefinition(c)); CXCursor cref = clang_getCursorDefinition(clang_getCursor(tu_file_->tu(), decloc)); if (clang_isUnexposed(cref.kind)) { fprintf(f, "<span class=\"code\">%s</span>", str); fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); break; } std::string rfile; std::string html_dir; unsigned refl = line; bool found = false; if (!clang_Cursor_isNull(cref) && cref.kind != CXCursor_Namespace) { CXSourceLocation refloc = clang_getCursorLocation(cref); if (!clang_equalLocations(tloc, refloc)) { CXFile cxfile; unsigned col; unsigned off; clang_getExpansionLocation(refloc, &cxfile, &refl, &col, &off); if (cxfile == file) { found = true; fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); } else { CXString cxfn = clang_getFileName(cxfile); const char* fn = clang_getCString(cxfn); if (fn) { if (files_.find(fn) != files_.end()) { rfile = fn; found = true; fprintf(f, "<!-- origin line: %i : (ref) %s : kind = %i -->", __LINE__, str, cref.kind); } } clang_disposeString(cxfn); } } } else if (!clang_isDeclaration(c.kind) && c.kind != CXCursor_Namespace) { CXCursor ref = clang_getCursorReferenced(c); if (ref.kind != CXCursor_Namespace) { std::string fsn = munge_fullyscopedname(fullyScopedName(ref)); if (fsn.empty()) { fprintf(f, "<!-- origin line: %i : (fsn empty) %s : kind = %i -->", __LINE__, str, c.kind); } else { std::map<std::string, Definition>::iterator r = defmap_.find(fsn); if (r != defmap_.end()) { found = true; fprintf(f, "<!-- origin line: %i : %s : kind = %i -->", __LINE__, fsn.c_str(), c.kind); rfile = r->second.file.c_str(); html_dir = r->second.html_path.c_str(); refl = r->second.line; } } } } // since we are linking to lines, no need to link to same line if (found && (!rfile.empty() || refl != line)) { if (!rfile.empty()) rfile = make_filename(rfile, html_dir, prefix_, ".html", !html_dir.empty()); fprintf(f, "<a class=\"code\" href=\"%s#l%05i\" title="">%s</a>", rfile.c_str(), refl , str); break; } fprintf(f, "<span class=\"code\">%s</span>", str); break; } } cur_column_ += strlen(str); }
cursor cursor::getCursorReferenced() { return { clang_getCursorReferenced(cur) }; }
CXChildVisitResult ClangIndexer::indexVisitor(CXCursor cursor, CXCursor parent, CXClientData data) { ClangIndexer *indexer = static_cast<ClangIndexer*>(data); // error() << "indexVisitor" << cursor; // FILE *f = fopen("/tmp/clangindex.log", "a"); // String str; // Log(&str) << cursor; // fwrite(str.constData(), 1, str.size(), f); // fwrite("\n", 1, 1, f); // fclose(f); const LastCursorUpdater updater(indexer->mLastCursor, cursor); const CXCursorKind kind = clang_getCursorKind(cursor); const RTags::CursorType type = RTags::cursorType(kind); if (type == RTags::Other) return CXChildVisit_Recurse; bool blocked = false; Location loc = indexer->createLocation(cursor, &blocked); if (blocked) { // error() << "blocked" << cursor; ++indexer->mBlocked; return CXChildVisit_Continue; } else if (loc.isNull()) { // error() << "Got null" << cursor; return CXChildVisit_Recurse; } ++indexer->mAllowed; if (indexer->mLogFile) { String out; Log(&out) << cursor; fwrite(out.constData(), 1, out.size(), indexer->mLogFile); fwrite("\n", 1, 1, indexer->mLogFile); } if (testLog(VerboseDebug)) { Log log(VerboseDebug); log << cursor; CXCursor ref = clang_getCursorReferenced(cursor); if (!clang_isInvalid(clang_getCursorKind(ref)) && !clang_equalCursors(ref, cursor)) { log << "refs" << ref; } } switch (type) { case RTags::Cursor: indexer->handleCursor(cursor, kind, loc); break; case RTags::Include: indexer->handleInclude(cursor, kind, loc); break; case RTags::Reference: switch (kind) { case CXCursor_OverloadedDeclRef: { const int count = clang_getNumOverloadedDecls(cursor); for (int i=0; i<count; ++i) { const CXCursor ref = clang_getOverloadedDecl(cursor, i); indexer->handleReference(cursor, kind, loc, ref, parent); } break; } case CXCursor_CXXDeleteExpr: indexer->handleReference(cursor, kind, loc, findDestructorForDelete(cursor), parent); break; case CXCursor_CallExpr: { // uglehack, see rtags/tests/nestedClassConstructorCallUgleHack/ const CXCursor ref = clang_getCursorReferenced(cursor); if (clang_getCursorKind(ref) == CXCursor_Constructor && clang_getCursorKind(indexer->mLastCursor) == CXCursor_TypeRef && clang_getCursorKind(parent) != CXCursor_VarDecl) { loc = indexer->createLocation(indexer->mLastCursor); indexer->handleReference(indexer->mLastCursor, kind, loc, ref, parent); } else { indexer->handleReference(cursor, kind, loc, ref, parent); } break; } default: indexer->handleReference(cursor, kind, loc, clang_getCursorReferenced(cursor), parent); break; } break; case RTags::Other: assert(0); break; } return CXChildVisit_Recurse; }
// Desired functions: // Go to definition of variable/function // Go to declaration of function/class bool Tokenizer::findToken(eFindTokenTypes ft, size_t origOffset, std::string &fn, size_t &line) { CLangAutoLock lock(mCLangLock, __LINE__, this); CXCursor startCursor = getCursorAtOffset(mTransUnit, mSourceFile, origOffset); DUMP_PARSE("find:start cursor", startCursor); // Instantiating type - <class> <type> - CXCursor_TypeRef // Method declaration - <class> { <method>(); }; CXCursor_NoDeclFound // Method definition - <class>::<method>(){} - CXCursor_CXXMethod // Class/method usage - <class>.<method>() // Instance usage - method(){ int v = typename[4]; } - CXCursor_DeclStmt // clang_getCursorSemanticParent returns method // clang_getCursorDefinition returns invalid if(startCursor.kind == CXCursor_InclusionDirective) { CXFile file = clang_getIncludedFile(startCursor); if(file) { fn = getDisposedString(clang_getFileName(file)); line = 1; } else { /// @todo - need to get the full path. // CXStringDisposer cfn = clang_getCursorSpelling(cursor); // fn = cfn; line = 1; } } else { CXCursor cursor = startCursor; switch(ft) { case FT_FindDecl: cursor = clang_getCursorReferenced(startCursor); DUMP_PARSE("find:decl", cursor); break; case FT_FindDef: // If instantiating a type (CXCursor_TypeRef), this goes to the type declaration. cursor = clang_getCursorDefinition(startCursor); // Method call can return invalid file when the definition is not in this // translation unit. if(clang_getCursorKind(cursor) == CXCursor_InvalidFile) { DUMP_PARSE("find:def-invalid", cursor); cursor = clang_getCursorReferenced(startCursor); } DUMP_PARSE("find:def", cursor); // cursor = clang_getCursor(mTransUnit, clang_getCursorLocation(cursor)); // cursor = clang_getCursorDefinition(cursor); break; // cursor = clang_getCursorReferenced(cursor); // cursor = clang_getCanonicalCursor(cursor); // cursor = clang_getCursorSemanticParent(cursor); // cursor = clang_getCursorLexicalParent(cursor); } if(!clang_Cursor_isNull(cursor)) { CXSourceLocation loc = clang_getCursorLocation(cursor); CXFile file; unsigned int uline; clang_getFileLocation(loc, &file, &uline, nullptr, nullptr); if(file) { line = uline; fn = getDisposedString(clang_getFileName(file)); } } } return(fn.size() > 0); }