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:
Nikolai Kosjar
2018-05-09 09:22:01 +02:00
parent aa65c7e5f3
commit 23df884f4a
32 changed files with 40 additions and 1659 deletions

2
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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 \

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -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);

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -4,7 +4,6 @@ SUBDIRS += \
algorithm \ algorithm \
aggregation \ aggregation \
changeset \ changeset \
clangtools \
cplusplus \ cplusplus \
debugger \ debugger \
diff \ diff \

View File

@@ -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",

View File

@@ -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

View File

@@ -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",
]
}

View File

@@ -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"

View File

@@ -1,6 +0,0 @@
TEMPLATE = subdirs
CONFIG += ordered
SUBDIRS = \
clangstaticanalyzerrunner \
clangtoolslogfilereader

View File

@@ -1,9 +0,0 @@
import qbs
Project {
name: "ClangTools autotests"
references: [
"clangtoolslogfilereader",
"clangstaticanalyzerrunner",
]
}

View File

@@ -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 + "/..")
}

View File

@@ -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

View File

@@ -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"
]
}

View File

@@ -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>

View File

@@ -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 &apos;foo&apos;</string>
<key>message</key>
<string>Null pointer value stored to &apos;foo&apos;</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>

View File

@@ -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"

View File

@@ -1,5 +0,0 @@
QTC_LIB_DEPENDS += utils
QTC_PLUGIN_DEPENDS += debugger
include(../qttest.pri)
PLUGINDIR=$$IDE_SOURCE_TREE/src/plugins/clangtools