// Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "clangdebugutils.h" #include "clangutils.h" #include #include #ifndef QT_NO_DEBUG_STREAM #ifdef Q_OS_WIN const char pathSep = '\\'; #else const char pathSep = '/'; #endif static const char *baseName(const char *fileName) { const char *b = std::strrchr(fileName, pathSep); return b ? b + 1 : fileName; } QDebug operator<<(QDebug s, const CXString &cs) { s << clang_getCString(cs); return s; } QDebug operator<<(QDebug s, CXCursorKind cursorKind) // Enum { const CXString kindName = clang_getCursorKindSpelling(cursorKind); s << kindName; clang_disposeString(kindName); return s; } static const char *accessSpecsStrings[] { // CX_CXXInvalidAccessSpecifier, CX_CXXPublic, CX_CXXProtected, CX_CXXPrivate "invalid", "public", "protected", "private" }; QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac) { s << accessSpecsStrings[ac]; return s; } struct formatCXTypeName { explicit formatCXTypeName(const CXType &type) : m_type(type) {} const CXType &m_type; }; QDebug operator<<(QDebug debug, const formatCXTypeName &ft) { CXString typeSpelling = clang_getTypeSpelling(ft.m_type); debug << typeSpelling; clang_disposeString(typeSpelling); return debug; } QDebug operator<<(QDebug debug, const CXType &type) { QDebugStateSaver saver(debug); debug.nospace(); debug.noquote(); debug << "CXType("; if (type.kind == CXType_Invalid) { debug << "invalid)"; return debug; } debug << type.kind; switch (type.kind) { case CXType_Unexposed: debug << " [unexposed]"; break; case CXType_Elaborated: debug << " [elaborated]"; break; default: break; } debug << ", " << formatCXTypeName(type) << ')'; return debug; } QDebug operator<<(QDebug debug, const CXCursor &cursor) { QDebugStateSaver saver(debug); debug.nospace(); debug.noquote(); const CXCursorKind kind = clang_getCursorKind(cursor); debug << "CXCursor("; if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid) { debug << "invalid)"; return debug; } const QString cursorSpelling = clang::getCursorSpelling(cursor); debug << '"' << cursorSpelling << '"'; CXString cursorDisplay = clang_getCursorDisplayName(cursor); if (const char *dpy = clang_getCString(cursorDisplay)) { const QString display = QString::fromUtf8(dpy); if (display != cursorSpelling) debug << ", display=\"" << dpy << '"'; } clang_disposeString(cursorDisplay); debug << ", kind=" << kind; const CXType type = clang_getCursorType(cursor); switch (kind) { case CXCursor_CXXAccessSpecifier: debug << ", " << clang_getCXXAccessSpecifier(cursor); break; case CXCursor_CXXBaseSpecifier: debug << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"'; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_ConversionFunction: debug << ", result type=\"" << formatCXTypeName(clang_getCursorResultType(cursor)) << '"'; break; case CXCursor_TypedefDecl: debug << ", underlyingType=\"" << formatCXTypeName(clang_getTypedefDeclUnderlyingType(cursor)) << '"'; break; default: break; } debug << ", type=\"" << formatCXTypeName(type) << '"'; if (clang_Cursor_hasAttrs(cursor)) debug << ", [attrs]"; debug << ')'; return debug; } QDebug operator<<(QDebug s, const CXSourceLocation &location) { QDebugStateSaver saver(s); s.nospace(); CXFile file{}; // void * unsigned line{}; unsigned column{}; unsigned offset{}; clang_getExpansionLocation(location, &file, &line, &column, &offset); const CXString cxFileName = clang_getFileName(file); // Has been observed to be 0 for invalid locations if (const char *cFileName = clang_getCString(cxFileName)) s << baseName(cFileName) << ':'; s << line << ':' << column; clang_disposeString(cxFileName); return s; } QDebug operator<<(QDebug s, const std::string_view &v) { QDebugStateSaver saver(s); s.nospace(); s.noquote(); s << '"'; for (auto c : v) s << c; s << '"'; return s; } #endif // !QT_NO_DEBUG_STREAM