ClangTools: Utilize TaskTree to parse diagnostics from file

This reduces the time the main thread is blocked for reading the diagnostics
from the result file.

Change-Id: If6cc5671c709cb519b651c2b7ce3e8067e0b5f39
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
David Schulz
2023-06-16 12:40:20 +02:00
parent d30689c9a9
commit 8b16e40858
4 changed files with 54 additions and 31 deletions

View File

@@ -242,26 +242,15 @@ void ClangToolRunWorker::onDone(const AnalyzeOutputData &output)
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << output.outputFilePath; qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << output.outputFilePath;
QString errorMessage; const Diagnostics diagnostics = output.diagnostics;
const Diagnostics diagnostics = m_tool->read(output.outputFilePath, m_projectFiles,
&errorMessage);
if (!errorMessage.isEmpty()) { if (!m_filesNotAnalyzed.contains(output.fileToAnalyze))
m_filesAnalyzed.remove(output.fileToAnalyze); m_filesAnalyzed.insert(output.fileToAnalyze);
m_filesNotAnalyzed.insert(output.fileToAnalyze); if (!diagnostics.isEmpty()) {
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage; // do not generate marks when we always analyze open files since marks from that
appendMessage(Tr::tr("Failed to analyze \"%1\": %2") // analysis should be more up to date
.arg(output.fileToAnalyze.toUserOutput(), errorMessage), const bool generateMarks = !m_runSettings.analyzeOpenFiles();
Utils::StdErrFormat); m_tool->onNewDiagnosticsAvailable(diagnostics, generateMarks);
} else {
if (!m_filesNotAnalyzed.contains(output.fileToAnalyze))
m_filesAnalyzed.insert(output.fileToAnalyze);
if (!diagnostics.isEmpty()) {
// do not generate marks when we always analyze open files since marks from that
// analysis should be more up to date
const bool generateMarks = !m_runSettings.analyzeOpenFiles();
m_tool->onNewDiagnosticsAvailable(diagnostics, generateMarks);
}
} }
} }

View File

