aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/clangtools/clangtoolslogfilereader.cpp
diff options
context:
space:
mode:
authorIvan Donchevskii <[email protected]>2018-01-17 15:08:30 +0100
committerIvan Donchevskii <[email protected]>2018-04-26 13:02:19 +0000
commit219e23332e5e21d3e4e1a9334bf3f5ef1d485b59 (patch)
tree2bfb49a89116180d3896503273e523b53bb989c7 /src/plugins/clangtools/clangtoolslogfilereader.cpp
parent4ec4f111cb3ce038a114769300647ee66875d658 (diff)
ClangTools: Add tool that runs clang-tidy and clazy
... over the whole project. Generate and read serialized files to get diagnostics. Change-Id: Iafc25fc70443107a040a995efc038aed35102bbf Reviewed-by: Nikolai Kosjar <[email protected]>
Diffstat (limited to 'src/plugins/clangtools/clangtoolslogfilereader.cpp')
-rw-r--r--src/plugins/clangtools/clangtoolslogfilereader.cpp173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/plugins/clangtools/clangtoolslogfilereader.cpp b/src/plugins/clangtools/clangtoolslogfilereader.cpp
index 22e4b6f1610..23bda8a8d5f 100644
--- a/src/plugins/clangtools/clangtoolslogfilereader.cpp
+++ b/src/plugins/clangtools/clangtoolslogfilereader.cpp
@@ -33,8 +33,13 @@
#include <QRegularExpression>
#include <QXmlStreamReader>
+#include <utils/executeondestruction.h>
+#include <utils/fileutils.h>
+#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
+#include <clang-c/Index.h>
+
namespace ClangTools {
namespace Internal {
@@ -74,6 +79,12 @@ private:
QList<Diagnostic> m_diagnostics;
};
+class ClangSerializedDiagnosticsReader
+{
+public:
+ QList<Diagnostic> read(const QString &filePath, const QString &logFilePath);
+};
+
static bool checkFilePath(const QString &filePath, QString *errorMessage)
{
QFileInfo fi(filePath);
@@ -133,6 +144,16 @@ QList<Diagnostic> LogFileReader::readPlist(const QString &filePath, QString *err
}
}
+QList<Diagnostic> LogFileReader::readSerialized(const QString &filePath, const QString &logFilePath,
+ QString *errorMessage)
+{
+ if (!checkFilePath(filePath, errorMessage))
+ return QList<Diagnostic>();
+
+ ClangSerializedDiagnosticsReader reader;
+ return reader.read(filePath, logFilePath);
+}
+
ClangStaticAnalyzerLogFileReader::ClangStaticAnalyzerLogFileReader(const QString &filePath)
: m_filePath(filePath)
{
@@ -390,5 +411,157 @@ int ClangStaticAnalyzerLogFileReader::readInteger(bool *convertedSuccessfully)
return -1;
}
+static QString fromCXString(CXString &&cxString)
+{
+ QString result = QString::fromUtf8(clang_getCString(cxString));
+ clang_disposeString(cxString);
+ return result;
+}
+
+static Debugger::DiagnosticLocation diagLocationFromSourceLocation(CXSourceLocation cxLocation)
+{
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ clang_getSpellingLocation(cxLocation, &file, &line, &column, nullptr);
+
+ Debugger::DiagnosticLocation location;
+ location.filePath = fromCXString(clang_getFileName(file));
+ location.line = line;
+ location.column = column;
+ return location;
+}
+
+static QString cxDiagnosticType(const CXDiagnostic cxDiagnostic)
+{
+ const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(cxDiagnostic);
+ switch (severity) {
+ case CXDiagnostic_Note:
+ return QString("note");
+ case CXDiagnostic_Warning:
+ return QString("warning");
+ case CXDiagnostic_Error:
+ return QString("error");
+ case CXDiagnostic_Fatal:
+ return QString("fatal");
+ case CXDiagnostic_Ignored:
+ return QString("ignored");
+ }
+ return QString("ignored");
+}
+
+static ExplainingStep buildChildDiagnostic(const CXDiagnostic cxDiagnostic)
+{
+ ExplainingStep diagnosticStep;
+ QString type = cxDiagnosticType(cxDiagnostic);
+ if (type == QStringLiteral("ignored"))
+ return diagnosticStep;
+
+ const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
+ diagnosticStep.location = diagLocationFromSourceLocation(cxLocation);
+ diagnosticStep.message = type + ": " + fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
+ return diagnosticStep;
+}
+
+static bool isInvalidDiagnosticLocation(const Diagnostic &diagnostic, const ExplainingStep &child,
+ const QString &nativeFilePath)
+{
+ // When main file is considered included by itself - this diagnostic has invalid location.
+ // This case usually happens when original diagnostic comes from system header but
+ // has main file name set in the source location instead (which is incorrect).
+ return child.message.indexOf(nativeFilePath) >= 0
+ && child.message.indexOf("in file included from") >= 0
+ && diagnostic.location.filePath == nativeFilePath;
+}
+
+static ExplainingStep buildFixIt(const CXDiagnostic cxDiagnostic, unsigned index)
+{
+ ExplainingStep fixItStep;
+ CXSourceRange cxFixItRange;
+ fixItStep.message = "fix-it: " + fromCXString(clang_getDiagnosticFixIt(cxDiagnostic, index,
+ &cxFixItRange));
+ fixItStep.location = diagLocationFromSourceLocation(clang_getRangeStart(cxFixItRange));
+ fixItStep.ranges.push_back(fixItStep.location);
+ fixItStep.ranges.push_back(diagLocationFromSourceLocation(clang_getRangeEnd(cxFixItRange)));
+ return fixItStep;
+}
+
+static Diagnostic buildDiagnostic(const CXDiagnostic cxDiagnostic, const QString &nativeFilePath)
+{
+ Diagnostic diagnostic;
+ diagnostic.type = cxDiagnosticType(cxDiagnostic);
+ if (diagnostic.type == QStringLiteral("ignored"))
+ return diagnostic;
+
+ const CXSourceLocation cxLocation = clang_getDiagnosticLocation(cxDiagnostic);
+ if (clang_Location_isInSystemHeader(cxLocation))
+ return diagnostic;
+
+ diagnostic.location = diagLocationFromSourceLocation(cxLocation);
+ if (diagnostic.location.filePath != nativeFilePath)
+ return diagnostic;
+
+ CXDiagnosticSet cxChildDiagnostics = clang_getChildDiagnostics(cxDiagnostic);
+ Utils::ExecuteOnDestruction onBuildExit([&]() {
+ clang_disposeDiagnosticSet(cxChildDiagnostics);
+ });
+
+ for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(cxChildDiagnostics); ++i) {
+ CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(cxChildDiagnostics, i);
+ Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
+ clang_disposeDiagnostic(cxDiagnostic);
+ });
+ const ExplainingStep diagnosticStep = buildChildDiagnostic(cxDiagnostic);
+ if (diagnosticStep.isValid())
+ continue;
+
+ if (isInvalidDiagnosticLocation(diagnostic, diagnosticStep, nativeFilePath))
+ return diagnostic;
+
+ diagnostic.explainingSteps.push_back(diagnosticStep);
+ }
+
+ for (unsigned i = 0; i < clang_getDiagnosticNumFixIts(cxDiagnostic); ++i)
+ diagnostic.explainingSteps.push_back(buildFixIt(cxDiagnostic, i));
+
+ diagnostic.description = fromCXString(clang_getDiagnosticSpelling(cxDiagnostic));
+ diagnostic.category = fromCXString(clang_getDiagnosticCategoryText(cxDiagnostic));
+
+ return diagnostic;
+}
+
+QList<Diagnostic> ClangSerializedDiagnosticsReader::read(const QString &filePath,
+ const QString &logFilePath)
+{
+ QList<Diagnostic> list;
+ CXLoadDiag_Error error;
+ CXString errorString;
+
+ CXDiagnosticSet diagnostics = clang_loadDiagnostics(logFilePath.toStdString().c_str(),
+ &error,
+ &errorString);
+ if (error != CXLoadDiag_None || !diagnostics)
+ return list;
+
+ Utils::ExecuteOnDestruction onReadExit([&]() {
+ clang_disposeDiagnosticSet(diagnostics);
+ });
+
+ const QString nativeFilePath = QDir::toNativeSeparators(filePath);
+ for (unsigned i = 0; i < clang_getNumDiagnosticsInSet(diagnostics); ++i) {
+ CXDiagnostic cxDiagnostic = clang_getDiagnosticInSet(diagnostics, i);
+ Utils::ExecuteOnDestruction cleanUpDiagnostic([&]() {
+ clang_disposeDiagnostic(cxDiagnostic);
+ });
+ const Diagnostic diagnostic = buildDiagnostic(cxDiagnostic, nativeFilePath);
+ if (!diagnostic.isValid())
+ continue;
+
+ list.push_back(diagnostic);
+ }
+
+ return list;
+}
+
} // namespace Internal
} // namespace ClangTools