2018-01-17 15:08:30 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator.
|
|
|
|
|
**
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "clangtoolruncontrol.h"
|
|
|
|
|
|
|
|
|
|
#include "clangtool.h"
|
|
|
|
|
#include "clangtoolslogfilereader.h"
|
2018-05-30 13:31:39 +02:00
|
|
|
#include "clangtoolsprojectsettings.h"
|
2018-01-17 15:08:30 +01:00
|
|
|
#include "clangtoolssettings.h"
|
|
|
|
|
#include "clangtoolsutils.h"
|
|
|
|
|
#include "clangtoolrunner.h"
|
|
|
|
|
|
|
|
|
|
#include <debugger/analyzer/analyzerconstants.h>
|
|
|
|
|
|
|
|
|
|
#include <clangcodemodel/clangutils.h>
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/progressmanager/futureprogress.h>
|
|
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
|
|
|
|
|
|
|
|
|
#include <cpptools/compileroptionsbuilder.h>
|
|
|
|
|
#include <cpptools/cppmodelmanager.h>
|
|
|
|
|
#include <cpptools/cppprojectfile.h>
|
|
|
|
|
#include <cpptools/cpptoolsreuse.h>
|
|
|
|
|
#include <cpptools/projectinfo.h>
|
|
|
|
|
|
|
|
|
|
#include <projectexplorer/abi.h>
|
|
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
|
|
|
|
#include <projectexplorer/buildmanager.h>
|
|
|
|
|
#include <projectexplorer/kitinformation.h>
|
|
|
|
|
#include <projectexplorer/project.h>
|
|
|
|
|
#include <projectexplorer/projectexplorer.h>
|
|
|
|
|
#include <projectexplorer/projectexplorericons.h>
|
|
|
|
|
#include <projectexplorer/runconfiguration.h>
|
|
|
|
|
#include <projectexplorer/target.h>
|
|
|
|
|
#include <projectexplorer/taskhub.h>
|
|
|
|
|
#include <projectexplorer/toolchain.h>
|
|
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
|
|
|
|
#include <utils/checkablemessagebox.h>
|
|
|
|
|
#include <utils/hostosinfo.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
|
|
|
|
|
|
|
|
|
#include <QAction>
|
|
|
|
|
#include <QLoggingCategory>
|
|
|
|
|
|
|
|
|
|
using namespace CppTools;
|
|
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
2018-10-12 09:33:30 +03:00
|
|
|
static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.runcontrol", QtWarningMsg)
|
2018-01-17 15:08:30 +01:00
|
|
|
|
|
|
|
|
static QStringList splitArgs(QString &argsString)
|
|
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
Utils::QtcProcess::ArgIterator it(&argsString);
|
|
|
|
|
while (it.next())
|
|
|
|
|
result.append(it.value());
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 08:30:33 +02:00
|
|
|
static QStringList extraOptions(const char *environment)
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
|
|
|
|
if (!qEnvironmentVariableIsSet(environment))
|
|
|
|
|
return QStringList();
|
|
|
|
|
QString arguments = QString::fromLocal8Bit(qgetenv(environment));
|
|
|
|
|
return splitArgs(arguments);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 08:30:33 +02:00
|
|
|
static QStringList extraClangToolsPrependOptions()
|
|
|
|
|
{
|
2018-01-17 15:08:30 +01:00
|
|
|
constexpr char csaPrependOptions[] = "QTC_CLANG_CSA_CMD_PREPEND";
|
|
|
|
|
constexpr char toolsPrependOptions[] = "QTC_CLANG_TOOLS_CMD_PREPEND";
|
|
|
|
|
static const QStringList options = extraOptions(csaPrependOptions)
|
|
|
|
|
+ extraOptions(toolsPrependOptions);
|
|
|
|
|
if (!options.isEmpty())
|
|
|
|
|
qWarning() << "ClangTools options are prepended with " << options.toVector();
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-12 08:30:33 +02:00
|
|
|
static QStringList extraClangToolsAppendOptions()
|
|
|
|
|
{
|
2018-01-17 15:08:30 +01:00
|
|
|
constexpr char csaAppendOptions[] = "QTC_CLANG_CSA_CMD_APPEND";
|
|
|
|
|
constexpr char toolsAppendOptions[] = "QTC_CLANG_TOOLS_CMD_APPEND";
|
|
|
|
|
static const QStringList options = extraOptions(csaAppendOptions)
|
|
|
|
|
+ extraOptions(toolsAppendOptions);
|
|
|
|
|
if (!options.isEmpty())
|
|
|
|
|
qWarning() << "ClangTools options are appended with " << options.toVector();
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace ClangTools {
|
|
|
|
|
namespace Internal {
|
|
|
|
|
|
2018-05-02 16:13:01 +02:00
|
|
|
class ProjectBuilder : public RunWorker
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ProjectBuilder(RunControl *runControl, Project *project, ClangToolRunControl *parent)
|
|
|
|
|
: RunWorker(runControl), m_project(project), m_parent(parent)
|
|
|
|
|
{
|
2018-08-21 08:28:27 +02:00
|
|
|
setId("ProjectBuilder");
|
2018-05-02 16:13:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setEnabled(bool enabled) { m_enabled = enabled; }
|
|
|
|
|
|
|
|
|
|
bool success() const { return m_success; }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void start() final
|
|
|
|
|
{
|
|
|
|
|
if (!m_enabled) {
|
|
|
|
|
ProjectExplorerPlugin::saveModifiedFiles();
|
|
|
|
|
onBuildFinished(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Target *target = m_project->activeTarget();
|
|
|
|
|
QTC_ASSERT(target, reportFailure(); return);
|
|
|
|
|
|
|
|
|
|
BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
|
|
|
|
|
if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
|
|
|
|
|
buildType = buildConfig->buildType();
|
|
|
|
|
|
|
|
|
|
if (buildType == BuildConfiguration::Release) {
|
|
|
|
|
const QString wrongMode = ClangToolRunControl::tr("Release");
|
|
|
|
|
const QString toolName = m_parent->tool()->name();
|
2018-07-19 15:02:54 +02:00
|
|
|
const QString title = ClangToolRunControl::tr("Run %1 in %2 Mode?").arg(toolName, wrongMode);
|
|
|
|
|
const QString problem = ClangToolRunControl::tr(
|
|
|
|
|
"You are trying to run the tool \"%1\" on an application in %2 mode. The tool is "
|
2018-05-02 16:13:01 +02:00
|
|
|
"designed to be used in Debug mode since enabled assertions can reduce the number of "
|
2018-07-19 15:02:54 +02:00
|
|
|
"false positives.").arg(toolName, wrongMode);
|
|
|
|
|
const QString question = ClangToolRunControl::tr(
|
|
|
|
|
"Do you want to continue and run the tool in %1 mode?").arg(wrongMode);
|
|
|
|
|
const QString message = QString("<html><head/><body>"
|
|
|
|
|
"<p>%1</p>"
|
|
|
|
|
"<p>%2</p>"
|
|
|
|
|
"</body></html>").arg(problem, question);
|
2018-05-02 16:13:01 +02:00
|
|
|
if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::mainWindow(),
|
|
|
|
|
title, message, Core::ICore::settings(),
|
2018-05-09 09:22:01 +02:00
|
|
|
"ClangToolsCorrectModeWarning") != QDialogButtonBox::Yes)
|
2018-05-02 16:13:01 +02:00
|
|
|
{
|
|
|
|
|
reportFailure();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect(BuildManager::instance(), &BuildManager::buildQueueFinished,
|
|
|
|
|
this, &ProjectBuilder::onBuildFinished, Qt::QueuedConnection);
|
|
|
|
|
|
|
|
|
|
ProjectExplorerPlugin::buildProject(m_project);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void onBuildFinished(bool success)
|
|
|
|
|
{
|
|
|
|
|
disconnect(BuildManager::instance(), &BuildManager::buildQueueFinished,
|
|
|
|
|
this, &ProjectBuilder::onBuildFinished);
|
|
|
|
|
m_success = success;
|
|
|
|
|
reportDone();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QPointer<Project> m_project;
|
|
|
|
|
ClangToolRunControl *m_parent;
|
|
|
|
|
bool m_enabled = true;
|
|
|
|
|
bool m_success = false;
|
|
|
|
|
};
|
|
|
|
|
|
2018-08-07 15:21:20 +02:00
|
|
|
static AnalyzeUnits toAnalyzeUnits(const FileInfos &fileInfos)
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
|
|
|
|
AnalyzeUnits unitsToAnalyze;
|
2018-11-30 10:34:05 +01:00
|
|
|
const UsePrecompiledHeaders usePrecompiledHeaders = CppTools::getPchUsage();
|
2018-05-02 14:51:05 +02:00
|
|
|
for (const FileInfo &fileInfo : fileInfos) {
|
2018-08-23 15:45:33 +02:00
|
|
|
CompilerOptionsBuilder optionsBuilder(*fileInfo.projectPart,
|
2018-11-30 11:02:49 +01:00
|
|
|
UseSystemHeader::No,
|
2018-11-30 12:15:07 +01:00
|
|
|
UseTweakedHeaderPaths::Yes,
|
2018-11-30 11:02:49 +01:00
|
|
|
UseLanguageDefines::No,
|
2019-01-31 10:16:28 +01:00
|
|
|
UseBuildSystemWarnings::No,
|
2018-08-23 15:45:33 +02:00
|
|
|
QString(CLANG_VERSION),
|
|
|
|
|
QString(CLANG_RESOURCE_DIR));
|
2018-05-02 14:51:05 +02:00
|
|
|
QStringList arguments = extraClangToolsPrependOptions();
|
2018-11-30 10:34:05 +01:00
|
|
|
arguments.append(optionsBuilder.build(fileInfo.kind, usePrecompiledHeaders));
|
2018-05-02 14:51:05 +02:00
|
|
|
arguments.append(extraClangToolsAppendOptions());
|
|
|
|
|
unitsToAnalyze << AnalyzeUnit(fileInfo.file.toString(), arguments);
|
2018-01-17 15:08:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return unitsToAnalyze;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-07 15:21:20 +02:00
|
|
|
AnalyzeUnits ClangToolRunControl::unitsToAnalyze()
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
|
|
|
|
|
|
2018-08-07 15:21:20 +02:00
|
|
|
return toAnalyzeUnits(m_fileInfos);
|
2018-01-17 15:08:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QDebug operator<<(QDebug debug, const Utils::Environment &environment)
|
|
|
|
|
{
|
2019-06-12 08:30:33 +02:00
|
|
|
for (const QString &entry : environment.toStringList())
|
2018-01-17 15:08:30 +01:00
|
|
|
debug << "\n " << entry;
|
|
|
|
|
return debug;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
|
|
|
|
|
{
|
2019-06-12 08:30:33 +02:00
|
|
|
for (const AnalyzeUnit &unit : analyzeUnits)
|
2018-01-17 15:08:30 +01:00
|
|
|
debug << "\n " << unit.file;
|
|
|
|
|
return debug;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-02 14:51:05 +02:00
|
|
|
ClangToolRunControl::ClangToolRunControl(RunControl *runControl,
|
|
|
|
|
Target *target,
|
|
|
|
|
const FileInfos &fileInfos)
|
2018-04-30 15:26:36 +02:00
|
|
|
: RunWorker(runControl)
|
2018-05-02 16:13:01 +02:00
|
|
|
, m_projectBuilder(new ProjectBuilder(runControl, target->project(), this))
|
2018-08-06 11:32:32 +02:00
|
|
|
, m_clangExecutable(Core::ICore::clangExecutable(CLANG_BINDIR))
|
2018-06-05 10:37:42 +02:00
|
|
|
, m_temporaryDir("clangtools-XXXXXX")
|
2018-04-30 15:26:36 +02:00
|
|
|
, m_target(target)
|
2018-05-02 14:51:05 +02:00
|
|
|
, m_fileInfos(fileInfos)
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
2018-05-02 16:13:01 +02:00
|
|
|
addStartDependency(m_projectBuilder);
|
|
|
|
|
|
2018-05-30 13:31:39 +02:00
|
|
|
ClangToolsProjectSettings *projectSettings = ClangToolsProjectSettingsManager::getSettings(
|
|
|
|
|
target->project());
|
|
|
|
|
if (projectSettings->useGlobalSettings())
|
|
|
|
|
m_projectBuilder->setEnabled(ClangToolsSettings::instance()->savedBuildBeforeAnalysis());
|
|
|
|
|
else
|
|
|
|
|
m_projectBuilder->setEnabled(projectSettings->buildBeforeAnalysis());
|
2018-01-17 15:08:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::init()
|
|
|
|
|
{
|
|
|
|
|
setSupportsReRunning(false);
|
|
|
|
|
m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(
|
|
|
|
|
m_target->project());
|
|
|
|
|
|
|
|
|
|
BuildConfiguration *buildConfiguration = m_target->activeBuildConfiguration();
|
|
|
|
|
QTC_ASSERT(buildConfiguration, return);
|
|
|
|
|
m_environment = buildConfiguration->environment();
|
|
|
|
|
|
2019-02-06 12:50:51 +01:00
|
|
|
ToolChain *toolChain = ToolChainKitAspect::toolChain(m_target->kit(),
|
2018-01-17 15:08:30 +01:00
|
|
|
ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
|
|
|
|
QTC_ASSERT(toolChain, return);
|
|
|
|
|
m_targetTriple = toolChain->originalTargetTriple();
|
|
|
|
|
m_toolChainType = toolChain->typeId();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::start()
|
|
|
|
|
{
|
2019-02-08 13:04:57 +01:00
|
|
|
TaskHub::clearTasks(Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
|
2018-05-02 16:13:01 +02:00
|
|
|
if (ClangToolsSettings::instance()->savedBuildBeforeAnalysis()) {
|
|
|
|
|
QTC_ASSERT(m_projectBuilder, return;);
|
|
|
|
|
if (!m_projectBuilder->success()) {
|
|
|
|
|
reportFailure();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-01-17 15:08:30 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-30 15:26:36 +02:00
|
|
|
const QString &toolName = tool()->name();
|
|
|
|
|
if (m_clangExecutable.isEmpty()) {
|
2018-05-04 15:58:41 +02:00
|
|
|
const QString errorMessage = tr("%1: Can't find clang executable, stop.").arg(toolName);
|
2018-04-30 15:26:36 +02:00
|
|
|
appendMessage(errorMessage, Utils::ErrorMessageFormat);
|
|
|
|
|
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
|
|
|
|
reportFailure();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
m_projectInfo = CppTools::CppModelManager::instance()->projectInfo(m_target->project());
|
2019-07-09 12:42:07 +02:00
|
|
|
m_projectFiles = Utils::toSet(m_target->project()->files(Project::AllFiles));
|
2018-01-17 15:08:30 +01:00
|
|
|
|
|
|
|
|
// Some projects provides CompilerCallData once a build is finished,
|
|
|
|
|
if (m_projectInfo.configurationOrFilesChanged(m_projectInfoBeforeBuild)) {
|
|
|
|
|
// If it's more than a release/debug build configuration change, e.g.
|
|
|
|
|
// a version control checkout, files might be not valid C++ anymore
|
|
|
|
|
// or even gone, so better stop here.
|
|
|
|
|
reportFailure(tr("The project configuration changed since the start of "
|
|
|
|
|
"the %1. Please re-run with current configuration.").arg(toolName));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath projectFile = m_projectInfo.project()->projectFilePath();
|
2018-01-17 15:08:30 +01:00
|
|
|
appendMessage(tr("Running %1 on %2").arg(toolName).arg(projectFile.toUserOutput()),
|
|
|
|
|
Utils::NormalMessageFormat);
|
|
|
|
|
|
|
|
|
|
// Create log dir
|
2018-06-05 10:37:42 +02:00
|
|
|
if (!m_temporaryDir.isValid()) {
|
2018-01-17 15:08:30 +01:00
|
|
|
const QString errorMessage
|
2018-07-19 15:45:06 +02:00
|
|
|
= tr("%1: Failed to create temporary dir, stop.").arg(toolName);
|
2018-01-17 15:08:30 +01:00
|
|
|
appendMessage(errorMessage, Utils::ErrorMessageFormat);
|
|
|
|
|
TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
TaskHub::requestPopup();
|
|
|
|
|
reportFailure(errorMessage);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Collect files
|
2018-08-07 15:21:20 +02:00
|
|
|
const AnalyzeUnits unitsToProcess = unitsToAnalyze();
|
2018-01-17 15:08:30 +01:00
|
|
|
qCDebug(LOG) << "Files to process:" << unitsToProcess;
|
|
|
|
|
m_unitsToProcess = unitsToProcess;
|
|
|
|
|
m_initialFilesToProcessSize = m_unitsToProcess.count();
|
|
|
|
|
m_filesAnalyzed = 0;
|
|
|
|
|
m_filesNotAnalyzed = 0;
|
|
|
|
|
|
|
|
|
|
// Set up progress information
|
|
|
|
|
using namespace Core;
|
|
|
|
|
m_progress = QFutureInterface<void>();
|
|
|
|
|
FutureProgress *futureProgress
|
|
|
|
|
= ProgressManager::addTask(m_progress.future(), tr("Analyzing"),
|
|
|
|
|
toolName.toStdString().c_str());
|
|
|
|
|
futureProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
|
|
|
|
|
connect(futureProgress, &FutureProgress::canceled,
|
|
|
|
|
this, &ClangToolRunControl::onProgressCanceled);
|
|
|
|
|
m_progress.setProgressRange(0, m_initialFilesToProcessSize);
|
|
|
|
|
m_progress.reportStarted();
|
|
|
|
|
|
|
|
|
|
// Start process(es)
|
|
|
|
|
qCDebug(LOG) << "Environment:" << m_environment;
|
|
|
|
|
m_runners.clear();
|
2018-04-30 15:26:36 +02:00
|
|
|
const int parallelRuns = ClangToolsSettings::instance()->savedSimultaneousProcesses();
|
2018-01-17 15:08:30 +01:00
|
|
|
QTC_ASSERT(parallelRuns >= 1, reportFailure(); return);
|
|
|
|
|
m_success = true;
|
|
|
|
|
|
|
|
|
|
if (m_unitsToProcess.isEmpty()) {
|
|
|
|
|
finalize();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reportStarted();
|
|
|
|
|
|
|
|
|
|
while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
|
|
|
|
|
analyzeNextFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::stop()
|
|
|
|
|
{
|
|
|
|
|
QSetIterator<ClangToolRunner *> i(m_runners);
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
ClangToolRunner *runner = i.next();
|
2018-11-04 22:30:54 +01:00
|
|
|
QObject::disconnect(runner, nullptr, this, nullptr);
|
2018-01-17 15:08:30 +01:00
|
|
|
delete runner;
|
|
|
|
|
}
|
2019-07-09 12:42:07 +02:00
|
|
|
m_projectFiles.clear();
|
2018-01-17 15:08:30 +01:00
|
|
|
m_runners.clear();
|
|
|
|
|
m_unitsToProcess.clear();
|
|
|
|
|
m_progress.reportFinished();
|
|
|
|
|
|
|
|
|
|
reportStopped();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::analyzeNextFile()
|
|
|
|
|
{
|
|
|
|
|
if (m_progress.isFinished())
|
|
|
|
|
return; // The previous call already reported that we are finished.
|
|
|
|
|
|
|
|
|
|
if (m_unitsToProcess.isEmpty()) {
|
|
|
|
|
if (m_runners.isEmpty())
|
|
|
|
|
finalize();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AnalyzeUnit unit = m_unitsToProcess.takeFirst();
|
|
|
|
|
qCDebug(LOG) << "analyzeNextFile:" << unit.file;
|
|
|
|
|
|
|
|
|
|
ClangToolRunner *runner = createRunner();
|
|
|
|
|
m_runners.insert(runner);
|
|
|
|
|
QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
|
|
|
|
|
|
2019-06-12 08:30:33 +02:00
|
|
|
appendMessage(tr("Analyzing \"%1\".").arg(FilePath::fromString(unit.file).toUserOutput()),
|
2018-01-17 15:08:30 +01:00
|
|
|
Utils::StdOutFormat);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-31 15:20:35 +02:00
|
|
|
void ClangToolRunControl::onRunnerFinishedWithSuccess(const QString &filePath)
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
2018-06-05 10:48:56 +02:00
|
|
|
const QString logFilePath = qobject_cast<ClangToolRunner *>(sender())->logFilePath();
|
2018-01-17 15:08:30 +01:00
|
|
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
|
|
|
|
|
|
|
|
|
|
QString errorMessage;
|
2019-07-23 10:04:01 +02:00
|
|
|
const Diagnostics diagnostics = tool()->read(filePath,
|
|
|
|
|
m_projectFiles,
|
|
|
|
|
logFilePath,
|
|
|
|
|
&errorMessage);
|
2018-05-31 15:20:35 +02:00
|
|
|
QFile::remove(logFilePath); // Clean-up.
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
if (!errorMessage.isEmpty()) {
|
|
|
|
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
|
|
|
|
|
const QString filePath = qobject_cast<ClangToolRunner *>(sender())->filePath();
|
|
|
|
|
appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage),
|
|
|
|
|
Utils::StdErrFormat);
|
|
|
|
|
} else {
|
|
|
|
|
++m_filesAnalyzed;
|
|
|
|
|
if (!diagnostics.isEmpty())
|
|
|
|
|
tool()->onNewDiagnosticsAvailable(diagnostics);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleFinished();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
|
2018-08-17 15:35:13 +02:00
|
|
|
const QString &errorDetails)
|
2018-01-17 15:08:30 +01:00
|
|
|
{
|
|
|
|
|
qCDebug(LOG).noquote() << "onRunnerFinishedWithFailure:"
|
|
|
|
|
<< errorMessage << '\n' << errorDetails;
|
|
|
|
|
|
2018-08-17 15:35:13 +02:00
|
|
|
auto *toolRunner = qobject_cast<ClangToolRunner *>(sender());
|
|
|
|
|
const QString filePath = toolRunner->filePath();
|
|
|
|
|
const QString logFilePath = toolRunner->logFilePath();
|
|
|
|
|
|
2018-05-31 15:20:35 +02:00
|
|
|
// Even in the error case the log file was created, so clean it up here, too.
|
2018-08-17 15:35:13 +02:00
|
|
|
QFile::remove(logFilePath);
|
|
|
|
|
|
|
|
|
|
const QString message = tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage);
|
2018-05-31 15:20:35 +02:00
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
++m_filesNotAnalyzed;
|
|
|
|
|
m_success = false;
|
2018-08-17 15:35:13 +02:00
|
|
|
appendMessage(message, Utils::StdErrFormat);
|
2018-01-17 15:08:30 +01:00
|
|
|
appendMessage(errorDetails, Utils::StdErrFormat);
|
2019-02-08 13:11:15 +01:00
|
|
|
TaskHub::addTask(Task::Error, message, Debugger::Constants::ANALYZERTASK_ID);
|
2018-01-17 15:08:30 +01:00
|
|
|
handleFinished();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::handleFinished()
|
|
|
|
|
{
|
|
|
|
|
m_runners.remove(qobject_cast<ClangToolRunner *>(sender()));
|
|
|
|
|
updateProgressValue();
|
|
|
|
|
sender()->deleteLater();
|
|
|
|
|
analyzeNextFile();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::onProgressCanceled()
|
|
|
|
|
{
|
|
|
|
|
m_progress.reportCanceled();
|
|
|
|
|
runControl()->initiateStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::updateProgressValue()
|
|
|
|
|
{
|
|
|
|
|
m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ClangToolRunControl::finalize()
|
|
|
|
|
{
|
|
|
|
|
const QString toolName = tool()->name();
|
2018-07-19 15:45:06 +02:00
|
|
|
appendMessage(tr("%1 finished: "
|
|
|
|
|
"Processed %2 files successfully, %3 failed.")
|
2018-08-17 17:31:30 +03:00
|
|
|
.arg(toolName).arg(m_filesAnalyzed).arg(m_filesNotAnalyzed),
|
2018-01-17 15:08:30 +01:00
|
|
|
Utils::NormalMessageFormat);
|
|
|
|
|
|
|
|
|
|
if (m_filesNotAnalyzed != 0) {
|
2018-07-19 15:45:06 +02:00
|
|
|
QString msg = tr("%1: Not all files could be analyzed.").arg(toolName);
|
2018-01-17 15:08:30 +01:00
|
|
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
2019-06-19 16:11:54 +02:00
|
|
|
if (m_target && !m_target->activeBuildConfiguration()->buildDirectory().exists()
|
|
|
|
|
&& !ClangToolsProjectSettingsManager::getSettings(m_target->project())
|
|
|
|
|
->buildBeforeAnalysis()) {
|
|
|
|
|
msg = tr("%1: You might need to build the project to generate or update source "
|
|
|
|
|
"files. To build automatically, enable \"Build the project before starting "
|
|
|
|
|
"analysis\".")
|
|
|
|
|
.arg(toolName);
|
|
|
|
|
TaskHub::addTask(Task::Error, msg, Debugger::Constants::ANALYZERTASK_ID);
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-17 15:08:30 +01:00
|
|
|
TaskHub::requestPopup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_progress.reportFinished();
|
|
|
|
|
runControl()->initiateStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
|
|
|
|
} // namespace ClangTools
|