forked from qt-creator/qt-creator
ClangTools: Remove clang static analyzer
...since it's superseded by the tidy integration. Change-Id: Idafa5e1fb5129b1af8e42231a664684d4b90821f Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -158,8 +158,6 @@ tmp/
|
|||||||
/tests/auto/aggregation/tst_aggregation
|
/tests/auto/aggregation/tst_aggregation
|
||||||
/tests/auto/algorithm/tst_algorithm
|
/tests/auto/algorithm/tst_algorithm
|
||||||
/tests/auto/changeset/tst_changeset
|
/tests/auto/changeset/tst_changeset
|
||||||
/tests/auto/clangstaticanalyzer/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader
|
|
||||||
/tests/auto/clangstaticanalyzer/clangstaticanalyzerrunner/tst_clangstaticanalyzerrunnertest
|
|
||||||
/tests/auto/cplusplus/ast/tst_ast
|
/tests/auto/cplusplus/ast/tst_ast
|
||||||
/tests/auto/cplusplus/c99/tst_c99
|
/tests/auto/cplusplus/c99/tst_c99
|
||||||
/tests/auto/cplusplus/checksymbols/tst_checksymbols
|
/tests/auto/cplusplus/checksymbols/tst_checksymbols
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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 "clangstaticanalyzerruncontrol.h"
|
|
||||||
|
|
||||||
#include "clangtoolslogfilereader.h"
|
|
||||||
#include "clangstaticanalyzerrunner.h"
|
|
||||||
#include "clangtoolssettings.h"
|
|
||||||
#include "clangstaticanalyzertool.h"
|
|
||||||
#include "clangtoolsutils.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/temporarydirectory.h>
|
|
||||||
#include <utils/qtcprocess.h>
|
|
||||||
|
|
||||||
#include <QAction>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(RunControl *runControl,
|
|
||||||
Target *target,
|
|
||||||
const FileInfos &fileInfos)
|
|
||||||
: ClangToolRunControl(runControl, target, fileInfos)
|
|
||||||
{
|
|
||||||
setDisplayName("ClangStaticAnalyzerRunner");
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClangToolRunner *ClangStaticAnalyzerRunControl::createRunner()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(!m_clangLogFileDir.isEmpty(), return nullptr);
|
|
||||||
|
|
||||||
auto runner = new ClangStaticAnalyzerRunner(m_clangExecutable,
|
|
||||||
m_clangLogFileDir,
|
|
||||||
m_environment,
|
|
||||||
this);
|
|
||||||
connect(runner, &ClangStaticAnalyzerRunner::finishedWithSuccess,
|
|
||||||
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess);
|
|
||||||
connect(runner, &ClangStaticAnalyzerRunner::finishedWithFailure,
|
|
||||||
this, &ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure);
|
|
||||||
return runner;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClangTool *ClangStaticAnalyzerRunControl::tool()
|
|
||||||
{
|
|
||||||
return ClangStaticAnalyzerTool::instance();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "clangfileinfo.h"
|
|
||||||
#include "clangtoolruncontrol.h"
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerRunControl final : public ClangToolRunControl
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerRunControl(ProjectExplorer::RunControl *runControl,
|
|
||||||
ProjectExplorer::Target *target,
|
|
||||||
const FileInfos &fileInfos);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ClangToolRunner *createRunner() final;
|
|
||||||
|
|
||||||
ClangTool *tool() final;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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 "clangstaticanalyzerrunner.h"
|
|
||||||
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runner")
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecutable,
|
|
||||||
const QString &clangLogFileDir,
|
|
||||||
const Utils::Environment &environment,
|
|
||||||
QObject *parent)
|
|
||||||
: ClangToolRunner(clangExecutable,
|
|
||||||
clangLogFileDir,
|
|
||||||
environment,
|
|
||||||
tr("Clang Static Analyzer"),
|
|
||||||
parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ClangStaticAnalyzerRunner::constructCommandLineArguments(const QStringList &options)
|
|
||||||
{
|
|
||||||
QStringList arguments;
|
|
||||||
|
|
||||||
if (LOG().isDebugEnabled())
|
|
||||||
arguments << QString("-v");
|
|
||||||
|
|
||||||
arguments << QLatin1String("--analyze")
|
|
||||||
<< QLatin1String("-o")
|
|
||||||
<< QDir::toNativeSeparators(m_logFile);
|
|
||||||
|
|
||||||
arguments += options;
|
|
||||||
|
|
||||||
arguments << QDir::toNativeSeparators(filePath());
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "clangtoolrunner.h"
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerRunner final : public ClangToolRunner
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerRunner(const QString &clangExecutable,
|
|
||||||
const QString &clangLogFileDir,
|
|
||||||
const Utils::Environment &environment,
|
|
||||||
QObject *parent = nullptr);
|
|
||||||
protected:
|
|
||||||
QStringList constructCommandLineArguments(const QStringList &options) final;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -1,243 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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 "clangstaticanalyzertool.h"
|
|
||||||
|
|
||||||
#include "clangtoolsconstants.h"
|
|
||||||
#include "clangtoolsdiagnosticmodel.h"
|
|
||||||
#include "clangtoolslogfilereader.h"
|
|
||||||
#include "clangtoolsdiagnosticview.h"
|
|
||||||
#include "clangstaticanalyzerruncontrol.h"
|
|
||||||
|
|
||||||
#include <coreplugin/actionmanager/actioncontainer.h>
|
|
||||||
#include <coreplugin/actionmanager/actionmanager.h>
|
|
||||||
|
|
||||||
#include <debugger/analyzer/analyzermanager.h>
|
|
||||||
|
|
||||||
#include <projectexplorer/kitinformation.h>
|
|
||||||
#include <projectexplorer/projectexplorer.h>
|
|
||||||
#include <projectexplorer/projectexplorericons.h>
|
|
||||||
#include <projectexplorer/target.h>
|
|
||||||
#include <projectexplorer/session.h>
|
|
||||||
|
|
||||||
#include <utils/utilsicons.h>
|
|
||||||
|
|
||||||
#include <QAction>
|
|
||||||
|
|
||||||
using namespace Core;
|
|
||||||
using namespace Debugger;
|
|
||||||
using namespace ProjectExplorer;
|
|
||||||
using namespace Utils;
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
static ClangStaticAnalyzerTool *s_instance;
|
|
||||||
|
|
||||||
ClangStaticAnalyzerTool::ClangStaticAnalyzerTool()
|
|
||||||
: ClangTool(tr("Clang Static Analyzer"))
|
|
||||||
{
|
|
||||||
setObjectName("ClangStaticAnalyzerTool");
|
|
||||||
s_instance = this;
|
|
||||||
|
|
||||||
m_diagnosticFilterModel = new DiagnosticFilterModel(this);
|
|
||||||
m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
|
|
||||||
|
|
||||||
m_diagnosticView = new DiagnosticView;
|
|
||||||
initDiagnosticView();
|
|
||||||
m_diagnosticView->setModel(m_diagnosticFilterModel);
|
|
||||||
m_diagnosticView->setObjectName(QLatin1String("ClangStaticAnalyzerIssuesView"));
|
|
||||||
m_diagnosticView->setWindowTitle(tr("Clang Static Analyzer Issues"));
|
|
||||||
|
|
||||||
foreach (auto * const model,
|
|
||||||
QList<QAbstractItemModel *>() << m_diagnosticModel << m_diagnosticFilterModel) {
|
|
||||||
connect(model, &QAbstractItemModel::rowsInserted,
|
|
||||||
this, &ClangStaticAnalyzerTool::handleStateUpdate);
|
|
||||||
connect(model, &QAbstractItemModel::rowsRemoved,
|
|
||||||
this, &ClangStaticAnalyzerTool::handleStateUpdate);
|
|
||||||
connect(model, &QAbstractItemModel::modelReset,
|
|
||||||
this, &ClangStaticAnalyzerTool::handleStateUpdate);
|
|
||||||
connect(model, &QAbstractItemModel::layoutChanged, // For QSortFilterProxyModel::invalidate()
|
|
||||||
this, &ClangStaticAnalyzerTool::handleStateUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go to previous diagnostic
|
|
||||||
auto action = new QAction(this);
|
|
||||||
action->setDisabled(true);
|
|
||||||
action->setIcon(Utils::Icons::PREV_TOOLBAR.icon());
|
|
||||||
action->setToolTip(tr("Go to previous bug."));
|
|
||||||
connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack);
|
|
||||||
m_goBack = action;
|
|
||||||
|
|
||||||
// Go to next diagnostic
|
|
||||||
action = new QAction(this);
|
|
||||||
action->setDisabled(true);
|
|
||||||
action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon());
|
|
||||||
action->setToolTip(tr("Go to next bug."));
|
|
||||||
connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext);
|
|
||||||
m_goNext = action;
|
|
||||||
|
|
||||||
ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
|
|
||||||
const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the Clang project "
|
|
||||||
"to find bugs.");
|
|
||||||
|
|
||||||
Debugger::registerPerspective(ClangStaticAnalyzerPerspectiveId, new Perspective(
|
|
||||||
tr("Clang Static Analyzer"),
|
|
||||||
{{ClangStaticAnalyzerDockId, m_diagnosticView, {}, Perspective::SplitVertical}}
|
|
||||||
));
|
|
||||||
|
|
||||||
action = new QAction(tr("Clang Static Analyzer..."), this);
|
|
||||||
action->setToolTip(toolTip);
|
|
||||||
menu->addAction(ActionManager::registerAction(action, "ClangStaticAnalyzer.Action"),
|
|
||||||
Debugger::Constants::G_ANALYZER_TOOLS);
|
|
||||||
QObject::connect(action, &QAction::triggered, this, [this]() { startTool(true); });
|
|
||||||
QObject::connect(m_startAction, &QAction::triggered, action, &QAction::triggered);
|
|
||||||
QObject::connect(m_startAction, &QAction::changed, action, [action, this] {
|
|
||||||
action->setEnabled(m_startAction->isEnabled());
|
|
||||||
});
|
|
||||||
|
|
||||||
ToolbarDescription toolbar;
|
|
||||||
toolbar.addAction(m_startAction);
|
|
||||||
toolbar.addAction(m_stopAction);
|
|
||||||
toolbar.addAction(m_goBack);
|
|
||||||
toolbar.addAction(m_goNext);
|
|
||||||
Debugger::registerToolbar(ClangStaticAnalyzerPerspectiveId, toolbar);
|
|
||||||
|
|
||||||
updateRunActions();
|
|
||||||
|
|
||||||
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::updateRunActions,
|
|
||||||
this, &ClangStaticAnalyzerTool::updateRunActions);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClangStaticAnalyzerTool *ClangStaticAnalyzerTool::instance()
|
|
||||||
{
|
|
||||||
return s_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerTool::startTool(bool askUserForFileSelection)
|
|
||||||
{
|
|
||||||
auto runControl = new RunControl(nullptr, Constants::CLANGSTATICANALYZER_RUN_MODE);
|
|
||||||
runControl->setDisplayName(tr("Clang Static Analyzer"));
|
|
||||||
runControl->setIcon(ProjectExplorer::Icons::ANALYZER_START_SMALL_TOOLBAR);
|
|
||||||
|
|
||||||
Project *project = SessionManager::startupProject();
|
|
||||||
QTC_ASSERT(project, return);
|
|
||||||
QTC_ASSERT(project->activeTarget(), return);
|
|
||||||
|
|
||||||
const FileInfos fileInfos = collectFileInfos(project, askUserForFileSelection);
|
|
||||||
if (fileInfos.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto clangTool = new ClangStaticAnalyzerRunControl(runControl,
|
|
||||||
project->activeTarget(),
|
|
||||||
fileInfos);
|
|
||||||
|
|
||||||
m_stopAction->disconnect();
|
|
||||||
connect(m_stopAction, &QAction::triggered, runControl, [runControl] {
|
|
||||||
runControl->appendMessage(tr("Clang Static Analyzer stopped by user."),
|
|
||||||
NormalMessageFormat);
|
|
||||||
runControl->initiateStop();
|
|
||||||
});
|
|
||||||
|
|
||||||
connect(runControl, &RunControl::stopped, this, [this, clangTool] {
|
|
||||||
bool success = clangTool->success();
|
|
||||||
setToolBusy(false);
|
|
||||||
m_running = false;
|
|
||||||
handleStateUpdate();
|
|
||||||
updateRunActions();
|
|
||||||
emit finished(success);
|
|
||||||
});
|
|
||||||
|
|
||||||
Debugger::selectPerspective(ClangStaticAnalyzerPerspectiveId);
|
|
||||||
|
|
||||||
m_diagnosticModel->clear();
|
|
||||||
setToolBusy(true);
|
|
||||||
m_diagnosticFilterModel->setProject(project);
|
|
||||||
m_running = true;
|
|
||||||
handleStateUpdate();
|
|
||||||
updateRunActions();
|
|
||||||
|
|
||||||
ProjectExplorerPlugin::startRunControl(runControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerTool::updateRunActions()
|
|
||||||
{
|
|
||||||
if (m_toolBusy) {
|
|
||||||
m_startAction->setEnabled(false);
|
|
||||||
m_startAction->setToolTip(tr("Clang Static Analyzer is still running."));
|
|
||||||
m_stopAction->setEnabled(true);
|
|
||||||
} else {
|
|
||||||
QString toolTip = tr("Start Clang Static Analyzer.");
|
|
||||||
Project *project = SessionManager::startupProject();
|
|
||||||
Target *target = project ? project->activeTarget() : nullptr;
|
|
||||||
const Core::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
|
|
||||||
bool canRun = target && project->projectLanguages().contains(cxx)
|
|
||||||
&& ToolChainKitInformation::toolChain(target->kit(), cxx);
|
|
||||||
if (!canRun)
|
|
||||||
toolTip = tr("This is not a C++ project.");
|
|
||||||
|
|
||||||
m_startAction->setToolTip(toolTip);
|
|
||||||
m_startAction->setEnabled(canRun);
|
|
||||||
m_stopAction->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerTool::handleStateUpdate()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_goBack, return);
|
|
||||||
QTC_ASSERT(m_goNext, return);
|
|
||||||
QTC_ASSERT(m_diagnosticModel, return);
|
|
||||||
QTC_ASSERT(m_diagnosticFilterModel, return);
|
|
||||||
|
|
||||||
const int issuesFound = m_diagnosticModel->diagnostics().count();
|
|
||||||
const int issuesVisible = m_diagnosticFilterModel->rowCount();
|
|
||||||
m_goBack->setEnabled(issuesVisible > 1);
|
|
||||||
m_goNext->setEnabled(issuesVisible > 1);
|
|
||||||
|
|
||||||
QString message;
|
|
||||||
if (m_running)
|
|
||||||
message = tr("Clang Static Analyzer is running.");
|
|
||||||
else
|
|
||||||
message = tr("Clang Static Analyzer finished.");
|
|
||||||
|
|
||||||
message += QLatin1Char(' ');
|
|
||||||
if (issuesFound == 0) {
|
|
||||||
message += tr("No issues found.");
|
|
||||||
} else {
|
|
||||||
message += tr("%n issues found (%1 suppressed).", 0, issuesFound)
|
|
||||||
.arg(issuesFound - issuesVisible);
|
|
||||||
}
|
|
||||||
Debugger::showPermanentStatusMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Diagnostic> ClangStaticAnalyzerTool::read(const QString &,
|
|
||||||
const QString &logFilePath,
|
|
||||||
QString *errorMessage) const
|
|
||||||
{
|
|
||||||
return LogFileReader::readPlist(logFilePath, errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "clangtool.h"
|
|
||||||
|
|
||||||
namespace ClangTools {
|
|
||||||
namespace Internal {
|
|
||||||
|
|
||||||
class DiagnosticFilterModel;
|
|
||||||
class ClangToolsDiagnosticModel;
|
|
||||||
class DiagnosticView;
|
|
||||||
class Diagnostic;
|
|
||||||
|
|
||||||
const char ClangStaticAnalyzerPerspectiveId[] = "ClangStaticAnalyzer.Perspective";
|
|
||||||
const char ClangStaticAnalyzerDockId[] = "ClangStaticAnalyzer.Dock";
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerTool final : public ClangTool
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerTool();
|
|
||||||
|
|
||||||
static ClangStaticAnalyzerTool *instance();
|
|
||||||
|
|
||||||
void startTool(bool askUserForFileSelection) final;
|
|
||||||
|
|
||||||
QList<Diagnostic> read(const QString &,
|
|
||||||
const QString &logFilePath,
|
|
||||||
QString *errorMessage) const final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void handleStateUpdate() final;
|
|
||||||
|
|
||||||
void updateRunActions();
|
|
||||||
|
|
||||||
DiagnosticFilterModel *m_diagnosticFilterModel = nullptr;
|
|
||||||
|
|
||||||
QAction *m_goBack = nullptr;
|
|
||||||
QAction *m_goNext = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Internal
|
|
||||||
} // namespace ClangTools
|
|
||||||
@@ -157,7 +157,7 @@ private:
|
|||||||
.arg(toolName).arg(wrongMode);
|
.arg(toolName).arg(wrongMode);
|
||||||
if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::mainWindow(),
|
if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::mainWindow(),
|
||||||
title, message, Core::ICore::settings(),
|
title, message, Core::ICore::settings(),
|
||||||
"ClangStaticAnalyzerCorrectModeWarning") != QDialogButtonBox::Yes)
|
"ClangToolsCorrectModeWarning") != QDialogButtonBox::Yes)
|
||||||
{
|
{
|
||||||
reportFailure();
|
reportFailure();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ SOURCES += \
|
|||||||
clangselectablefilesdialog.cpp \
|
clangselectablefilesdialog.cpp \
|
||||||
clangtoolsdiagnosticview.cpp \
|
clangtoolsdiagnosticview.cpp \
|
||||||
clangtoolsprojectsettingswidget.cpp \
|
clangtoolsprojectsettingswidget.cpp \
|
||||||
clangstaticanalyzerruncontrol.cpp \
|
|
||||||
clangstaticanalyzerrunner.cpp \
|
|
||||||
clangstaticanalyzertool.cpp \
|
|
||||||
clangtidyclazyruncontrol.cpp \
|
clangtidyclazyruncontrol.cpp \
|
||||||
clangtidyclazyrunner.cpp \
|
clangtidyclazyrunner.cpp \
|
||||||
clangtidyclazytool.cpp \
|
clangtidyclazytool.cpp \
|
||||||
@@ -35,9 +32,6 @@ HEADERS += \
|
|||||||
clangselectablefilesdialog.h \
|
clangselectablefilesdialog.h \
|
||||||
clangtoolsdiagnosticview.h \
|
clangtoolsdiagnosticview.h \
|
||||||
clangtoolsprojectsettingswidget.h \
|
clangtoolsprojectsettingswidget.h \
|
||||||
clangstaticanalyzerruncontrol.h \
|
|
||||||
clangstaticanalyzerrunner.h \
|
|
||||||
clangstaticanalyzertool.h \
|
|
||||||
clangtidyclazyruncontrol.h \
|
clangtidyclazyruncontrol.h \
|
||||||
clangtidyclazyrunner.h \
|
clangtidyclazyrunner.h \
|
||||||
clangtidyclazytool.h \
|
clangtidyclazytool.h \
|
||||||
|
|||||||
@@ -50,12 +50,6 @@ QtcPlugin {
|
|||||||
"clangtoolsprojectsettingswidget.cpp",
|
"clangtoolsprojectsettingswidget.cpp",
|
||||||
"clangtoolsprojectsettingswidget.h",
|
"clangtoolsprojectsettingswidget.h",
|
||||||
"clangtoolsprojectsettingswidget.ui",
|
"clangtoolsprojectsettingswidget.ui",
|
||||||
"clangstaticanalyzerruncontrol.cpp",
|
|
||||||
"clangstaticanalyzerruncontrol.h",
|
|
||||||
"clangstaticanalyzerrunner.cpp",
|
|
||||||
"clangstaticanalyzerrunner.h",
|
|
||||||
"clangstaticanalyzertool.cpp",
|
|
||||||
"clangstaticanalyzertool.h",
|
|
||||||
"clangtidyclazyruncontrol.cpp",
|
"clangtidyclazyruncontrol.cpp",
|
||||||
"clangtidyclazyruncontrol.h",
|
"clangtidyclazyruncontrol.h",
|
||||||
"clangtidyclazyrunner.cpp",
|
"clangtidyclazyrunner.cpp",
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
#if defined(CLANGSTATICANALYZER_LIBRARY)
|
#if defined(CLANGTOOLS_LIBRARY)
|
||||||
# define CLANGSTATICANALYZER_EXPORT Q_DECL_EXPORT
|
# define CLANGTOOLS_EXPORT Q_DECL_EXPORT
|
||||||
#else
|
#else
|
||||||
# define CLANGSTATICANALYZER_EXPORT Q_DECL_IMPORT
|
# define CLANGTOOLS_EXPORT Q_DECL_IMPORT
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ namespace ClangTools {
|
|||||||
namespace Constants {
|
namespace Constants {
|
||||||
|
|
||||||
const char SETTINGS_ID[] = "ClangTools";
|
const char SETTINGS_ID[] = "ClangTools";
|
||||||
const char CLANGSTATICANALYZER_RUN_MODE[] = "ClangStaticAnalyzer.RunMode";
|
|
||||||
const char CLANGTIDYCLAZY_RUN_MODE[] = "ClangTidyClazy.RunMode";
|
const char CLANGTIDYCLAZY_RUN_MODE[] = "ClangTidyClazy.RunMode";
|
||||||
|
|
||||||
} // Constants
|
} // Constants
|
||||||
|
|||||||
@@ -43,42 +43,6 @@
|
|||||||
namespace ClangTools {
|
namespace ClangTools {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class ClangStaticAnalyzerLogFileReader
|
|
||||||
{
|
|
||||||
Q_DECLARE_TR_FUNCTIONS(ClangTools::Internal::ClangStaticAnalyzerLogFileReader)
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerLogFileReader(const QString &filePath);
|
|
||||||
|
|
||||||
QXmlStreamReader::Error read();
|
|
||||||
|
|
||||||
// Output
|
|
||||||
QString clangVersion() const;
|
|
||||||
QStringList files() const;
|
|
||||||
QList<Diagnostic> diagnostics() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void readPlist();
|
|
||||||
void readTopLevelDict();
|
|
||||||
void readDiagnosticsArray();
|
|
||||||
void readDiagnosticsDict();
|
|
||||||
QList<ExplainingStep> readPathArray();
|
|
||||||
ExplainingStep readPathDict();
|
|
||||||
Debugger::DiagnosticLocation readLocationDict(bool elementIsRead = false);
|
|
||||||
QList<Debugger::DiagnosticLocation> readRangesArray();
|
|
||||||
|
|
||||||
QString readString();
|
|
||||||
QStringList readStringArray();
|
|
||||||
int readInteger(bool *convertedSuccessfully);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_filePath;
|
|
||||||
QXmlStreamReader m_xml;
|
|
||||||
|
|
||||||
QString m_clangVersion;
|
|
||||||
QStringList m_referencedFiles;
|
|
||||||
QList<Diagnostic> m_diagnostics;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClangSerializedDiagnosticsReader
|
class ClangSerializedDiagnosticsReader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -100,50 +64,6 @@ static bool checkFilePath(const QString &filePath, QString *errorMessage)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Diagnostic> LogFileReader::readPlist(const QString &filePath, QString *errorMessage)
|
|
||||||
{
|
|
||||||
if (!checkFilePath(filePath, errorMessage))
|
|
||||||
return QList<Diagnostic>();
|
|
||||||
|
|
||||||
// Read
|
|
||||||
ClangStaticAnalyzerLogFileReader reader(filePath);
|
|
||||||
const QXmlStreamReader::Error error = reader.read();
|
|
||||||
|
|
||||||
// Return diagnostics
|
|
||||||
switch (error) {
|
|
||||||
case QXmlStreamReader::NoError:
|
|
||||||
return reader.diagnostics();
|
|
||||||
|
|
||||||
// Handle errors
|
|
||||||
case QXmlStreamReader::UnexpectedElementError:
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = tr("Could not read file \"%1\": UnexpectedElementError.")
|
|
||||||
.arg(filePath);
|
|
||||||
}
|
|
||||||
Q_FALLTHROUGH();
|
|
||||||
case QXmlStreamReader::CustomError:
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = tr("Could not read file \"%1\": CustomError.")
|
|
||||||
.arg(filePath);
|
|
||||||
}
|
|
||||||
Q_FALLTHROUGH();
|
|
||||||
case QXmlStreamReader::NotWellFormedError:
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = tr("Could not read file \"%1\": NotWellFormedError.")
|
|
||||||
.arg(filePath);
|
|
||||||
}
|
|
||||||
Q_FALLTHROUGH();
|
|
||||||
case QXmlStreamReader::PrematureEndOfDocumentError:
|
|
||||||
if (errorMessage) {
|
|
||||||
*errorMessage = tr("Could not read file \"%1\": PrematureEndOfDocumentError.")
|
|
||||||
.arg(filePath);
|
|
||||||
}
|
|
||||||
Q_FALLTHROUGH();
|
|
||||||
default:
|
|
||||||
return QList<Diagnostic>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Diagnostic> LogFileReader::readSerialized(const QString &filePath, const QString &logFilePath,
|
QList<Diagnostic> LogFileReader::readSerialized(const QString &filePath, const QString &logFilePath,
|
||||||
QString *errorMessage)
|
QString *errorMessage)
|
||||||
{
|
{
|
||||||
@@ -154,263 +74,6 @@ QList<Diagnostic> LogFileReader::readSerialized(const QString &filePath, const Q
|
|||||||
return reader.read(filePath, logFilePath);
|
return reader.read(filePath, logFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangStaticAnalyzerLogFileReader::ClangStaticAnalyzerLogFileReader(const QString &filePath)
|
|
||||||
: m_filePath(filePath)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QXmlStreamReader::Error ClangStaticAnalyzerLogFileReader::read()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(!m_filePath.isEmpty(), return QXmlStreamReader::CustomError);
|
|
||||||
QFile file(m_filePath);
|
|
||||||
QTC_ASSERT(file.open(QIODevice::ReadOnly | QIODevice::Text),
|
|
||||||
return QXmlStreamReader::CustomError);
|
|
||||||
|
|
||||||
m_xml.setDevice(&file);
|
|
||||||
readPlist();
|
|
||||||
|
|
||||||
// If file is empty, m_xml.error() == QXmlStreamReader::PrematureEndOfDocumentError
|
|
||||||
return m_xml.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ClangStaticAnalyzerLogFileReader::clangVersion() const
|
|
||||||
{
|
|
||||||
return m_clangVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ClangStaticAnalyzerLogFileReader::files() const
|
|
||||||
{
|
|
||||||
return m_referencedFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Diagnostic> ClangStaticAnalyzerLogFileReader::diagnostics() const
|
|
||||||
{
|
|
||||||
return m_diagnostics;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerLogFileReader::readPlist()
|
|
||||||
{
|
|
||||||
if (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("plist")) {
|
|
||||||
if (m_xml.attributes().value(QLatin1String("version")) == QLatin1String("1.0"))
|
|
||||||
readTopLevelDict();
|
|
||||||
} else {
|
|
||||||
m_xml.raiseError(tr("File is not a plist version 1.0 file."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerLogFileReader::readTopLevelDict()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("plist"), return);
|
|
||||||
QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("dict"), return);
|
|
||||||
|
|
||||||
while (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("key")) {
|
|
||||||
const QString key = m_xml.readElementText();
|
|
||||||
if (key == QLatin1String("clang_version"))
|
|
||||||
m_clangVersion = readString();
|
|
||||||
else if (key == QLatin1String("files"))
|
|
||||||
m_referencedFiles = readStringArray();
|
|
||||||
else if (key == QLatin1String("diagnostics"))
|
|
||||||
readDiagnosticsArray();
|
|
||||||
} else {
|
|
||||||
m_xml.skipCurrentElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerLogFileReader::readDiagnosticsArray()
|
|
||||||
{
|
|
||||||
if (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array")) {
|
|
||||||
while (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("dict"))
|
|
||||||
readDiagnosticsDict();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerLogFileReader::readDiagnosticsDict()
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"), return);
|
|
||||||
|
|
||||||
Diagnostic diagnostic;
|
|
||||||
|
|
||||||
while (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("key")) {
|
|
||||||
const QString key = m_xml.readElementText();
|
|
||||||
if (key == QLatin1String("path"))
|
|
||||||
diagnostic.explainingSteps = readPathArray();
|
|
||||||
else if (key == QLatin1String("description"))
|
|
||||||
diagnostic.description = readString();
|
|
||||||
else if (key == QLatin1String("category"))
|
|
||||||
diagnostic.category = readString();
|
|
||||||
else if (key == QLatin1String("type"))
|
|
||||||
diagnostic.type = readString();
|
|
||||||
else if (key == QLatin1String("issue_context_kind"))
|
|
||||||
diagnostic.issueContextKind = readString();
|
|
||||||
else if (key == QLatin1String("issue_context"))
|
|
||||||
diagnostic.issueContext = readString();
|
|
||||||
else if (key == QLatin1String("location"))
|
|
||||||
diagnostic.location = readLocationDict();
|
|
||||||
} else {
|
|
||||||
m_xml.skipCurrentElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_diagnostics << diagnostic;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<ExplainingStep> ClangStaticAnalyzerLogFileReader::readPathArray()
|
|
||||||
{
|
|
||||||
QList<ExplainingStep> result;
|
|
||||||
|
|
||||||
if (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array")) {
|
|
||||||
while (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("dict")) {
|
|
||||||
const ExplainingStep step = readPathDict();
|
|
||||||
if (step.isValid())
|
|
||||||
result << step;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExplainingStep ClangStaticAnalyzerLogFileReader::readPathDict()
|
|
||||||
{
|
|
||||||
ExplainingStep explainingStep;
|
|
||||||
|
|
||||||
QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"),
|
|
||||||
return explainingStep);
|
|
||||||
|
|
||||||
// We are interested only in dict entries an kind=event type
|
|
||||||
if (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("key")) {
|
|
||||||
const QString key = m_xml.readElementText();
|
|
||||||
QTC_ASSERT(key == QLatin1String("kind"), return explainingStep);
|
|
||||||
const QString kind = readString();
|
|
||||||
if (kind != QLatin1String("event")) {
|
|
||||||
m_xml.skipCurrentElement();
|
|
||||||
return explainingStep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool depthOk = false;
|
|
||||||
|
|
||||||
while (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("key")) {
|
|
||||||
const QString key = m_xml.readElementText();
|
|
||||||
if (key == QLatin1String("location"))
|
|
||||||
explainingStep.location = readLocationDict();
|
|
||||||
else if (key == QLatin1String("ranges"))
|
|
||||||
explainingStep.ranges = readRangesArray();
|
|
||||||
else if (key == QLatin1String("depth"))
|
|
||||||
explainingStep.depth = readInteger(&depthOk);
|
|
||||||
else if (key == QLatin1String("message"))
|
|
||||||
explainingStep.message = readString();
|
|
||||||
else if (key == QLatin1String("extended_message"))
|
|
||||||
explainingStep.extendedMessage = readString();
|
|
||||||
} else {
|
|
||||||
m_xml.skipCurrentElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QTC_CHECK(depthOk);
|
|
||||||
return explainingStep;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debugger::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead)
|
|
||||||
{
|
|
||||||
Debugger::DiagnosticLocation location;
|
|
||||||
if (elementIsRead) {
|
|
||||||
QTC_ASSERT(m_xml.isStartElement() && m_xml.name() == QLatin1String("dict"),
|
|
||||||
return location);
|
|
||||||
} else {
|
|
||||||
QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("dict"),
|
|
||||||
return location);
|
|
||||||
}
|
|
||||||
|
|
||||||
int line = 0;
|
|
||||||
int column = 0;
|
|
||||||
int fileIndex = 0;
|
|
||||||
bool lineOk = false, columnOk = false, fileIndexOk = false;
|
|
||||||
|
|
||||||
// Collect values
|
|
||||||
while (m_xml.readNextStartElement()) {
|
|
||||||
if (m_xml.name() == QLatin1String("key")) {
|
|
||||||
const QString keyName = m_xml.readElementText();
|
|
||||||
if (keyName == QLatin1String("line"))
|
|
||||||
line = readInteger(&lineOk);
|
|
||||||
else if (keyName == QLatin1String("col"))
|
|
||||||
column = readInteger(&columnOk);
|
|
||||||
else if (keyName == QLatin1String("file"))
|
|
||||||
fileIndex = readInteger(&fileIndexOk);
|
|
||||||
} else {
|
|
||||||
m_xml.skipCurrentElement();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lineOk && columnOk && fileIndexOk) {
|
|
||||||
QTC_ASSERT(fileIndex < m_referencedFiles.size(), return location);
|
|
||||||
location = Debugger::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column);
|
|
||||||
}
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Debugger::DiagnosticLocation> ClangStaticAnalyzerLogFileReader::readRangesArray()
|
|
||||||
{
|
|
||||||
QList<Debugger::DiagnosticLocation> result;
|
|
||||||
|
|
||||||
// It's an array of arrays...
|
|
||||||
QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"),
|
|
||||||
return result);
|
|
||||||
QTC_ASSERT(m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array"),
|
|
||||||
return result);
|
|
||||||
|
|
||||||
while (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("dict"))
|
|
||||||
result << readLocationDict(true);
|
|
||||||
|
|
||||||
m_xml.skipCurrentElement(); // Laeve outer array
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ClangStaticAnalyzerLogFileReader::readString()
|
|
||||||
{
|
|
||||||
if (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("string"))
|
|
||||||
return m_xml.readElementText();
|
|
||||||
|
|
||||||
m_xml.raiseError(tr("Expected a string element."));
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList ClangStaticAnalyzerLogFileReader::readStringArray()
|
|
||||||
{
|
|
||||||
if (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("array")) {
|
|
||||||
QStringList result;
|
|
||||||
while (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("string")) {
|
|
||||||
const QString string = m_xml.readElementText();
|
|
||||||
if (!string.isEmpty())
|
|
||||||
result << string;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_xml.raiseError(tr("Expected an array element."));
|
|
||||||
return QStringList();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClangStaticAnalyzerLogFileReader::readInteger(bool *convertedSuccessfully)
|
|
||||||
{
|
|
||||||
if (m_xml.readNextStartElement() && m_xml.name() == QLatin1String("integer")) {
|
|
||||||
const QString contents = m_xml.readElementText();
|
|
||||||
return contents.toInt(convertedSuccessfully);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_xml.raiseError(tr("Expected an integer element."));
|
|
||||||
if (convertedSuccessfully)
|
|
||||||
*convertedSuccessfully = false;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString fromCXString(CXString &&cxString)
|
static QString fromCXString(CXString &&cxString)
|
||||||
{
|
{
|
||||||
QString result = QString::fromUtf8(clang_getCString(cxString));
|
QString result = QString::fromUtf8(clang_getCString(cxString));
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class LogFileReader
|
|||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(ClangTools::Internal::LogFileReader)
|
Q_DECLARE_TR_FUNCTIONS(ClangTools::Internal::LogFileReader)
|
||||||
public:
|
public:
|
||||||
static QList<Diagnostic> readPlist(const QString &filePath, QString *errorMessage);
|
|
||||||
static QList<Diagnostic> readSerialized(const QString &filePath,
|
static QList<Diagnostic> readSerialized(const QString &filePath,
|
||||||
const QString &logFilePath,
|
const QString &logFilePath,
|
||||||
QString *errorMessage);
|
QString *errorMessage);
|
||||||
|
|||||||
@@ -28,8 +28,6 @@
|
|||||||
#include "clangtoolsconfigwidget.h"
|
#include "clangtoolsconfigwidget.h"
|
||||||
#include "clangtoolsconstants.h"
|
#include "clangtoolsconstants.h"
|
||||||
#include "clangtoolsprojectsettingswidget.h"
|
#include "clangtoolsprojectsettingswidget.h"
|
||||||
#include "clangstaticanalyzerruncontrol.h"
|
|
||||||
#include "clangstaticanalyzertool.h"
|
|
||||||
#include "clangtidyclazytool.h"
|
#include "clangtidyclazytool.h"
|
||||||
#include "clangtoolsprojectsettings.h"
|
#include "clangtoolsprojectsettings.h"
|
||||||
|
|
||||||
@@ -72,7 +70,7 @@ class ClangToolsOptionsPage : public Core::IOptionsPage
|
|||||||
public:
|
public:
|
||||||
explicit ClangToolsOptionsPage()
|
explicit ClangToolsOptionsPage()
|
||||||
{
|
{
|
||||||
setId("Analyzer.ClangTools.Settings"); // TODO: Get it from "clangstaticanalyzersettings.h"
|
setId("Analyzer.ClangTools.Settings");
|
||||||
setDisplayName(QCoreApplication::translate(
|
setDisplayName(QCoreApplication::translate(
|
||||||
"ClangTools::Internal::ClangToolsOptionsPage",
|
"ClangTools::Internal::ClangToolsOptionsPage",
|
||||||
"Clang Tools"));
|
"Clang Tools"));
|
||||||
@@ -105,7 +103,6 @@ private:
|
|||||||
class ClangToolsPluginPrivate
|
class ClangToolsPluginPrivate
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClangStaticAnalyzerTool staticAnalyzerTool;
|
|
||||||
ClangTidyClazyTool clangTidyClazyTool;
|
ClangTidyClazyTool clangTidyClazyTool;
|
||||||
ClangToolsOptionsPage optionsPage;
|
ClangToolsOptionsPage optionsPage;
|
||||||
ClangToolsProjectSettingsManager settingsManager;
|
ClangToolsProjectSettingsManager settingsManager;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "clangtoolspreconfiguredsessiontests.h"
|
#include "clangtoolspreconfiguredsessiontests.h"
|
||||||
|
|
||||||
#include "clangtoolsdiagnostic.h"
|
#include "clangtoolsdiagnostic.h"
|
||||||
#include "clangstaticanalyzertool.h"
|
#include "clangtidyclazytool.h"
|
||||||
#include "clangtoolsutils.h"
|
#include "clangtoolsutils.h"
|
||||||
|
|
||||||
#include <cpptools/compileroptionsbuilder.h>
|
#include <cpptools/compileroptionsbuilder.h>
|
||||||
@@ -120,13 +120,13 @@ void PreconfiguredSessionTests::testPreconfiguredSession()
|
|||||||
|
|
||||||
QVERIFY(switchToProjectAndTarget(project, target));
|
QVERIFY(switchToProjectAndTarget(project, target));
|
||||||
|
|
||||||
ClangStaticAnalyzerTool::instance()->startTool(false);
|
ClangTidyClazyTool::instance()->startTool(false);
|
||||||
QSignalSpy waitUntilAnalyzerFinished(ClangStaticAnalyzerTool::instance(), SIGNAL(finished(bool)));
|
QSignalSpy waitUntilAnalyzerFinished(ClangTidyClazyTool::instance(), SIGNAL(finished(bool)));
|
||||||
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
|
QVERIFY(waitUntilAnalyzerFinished.wait(30000));
|
||||||
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
|
const QList<QVariant> arguments = waitUntilAnalyzerFinished.takeFirst();
|
||||||
const bool analyzerFinishedSuccessfully = arguments.first().toBool();
|
const bool analyzerFinishedSuccessfully = arguments.first().toBool();
|
||||||
QVERIFY(analyzerFinishedSuccessfully);
|
QVERIFY(analyzerFinishedSuccessfully);
|
||||||
QCOMPARE(ClangStaticAnalyzerTool::instance()->diagnostics().count(), 0);
|
QCOMPARE(ClangTidyClazyTool::instance()->diagnostics().count(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<Project *> validProjects(const QList<Project *> projectsOfSession)
|
static QList<Project *> validProjects(const QList<Project *> projectsOfSession)
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "clangtoolsunittests.h"
|
#include "clangtoolsunittests.h"
|
||||||
|
|
||||||
#include "clangtoolsdiagnostic.h"
|
#include "clangtoolsdiagnostic.h"
|
||||||
#include "clangstaticanalyzertool.h"
|
|
||||||
#include "clangtidyclazytool.h"
|
#include "clangtidyclazytool.h"
|
||||||
#include "clangtoolsutils.h"
|
#include "clangtoolsutils.h"
|
||||||
|
|
||||||
@@ -90,7 +89,6 @@ static CppTools::ClangDiagnosticConfig createTidyClazyConfig()
|
|||||||
|
|
||||||
void ClangToolsUnitTests::testProject()
|
void ClangToolsUnitTests::testProject()
|
||||||
{
|
{
|
||||||
QFETCH(Tool, clangtool);
|
|
||||||
QFETCH(QString, projectFilePath);
|
QFETCH(QString, projectFilePath);
|
||||||
QFETCH(int, expectedDiagCount);
|
QFETCH(int, expectedDiagCount);
|
||||||
if (projectFilePath.contains("mingw")) {
|
if (projectFilePath.contains("mingw")) {
|
||||||
@@ -104,16 +102,11 @@ void ClangToolsUnitTests::testProject()
|
|||||||
CppTools::Tests::ProjectOpenerAndCloser projectManager;
|
CppTools::Tests::ProjectOpenerAndCloser projectManager;
|
||||||
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
|
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
|
||||||
QVERIFY(projectInfo.isValid());
|
QVERIFY(projectInfo.isValid());
|
||||||
ClangTool *tool = (clangtool == Tool::ClangStaticAnalyzer)
|
ClangTool *tool = ClangTidyClazyTool::instance();
|
||||||
? ClangStaticAnalyzerTool::instance()
|
|
||||||
: static_cast<ClangTool *>(ClangTidyClazyTool::instance());
|
|
||||||
|
|
||||||
ExecuteOnDestruction executeOnDestruction;
|
|
||||||
if (clangtool == Tool::ClangTidyAndClazy) {
|
|
||||||
// Change configs
|
// Change configs
|
||||||
QSharedPointer<CppTools::CppCodeModelSettings> settings = CppTools::codeModelSettings();
|
QSharedPointer<CppTools::CppCodeModelSettings> settings = CppTools::codeModelSettings();
|
||||||
const CppTools::ClangDiagnosticConfigs originalConfigs
|
const CppTools::ClangDiagnosticConfigs originalConfigs = settings->clangCustomDiagnosticConfigs();
|
||||||
= settings->clangCustomDiagnosticConfigs();
|
|
||||||
const Core::Id originalId = settings->clangDiagnosticConfigId();
|
const Core::Id originalId = settings->clangDiagnosticConfigId();
|
||||||
|
|
||||||
CppTools::ClangDiagnosticConfigs modifiedConfigs = originalConfigs;
|
CppTools::ClangDiagnosticConfigs modifiedConfigs = originalConfigs;
|
||||||
@@ -121,7 +114,7 @@ void ClangToolsUnitTests::testProject()
|
|||||||
const CppTools::ClangDiagnosticConfig clangTidyConfig = createTidyClazyConfig();
|
const CppTools::ClangDiagnosticConfig clangTidyConfig = createTidyClazyConfig();
|
||||||
modifiedConfigs.push_back(clangTidyConfig);
|
modifiedConfigs.push_back(clangTidyConfig);
|
||||||
|
|
||||||
executeOnDestruction.reset([=]() {
|
ExecuteOnDestruction executeOnDestruction([=]() {
|
||||||
// Restore configs
|
// Restore configs
|
||||||
settings->setClangCustomDiagnosticConfigs(originalConfigs);
|
settings->setClangCustomDiagnosticConfigs(originalConfigs);
|
||||||
settings->setClangDiagnosticConfigId(originalId);
|
settings->setClangDiagnosticConfigId(originalId);
|
||||||
@@ -129,7 +122,6 @@ void ClangToolsUnitTests::testProject()
|
|||||||
|
|
||||||
settings->setClangCustomDiagnosticConfigs(modifiedConfigs);
|
settings->setClangCustomDiagnosticConfigs(modifiedConfigs);
|
||||||
settings->setClangDiagnosticConfigId(clangTidyConfig.id());
|
settings->setClangDiagnosticConfigId(clangTidyConfig.id());
|
||||||
}
|
|
||||||
|
|
||||||
tool->startTool(false);
|
tool->startTool(false);
|
||||||
QSignalSpy waiter(tool, SIGNAL(finished(bool)));
|
QSignalSpy waiter(tool, SIGNAL(finished(bool)));
|
||||||
@@ -142,40 +134,39 @@ void ClangToolsUnitTests::testProject()
|
|||||||
|
|
||||||
void ClangToolsUnitTests::testProject_data()
|
void ClangToolsUnitTests::testProject_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<Tool>("clangtool");
|
|
||||||
QTest::addColumn<QString>("projectFilePath");
|
QTest::addColumn<QString>("projectFilePath");
|
||||||
QTest::addColumn<int>("expectedDiagCount");
|
QTest::addColumn<int>("expectedDiagCount");
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "simple/simple.qbs", 1);
|
addTestRow("simple/simple.qbs", 1);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "simple/simple.pro", 1);
|
addTestRow("simple/simple.pro", 1);
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "simple-library/simple-library.qbs", 0);
|
addTestRow("simple-library/simple-library.qbs", 0);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "simple-library/simple-library.pro", 0);
|
addTestRow("simple-library/simple-library.pro", 0);
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "stdc++11-includes/stdc++11-includes.qbs", 0);
|
addTestRow("stdc++11-includes/stdc++11-includes.qbs", 0);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "stdc++11-includes/stdc++11-includes.pro", 0);
|
addTestRow("stdc++11-includes/stdc++11-includes.pro", 0);
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "qt-widgets-app/qt-widgets-app.qbs", 0);
|
addTestRow("qt-widgets-app/qt-widgets-app.qbs", 0);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "qt-widgets-app/qt-widgets-app.pro", 0);
|
addTestRow("qt-widgets-app/qt-widgets-app.pro", 0);
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "qt-essential-includes/qt-essential-includes.qbs", 0);
|
addTestRow("qt-essential-includes/qt-essential-includes.qbs", 0);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "qt-essential-includes/qt-essential-includes.pro", 0);
|
addTestRow("qt-essential-includes/qt-essential-includes.pro", 0);
|
||||||
|
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "mingw-includes/mingw-includes.qbs", 0);
|
addTestRow("mingw-includes/mingw-includes.qbs", 0);
|
||||||
addTestRow(Tool::ClangStaticAnalyzer, "mingw-includes/mingw-includes.pro", 0);
|
addTestRow("mingw-includes/mingw-includes.pro", 0);
|
||||||
|
|
||||||
addTestRow(Tool::ClangTidyAndClazy, "clangtidy_clazy/clangtidy_clazy.pro",
|
addTestRow("clangtidy_clazy/clangtidy_clazy.pro",
|
||||||
4 /* ClangTidy: modernize-*,misc-* */
|
4 /* ClangTidy: modernize-*,misc-* */
|
||||||
+ 2 /* Clazy: level1 */);
|
+ 2 /* Clazy: level1 */);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangToolsUnitTests::addTestRow(Tool tool, const QByteArray &relativeFilePath,
|
void ClangToolsUnitTests::addTestRow(const QByteArray &relativeFilePath,
|
||||||
int expectedDiagCount)
|
int expectedDiagCount)
|
||||||
{
|
{
|
||||||
const QString absoluteFilePath = m_tmpDir->absolutePath(relativeFilePath);
|
const QString absoluteFilePath = m_tmpDir->absolutePath(relativeFilePath);
|
||||||
const QString fileName = QFileInfo(absoluteFilePath).fileName();
|
const QString fileName = QFileInfo(absoluteFilePath).fileName();
|
||||||
|
|
||||||
QTest::newRow(fileName.toUtf8().constData()) << tool << absoluteFilePath << expectedDiagCount;
|
QTest::newRow(fileName.toUtf8().constData()) << absoluteFilePath << expectedDiagCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -32,12 +32,6 @@ namespace CppTools { namespace Tests { class TemporaryCopiedDir; } }
|
|||||||
namespace ClangTools {
|
namespace ClangTools {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
enum class Tool
|
|
||||||
{
|
|
||||||
ClangStaticAnalyzer,
|
|
||||||
ClangTidyAndClazy
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClangToolsUnitTests : public QObject
|
class ClangToolsUnitTests : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -52,7 +46,7 @@ private slots:
|
|||||||
void testProject_data();
|
void testProject_data();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addTestRow(Tool tool, const QByteArray &relativeFilePath, int expectedDiagCount);
|
void addTestRow(const QByteArray &relativeFilePath, int expectedDiagCount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CppTools::Tests::TemporaryCopiedDir *m_tmpDir = nullptr;
|
CppTools::Tests::TemporaryCopiedDir *m_tmpDir = nullptr;
|
||||||
@@ -60,5 +54,3 @@ private:
|
|||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangTools
|
} // namespace ClangTools
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(ClangTools::Internal::Tool)
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ SUBDIRS += \
|
|||||||
algorithm \
|
algorithm \
|
||||||
aggregation \
|
aggregation \
|
||||||
changeset \
|
changeset \
|
||||||
clangtools \
|
|
||||||
cplusplus \
|
cplusplus \
|
||||||
debugger \
|
debugger \
|
||||||
diff \
|
diff \
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ Project {
|
|||||||
"aggregation/aggregation.qbs",
|
"aggregation/aggregation.qbs",
|
||||||
"algorithm/algorithm.qbs",
|
"algorithm/algorithm.qbs",
|
||||||
"changeset/changeset.qbs",
|
"changeset/changeset.qbs",
|
||||||
"clangtools/clangtools.qbs",
|
|
||||||
"cplusplus/cplusplus.qbs",
|
"cplusplus/cplusplus.qbs",
|
||||||
"debugger/debugger.qbs",
|
"debugger/debugger.qbs",
|
||||||
"diff/diff.qbs",
|
"diff/diff.qbs",
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
include(../clangtoolstest.pri)
|
|
||||||
|
|
||||||
TARGET = tst_clangstaticanalyzerrunnertest
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
tst_clangstaticanalyzerrunner.cpp \
|
|
||||||
$$PLUGINDIR/clangtoolrunner.cpp \
|
|
||||||
$$PLUGINDIR/clangstaticanalyzerrunner.cpp
|
|
||||||
HEADERS += \
|
|
||||||
$$PLUGINDIR/clangtoolrunner.h \
|
|
||||||
$$PLUGINDIR/clangstaticanalyzerrunner.h
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import qbs
|
|
||||||
import "../clangtoolsautotest.qbs" as ClangToolsAutotest
|
|
||||||
|
|
||||||
ClangToolsAutotest {
|
|
||||||
name: "ClangStaticAnalyzerRunner Autotest"
|
|
||||||
|
|
||||||
Group {
|
|
||||||
name: "sources from plugin"
|
|
||||||
prefix: pluginDir + '/'
|
|
||||||
files: [
|
|
||||||
"clangstaticanalyzerrunner.cpp",
|
|
||||||
"clangstaticanalyzerrunner.h",
|
|
||||||
"clangtoolrunner.cpp",
|
|
||||||
"clangtoolrunner.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
files: [
|
|
||||||
"tst_clangstaticanalyzerrunner.cpp",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,210 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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 <clangtools/clangtoolsconstants.h>
|
|
||||||
#include <clangtools/clangstaticanalyzerrunner.h>
|
|
||||||
|
|
||||||
#include <utils/environment.h>
|
|
||||||
#include <utils/hostosinfo.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
|
||||||
|
|
||||||
#include <QtTest>
|
|
||||||
|
|
||||||
using namespace ClangTools::Internal;
|
|
||||||
|
|
||||||
static QString clangExecutablePath()
|
|
||||||
{
|
|
||||||
const QString clangFileName = Utils::HostOsInfo::withExecutableSuffix(QStringLiteral("clang"));
|
|
||||||
const Utils::Environment environment = Utils::Environment::systemEnvironment();
|
|
||||||
|
|
||||||
return environment.searchInPath(clangFileName).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool writeFile(const QString &filePath, const QByteArray &source)
|
|
||||||
{
|
|
||||||
Utils::FileSaver saver(filePath);
|
|
||||||
return saver.write(source) && saver.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool waitUntilSignalCounterIsGreatorThanZero(int &signalCounter, int timeOutInMs = 5000)
|
|
||||||
{
|
|
||||||
QElapsedTimer timer;
|
|
||||||
timer.start();
|
|
||||||
|
|
||||||
while (timer.elapsed() <= timeOutInMs) {
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
if (signalCounter != 0) {
|
|
||||||
if (signalCounter == 1)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
qDebug() << "signalCounter:" << signalCounter;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QThread::msleep(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "signalCounter:" << signalCounter;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerRunnerTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerRunnerTest();
|
|
||||||
virtual ~ClangStaticAnalyzerRunnerTest() {}
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void runWithTestCodeGeneratedOneIssue();
|
|
||||||
void runWithNonExistentFileToAnalyze();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_clangExecutable;
|
|
||||||
};
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunnerTest::ClangStaticAnalyzerRunnerTest()
|
|
||||||
: m_clangExecutable(clangExecutablePath())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
class ClangStaticAnalyzerRunnerSignalTester
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ClangStaticAnalyzerRunnerSignalTester(ClangStaticAnalyzerRunner *runner);
|
|
||||||
|
|
||||||
bool expectStartedSignal();
|
|
||||||
bool expectFinishWithSuccessSignal();
|
|
||||||
bool expectFinishWithFailureSignal(const QString &expectedErrorMessage = QString());
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_startedSignalEmitted;
|
|
||||||
int m_finishedWithSuccessEmitted;
|
|
||||||
int m_finishedWithFailureEmitted;
|
|
||||||
QString m_finishedWithFailureErrorMessage;
|
|
||||||
};
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunnerSignalTester::ClangStaticAnalyzerRunnerSignalTester(
|
|
||||||
ClangStaticAnalyzerRunner *runner)
|
|
||||||
: m_startedSignalEmitted(0)
|
|
||||||
, m_finishedWithSuccessEmitted(0)
|
|
||||||
, m_finishedWithFailureEmitted(0)
|
|
||||||
{
|
|
||||||
QObject::connect(runner, &ClangStaticAnalyzerRunner::started, [this] {
|
|
||||||
++m_startedSignalEmitted;
|
|
||||||
});
|
|
||||||
|
|
||||||
QObject::connect(runner, &ClangStaticAnalyzerRunner::finishedWithSuccess, [this] {
|
|
||||||
++m_finishedWithSuccessEmitted;
|
|
||||||
});
|
|
||||||
|
|
||||||
QObject::connect(runner,
|
|
||||||
&ClangStaticAnalyzerRunner::finishedWithFailure,
|
|
||||||
[this] (const QString &errorMessage, const QString &) {
|
|
||||||
++m_finishedWithFailureEmitted;
|
|
||||||
m_finishedWithFailureErrorMessage = errorMessage;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClangStaticAnalyzerRunnerSignalTester::expectStartedSignal()
|
|
||||||
{
|
|
||||||
return waitUntilSignalCounterIsGreatorThanZero(m_startedSignalEmitted);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClangStaticAnalyzerRunnerSignalTester::expectFinishWithSuccessSignal()
|
|
||||||
{
|
|
||||||
return waitUntilSignalCounterIsGreatorThanZero(m_finishedWithSuccessEmitted);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClangStaticAnalyzerRunnerSignalTester::expectFinishWithFailureSignal(
|
|
||||||
const QString &expectedErrorMessage)
|
|
||||||
{
|
|
||||||
if (waitUntilSignalCounterIsGreatorThanZero(m_finishedWithFailureEmitted)) {
|
|
||||||
if (m_finishedWithFailureErrorMessage == expectedErrorMessage) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
qDebug() << "Actual error message:" << m_finishedWithFailureErrorMessage;
|
|
||||||
qDebug() << "Expected error message:" << expectedErrorMessage;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerRunnerTest::runWithTestCodeGeneratedOneIssue()
|
|
||||||
{
|
|
||||||
if (m_clangExecutable.isEmpty())
|
|
||||||
QSKIP("Clang executable in PATH required.");
|
|
||||||
|
|
||||||
const QString testFilePath = QDir::tempPath() + QLatin1String("/testcode.cpp");
|
|
||||||
const QByteArray source =
|
|
||||||
"void f(int *p) {}\n"
|
|
||||||
"void f2(int *p) {\n"
|
|
||||||
" delete p;\n"
|
|
||||||
" f(p); // warn: use after free\n"
|
|
||||||
"}\n";
|
|
||||||
QVERIFY(writeFile(testFilePath, source));
|
|
||||||
|
|
||||||
Utils::TemporaryDirectory temporaryDir("runWithTestCodeGeneratedOneIssue");
|
|
||||||
ClangStaticAnalyzerRunner runner(m_clangExecutable, temporaryDir.path(),
|
|
||||||
Utils::Environment::systemEnvironment());
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunnerSignalTester st(&runner);
|
|
||||||
QVERIFY(runner.run(testFilePath));
|
|
||||||
|
|
||||||
QVERIFY(st.expectStartedSignal());
|
|
||||||
QVERIFY(st.expectFinishWithSuccessSignal());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangStaticAnalyzerRunnerTest::runWithNonExistentFileToAnalyze()
|
|
||||||
{
|
|
||||||
if (m_clangExecutable.isEmpty())
|
|
||||||
QSKIP("Clang executable in PATH required.");
|
|
||||||
|
|
||||||
Utils::TemporaryDirectory temporaryDir("runWithNonExistentFileToAnalyze");
|
|
||||||
ClangStaticAnalyzerRunner runner(m_clangExecutable, temporaryDir.path(),
|
|
||||||
Utils::Environment::systemEnvironment());
|
|
||||||
|
|
||||||
ClangStaticAnalyzerRunnerSignalTester st(&runner);
|
|
||||||
QVERIFY(runner.run(QLatin1String("not.existing.file.111")));
|
|
||||||
|
|
||||||
QVERIFY(st.expectStartedSignal());
|
|
||||||
QVERIFY(st.expectFinishWithFailureSignal(finishedWithBadExitCode("Clang Static Analyzer", 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
Utils::TemporaryDirectory::setMasterTemporaryDirectory(
|
|
||||||
QDir::tempPath() + "/qtc-clangstaticanalyzer-test-XXXXXX");
|
|
||||||
|
|
||||||
QCoreApplication app(argc, argv);
|
|
||||||
ClangStaticAnalyzerRunnerTest test;
|
|
||||||
return QTest::qExec(&test, argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "tst_clangstaticanalyzerrunner.moc"
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
TEMPLATE = subdirs
|
|
||||||
CONFIG += ordered
|
|
||||||
|
|
||||||
SUBDIRS = \
|
|
||||||
clangstaticanalyzerrunner \
|
|
||||||
clangtoolslogfilereader
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import qbs
|
|
||||||
|
|
||||||
Project {
|
|
||||||
name: "ClangTools autotests"
|
|
||||||
references: [
|
|
||||||
"clangtoolslogfilereader",
|
|
||||||
"clangstaticanalyzerrunner",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import qbs
|
|
||||||
|
|
||||||
QtcAutotest {
|
|
||||||
Depends { name: "Qt.widgets" }
|
|
||||||
Depends { name: "Debugger" }
|
|
||||||
Depends { name: "Utils" }
|
|
||||||
|
|
||||||
property path pluginDir: project.ide_source_tree + "/src/plugins/clangtools"
|
|
||||||
cpp.includePaths: base.concat(pluginDir + "/..")
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
include(../clangtoolstest.pri)
|
|
||||||
include(../../../../src/shared/clang/clang_installation.pri)
|
|
||||||
|
|
||||||
requires(!isEmpty(LLVM_VERSION))
|
|
||||||
|
|
||||||
TARGET = tst_clangtoolslogfilereader
|
|
||||||
|
|
||||||
DEFINES += SRCDIR=\\\"$$PWD/\\\"
|
|
||||||
|
|
||||||
LIBS += $$LIBCLANG_LIBS
|
|
||||||
INCLUDEPATH += $$LLVM_INCLUDEPATH
|
|
||||||
|
|
||||||
SOURCES += \
|
|
||||||
tst_clangtoolslogfilereader.cpp \
|
|
||||||
$$PLUGINDIR/clangtoolsdiagnostic.cpp \
|
|
||||||
$$PLUGINDIR/clangtoolslogfilereader.cpp
|
|
||||||
|
|
||||||
HEADERS += \
|
|
||||||
$$PLUGINDIR/clangtoolsdiagnostic.h \
|
|
||||||
$$PLUGINDIR/clangtoolslogfilereader.h
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import qbs
|
|
||||||
import "../clangtoolsautotest.qbs" as ClangToolsAutotest
|
|
||||||
|
|
||||||
ClangToolsAutotest {
|
|
||||||
name: "ClangToolsLogFileReader Autotest"
|
|
||||||
|
|
||||||
Depends { name: "libclang"; required: false }
|
|
||||||
|
|
||||||
cpp.defines: base.concat('SRCDIR="' + sourceDirectory + '"')
|
|
||||||
|
|
||||||
condition: libclang.present
|
|
||||||
|
|
||||||
cpp.includePaths: base.concat(libclang.llvmIncludeDir)
|
|
||||||
cpp.libraryPaths: base.concat(libclang.llvmLibDir)
|
|
||||||
cpp.dynamicLibraries: base.concat(libclang.llvmLibs)
|
|
||||||
cpp.rpaths: base.concat(libclang.llvmLibDir)
|
|
||||||
|
|
||||||
Group {
|
|
||||||
name: "sources from plugin"
|
|
||||||
prefix: pluginDir + '/'
|
|
||||||
files: [
|
|
||||||
"clangtoolsdiagnostic.cpp",
|
|
||||||
"clangtoolsdiagnostic.h",
|
|
||||||
"clangtoolslogfilereader.cpp",
|
|
||||||
"clangtoolslogfilereader.h",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
files: [
|
|
||||||
"tst_clangtoolslogfilereader.cpp"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>clang_version</key>
|
|
||||||
<string>Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)</string>
|
|
||||||
<key>files</key>
|
|
||||||
<array>
|
|
||||||
</array>
|
|
||||||
<key>diagnostics</key>
|
|
||||||
<array>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>clang_version</key>
|
|
||||||
<string>Ubuntu clang version 3.5-1ubuntu1 (trunk) (based on LLVM 3.5)</string>
|
|
||||||
<key>files</key>
|
|
||||||
<array>
|
|
||||||
<string>../csatestproject/core.CallAndMessage3.cpp</string>
|
|
||||||
</array>
|
|
||||||
<key>diagnostics</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>path</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>kind</key><string>control</string>
|
|
||||||
<key>edges</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>start</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>34</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>34</integer>
|
|
||||||
<key>col</key><integer>6</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>end</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>5</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>kind</key><string>event</string>
|
|
||||||
<key>location</key>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<key>ranges</key>
|
|
||||||
<array>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>9</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</array>
|
|
||||||
<key>depth</key><integer>0</integer>
|
|
||||||
<key>extended_message</key>
|
|
||||||
<string>Null pointer value stored to 'foo'</string>
|
|
||||||
<key>message</key>
|
|
||||||
<string>Null pointer value stored to 'foo'</string>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>kind</key><string>control</string>
|
|
||||||
<key>edges</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>start</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>35</integer>
|
|
||||||
<key>col</key><integer>5</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>end</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>5</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>kind</key><string>event</string>
|
|
||||||
<key>location</key>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<key>ranges</key>
|
|
||||||
<array>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>5</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</array>
|
|
||||||
<key>depth</key><integer>0</integer>
|
|
||||||
<key>extended_message</key>
|
|
||||||
<string>Called function pointer is null (null dereference)</string>
|
|
||||||
<key>message</key>
|
|
||||||
<string>Called function pointer is null (null dereference)</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
<key>description</key><string>Called function pointer is null (null dereference)</string>
|
|
||||||
<key>category</key><string>Logic error</string>
|
|
||||||
<key>type</key><string>Called function pointer is null (null dereference)</string>
|
|
||||||
<key>issue_context_kind</key><string>function</string>
|
|
||||||
<key>issue_context</key><string>test</string>
|
|
||||||
<key>issue_hash</key><string>3</string>
|
|
||||||
<key>location</key>
|
|
||||||
<dict>
|
|
||||||
<key>line</key><integer>36</integer>
|
|
||||||
<key>col</key><integer>3</integer>
|
|
||||||
<key>file</key><integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
<key>HTMLDiagnostics_files</key>
|
|
||||||
<array>
|
|
||||||
<string>report-6c3c2a.html</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** 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 <clangtools/clangtoolslogfilereader.h>
|
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
|
||||||
|
|
||||||
#include <QtTest>
|
|
||||||
|
|
||||||
enum { debug = 0 };
|
|
||||||
|
|
||||||
using namespace Debugger;
|
|
||||||
using namespace ClangTools::Internal;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const ExplainingStep &step)
|
|
||||||
{
|
|
||||||
dbg << '\n'
|
|
||||||
<< " ExplainingStep\n"
|
|
||||||
<< " location:" << step.location << '\n'
|
|
||||||
<< " ranges:\n";
|
|
||||||
foreach (const DiagnosticLocation &location, step.ranges)
|
|
||||||
dbg << " " << location << '\n';
|
|
||||||
dbg
|
|
||||||
<< " message:" << step.message << '\n'
|
|
||||||
<< " extendedMessage:" << step.extendedMessage << '\n'
|
|
||||||
<< " depth:" << step.depth << '\n';
|
|
||||||
return dbg;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDebug operator<<(QDebug dbg, const Diagnostic &diagnostic)
|
|
||||||
{
|
|
||||||
dbg << "\nDiagnostic\n"
|
|
||||||
<< " description:" << diagnostic.description << '\n'
|
|
||||||
<< " category:" << diagnostic.category << '\n'
|
|
||||||
<< " type:" << diagnostic.type << '\n'
|
|
||||||
<< " issueContextKind:" << diagnostic.issueContextKind << '\n'
|
|
||||||
<< " issueContext:" << diagnostic.issueContext << '\n'
|
|
||||||
<< " location:" << diagnostic.location << '\n'
|
|
||||||
<< " explaining steps:\n";
|
|
||||||
foreach (const ExplainingStep &explaingStep, diagnostic.explainingSteps)
|
|
||||||
dbg << explaingStep;
|
|
||||||
return dbg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool createEmptyFile(const QString &filePath)
|
|
||||||
{
|
|
||||||
Utils::FileSaver saver(filePath);
|
|
||||||
return saver.write("") && saver.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString testFilePath(const QString &relativePath)
|
|
||||||
{
|
|
||||||
const QString fullPath = QString::fromLatin1(SRCDIR) + relativePath;
|
|
||||||
const QFileInfo fi(fullPath);
|
|
||||||
if (fi.exists() && fi.isReadable())
|
|
||||||
return fullPath;
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
class ClangToolsLogFileReaderTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void readEmptyFile();
|
|
||||||
void readFileWithNoDiagnostics();
|
|
||||||
void readFileWithDiagnostics();
|
|
||||||
};
|
|
||||||
|
|
||||||
void ClangToolsLogFileReaderTest::readEmptyFile()
|
|
||||||
{
|
|
||||||
const QString filePath = QDir::tempPath() + QLatin1String("/empty.file");
|
|
||||||
QVERIFY(createEmptyFile(filePath));
|
|
||||||
|
|
||||||
QString errorMessage;
|
|
||||||
const QList<Diagnostic> diagnostics = LogFileReader::readPlist(filePath, &errorMessage);
|
|
||||||
QVERIFY(!errorMessage.isEmpty());
|
|
||||||
if (debug)
|
|
||||||
qDebug() << errorMessage;
|
|
||||||
QVERIFY(diagnostics.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangToolsLogFileReaderTest::readFileWithNoDiagnostics()
|
|
||||||
{
|
|
||||||
const QString filePath = testFilePath(QLatin1String("/data/noDiagnostics.plist"));
|
|
||||||
|
|
||||||
QString errorMessage;
|
|
||||||
const QList<Diagnostic> diagnostics = LogFileReader::readPlist(filePath, &errorMessage);
|
|
||||||
QVERIFY(errorMessage.isEmpty());
|
|
||||||
QVERIFY(diagnostics.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClangToolsLogFileReaderTest::readFileWithDiagnostics()
|
|
||||||
{
|
|
||||||
const QString filePath = testFilePath(QLatin1String("/data/someDiagnostics.plist"));
|
|
||||||
|
|
||||||
QString errorMessage;
|
|
||||||
const QList<Diagnostic> diagnostics = LogFileReader::readPlist(filePath, &errorMessage);
|
|
||||||
QVERIFY(errorMessage.isEmpty());
|
|
||||||
QVERIFY(!diagnostics.isEmpty());
|
|
||||||
|
|
||||||
const QString commonPath = QLatin1String("../csatestproject/core.CallAndMessage3.cpp");
|
|
||||||
|
|
||||||
const Diagnostic d1 = diagnostics.first();
|
|
||||||
if (debug)
|
|
||||||
qDebug() << d1;
|
|
||||||
QCOMPARE(d1.description, QLatin1String("Called function pointer is null (null dereference)"));
|
|
||||||
QCOMPARE(d1.category, QLatin1String("Logic error"));
|
|
||||||
QCOMPARE(d1.type, d1.description);
|
|
||||||
QCOMPARE(d1.issueContextKind, QLatin1String("function"));
|
|
||||||
QCOMPARE(d1.issueContext, QLatin1String("test"));
|
|
||||||
QCOMPARE(d1.location, DiagnosticLocation(commonPath, 36, 3));
|
|
||||||
|
|
||||||
QCOMPARE(d1.explainingSteps.size(), 2);
|
|
||||||
const ExplainingStep step1 = d1.explainingSteps.at(0);
|
|
||||||
QCOMPARE(step1.location, DiagnosticLocation(commonPath, 35, 3));
|
|
||||||
QCOMPARE(step1.ranges.size(), 2);
|
|
||||||
QCOMPARE(step1.ranges.at(0), DiagnosticLocation(commonPath, 35, 3));
|
|
||||||
QCOMPARE(step1.ranges.at(1), DiagnosticLocation(commonPath, 35, 9));
|
|
||||||
QCOMPARE(step1.depth, 0);
|
|
||||||
QCOMPARE(step1.message, QLatin1String("Null pointer value stored to 'foo'"));
|
|
||||||
QCOMPARE(step1.extendedMessage, step1.message);
|
|
||||||
|
|
||||||
const ExplainingStep step2 = d1.explainingSteps.at(1);
|
|
||||||
QCOMPARE(step2.location, DiagnosticLocation(commonPath, 36, 3));
|
|
||||||
QCOMPARE(step2.ranges.size(), 2);
|
|
||||||
QCOMPARE(step2.ranges.at(0), DiagnosticLocation(commonPath, 36, 3));
|
|
||||||
QCOMPARE(step2.ranges.at(1), DiagnosticLocation(commonPath, 36, 5));
|
|
||||||
QCOMPARE(step2.depth, 0);
|
|
||||||
QCOMPARE(step2.message, QLatin1String("Called function pointer is null (null dereference)"));
|
|
||||||
QCOMPARE(step2.extendedMessage, step2.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
QTEST_MAIN(ClangToolsLogFileReaderTest)
|
|
||||||
|
|
||||||
#include "tst_clangtoolslogfilereader.moc"
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
QTC_LIB_DEPENDS += utils
|
|
||||||
QTC_PLUGIN_DEPENDS += debugger
|
|
||||||
include(../qttest.pri)
|
|
||||||
|
|
||||||
PLUGINDIR=$$IDE_SOURCE_TREE/src/plugins/clangtools
|
|
||||||
Reference in New Issue
Block a user