@@ -3,6 +3,7 @@
#include "clangtoolrunner.h" #include "clangtoolrunner.h"
#include "clangtoolslogfilereader.h"
#include "clangtoolstr.h" #include "clangtoolstr.h"
#include "clangtoolsutils.h" #include "clangtoolsutils.h"
@@ -11,6 +12,9 @@
#include <cppeditor/clangdiagnosticconfigsmodel.h> #include <cppeditor/clangdiagnosticconfigsmodel.h>
#include <cppeditor/cpptoolsreuse.h> #include <cppeditor/cpptoolsreuse.h>
#include <extensionsystem/pluginmanager.h>
#include <utils/async.h>
#include <utils/process.h> #include <utils/process.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/temporaryfile.h> #include <utils/temporaryfile.h>
@@ -20,6 +24,7 @@
#include <QFileInfo> #include <QFileInfo>
#include <QLoggingCategory> #include <QLoggingCategory>
static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runner", QtWarningMsg) static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runner", QtWarningMsg)
using namespace CppEditor; using namespace CppEditor;
@@ -109,6 +114,7 @@ GroupItem clangToolTask(const AnalyzeInputData &input,
QString name; QString name;
FilePath executable; FilePath executable;
FilePath outputFilePath; FilePath outputFilePath;
QString errorMessage;
}; };
const TreeStorage<ClangToolStorage> storage; const TreeStorage<ClangToolStorage> storage;
@@ -160,9 +166,6 @@ GroupItem clangToolTask(const AnalyzeInputData &input,
}; };
const auto onProcessDone = [=](const Process &process) { const auto onProcessDone = [=](const Process &process) {
qCDebug(LOG).noquote() << "Output:\n" << process.cleanedStdOut(); qCDebug(LOG).noquote() << "Output:\n" << process.cleanedStdOut();
if (!outputHandler)
return;
outputHandler({true, input.unit.file, storage->outputFilePath, input.tool});
}; };
const auto onProcessError = [=](const Process &process) { const auto onProcessError = [=](const Process &process) {
if (!outputHandler) if (!outputHandler)
@@ -179,15 +182,38 @@ GroupItem clangToolTask(const AnalyzeInputData &input,
message = Tr::tr("%1 finished with exit code: %2.").arg(data.name).arg(process.exitCode()); message = Tr::tr("%1 finished with exit code: %2.").arg(data.name).arg(process.exitCode());
else else
message = Tr::tr("%1 crashed.").arg(data.name); message = Tr::tr("%1 crashed.").arg(data.name);
outputHandler({false, input.unit.file, data.outputFilePath, input.tool, message, details}); outputHandler(
{false, input.unit.file, data.outputFilePath, {}, input.tool, message, details});
};
const auto onReadSetup = [=](Async<Diagnostics> &data) {
data.setConcurrentCallData(&readExportedDiagnostics,
storage->outputFilePath,
input.diagnosticsFilter,
&storage->errorMessage);
data.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
};
const auto onReadDone = [=](const Async<Diagnostics> &data) {
if (!outputHandler)
return;
outputHandler(
{true, input.unit.file, storage->outputFilePath, data.result(), input.tool});
};
const auto onReadError = [=](const Async<Diagnostics> &) {
if (!outputHandler)
return;
outputHandler(
{false, input.unit.file, storage->outputFilePath, {}, input.tool, storage->errorMessage});
}; };
const Group group { const Group group {
Storage(storage), Storage(storage),
onGroupSetup(onSetup), onGroupSetup(onSetup),
Group { Group {
sequential,
finishAllAndDone, finishAllAndDone,
ProcessTask(onProcessSetup, onProcessDone, onProcessError) ProcessTask(onProcessSetup, onProcessDone, onProcessError),
AsyncTask<Diagnostics>(onReadSetup, onReadDone, onReadError)
} }
}; };
return group; return group;

View File

@@ -4,6 +4,8 @@
#pragma once #pragma once
#include "clangfileinfo.h" #include "clangfileinfo.h"
#include "clangtoolsdiagnostic.h"
#include "clangtoolslogfilereader.h"
#include "clangtoolssettings.h" #include "clangtoolssettings.h"
#include <cppeditor/clangdiagnosticconfig.h> #include <cppeditor/clangdiagnosticconfig.h>
@@ -35,6 +37,7 @@ struct AnalyzeInputData
Utils::Environment environment; Utils::Environment environment;
AnalyzeUnit unit; AnalyzeUnit unit;
QString overlayFilePath = {}; QString overlayFilePath = {};
AcceptDiagsFromFilePath diagnosticsFilter = {};
}; };
struct AnalyzeOutputData struct AnalyzeOutputData
@@ -42,6 +45,7 @@ struct AnalyzeOutputData
bool success = true; bool success = true;
Utils::FilePath fileToAnalyze; Utils::FilePath fileToAnalyze;
Utils::FilePath outputFilePath; Utils::FilePath outputFilePath;
Diagnostics diagnostics;
CppEditor::ClangToolType toolType; CppEditor::ClangToolType toolType;
QString errorMessage = {}; QString errorMessage = {};
QString errorDetails = {}; QString errorDetails = {};

View File

@@ -201,8 +201,16 @@ void DocumentClangToolRunner::run()
if (includeDir.isEmpty() || clangVersion.isEmpty()) if (includeDir.isEmpty() || clangVersion.isEmpty())
return; return;
const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion); const AnalyzeUnit unit(m_fileInfo, includeDir, clangVersion);
const AnalyzeInputData input{tool, runSettings, config, m_temporaryDir.path(), env, unit, auto diagnosticFilter = [mappedPath = vfso().autoSavedFilePath(m_document)](
vfso().overlayFilePath().toString()}; const FilePath &path) { return path == mappedPath; };
const AnalyzeInputData input{tool,
runSettings,
config,
m_temporaryDir.path(),
env,
unit,
vfso().overlayFilePath().toString(),
diagnosticFilter};
const auto setupHandler = [this, executable] { const auto setupHandler = [this, executable] {
return !m_document->isModified() || isVFSOverlaySupported(executable); return !m_document->isModified() || isVFSOverlaySupported(executable);
}; };
@@ -234,11 +242,7 @@ void DocumentClangToolRunner::onDone(const AnalyzeOutputData &output)
return; return;
} }
const FilePath mappedPath = vfso().autoSavedFilePath(m_document); Diagnostics diagnostics = output.diagnostics;
Diagnostics diagnostics = readExportedDiagnostics(
output.outputFilePath,
[&](const FilePath &path) { return path == mappedPath; });
for (Diagnostic &diag : diagnostics) { for (Diagnostic &diag : diagnostics) {
updateLocation(diag.location); updateLocation(diag.location);
for (ExplainingStep &explainingStep : diag.explainingSteps) { for (ExplainingStep &explainingStep : diag.explainingSteps) {