/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt for Python. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "clangutils.h" #include #include #include #include bool operator==(const CXCursor &c1, const CXCursor &c2) { return c1.kind == c2.kind && c1.xdata == c2.xdata && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data); } uint qHash(const CXCursor &c, uint seed) { return qHash(c.kind) ^ qHash(c.xdata) ^ qHash(c.data[0]) ^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed; } namespace clang { SourceLocation getExpansionLocation(const CXSourceLocation &location) { SourceLocation result; CXFile file; // void * clang_getExpansionLocation(location, &file, &result.line, &result.column, &result.offset); const CXString cxFileName = clang_getFileName(file); // Has been observed to be 0 for invalid locations if (const char *cFileName = clang_getCString(cxFileName)) result.file = QString::fromUtf8(cFileName); clang_disposeString(cxFileName); return result; } SourceLocation getCursorLocation(const CXCursor &cursor) { const CXSourceRange extent = clang_getCursorExtent(cursor); return getExpansionLocation(clang_getRangeStart(extent)); } CXString getFileNameFromLocation(const CXSourceLocation &location) { CXFile file; unsigned line; unsigned column; unsigned offset; clang_getExpansionLocation(location, &file, &line, &column, &offset); return clang_getFileName(file); } SourceRange getCursorRange(const CXCursor &cursor) { const CXSourceRange extent = clang_getCursorExtent(cursor); return qMakePair(getExpansionLocation(clang_getRangeStart(extent)), getExpansionLocation(clang_getRangeEnd(extent))); } QString getCursorKindName(CXCursorKind cursorKind) { CXString kindName = clang_getCursorKindSpelling(cursorKind); const QString result = QString::fromUtf8(clang_getCString(kindName)); clang_disposeString(kindName); return result; } QString getCursorSpelling(const CXCursor &cursor) { CXString cursorSpelling = clang_getCursorSpelling(cursor); const QString result = QString::fromUtf8(clang_getCString(cursorSpelling)); clang_disposeString(cursorSpelling); return result; } QString getCursorDisplayName(const CXCursor &cursor) { CXString displayName = clang_getCursorDisplayName(cursor); const QString result = QString::fromUtf8(clang_getCString(displayName)); clang_disposeString(displayName); return result; } QString getTypeName(const CXType &type) { CXString typeSpelling = clang_getTypeSpelling(type); const QString result = QString::fromUtf8(clang_getCString(typeSpelling)); clang_disposeString(typeSpelling); return result; } Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s) : message(m), location(getCursorLocation(c)), source(Other), severity(s) { } Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd) { Diagnostic result; result.source = Clang; CXString spelling = clang_getDiagnosticSpelling(cd); result.message = QString::fromUtf8(clang_getCString(spelling)); clang_disposeString(spelling); result.severity = clang_getDiagnosticSeverity(cd); result.location = getExpansionLocation(clang_getDiagnosticLocation(cd)); CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd); if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) { result.childMessages.reserve(int(childCount)); const unsigned format = clang_defaultDiagnosticDisplayOptions(); for (unsigned i = 0; i < childCount; ++i) { CXDiagnostic childDiagnostic = clang_getDiagnosticInSet(childDiagnostics, i); CXString cdm = clang_formatDiagnostic(childDiagnostic, format); result.childMessages.append(QString::fromUtf8(clang_getCString(cdm))); clang_disposeString(cdm); clang_disposeDiagnostic(childDiagnostic); } } return result; } QVector getDiagnostics(CXTranslationUnit tu) { QVector result; const unsigned count = clang_getNumDiagnostics(tu); result.reserve(int(count)); for (unsigned i = 0; i < count; ++i) { const CXDiagnostic d = clang_getDiagnostic(tu, i); result.append(Diagnostic::fromCXDiagnostic(d)); clang_disposeDiagnostic(d); } return result; } CXDiagnosticSeverity maxSeverity(const QVector &ds) { CXDiagnosticSeverity result = CXDiagnostic_Ignored; for (const Diagnostic& d : ds) { if (d.severity > result) result = d.severity; } return result; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug s, const SourceLocation &l) { QDebugStateSaver saver(s); s.nospace(); s.noquote(); s << QDir::toNativeSeparators(l.file) << ':' << l.line; if (l.column) s << ':' << l.column; return s; } // Roughly follow g++ format: // file.cpp:214:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] QDebug operator<<(QDebug s, const Diagnostic &d) { QDebugStateSaver saver(s); s.nospace(); s.noquote(); s << d.location << ": "; switch (d.severity) { case CXDiagnostic_Ignored: s << "ignored"; break; case CXDiagnostic_Note: s << "note"; break; case CXDiagnostic_Warning: s << "warning"; break; case CXDiagnostic_Error: s << "error"; break; case CXDiagnostic_Fatal: s << "fatal"; break; } s << ": " << d.message; if (d.source != Diagnostic::Clang) s << " [other]"; if (const int childMessagesCount = d.childMessages.size()) { s << '\n'; for (int i = 0; i < childMessagesCount; ++i) s << " " << d.childMessages.at(i) << '\n'; } return s; } #endif // QT_NO_DEBUG_STREAM } // namespace clang