forked from qt-creator/qt-creator
Merge Clang static analyzer plugin
Change-Id: I2c67655ac5703feda9a256d349306bad16deace7
This commit is contained in:
19
src/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
Normal file
19
src/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
\"Name\" : \"ClangStaticAnalyzer\",
|
||||||
|
\"Version\" : \"$$QTCREATOR_VERSION\",
|
||||||
|
\"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
|
||||||
|
\"Vendor\" : \"The Qt Company Ltd\",
|
||||||
|
\"Copyright\" : \"(C) 2016 The Qt Company Ltd\",
|
||||||
|
\"License\" : [ \"Commercial 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.\"
|
||||||
|
],
|
||||||
|
\"Category\" : \"Code Analyzer\",
|
||||||
|
\"Description\" : \"ClangStaticAnalyzer Plugin.\",
|
||||||
|
\"Url\" : \"http://www.qt.io\",
|
||||||
|
$$dependencyList
|
||||||
|
}
|
||||||
54
src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
Normal file
54
src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
TARGET = ClangStaticAnalyzer
|
||||||
|
TEMPLATE = lib
|
||||||
|
|
||||||
|
include(../../qtcreatorplugin.pri)
|
||||||
|
include(clangstaticanalyzer_dependencies.pri)
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
clangstaticanalyzerconfigwidget.cpp \
|
||||||
|
clangstaticanalyzerdiagnostic.cpp \
|
||||||
|
clangstaticanalyzerdiagnosticmodel.cpp \
|
||||||
|
clangstaticanalyzerdiagnosticview.cpp \
|
||||||
|
clangstaticanalyzerlogfilereader.cpp \
|
||||||
|
clangstaticanalyzerplugin.cpp \
|
||||||
|
clangstaticanalyzerprojectsettings.cpp \
|
||||||
|
clangstaticanalyzerprojectsettingsmanager.cpp \
|
||||||
|
clangstaticanalyzerprojectsettingswidget.cpp \
|
||||||
|
clangstaticanalyzerruncontrol.cpp \
|
||||||
|
clangstaticanalyzerruncontrolfactory.cpp \
|
||||||
|
clangstaticanalyzerrunner.cpp \
|
||||||
|
clangstaticanalyzersettings.cpp \
|
||||||
|
clangstaticanalyzertool.cpp \
|
||||||
|
clangstaticanalyzerutils.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
clangstaticanalyzerconfigwidget.h \
|
||||||
|
clangstaticanalyzerconstants.h \
|
||||||
|
clangstaticanalyzerdiagnostic.h \
|
||||||
|
clangstaticanalyzerdiagnosticmodel.h \
|
||||||
|
clangstaticanalyzerdiagnosticview.h \
|
||||||
|
clangstaticanalyzer_global.h \
|
||||||
|
clangstaticanalyzerlogfilereader.h \
|
||||||
|
clangstaticanalyzerplugin.h \
|
||||||
|
clangstaticanalyzerprojectsettings.h \
|
||||||
|
clangstaticanalyzerprojectsettingsmanager.h \
|
||||||
|
clangstaticanalyzerprojectsettingswidget.h \
|
||||||
|
clangstaticanalyzerruncontrolfactory.h \
|
||||||
|
clangstaticanalyzerruncontrol.h \
|
||||||
|
clangstaticanalyzerrunner.h \
|
||||||
|
clangstaticanalyzersettings.h \
|
||||||
|
clangstaticanalyzertool.h \
|
||||||
|
clangstaticanalyzerutils.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
clangstaticanalyzerconfigwidget.ui \
|
||||||
|
clangstaticanalyzerprojectsettingswidget.ui
|
||||||
|
|
||||||
|
equals(TEST, 1) {
|
||||||
|
HEADERS += clangstaticanalyzerunittests.h
|
||||||
|
SOURCES += clangstaticanalyzerunittests.cpp
|
||||||
|
RESOURCES += clangstaticanalyzerunittests.qrc
|
||||||
|
}
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
tests/tests.pri
|
||||||
74
src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
Normal file
74
src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import qbs
|
||||||
|
|
||||||
|
QtcPlugin {
|
||||||
|
name: "ClangStaticAnalyzer"
|
||||||
|
|
||||||
|
Depends { name: "AnalyzerBase" }
|
||||||
|
Depends { name: "Core" }
|
||||||
|
Depends { name: "CppTools" }
|
||||||
|
Depends { name: "ExtensionSystem" }
|
||||||
|
Depends { name: "ProjectExplorer" }
|
||||||
|
Depends { name: "QtcSsh" }
|
||||||
|
Depends { name: "Utils" }
|
||||||
|
|
||||||
|
Depends { name: "Qt.widgets" }
|
||||||
|
|
||||||
|
pluginTestDepends: [
|
||||||
|
"QbsProjectManager",
|
||||||
|
"QmakeProjectManager",
|
||||||
|
]
|
||||||
|
|
||||||
|
files: [
|
||||||
|
"clangstaticanalyzerconfigwidget.cpp",
|
||||||
|
"clangstaticanalyzerconfigwidget.h",
|
||||||
|
"clangstaticanalyzerconfigwidget.ui",
|
||||||
|
"clangstaticanalyzerconstants.h",
|
||||||
|
"clangstaticanalyzerdiagnostic.cpp",
|
||||||
|
"clangstaticanalyzerdiagnostic.h",
|
||||||
|
"clangstaticanalyzerdiagnosticmodel.cpp",
|
||||||
|
"clangstaticanalyzerdiagnosticmodel.h",
|
||||||
|
"clangstaticanalyzerdiagnosticview.cpp",
|
||||||
|
"clangstaticanalyzerdiagnosticview.h",
|
||||||
|
"clangstaticanalyzerlogfilereader.cpp",
|
||||||
|
"clangstaticanalyzerlogfilereader.h",
|
||||||
|
"clangstaticanalyzerplugin.cpp",
|
||||||
|
"clangstaticanalyzerplugin.h",
|
||||||
|
"clangstaticanalyzerprojectsettings.cpp",
|
||||||
|
"clangstaticanalyzerprojectsettings.h",
|
||||||
|
"clangstaticanalyzerprojectsettingsmanager.cpp",
|
||||||
|
"clangstaticanalyzerprojectsettingsmanager.h",
|
||||||
|
"clangstaticanalyzerprojectsettingswidget.cpp",
|
||||||
|
"clangstaticanalyzerprojectsettingswidget.h",
|
||||||
|
"clangstaticanalyzerprojectsettingswidget.ui",
|
||||||
|
"clangstaticanalyzerruncontrol.cpp",
|
||||||
|
"clangstaticanalyzerruncontrol.h",
|
||||||
|
"clangstaticanalyzerruncontrolfactory.cpp",
|
||||||
|
"clangstaticanalyzerruncontrolfactory.h",
|
||||||
|
"clangstaticanalyzerrunner.cpp",
|
||||||
|
"clangstaticanalyzerrunner.h",
|
||||||
|
"clangstaticanalyzersettings.cpp",
|
||||||
|
"clangstaticanalyzersettings.h",
|
||||||
|
"clangstaticanalyzertool.cpp",
|
||||||
|
"clangstaticanalyzertool.h",
|
||||||
|
"clangstaticanalyzerutils.cpp",
|
||||||
|
"clangstaticanalyzerutils.h",
|
||||||
|
"clangstaticanalyzer_global.h",
|
||||||
|
]
|
||||||
|
|
||||||
|
Group {
|
||||||
|
name: "Unit tests"
|
||||||
|
condition: project.testsEnabled
|
||||||
|
files: [
|
||||||
|
"clangstaticanalyzerunittests.cpp",
|
||||||
|
"clangstaticanalyzerunittests.h",
|
||||||
|
"clangstaticanalyzerunittests.qrc",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Group {
|
||||||
|
name: "Unit test resources"
|
||||||
|
prefix: "unit-tests/"
|
||||||
|
fileTags: []
|
||||||
|
files: ["**/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
QTC_PLUGIN_NAME = ClangStaticAnalyzer
|
||||||
|
QTC_LIB_DEPENDS += \
|
||||||
|
extensionsystem \
|
||||||
|
utils
|
||||||
|
QTC_PLUGIN_DEPENDS += \
|
||||||
|
analyzerbase \
|
||||||
|
cpptools
|
||||||
|
QTC_TEST_DEPENDS += \
|
||||||
|
qbsprojectmanager \
|
||||||
|
qmakeprojectmanager
|
||||||
38
src/plugins/clangstaticanalyzer/clangstaticanalyzer_global.h
Normal file
38
src/plugins/clangstaticanalyzer/clangstaticanalyzer_global.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZER_GLOBAL_H
|
||||||
|
#define CLANGSTATICANALYZER_GLOBAL_H
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
#if defined(CLANGSTATICANALYZER_LIBRARY)
|
||||||
|
# define CLANGSTATICANALYZER_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
# define CLANGSTATICANALYZER_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZER_GLOBAL_H
|
||||||
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerconfigwidget.h"
|
||||||
|
#include "ui_clangstaticanalyzerconfigwidget.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerConfigWidget::ClangStaticAnalyzerConfigWidget(
|
||||||
|
ClangStaticAnalyzerSettings *settings,
|
||||||
|
QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_ui(new Ui::ClangStaticAnalyzerConfigWidget)
|
||||||
|
, m_settings(settings)
|
||||||
|
{
|
||||||
|
m_ui->setupUi(this);
|
||||||
|
|
||||||
|
Utils::PathChooser * const chooser = m_ui->clangExecutableChooser;
|
||||||
|
chooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
|
||||||
|
chooser->setHistoryCompleter(QLatin1String("ClangStaticAnalyzer.ClangCommand.History"));
|
||||||
|
chooser->setPromptDialogTitle(tr("Clang Command"));
|
||||||
|
const auto validator = [chooser](Utils::FancyLineEdit *edit, QString *errorMessage) {
|
||||||
|
const QString currentFilePath = chooser->fileName().toString();
|
||||||
|
Utils::PathChooser pc;
|
||||||
|
Utils::PathChooser *helperPathChooser;
|
||||||
|
if (currentFilePath.isEmpty()) {
|
||||||
|
pc.setExpectedKind(chooser->expectedKind());
|
||||||
|
pc.setPath(edit->placeholderText());
|
||||||
|
helperPathChooser = &pc;
|
||||||
|
} else {
|
||||||
|
helperPathChooser = chooser;
|
||||||
|
}
|
||||||
|
return chooser->defaultValidationFunction()(helperPathChooser->lineEdit(), errorMessage)
|
||||||
|
&& isClangExecutableUsable(helperPathChooser->fileName().toString(), errorMessage);
|
||||||
|
};
|
||||||
|
chooser->setValidationFunction(validator);
|
||||||
|
bool clangExeIsSet;
|
||||||
|
const QString clangExe = settings->clangExecutable(&clangExeIsSet);
|
||||||
|
chooser->lineEdit()->setPlaceholderText(settings->defaultClangExecutable());
|
||||||
|
if (clangExeIsSet) {
|
||||||
|
chooser->setPath(clangExe);
|
||||||
|
} else {
|
||||||
|
// Setting an empty string does not trigger the validator, as that is the initial value
|
||||||
|
// in the line edit.
|
||||||
|
chooser->setPath(QLatin1String(" "));
|
||||||
|
chooser->lineEdit()->clear();
|
||||||
|
}
|
||||||
|
connect(m_ui->clangExecutableChooser, &Utils::PathChooser::rawPathChanged,
|
||||||
|
[settings](const QString &path) { settings->setClangExecutable(path); });
|
||||||
|
|
||||||
|
m_ui->simultaneousProccessesSpinBox->setValue(settings->simultaneousProcesses());
|
||||||
|
m_ui->simultaneousProccessesSpinBox->setMinimum(1);
|
||||||
|
m_ui->simultaneousProccessesSpinBox->setMaximum(QThread::idealThreadCount());
|
||||||
|
connect(m_ui->simultaneousProccessesSpinBox,
|
||||||
|
static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
|
||||||
|
[settings](int count) { settings->setSimultaneousProcesses(count); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerConfigWidget::~ClangStaticAnalyzerConfigWidget()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERCONFIGWIDGET_H
|
||||||
|
#define CLANGSTATICANALYZERCONFIGWIDGET_H
|
||||||
|
|
||||||
|
#include "clangstaticanalyzersettings.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
namespace Ui { class ClangStaticAnalyzerConfigWidget; }
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerConfigWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ClangStaticAnalyzerConfigWidget(ClangStaticAnalyzerSettings *settings,
|
||||||
|
QWidget *parent = 0);
|
||||||
|
~ClangStaticAnalyzerConfigWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ClangStaticAnalyzerConfigWidget *m_ui;
|
||||||
|
ClangStaticAnalyzerSettings *m_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERCONFIGWIDGET_H
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ClangStaticAnalyzer::Internal::ClangStaticAnalyzerConfigWidget</class>
|
||||||
|
<widget class="QWidget" name="ClangStaticAnalyzer::Internal::ClangStaticAnalyzerConfigWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Clang executable:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="Utils::PathChooser" name="clangExecutableChooser" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Simultaneous processes:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="simultaneousProccessesSpinBox">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>32</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>183</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>Utils::PathChooser</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header location="global">utils/pathchooser.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERCONSTANTS_H
|
||||||
|
#define CLANGSTATICANALYZERCONSTANTS_H
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Constants {
|
||||||
|
|
||||||
|
const char SETTINGS_ID[] = "ClangStaticAnalyzer";
|
||||||
|
const char CLANGSTATICANALYZER_RUN_MODE[] = "ClangStaticAnalyzer.RunMode";
|
||||||
|
|
||||||
|
} // Constants
|
||||||
|
} // ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERCONSTANTS_H
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerdiagnostic.h"
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ExplainingStep::ExplainingStep()
|
||||||
|
: depth(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExplainingStep::isValid() const
|
||||||
|
{
|
||||||
|
return location.isValid() && !ranges.isEmpty() && !message.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Diagnostic::isValid() const
|
||||||
|
{
|
||||||
|
return !description.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALZYERDIAGNOSTIC_H
|
||||||
|
#define CLANGSTATICANALZYERDIAGNOSTIC_H
|
||||||
|
|
||||||
|
#include <analyzerbase/diagnosticlocation.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QMetaType>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ExplainingStep
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExplainingStep();
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
QString message;
|
||||||
|
QString extendedMessage;
|
||||||
|
Analyzer::DiagnosticLocation location;
|
||||||
|
QList<Analyzer::DiagnosticLocation> ranges;
|
||||||
|
int depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Diagnostic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
QString description;
|
||||||
|
QString category;
|
||||||
|
QString type;
|
||||||
|
QString issueContextKind;
|
||||||
|
QString issueContext;
|
||||||
|
Analyzer::DiagnosticLocation location;
|
||||||
|
QList<ExplainingStep> explainingSteps;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(ClangStaticAnalyzer::Internal::Diagnostic)
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALZYERDIAGNOSTIC_H
|
||||||
@@ -0,0 +1,357 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerdiagnosticmodel.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnosticview.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettingsmanager.h"
|
||||||
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <projectexplorer/session.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class DiagnosticItem : public Utils::TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DiagnosticItem(const Diagnostic &diag);
|
||||||
|
|
||||||
|
Diagnostic diagnostic() const { return m_diagnostic; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVariant data(int column, int role) const override;
|
||||||
|
|
||||||
|
const Diagnostic m_diagnostic;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExplainingStepItem : public Utils::TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExplainingStepItem(const ExplainingStep &step);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QVariant data(int column, int role) const override;
|
||||||
|
|
||||||
|
const ExplainingStep m_step;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClangStaticAnalyzerDiagnosticModel::ClangStaticAnalyzerDiagnosticModel(QObject *parent)
|
||||||
|
: Utils::TreeModel(parent)
|
||||||
|
{
|
||||||
|
setHeader(QStringList() << tr("Issue") << tr("Location"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticModel::addDiagnostics(const QList<Diagnostic> &diagnostics)
|
||||||
|
{
|
||||||
|
foreach (const Diagnostic &d, diagnostics)
|
||||||
|
rootItem()->appendChild(new DiagnosticItem(d));
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Diagnostic> ClangStaticAnalyzerDiagnosticModel::diagnostics() const
|
||||||
|
{
|
||||||
|
QList<Diagnostic> diags;
|
||||||
|
foreach (const Utils::TreeItem * const item, rootItem()->children())
|
||||||
|
diags << static_cast<const DiagnosticItem *>(item)->diagnostic();
|
||||||
|
return diags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createDiagnosticToolTipString(const Diagnostic &diagnostic)
|
||||||
|
{
|
||||||
|
typedef QPair<QString, QString> StringPair;
|
||||||
|
QList<StringPair> lines;
|
||||||
|
|
||||||
|
if (!diagnostic.category.isEmpty()) {
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::Diagnostic", "Category:"),
|
||||||
|
diagnostic.category.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!diagnostic.type.isEmpty()) {
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::Diagnostic", "Type:"),
|
||||||
|
diagnostic.type.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!diagnostic.issueContext.isEmpty() && !diagnostic.issueContextKind.isEmpty()) {
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::Diagnostic", "Context:"),
|
||||||
|
diagnostic.issueContextKind.toHtmlEscaped() + QLatin1Char(' ')
|
||||||
|
+ diagnostic.issueContext.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::Diagnostic", "Location:"),
|
||||||
|
createFullLocationString(diagnostic.location));
|
||||||
|
|
||||||
|
QString html = QLatin1String("<html>"
|
||||||
|
"<head>"
|
||||||
|
"<style>dt { font-weight:bold; } dd { font-family: monospace; }</style>\n"
|
||||||
|
"<body><dl>");
|
||||||
|
|
||||||
|
foreach (const StringPair &pair, lines) {
|
||||||
|
html += QLatin1String("<dt>");
|
||||||
|
html += pair.first;
|
||||||
|
html += QLatin1String("</dt><dd>");
|
||||||
|
html += pair.second;
|
||||||
|
html += QLatin1String("</dd>\n");
|
||||||
|
}
|
||||||
|
html += QLatin1String("</dl></body></html>");
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createExplainingStepToolTipString(const ExplainingStep &step)
|
||||||
|
{
|
||||||
|
if (step.message == step.extendedMessage)
|
||||||
|
return createFullLocationString(step.location);
|
||||||
|
|
||||||
|
typedef QPair<QString, QString> StringPair;
|
||||||
|
QList<StringPair> lines;
|
||||||
|
|
||||||
|
if (!step.message.isEmpty()) {
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Message:"),
|
||||||
|
step.message.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
if (!step.extendedMessage.isEmpty()) {
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Extended Message:"),
|
||||||
|
step.extendedMessage.toHtmlEscaped());
|
||||||
|
}
|
||||||
|
|
||||||
|
lines << qMakePair(
|
||||||
|
QCoreApplication::translate("ClangStaticAnalyzer::ExplainingStep", "Location:"),
|
||||||
|
createFullLocationString(step.location));
|
||||||
|
|
||||||
|
QString html = QLatin1String("<html>"
|
||||||
|
"<head>"
|
||||||
|
"<style>dt { font-weight:bold; } dd { font-family: monospace; }</style>\n"
|
||||||
|
"<body><dl>");
|
||||||
|
|
||||||
|
foreach (const StringPair &pair, lines) {
|
||||||
|
html += QLatin1String("<dt>");
|
||||||
|
html += pair.first;
|
||||||
|
html += QLatin1String("</dt><dd>");
|
||||||
|
html += pair.second;
|
||||||
|
html += QLatin1String("</dd>\n");
|
||||||
|
}
|
||||||
|
html += QLatin1String("</dl></body></html>");
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createLocationString(const Analyzer::DiagnosticLocation &location)
|
||||||
|
{
|
||||||
|
const QString filePath = location.filePath;
|
||||||
|
const QString lineNumber = QString::number(location.line);
|
||||||
|
const QString fileAndLine = filePath + QLatin1Char(':') + lineNumber;
|
||||||
|
return QLatin1String("in ") + fileAndLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createExplainingStepNumberString(int number)
|
||||||
|
{
|
||||||
|
const int fieldWidth = 2;
|
||||||
|
return QString::fromLatin1("%1:").arg(number, fieldWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createExplainingStepString(const ExplainingStep &explainingStep, int number)
|
||||||
|
{
|
||||||
|
return createExplainingStepNumberString(number)
|
||||||
|
+ QLatin1Char(' ')
|
||||||
|
+ explainingStep.extendedMessage
|
||||||
|
+ QLatin1Char(' ')
|
||||||
|
+ createLocationString(explainingStep.location);
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString fullText(const Diagnostic &diagnostic)
|
||||||
|
{
|
||||||
|
// Summary.
|
||||||
|
QString text = diagnostic.category + QLatin1String(": ") + diagnostic.type;
|
||||||
|
if (diagnostic.type != diagnostic.description)
|
||||||
|
text += QLatin1String(": ") + diagnostic.description;
|
||||||
|
text += QLatin1Char('\n');
|
||||||
|
|
||||||
|
// Explaining steps.
|
||||||
|
int explainingStepNumber = 1;
|
||||||
|
foreach (const ExplainingStep &explainingStep, diagnostic.explainingSteps) {
|
||||||
|
text += createExplainingStepString(explainingStep, explainingStepNumber++)
|
||||||
|
+ QLatin1Char('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
text.chop(1); // Trailing newline.
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DiagnosticItem::DiagnosticItem(const Diagnostic &diag) : m_diagnostic(diag)
|
||||||
|
{
|
||||||
|
// Don't show explaining steps if they add no information.
|
||||||
|
if (diag.explainingSteps.count() == 1) {
|
||||||
|
const ExplainingStep &step = diag.explainingSteps.first();
|
||||||
|
if (step.message == diag.description && step.location == diag.location)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const ExplainingStep &s, diag.explainingSteps)
|
||||||
|
appendChild(new ExplainingStepItem(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant locationData(int role, const Analyzer::DiagnosticLocation &location)
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case Analyzer::DetailedErrorView::LocationRole:
|
||||||
|
return QVariant::fromValue(location);
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return location.filePath.isEmpty() ? QVariant() : QVariant(location.filePath);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant DiagnosticItem::data(int column, int role) const
|
||||||
|
{
|
||||||
|
if (column == Analyzer::DetailedErrorView::LocationColumn)
|
||||||
|
return locationData(role, m_diagnostic.location);
|
||||||
|
|
||||||
|
// DiagnosticColumn
|
||||||
|
switch (role) {
|
||||||
|
case Analyzer::DetailedErrorView::FullTextRole:
|
||||||
|
return fullText(m_diagnostic);
|
||||||
|
case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole:
|
||||||
|
return QVariant::fromValue(m_diagnostic);
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return m_diagnostic.description;
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return createDiagnosticToolTipString(m_diagnostic);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplainingStepItem::ExplainingStepItem(const ExplainingStep &step) : m_step(step)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ExplainingStepItem::data(int column, int role) const
|
||||||
|
{
|
||||||
|
if (column == Analyzer::DetailedErrorView::LocationColumn)
|
||||||
|
return locationData(role, m_step.location);
|
||||||
|
|
||||||
|
// DiagnosticColumn
|
||||||
|
switch (role) {
|
||||||
|
case Analyzer::DetailedErrorView::FullTextRole:
|
||||||
|
return fullText(static_cast<DiagnosticItem *>(parent())->diagnostic());
|
||||||
|
case ClangStaticAnalyzerDiagnosticModel::DiagnosticRole:
|
||||||
|
return QVariant::fromValue(static_cast<DiagnosticItem *>(parent())->diagnostic());
|
||||||
|
case Qt::DisplayRole: {
|
||||||
|
const int row = parent()->children().indexOf(const_cast<ExplainingStepItem *>(this)) + 1;
|
||||||
|
const int padding = static_cast<int>(std::log10(parent()->rowCount()))
|
||||||
|
- static_cast<int>(std::log10(row));
|
||||||
|
return QString::fromLatin1("%1%2: %3")
|
||||||
|
.arg(QString(padding, QLatin1Char(' ')))
|
||||||
|
.arg(row)
|
||||||
|
.arg(m_step.message);
|
||||||
|
}
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return createExplainingStepToolTipString(m_step);
|
||||||
|
default:
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ClangStaticAnalyzerDiagnosticFilterModel::ClangStaticAnalyzerDiagnosticFilterModel(QObject *parent)
|
||||||
|
: QSortFilterProxyModel(parent)
|
||||||
|
{
|
||||||
|
// So that when a user closes and re-opens a project and *then* clicks "Suppress",
|
||||||
|
// we enter that information into the project settings.
|
||||||
|
connect(ProjectExplorer::SessionManager::instance(),
|
||||||
|
&ProjectExplorer::SessionManager::projectAdded, this,
|
||||||
|
[this](ProjectExplorer::Project *project) {
|
||||||
|
if (!m_project && project->projectDirectory() == m_lastProjectDirectory)
|
||||||
|
setProject(project);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticFilterModel::setProject(ProjectExplorer::Project *project)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(project, return);
|
||||||
|
if (m_project) {
|
||||||
|
disconnect(ProjectSettingsManager::getSettings(m_project),
|
||||||
|
&ProjectSettings::suppressedDiagnosticsChanged, this,
|
||||||
|
&ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged);
|
||||||
|
}
|
||||||
|
m_project = project;
|
||||||
|
m_lastProjectDirectory = m_project->projectDirectory();
|
||||||
|
connect(ProjectSettingsManager::getSettings(m_project),
|
||||||
|
&ProjectSettings::suppressedDiagnosticsChanged,
|
||||||
|
this, &ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged);
|
||||||
|
handleSuppressedDiagnosticsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticFilterModel::addSuppressedDiagnostic(
|
||||||
|
const SuppressedDiagnostic &diag)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_project, return);
|
||||||
|
m_suppressedDiagnostics << diag;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerDiagnosticFilterModel::filterAcceptsRow(int sourceRow,
|
||||||
|
const QModelIndex &sourceParent) const
|
||||||
|
{
|
||||||
|
if (sourceParent.isValid())
|
||||||
|
return true;
|
||||||
|
const Diagnostic diag = static_cast<ClangStaticAnalyzerDiagnosticModel *>(sourceModel())
|
||||||
|
->diagnostics().at(sourceRow);
|
||||||
|
foreach (const SuppressedDiagnostic &d, m_suppressedDiagnostics) {
|
||||||
|
if (d.description != diag.description)
|
||||||
|
continue;
|
||||||
|
QString filePath = d.filePath.toString();
|
||||||
|
QFileInfo fi(filePath);
|
||||||
|
if (fi.isRelative())
|
||||||
|
filePath = m_lastProjectDirectory.toString() + QLatin1Char('/') + filePath;
|
||||||
|
if (filePath == diag.location.filePath)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticFilterModel::handleSuppressedDiagnosticsChanged()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_project, return);
|
||||||
|
m_suppressedDiagnostics
|
||||||
|
= ProjectSettingsManager::getSettings(m_project)->suppressedDiagnostics();
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERDIAGNOSTICMODEL_H
|
||||||
|
#define CLANGSTATICANALYZERDIAGNOSTICMODEL_H
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettings.h"
|
||||||
|
|
||||||
|
#include <analyzerbase/detailederrorview.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
namespace ProjectExplorer { class Project; }
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerDiagnosticModel : public Utils::TreeModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerDiagnosticModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
void addDiagnostics(const QList<Diagnostic> &diagnostics);
|
||||||
|
QList<Diagnostic> diagnostics() const;
|
||||||
|
|
||||||
|
enum ItemRole {
|
||||||
|
DiagnosticRole = Analyzer::DetailedErrorView::FullTextRole + 1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerDiagnosticFilterModel : public QSortFilterProxyModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerDiagnosticFilterModel(QObject *parent = 0);
|
||||||
|
|
||||||
|
void setProject(ProjectExplorer::Project *project);
|
||||||
|
void addSuppressedDiagnostic(const SuppressedDiagnostic &diag);
|
||||||
|
ProjectExplorer::Project *project() const { return m_project; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||||
|
void handleSuppressedDiagnosticsChanged();
|
||||||
|
|
||||||
|
QPointer<ProjectExplorer::Project> m_project;
|
||||||
|
Utils::FileName m_lastProjectDirectory;
|
||||||
|
SuppressedDiagnosticsList m_suppressedDiagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERDIAGNOSTICMODEL_H
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerdiagnosticview.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnosticmodel.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettings.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettingsmanager.h"
|
||||||
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerDiagnosticView::ClangStaticAnalyzerDiagnosticView(QWidget *parent)
|
||||||
|
: Analyzer::DetailedErrorView(parent)
|
||||||
|
{
|
||||||
|
m_suppressAction = new QAction(tr("Suppress this diagnostic"), this);
|
||||||
|
connect(m_suppressAction, &QAction::triggered, [this](bool) { suppressCurrentDiagnostic(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerDiagnosticView::suppressCurrentDiagnostic()
|
||||||
|
{
|
||||||
|
const QModelIndexList indexes = selectionModel()->selectedRows();
|
||||||
|
QTC_ASSERT(indexes.count() == 1, return);
|
||||||
|
const Diagnostic diag = model()->data(indexes.first(),
|
||||||
|
ClangStaticAnalyzerDiagnosticModel::DiagnosticRole)
|
||||||
|
.value<Diagnostic>();
|
||||||
|
QTC_ASSERT(diag.isValid(), return);
|
||||||
|
|
||||||
|
// If the original project was closed, we work directly on the filter model, otherwise
|
||||||
|
// we go via the project settings.
|
||||||
|
auto * const filterModel = static_cast<ClangStaticAnalyzerDiagnosticFilterModel *>(model());
|
||||||
|
ProjectExplorer::Project * const project = filterModel->project();
|
||||||
|
if (project) {
|
||||||
|
Utils::FileName filePath = Utils::FileName::fromString(diag.location.filePath);
|
||||||
|
const Utils::FileName relativeFilePath
|
||||||
|
= filePath.relativeChildPath(project->projectDirectory());
|
||||||
|
if (!relativeFilePath.isEmpty())
|
||||||
|
filePath = relativeFilePath;
|
||||||
|
const SuppressedDiagnostic supDiag(filePath, diag.description, diag.issueContextKind,
|
||||||
|
diag.issueContext, diag.explainingSteps.count());
|
||||||
|
ProjectSettingsManager::getSettings(project)->addSuppressedDiagnostic(supDiag);
|
||||||
|
} else {
|
||||||
|
filterModel->addSuppressedDiagnostic(SuppressedDiagnostic(diag));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QAction *> ClangStaticAnalyzerDiagnosticView::customActions() const
|
||||||
|
{
|
||||||
|
return QList<QAction *>() << m_suppressAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERDIAGNOSTICVIEW_H
|
||||||
|
#define CLANGSTATICANALYZERDIAGNOSTICVIEW_H
|
||||||
|
|
||||||
|
#include <analyzerbase/detailederrorview.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerDiagnosticView : public Analyzer::DetailedErrorView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerDiagnosticView(QWidget *parent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void suppressCurrentDiagnostic();
|
||||||
|
|
||||||
|
QList<QAction *> customActions() const;
|
||||||
|
|
||||||
|
QAction *m_suppressAction;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERDIAGNOSTICVIEW_H
|
||||||
@@ -0,0 +1,381 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerlogfilereader.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class 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();
|
||||||
|
Analyzer::DiagnosticLocation readLocationDict(bool elementIsRead = false);
|
||||||
|
QList<Analyzer::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;
|
||||||
|
};
|
||||||
|
|
||||||
|
QList<Diagnostic> LogFileReader::read(const QString &filePath, QString *errorMessage)
|
||||||
|
{
|
||||||
|
const QList<Diagnostic> emptyList;
|
||||||
|
|
||||||
|
// Check file path
|
||||||
|
QFileInfo fi(filePath);
|
||||||
|
if (!fi.exists() || !fi.isReadable()) {
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = QObject::tr("File \"%1\" does not exist or is not readable.")
|
||||||
|
.arg(filePath);
|
||||||
|
}
|
||||||
|
return emptyList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 = QObject::tr("Could not read file \"%1\": UnexpectedElementError.")
|
||||||
|
.arg(filePath);
|
||||||
|
} // fall-through
|
||||||
|
case QXmlStreamReader::CustomError:
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = QObject::tr("Could not read file \"%1\": CustomError.")
|
||||||
|
.arg(filePath);
|
||||||
|
} // fall-through
|
||||||
|
case QXmlStreamReader::NotWellFormedError:
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = QObject::tr("Could not read file \"%1\": NotWellFormedError.")
|
||||||
|
.arg(filePath);
|
||||||
|
} // fall-through
|
||||||
|
case QXmlStreamReader::PrematureEndOfDocumentError:
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = QObject::tr("Could not read file \"%1\": PrematureEndOfDocumentError.")
|
||||||
|
.arg(filePath);
|
||||||
|
} // fall-through
|
||||||
|
default:
|
||||||
|
return emptyList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(QObject::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Analyzer::DiagnosticLocation ClangStaticAnalyzerLogFileReader::readLocationDict(bool elementIsRead)
|
||||||
|
{
|
||||||
|
Analyzer::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 = Analyzer::DiagnosticLocation(m_referencedFiles.at(fileIndex), line, column);
|
||||||
|
}
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Analyzer::DiagnosticLocation> ClangStaticAnalyzerLogFileReader::readRangesArray()
|
||||||
|
{
|
||||||
|
QList<Analyzer::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(QObject::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(QObject::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(QObject::tr("Expected an integer element."));
|
||||||
|
if (convertedSuccessfully)
|
||||||
|
*convertedSuccessfully = false;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERLOGFILEREADER_H
|
||||||
|
#define CLANGSTATICANALYZERLOGFILEREADER_H
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class LogFileReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QList<Diagnostic> read(const QString &filePath, QString *errorMessage);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERLOGFILEREADER_H
|
||||||
184
src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
Normal file
184
src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerplugin.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerconfigwidget.h"
|
||||||
|
#include "clangstaticanalyzerconstants.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettingswidget.h"
|
||||||
|
#include "clangstaticanalyzerruncontrolfactory.h"
|
||||||
|
#include "clangstaticanalyzertool.h"
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
#include "clangstaticanalyzerunittests.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzermanager.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
|
#include <coreplugin/actionmanager/command.h>
|
||||||
|
#include <coreplugin/actionmanager/actioncontainer.h>
|
||||||
|
#include <coreplugin/coreconstants.h>
|
||||||
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
|
#include <projectexplorer/projectpanelfactory.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QMenu>
|
||||||
|
|
||||||
|
#include <QtPlugin>
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerOptionsPage : public Core::IOptionsPage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ClangStaticAnalyzerOptionsPage()
|
||||||
|
{
|
||||||
|
setId("Analyzer.ClangStaticAnalyzer.Settings"); // TODO: Get it from "clangstaticanalyzersettings.h"
|
||||||
|
setDisplayName(QCoreApplication::translate(
|
||||||
|
"ClangStaticAnalyzer::Internal::ClangStaticAnalyzerOptionsPage",
|
||||||
|
"Clang Static Analyzer"));
|
||||||
|
setCategory("T.Analyzer");
|
||||||
|
setDisplayCategory(QCoreApplication::translate("Analyzer", "Analyzer"));
|
||||||
|
setCategoryIcon(QLatin1String(":/images/analyzer_category.png"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *widget()
|
||||||
|
{
|
||||||
|
if (!m_widget)
|
||||||
|
m_widget = new ClangStaticAnalyzerConfigWidget(ClangStaticAnalyzerSettings::instance());
|
||||||
|
return m_widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply()
|
||||||
|
{
|
||||||
|
ClangStaticAnalyzerSettings::instance()->writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void finish()
|
||||||
|
{
|
||||||
|
delete m_widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<QWidget> m_widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClangStaticAnalyzerPlugin::ClangStaticAnalyzerPlugin()
|
||||||
|
{
|
||||||
|
// Create your members
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerPlugin::~ClangStaticAnalyzerPlugin()
|
||||||
|
{
|
||||||
|
// Unregister objects from the plugin manager's object pool
|
||||||
|
// Delete members
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerPlugin::initialize(const QStringList &arguments, QString *errorString)
|
||||||
|
{
|
||||||
|
// Register objects in the plugin manager's object pool
|
||||||
|
// Load settings
|
||||||
|
// Add actions to menus
|
||||||
|
// Connect to other plugins' signals
|
||||||
|
// In the initialize method, a plugin can be sure that the plugins it
|
||||||
|
// depends on have initialized their members.
|
||||||
|
|
||||||
|
auto panelFactory = new ProjectExplorer::ProjectPanelFactory();
|
||||||
|
panelFactory->setPriority(100);
|
||||||
|
panelFactory->setDisplayName(tr("Clang Static Analyzer Settings"));
|
||||||
|
panelFactory->setSimpleCreateWidgetFunction<ProjectSettingsWidget>(QIcon());
|
||||||
|
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
|
||||||
|
return initializeEnterpriseFeatures(arguments, errorString);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerPlugin::initializeEnterpriseFeatures(const QStringList &arguments,
|
||||||
|
QString *errorString)
|
||||||
|
{
|
||||||
|
Q_UNUSED(arguments);
|
||||||
|
Q_UNUSED(errorString);
|
||||||
|
|
||||||
|
auto tool = m_analyzerTool = new ClangStaticAnalyzerTool(this);
|
||||||
|
addAutoReleasedObject(new ClangStaticAnalyzerRunControlFactory(m_analyzerTool));
|
||||||
|
addAutoReleasedObject(new ClangStaticAnalyzerOptionsPage);
|
||||||
|
|
||||||
|
auto widgetCreator = [tool] { return tool->createWidgets(); };
|
||||||
|
auto runControlCreator = [tool](const AnalyzerStartParameters &,
|
||||||
|
ProjectExplorer::RunConfiguration *runConfiguration, Core::Id runMode) {
|
||||||
|
return tool->createRunControl(runConfiguration, runMode);
|
||||||
|
};
|
||||||
|
|
||||||
|
const QString toolTip = tr("Clang Static Analyzer uses the analyzer from the clang project "
|
||||||
|
"to find bugs.");
|
||||||
|
|
||||||
|
auto action = new AnalyzerAction(this);
|
||||||
|
action->setRunMode(Constants::CLANGSTATICANALYZER_RUN_MODE);
|
||||||
|
action->setToolId(ClangStaticAnalyzerToolId);
|
||||||
|
action->setActionId("ClangStaticAnalyzer");
|
||||||
|
action->setWidgetCreator(widgetCreator);
|
||||||
|
action->setRunControlCreator(runControlCreator);
|
||||||
|
action->setCustomToolStarter([tool] { tool->startTool(); });
|
||||||
|
action->setText(tr("Clang Static Analyzer"));
|
||||||
|
action->setToolTip(toolTip);
|
||||||
|
action->setMenuGroup(Analyzer::Constants::G_ANALYZER_TOOLS);
|
||||||
|
action->setEnabled(false);
|
||||||
|
AnalyzerManager::addAction(action);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerPlugin::extensionsInitialized()
|
||||||
|
{
|
||||||
|
// Retrieve objects from the plugin manager's object pool
|
||||||
|
// In the extensionsInitialized method, a plugin can be sure that all
|
||||||
|
// plugins that depend on it are completely initialized.
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtensionSystem::IPlugin::ShutdownFlag ClangStaticAnalyzerPlugin::aboutToShutdown()
|
||||||
|
{
|
||||||
|
// Save settings
|
||||||
|
// Disconnect from signals that are not needed during shutdown
|
||||||
|
// Hide UI (if you add UI that is not in the main window directly)
|
||||||
|
return SynchronousShutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QObject *> ClangStaticAnalyzerPlugin::createTestObjects() const
|
||||||
|
{
|
||||||
|
QList<QObject *> tests;
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
tests << new ClangStaticAnalyzerUnitTests(m_analyzerTool);
|
||||||
|
#endif
|
||||||
|
return tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzerPlugin
|
||||||
61
src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.h
Normal file
61
src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERPLUGIN_H
|
||||||
|
#define CLANGSTATICANALYZERPLUGIN_H
|
||||||
|
|
||||||
|
#include <extensionsystem/iplugin.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerTool;
|
||||||
|
class ClangStaticAnalyzerSettings;
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerPlugin : public ExtensionSystem::IPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "ClangStaticAnalyzer.json")
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerPlugin();
|
||||||
|
~ClangStaticAnalyzerPlugin();
|
||||||
|
|
||||||
|
bool initialize(const QStringList &arguments, QString *errorString);
|
||||||
|
bool initializeEnterpriseFeatures(const QStringList &arguments, QString *errorString);
|
||||||
|
void extensionsInitialized();
|
||||||
|
ShutdownFlag aboutToShutdown();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<QObject *> createTestObjects() const;
|
||||||
|
|
||||||
|
ClangStaticAnalyzerTool *m_analyzerTool;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzerPlugin
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERPLUGIN_H
|
||||||
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerprojectsettings.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticsKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnostics");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticFilePathKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticFilePath");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticMessageKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticMessage");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticContextKindKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticContextKind");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticContextKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticContext");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString suppressedDiagnosticUniquifierKey()
|
||||||
|
{
|
||||||
|
return QLatin1String("ClangStaticAnalyzer.SuppressedDiagnosticUniquifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectSettings::ProjectSettings(ProjectExplorer::Project *project) : m_project(project)
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
connect(project, &ProjectExplorer::Project::aboutToSaveSettings, this,
|
||||||
|
&ProjectSettings::store);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettings::addSuppressedDiagnostic(const SuppressedDiagnostic &diag)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_suppressedDiagnostics.contains(diag), return);
|
||||||
|
m_suppressedDiagnostics << diag;
|
||||||
|
emit suppressedDiagnosticsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettings::removeSuppressedDiagnostic(const SuppressedDiagnostic &diag)
|
||||||
|
{
|
||||||
|
const bool wasPresent = m_suppressedDiagnostics.removeOne(diag);
|
||||||
|
QTC_ASSERT(wasPresent, return);
|
||||||
|
emit suppressedDiagnosticsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettings::removeAllSuppressedDiagnostics()
|
||||||
|
{
|
||||||
|
m_suppressedDiagnostics.clear();
|
||||||
|
emit suppressedDiagnosticsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettings::load()
|
||||||
|
{
|
||||||
|
const QVariantList list = m_project->namedSettings(suppressedDiagnosticsKey()).toList();
|
||||||
|
foreach (const QVariant &v, list) {
|
||||||
|
const QVariantMap diag = v.toMap();
|
||||||
|
const QString fp = diag.value(suppressedDiagnosticFilePathKey()).toString();
|
||||||
|
if (fp.isEmpty())
|
||||||
|
continue;
|
||||||
|
const QString message = diag.value(suppressedDiagnosticMessageKey()).toString();
|
||||||
|
if (message.isEmpty())
|
||||||
|
continue;
|
||||||
|
Utils::FileName fullPath = Utils::FileName::fromString(fp);
|
||||||
|
if (fullPath.toFileInfo().isRelative()) {
|
||||||
|
fullPath = m_project->projectDirectory();
|
||||||
|
fullPath.appendPath(fp);
|
||||||
|
}
|
||||||
|
if (!fullPath.exists())
|
||||||
|
continue;
|
||||||
|
const QString contextKind = diag.value(suppressedDiagnosticContextKindKey()).toString();
|
||||||
|
const QString context = diag.value(suppressedDiagnosticContextKey()).toString();
|
||||||
|
const int uniquifier = diag.value(suppressedDiagnosticUniquifierKey()).toInt();
|
||||||
|
m_suppressedDiagnostics << SuppressedDiagnostic(Utils::FileName::fromString(fp), message,
|
||||||
|
contextKind, context, uniquifier);
|
||||||
|
}
|
||||||
|
emit suppressedDiagnosticsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettings::store()
|
||||||
|
{
|
||||||
|
QVariantList list;
|
||||||
|
foreach (const SuppressedDiagnostic &diag, m_suppressedDiagnostics) {
|
||||||
|
QVariantMap diagMap;
|
||||||
|
diagMap.insert(suppressedDiagnosticFilePathKey(), diag.filePath.toString());
|
||||||
|
diagMap.insert(suppressedDiagnosticMessageKey(), diag.description);
|
||||||
|
diagMap.insert(suppressedDiagnosticContextKindKey(), diag.contextKind);
|
||||||
|
diagMap.insert(suppressedDiagnosticContextKey(), diag.context);
|
||||||
|
diagMap.insert(suppressedDiagnosticUniquifierKey(), diag.uniquifier);
|
||||||
|
list << diagMap;
|
||||||
|
}
|
||||||
|
m_project->setNamedSettings(suppressedDiagnosticsKey(), list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SuppressedDiagnostic::SuppressedDiagnostic(const Diagnostic &diag)
|
||||||
|
: filePath(Utils::FileName::fromString(diag.location.filePath))
|
||||||
|
, description(diag.description)
|
||||||
|
, contextKind(diag.issueContextKind)
|
||||||
|
, context(diag.issueContext)
|
||||||
|
, uniquifier(diag.explainingSteps.count())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERPROJECTSETTINGS_H
|
||||||
|
#define CLANGSTATICANALYZERPROJECTSETTINGS_H
|
||||||
|
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
class Diagnostic;
|
||||||
|
|
||||||
|
class SuppressedDiagnostic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SuppressedDiagnostic(const Utils::FileName &filePath, const QString &description,
|
||||||
|
const QString &contextKind, const QString &context, int uniquifier)
|
||||||
|
: filePath(filePath)
|
||||||
|
, description(description)
|
||||||
|
, contextKind(contextKind)
|
||||||
|
, context(context)
|
||||||
|
, uniquifier(uniquifier)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SuppressedDiagnostic(const Diagnostic &diag);
|
||||||
|
|
||||||
|
Utils::FileName filePath; // Relative for files in project, absolute otherwise.
|
||||||
|
QString description;
|
||||||
|
QString contextKind;
|
||||||
|
QString context;
|
||||||
|
int uniquifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(const SuppressedDiagnostic &d1, const SuppressedDiagnostic &d2)
|
||||||
|
{
|
||||||
|
return d1.filePath == d2.filePath && d1.description == d2.description
|
||||||
|
&& d1.contextKind == d2.contextKind && d1.context == d2.context
|
||||||
|
&& d1.uniquifier == d2.uniquifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef QList<SuppressedDiagnostic> SuppressedDiagnosticsList;
|
||||||
|
|
||||||
|
class ProjectSettings : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ProjectSettings(ProjectExplorer::Project *project);
|
||||||
|
|
||||||
|
SuppressedDiagnosticsList suppressedDiagnostics() const { return m_suppressedDiagnostics; }
|
||||||
|
void addSuppressedDiagnostic(const SuppressedDiagnostic &diag);
|
||||||
|
void removeSuppressedDiagnostic(const SuppressedDiagnostic &diag);
|
||||||
|
void removeAllSuppressedDiagnostics();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void suppressedDiagnosticsChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void load();
|
||||||
|
void store();
|
||||||
|
|
||||||
|
ProjectExplorer::Project * const m_project;
|
||||||
|
SuppressedDiagnosticsList m_suppressedDiagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // Include guard.
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerprojectsettingsmanager.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerprojectsettings.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/session.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ProjectSettingsManager::ProjectSettingsManager()
|
||||||
|
{
|
||||||
|
QObject::connect(ProjectExplorer::SessionManager::instance(),
|
||||||
|
&ProjectExplorer::SessionManager::aboutToRemoveProject,
|
||||||
|
&ProjectSettingsManager::handleProjectToBeRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectSettings *ProjectSettingsManager::getSettings(ProjectExplorer::Project *project)
|
||||||
|
{
|
||||||
|
auto &settings = m_settings[project];
|
||||||
|
if (!settings)
|
||||||
|
settings.reset(new ProjectSettings(project));
|
||||||
|
return settings.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsManager::handleProjectToBeRemoved(ProjectExplorer::Project *project)
|
||||||
|
{
|
||||||
|
m_settings.remove(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectSettingsManager::SettingsMap ProjectSettingsManager::m_settings;
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERPROJECTSETTINGSMANAGER_H
|
||||||
|
#define CLANGSTATICANALYZERPROJECTSETTINGSMANAGER_H
|
||||||
|
|
||||||
|
namespace ProjectExplorer { class Project; }
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
class ProjectSettings;
|
||||||
|
|
||||||
|
class ProjectSettingsManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProjectSettingsManager();
|
||||||
|
|
||||||
|
static ProjectSettings *getSettings(ProjectExplorer::Project *project);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void handleProjectToBeRemoved(ProjectExplorer::Project *project);
|
||||||
|
|
||||||
|
typedef QHash<ProjectExplorer::Project *, QSharedPointer<ProjectSettings>> SettingsMap;
|
||||||
|
static SettingsMap m_settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // Include guard.
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerprojectsettingswidget.h"
|
||||||
|
#include "ui_clangstaticanalyzerprojectsettingswidget.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerprojectsettings.h"
|
||||||
|
#include "clangstaticanalyzerprojectsettingsmanager.h"
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class SuppressedDiagnosticsModel : public QAbstractTableModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SuppressedDiagnosticsModel(QObject *parent = 0) : QAbstractTableModel(parent) { }
|
||||||
|
|
||||||
|
void setDiagnostics(const SuppressedDiagnosticsList &diagnostics);
|
||||||
|
SuppressedDiagnostic diagnosticAt(int i) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Columns { ColumnFile, ColumnContext, ColumnDescription, ColumnLast = ColumnDescription };
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||||
|
int columnCount(const QModelIndex & = QModelIndex()) const { return ColumnLast + 1; }
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||||
|
|
||||||
|
SuppressedDiagnosticsList m_diagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
ProjectSettingsWidget::ProjectSettingsWidget(ProjectExplorer::Project *project, QWidget *parent) :
|
||||||
|
QWidget(parent),
|
||||||
|
m_ui(new Ui::ProjectSettingsWidget)
|
||||||
|
, m_projectSettings(ProjectSettingsManager::getSettings(project))
|
||||||
|
{
|
||||||
|
m_ui->setupUi(this);
|
||||||
|
auto * const model = new SuppressedDiagnosticsModel(this);
|
||||||
|
model->setDiagnostics(m_projectSettings->suppressedDiagnostics());
|
||||||
|
connect(m_projectSettings, &ProjectSettings::suppressedDiagnosticsChanged,
|
||||||
|
[model, this] {
|
||||||
|
model->setDiagnostics(m_projectSettings->suppressedDiagnostics());
|
||||||
|
updateButtonStates();
|
||||||
|
});
|
||||||
|
m_ui->diagnosticsView->setModel(model);
|
||||||
|
updateButtonStates();
|
||||||
|
connect(m_ui->diagnosticsView->selectionModel(), &QItemSelectionModel::selectionChanged,
|
||||||
|
[this](const QItemSelection &, const QItemSelection &) {
|
||||||
|
updateButtonStateRemoveSelected();
|
||||||
|
});
|
||||||
|
connect(m_ui->removeSelectedButton, &QAbstractButton::clicked,
|
||||||
|
[this](bool) { removeSelected(); });
|
||||||
|
connect(m_ui->removeAllButton, &QAbstractButton::clicked,
|
||||||
|
[this](bool) { m_projectSettings->removeAllSuppressedDiagnostics();});
|
||||||
|
}
|
||||||
|
|
||||||
|
ProjectSettingsWidget::~ProjectSettingsWidget()
|
||||||
|
{
|
||||||
|
delete m_ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsWidget::updateButtonStates()
|
||||||
|
{
|
||||||
|
updateButtonStateRemoveSelected();
|
||||||
|
updateButtonStateRemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsWidget::updateButtonStateRemoveSelected()
|
||||||
|
{
|
||||||
|
const auto selectedRows = m_ui->diagnosticsView->selectionModel()->selectedRows();
|
||||||
|
QTC_ASSERT(selectedRows.count() <= 1, return);
|
||||||
|
m_ui->removeSelectedButton->setEnabled(!selectedRows.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsWidget::updateButtonStateRemoveAll()
|
||||||
|
{
|
||||||
|
m_ui->removeAllButton->setEnabled(m_ui->diagnosticsView->model()->rowCount() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectSettingsWidget::removeSelected()
|
||||||
|
{
|
||||||
|
const auto selectedRows = m_ui->diagnosticsView->selectionModel()->selectedRows();
|
||||||
|
QTC_ASSERT(selectedRows.count() == 1, return);
|
||||||
|
const auto * const model
|
||||||
|
= static_cast<SuppressedDiagnosticsModel *>(m_ui->diagnosticsView->model());
|
||||||
|
m_projectSettings->removeSuppressedDiagnostic(model->diagnosticAt(selectedRows.first().row()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SuppressedDiagnosticsModel::setDiagnostics(const SuppressedDiagnosticsList &diagnostics)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_diagnostics = diagnostics;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
SuppressedDiagnostic SuppressedDiagnosticsModel::diagnosticAt(int i) const
|
||||||
|
{
|
||||||
|
return m_diagnostics.at(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SuppressedDiagnosticsModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return parent.isValid() ? 0 : m_diagnostics.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SuppressedDiagnosticsModel::headerData(int section, Qt::Orientation orientation,
|
||||||
|
int role) const
|
||||||
|
{
|
||||||
|
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
|
||||||
|
if (section == ColumnFile)
|
||||||
|
return tr("File");
|
||||||
|
if (section == ColumnContext)
|
||||||
|
return tr("Context");
|
||||||
|
if (section == ColumnDescription)
|
||||||
|
return tr("Diagnostic");
|
||||||
|
}
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant SuppressedDiagnosticsModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid() || role != Qt::DisplayRole || index.row() >= rowCount())
|
||||||
|
return QVariant();
|
||||||
|
const SuppressedDiagnostic &diag = m_diagnostics.at(index.row());
|
||||||
|
if (index.column() == ColumnFile)
|
||||||
|
return diag.filePath.toUserOutput();
|
||||||
|
if (index.column() == ColumnContext) {
|
||||||
|
if (diag.contextKind == QLatin1String("function") && !diag.context.isEmpty())
|
||||||
|
return tr("Function \"%1\"").arg(diag.context);
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
if (index.column() == ColumnDescription)
|
||||||
|
return diag.description;
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerprojectsettingswidget.moc"
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERPROJECTSETTINGSWIDGET_H
|
||||||
|
#define CLANGSTATICANALYZERPROJECTSETTINGSWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace ProjectExplorer { class Project; }
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
class ProjectSettings;
|
||||||
|
|
||||||
|
namespace Ui { class ProjectSettingsWidget; }
|
||||||
|
|
||||||
|
class ProjectSettingsWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ProjectSettingsWidget(ProjectExplorer::Project *project, QWidget *parent = 0);
|
||||||
|
~ProjectSettingsWidget();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateButtonStates();
|
||||||
|
void updateButtonStateRemoveSelected();
|
||||||
|
void updateButtonStateRemoveAll();
|
||||||
|
void removeSelected();
|
||||||
|
|
||||||
|
Ui::ProjectSettingsWidget * const m_ui;
|
||||||
|
ProjectSettings * const m_projectSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // Include guard.
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ClangStaticAnalyzer::Internal::ProjectSettingsWidget</class>
|
||||||
|
<widget class="QWidget" name="ClangStaticAnalyzer::Internal::ProjectSettingsWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Suppressed Diagnostics:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="diagnosticsView">
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeSelectedButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove Selected</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeAllButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove All</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,511 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerlogfilereader.h"
|
||||||
|
#include "clangstaticanalyzerrunner.h"
|
||||||
|
#include "clangstaticanalyzersettings.h"
|
||||||
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzermanager.h>
|
||||||
|
#include <analyzerbase/analyzerutils.h>
|
||||||
|
|
||||||
|
#include <clangcodemodel/clangutils.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/projectinfo.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/abi.h>
|
||||||
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
|
#include <projectexplorer/kitinformation.h>
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <projectexplorer/runconfiguration.h>
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
#include <projectexplorer/taskhub.h>
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
|
using namespace CppTools;
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
|
||||||
|
static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runcontrol")
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunControl::ClangStaticAnalyzerRunControl(
|
||||||
|
RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode,
|
||||||
|
const ProjectInfo &projectInfo)
|
||||||
|
: AnalyzerRunControl(runConfiguration, runMode)
|
||||||
|
, m_projectInfo(projectInfo)
|
||||||
|
, m_wordWidth(runConfiguration->abi().wordWidth())
|
||||||
|
, m_initialFilesToProcessSize(0)
|
||||||
|
, m_filesAnalyzed(0)
|
||||||
|
, m_filesNotAnalyzed(0)
|
||||||
|
{
|
||||||
|
Target *target = runConfiguration->target();
|
||||||
|
BuildConfiguration *buildConfiguration = target->activeBuildConfiguration();
|
||||||
|
QTC_ASSERT(buildConfiguration, return);
|
||||||
|
m_environment = buildConfiguration->environment();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prependWordWidthArgumentIfNotIncluded(QStringList *arguments, unsigned char wordWidth)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(arguments, return);
|
||||||
|
|
||||||
|
const QString m64Argument = QLatin1String("-m64");
|
||||||
|
const QString m32Argument = QLatin1String("-m32");
|
||||||
|
|
||||||
|
const QString argument = wordWidth == 64 ? m64Argument : m32Argument;
|
||||||
|
if (!arguments->contains(argument))
|
||||||
|
arguments->prepend(argument);
|
||||||
|
|
||||||
|
QTC_CHECK(!arguments->contains(m32Argument) || !arguments->contains(m64Argument));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes (1) filePath (2) -o <somePath>.
|
||||||
|
// Adds -m64/-m32 argument if not already included.
|
||||||
|
static QStringList tweakedArguments(const QString &filePath,
|
||||||
|
const QStringList &arguments,
|
||||||
|
unsigned char wordWidth)
|
||||||
|
{
|
||||||
|
QStringList newArguments;
|
||||||
|
|
||||||
|
bool skip = false;
|
||||||
|
foreach (const QString &argument, arguments) {
|
||||||
|
if (skip) {
|
||||||
|
skip = false;
|
||||||
|
continue;
|
||||||
|
} else if (argument == QLatin1String("-o")) {
|
||||||
|
skip = true;
|
||||||
|
continue;
|
||||||
|
} else if (QDir::fromNativeSeparators(argument) == filePath) {
|
||||||
|
continue; // TODO: Let it in?
|
||||||
|
}
|
||||||
|
|
||||||
|
newArguments << argument;
|
||||||
|
}
|
||||||
|
QTC_CHECK(skip == false);
|
||||||
|
|
||||||
|
prependWordWidthArgumentIfNotIncluded(&newArguments, wordWidth);
|
||||||
|
|
||||||
|
return newArguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString createLanguageOptionMsvc(ProjectFile::Kind fileKind)
|
||||||
|
{
|
||||||
|
switch (fileKind) {
|
||||||
|
case ProjectFile::CHeader:
|
||||||
|
case ProjectFile::CSource:
|
||||||
|
return QLatin1String("/TC");
|
||||||
|
break;
|
||||||
|
case ProjectFile::CXXHeader:
|
||||||
|
case ProjectFile::CXXSource:
|
||||||
|
return QLatin1String("/TP");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerOptionsBuilder : public CompilerOptionsBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QStringList build(const CppTools::ProjectPart &projectPart,
|
||||||
|
CppTools::ProjectFile::Kind fileKind,
|
||||||
|
unsigned char wordWidth)
|
||||||
|
{
|
||||||
|
ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart);
|
||||||
|
optionsBuilder.addLanguageOption(fileKind);
|
||||||
|
optionsBuilder.addOptionsForLanguage(false);
|
||||||
|
|
||||||
|
// In gcc headers, lots of built-ins are referenced that clang does not understand.
|
||||||
|
// Therefore, prevent the inclusion of the header that references them. Of course, this
|
||||||
|
// will break if code actually requires stuff from there, but that should be the less common
|
||||||
|
// case.
|
||||||
|
const Core::Id type = projectPart.toolchainType;
|
||||||
|
if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
||||||
|
|| type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
|
||||||
|
optionsBuilder.addDefine("#define _X86INTRIN_H_INCLUDED\n");
|
||||||
|
|
||||||
|
optionsBuilder.addToolchainAndProjectDefines();
|
||||||
|
optionsBuilder.addHeaderPathOptions();
|
||||||
|
|
||||||
|
if (type == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||||
|
optionsBuilder.add(QLatin1String("/EHsc")); // clang-cl does not understand exceptions
|
||||||
|
else
|
||||||
|
optionsBuilder.add(QLatin1String("-fPIC")); // TODO: Remove?
|
||||||
|
|
||||||
|
QStringList options = optionsBuilder.options();
|
||||||
|
prependWordWidthArgumentIfNotIncluded(&options, wordWidth);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart)
|
||||||
|
: CompilerOptionsBuilder(projectPart)
|
||||||
|
, m_isMsvcToolchain(m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLanguageOption(ProjectFile::Kind fileKind) override
|
||||||
|
{
|
||||||
|
if (m_isMsvcToolchain)
|
||||||
|
add(createLanguageOptionMsvc(fileKind));
|
||||||
|
else
|
||||||
|
CompilerOptionsBuilder::addLanguageOption(fileKind);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addOptionsForLanguage(bool checkForBorlandExtensions) override
|
||||||
|
{
|
||||||
|
if (m_isMsvcToolchain)
|
||||||
|
return;
|
||||||
|
CompilerOptionsBuilder::addOptionsForLanguage(checkForBorlandExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString includeOption() const override
|
||||||
|
{
|
||||||
|
if (m_isMsvcToolchain)
|
||||||
|
return QLatin1String("/I");
|
||||||
|
return CompilerOptionsBuilder::includeOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString defineOption() const override
|
||||||
|
{
|
||||||
|
if (m_isMsvcToolchain)
|
||||||
|
return QLatin1String("/D");
|
||||||
|
return CompilerOptionsBuilder::defineOption();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isMsvcToolchain;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AnalyzeUnits unitsToAnalyzeFromCompilerCallData(
|
||||||
|
const ProjectInfo::CompilerCallData &compilerCallData,
|
||||||
|
unsigned char wordWidth)
|
||||||
|
{
|
||||||
|
qCDebug(LOG) << "Taking arguments for analyzing from CompilerCallData.";
|
||||||
|
|
||||||
|
AnalyzeUnits unitsToAnalyze;
|
||||||
|
|
||||||
|
QHashIterator<QString, QList<QStringList> > it(compilerCallData);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
const QString file = it.key();
|
||||||
|
const QList<QStringList> compilerCalls = it.value();
|
||||||
|
foreach (const QStringList &options, compilerCalls) {
|
||||||
|
const QStringList arguments = tweakedArguments(file, options, wordWidth);
|
||||||
|
unitsToAnalyze << AnalyzeUnit(file, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unitsToAnalyze;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QList<ProjectPart::Ptr> projectParts,
|
||||||
|
unsigned char wordWidth)
|
||||||
|
{
|
||||||
|
qCDebug(LOG) << "Taking arguments for analyzing from ProjectParts.";
|
||||||
|
|
||||||
|
AnalyzeUnits unitsToAnalyze;
|
||||||
|
|
||||||
|
foreach (const ProjectPart::Ptr &projectPart, projectParts) {
|
||||||
|
if (!projectPart->selectedForBuilding)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (const ProjectFile &file, projectPart->files) {
|
||||||
|
if (file.path == CppModelManager::configurationFileName())
|
||||||
|
continue;
|
||||||
|
QTC_CHECK(file.kind != ProjectFile::Unclassified);
|
||||||
|
if (ProjectFile::isSource(file.kind)) {
|
||||||
|
const QStringList arguments
|
||||||
|
= ClangStaticAnalyzerOptionsBuilder::build(*projectPart.data(),
|
||||||
|
file.kind,
|
||||||
|
wordWidth);
|
||||||
|
unitsToAnalyze << AnalyzeUnit(file.path, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return unitsToAnalyze;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyzeUnits ClangStaticAnalyzerRunControl::sortedUnitsToAnalyze()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_projectInfo.isValid(), return AnalyzeUnits());
|
||||||
|
|
||||||
|
AnalyzeUnits units;
|
||||||
|
const ProjectInfo::CompilerCallData compilerCallData = m_projectInfo.compilerCallData();
|
||||||
|
if (compilerCallData.isEmpty()) {
|
||||||
|
units = unitsToAnalyzeFromProjectParts(m_projectInfo.projectParts(),
|
||||||
|
m_wordWidth);
|
||||||
|
} else {
|
||||||
|
units = unitsToAnalyzeFromCompilerCallData(compilerCallData, m_wordWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::sort(units, [](const AnalyzeUnit &a1, const AnalyzeUnit &a2) -> bool {
|
||||||
|
return a1.file < a2.file;
|
||||||
|
});
|
||||||
|
return units;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QDebug operator<<(QDebug debug, const Utils::Environment &environment)
|
||||||
|
{
|
||||||
|
foreach (const QString &entry, environment.toStringList())
|
||||||
|
debug << "\n " << entry;
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QDebug operator<<(QDebug debug, const AnalyzeUnits &analyzeUnits)
|
||||||
|
{
|
||||||
|
foreach (const AnalyzeUnit &unit, analyzeUnits)
|
||||||
|
debug << "\n " << unit.file;
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Core::Id toolchainType(ProjectExplorer::RunConfiguration *runConfiguration)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(runConfiguration, return Core::Id());
|
||||||
|
return ToolChainKitInformation::toolChain(runConfiguration->target()->kit())->typeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunControl::startEngine()
|
||||||
|
{
|
||||||
|
m_success = false;
|
||||||
|
emit starting(this);
|
||||||
|
|
||||||
|
QTC_ASSERT(m_projectInfo.isValid(), emit finished(); return false);
|
||||||
|
const Utils::FileName projectFile = m_projectInfo.project()->projectFilePath();
|
||||||
|
appendMessage(tr("Running Clang Static Analyzer on %1").arg(projectFile.toUserOutput())
|
||||||
|
+ QLatin1Char('\n'), Utils::NormalMessageFormat);
|
||||||
|
|
||||||
|
// Check clang executable
|
||||||
|
bool isValidClangExecutable;
|
||||||
|
const QString executable = clangExecutableFromSettings(toolchainType(runConfiguration()),
|
||||||
|
&isValidClangExecutable);
|
||||||
|
if (!isValidClangExecutable) {
|
||||||
|
const QString errorMessage = tr("Clang Static Analyzer: Invalid executable \"%1\", stop.")
|
||||||
|
.arg(executable);
|
||||||
|
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
|
||||||
|
AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage);
|
||||||
|
emit finished();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_clangExecutable = executable;
|
||||||
|
|
||||||
|
// Create log dir
|
||||||
|
QTemporaryDir temporaryDir(QDir::tempPath() + QLatin1String("/qtc-clangstaticanalyzer-XXXXXX"));
|
||||||
|
temporaryDir.setAutoRemove(false);
|
||||||
|
if (!temporaryDir.isValid()) {
|
||||||
|
const QString errorMessage
|
||||||
|
= tr("Clang Static Analyzer: Failed to create temporary dir, stop.");
|
||||||
|
appendMessage(errorMessage + QLatin1Char('\n'), Utils::ErrorMessageFormat);
|
||||||
|
AnalyzerUtils::logToIssuesPane(Task::Error, errorMessage);
|
||||||
|
emit finished();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_clangLogFileDir = temporaryDir.path();
|
||||||
|
|
||||||
|
// Collect files
|
||||||
|
const AnalyzeUnits unitsToProcess = sortedUnitsToAnalyze();
|
||||||
|
qCDebug(LOG) << "Files to process:" << unitsToProcess;
|
||||||
|
m_unitsToProcess = unitsToProcess;
|
||||||
|
m_initialFilesToProcessSize = m_unitsToProcess.count();
|
||||||
|
m_filesAnalyzed = 0;
|
||||||
|
m_filesNotAnalyzed = 0;
|
||||||
|
|
||||||
|
// Set up progress information
|
||||||
|
using namespace Core;
|
||||||
|
m_progress = QFutureInterface<void>();
|
||||||
|
FutureProgress *futureProgress
|
||||||
|
= ProgressManager::addTask(m_progress.future(), tr("Analyzing"), "ClangStaticAnalyzer");
|
||||||
|
futureProgress->setKeepOnFinish(FutureProgress::HideOnFinish);
|
||||||
|
connect(futureProgress, &FutureProgress::canceled,
|
||||||
|
this, &ClangStaticAnalyzerRunControl::onProgressCanceled);
|
||||||
|
m_progress.setProgressRange(0, m_initialFilesToProcessSize);
|
||||||
|
m_progress.reportStarted();
|
||||||
|
|
||||||
|
// Start process(es)
|
||||||
|
qCDebug(LOG) << "Environment:" << m_environment;
|
||||||
|
m_runners.clear();
|
||||||
|
const int parallelRuns = ClangStaticAnalyzerSettings::instance()->simultaneousProcesses();
|
||||||
|
QTC_ASSERT(parallelRuns >= 1, emit finished(); return false);
|
||||||
|
m_success = true;
|
||||||
|
|
||||||
|
if (m_unitsToProcess.isEmpty()) {
|
||||||
|
finalize();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (m_runners.size() < parallelRuns && !m_unitsToProcess.isEmpty())
|
||||||
|
analyzeNextFile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::stopEngine()
|
||||||
|
{
|
||||||
|
QSetIterator<ClangStaticAnalyzerRunner *> i(m_runners);
|
||||||
|
while (i.hasNext()) {
|
||||||
|
ClangStaticAnalyzerRunner *runner = i.next();
|
||||||
|
QObject::disconnect(runner, 0, this, 0);
|
||||||
|
delete runner;
|
||||||
|
}
|
||||||
|
m_runners.clear();
|
||||||
|
m_unitsToProcess.clear();
|
||||||
|
appendMessage(tr("Clang Static Analyzer stopped by user.") + QLatin1Char('\n'),
|
||||||
|
Utils::NormalMessageFormat);
|
||||||
|
m_progress.reportFinished();
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::analyzeNextFile()
|
||||||
|
{
|
||||||
|
if (m_progress.isFinished())
|
||||||
|
return; // The previous call already reported that we are finished.
|
||||||
|
|
||||||
|
if (m_unitsToProcess.isEmpty()) {
|
||||||
|
if (m_runners.isEmpty())
|
||||||
|
finalize();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AnalyzeUnit unit = m_unitsToProcess.takeFirst();
|
||||||
|
qCDebug(LOG) << "analyzeNextFile:" << unit.file;
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunner *runner = createRunner();
|
||||||
|
m_runners.insert(runner);
|
||||||
|
QTC_ASSERT(runner->run(unit.file, unit.arguments), return);
|
||||||
|
|
||||||
|
appendMessage(tr("Analyzing \"%1\".").arg(
|
||||||
|
Utils::FileName::fromString(unit.file).toUserOutput()) + QLatin1Char('\n'),
|
||||||
|
Utils::StdOutFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunner *ClangStaticAnalyzerRunControl::createRunner()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_clangExecutable.isEmpty(), return 0);
|
||||||
|
QTC_ASSERT(!m_clangLogFileDir.isEmpty(), return 0);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithSuccess(const QString &logFilePath)
|
||||||
|
{
|
||||||
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess:" << logFilePath;
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
const QList<Diagnostic> diagnostics = LogFileReader::read(logFilePath, &errorMessage);
|
||||||
|
if (!errorMessage.isEmpty()) {
|
||||||
|
qCDebug(LOG) << "onRunnerFinishedWithSuccess: Error reading log file:" << errorMessage;
|
||||||
|
const QString filePath = qobject_cast<ClangStaticAnalyzerRunner *>(sender())->filePath();
|
||||||
|
appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage)
|
||||||
|
+ QLatin1Char('\n')
|
||||||
|
, Utils::StdErrFormat);
|
||||||
|
} else {
|
||||||
|
++m_filesAnalyzed;
|
||||||
|
if (!diagnostics.isEmpty())
|
||||||
|
emit newDiagnosticsAvailable(diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::onRunnerFinishedWithFailure(const QString &errorMessage,
|
||||||
|
const QString &errorDetails)
|
||||||
|
{
|
||||||
|
qCDebug(LOG) << "onRunnerFinishedWithFailure:" << errorMessage << errorDetails;
|
||||||
|
|
||||||
|
++m_filesNotAnalyzed;
|
||||||
|
m_success = false;
|
||||||
|
const QString filePath = qobject_cast<ClangStaticAnalyzerRunner *>(sender())->filePath();
|
||||||
|
appendMessage(tr("Failed to analyze \"%1\": %2").arg(filePath, errorMessage)
|
||||||
|
+ QLatin1Char('\n')
|
||||||
|
, Utils::StdErrFormat);
|
||||||
|
appendMessage(errorDetails, Utils::StdErrFormat);
|
||||||
|
AnalyzerUtils::logToIssuesPane(Task::Warning, errorMessage);
|
||||||
|
AnalyzerUtils::logToIssuesPane(Task::Warning, errorDetails);
|
||||||
|
handleFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::handleFinished()
|
||||||
|
{
|
||||||
|
m_runners.remove(qobject_cast<ClangStaticAnalyzerRunner *>(sender()));
|
||||||
|
updateProgressValue();
|
||||||
|
sender()->deleteLater();
|
||||||
|
analyzeNextFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::onProgressCanceled()
|
||||||
|
{
|
||||||
|
Analyzer::AnalyzerManager::stopTool();
|
||||||
|
m_progress.reportCanceled();
|
||||||
|
m_progress.reportFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::updateProgressValue()
|
||||||
|
{
|
||||||
|
m_progress.setProgressValue(m_initialFilesToProcessSize - m_unitsToProcess.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunControl::finalize()
|
||||||
|
{
|
||||||
|
appendMessage(tr("Clang Static Analyzer finished: "
|
||||||
|
"Processed %1 files successfully, %2 failed.")
|
||||||
|
.arg(m_filesAnalyzed)
|
||||||
|
.arg(m_filesNotAnalyzed)
|
||||||
|
+ QLatin1Char('\n'),
|
||||||
|
Utils::NormalMessageFormat);
|
||||||
|
|
||||||
|
if (m_filesAnalyzed == 0 && m_filesNotAnalyzed != 0) {
|
||||||
|
AnalyzerUtils::logToIssuesPane(Task::Error,
|
||||||
|
tr("Clang Static Analyzer: Failed to analyze any files."));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_progress.reportFinished();
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
101
src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
Normal file
101
src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERRUNCONTROL_H
|
||||||
|
#define CLANGSTATICANALYZERRUNCONTROL_H
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzerruncontrol.h>
|
||||||
|
#include <cpptools/projectinfo.h>
|
||||||
|
#include <utils/environment.h>
|
||||||
|
|
||||||
|
#include <QFutureInterface>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunner;
|
||||||
|
class Diagnostic;
|
||||||
|
|
||||||
|
struct AnalyzeUnit {
|
||||||
|
AnalyzeUnit(const QString &file, const QStringList &options)
|
||||||
|
: file(file), arguments(options) {}
|
||||||
|
|
||||||
|
QString file;
|
||||||
|
QStringList arguments; // without file itself and "-o somePath"
|
||||||
|
};
|
||||||
|
typedef QList<AnalyzeUnit> AnalyzeUnits;
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunControl : public Analyzer::AnalyzerRunControl
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode,
|
||||||
|
const CppTools::ProjectInfo &projectInfo);
|
||||||
|
|
||||||
|
bool startEngine();
|
||||||
|
void stopEngine();
|
||||||
|
|
||||||
|
bool success() const { return m_success; } // For testing.
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void newDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AnalyzeUnits sortedUnitsToAnalyze();
|
||||||
|
void analyzeNextFile();
|
||||||
|
ClangStaticAnalyzerRunner *createRunner();
|
||||||
|
|
||||||
|
void onRunnerFinishedWithSuccess(const QString &logFilePath);
|
||||||
|
void onRunnerFinishedWithFailure(const QString &errorMessage, const QString &errorDetails);
|
||||||
|
void handleFinished();
|
||||||
|
|
||||||
|
void onProgressCanceled();
|
||||||
|
void updateProgressValue();
|
||||||
|
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CppTools::ProjectInfo m_projectInfo;
|
||||||
|
const unsigned char m_wordWidth;
|
||||||
|
|
||||||
|
Utils::Environment m_environment;
|
||||||
|
QString m_clangExecutable;
|
||||||
|
QString m_clangLogFileDir;
|
||||||
|
QFutureInterface<void> m_progress;
|
||||||
|
AnalyzeUnits m_unitsToProcess;
|
||||||
|
QSet<ClangStaticAnalyzerRunner *> m_runners;
|
||||||
|
int m_initialFilesToProcessSize;
|
||||||
|
int m_filesAnalyzed;
|
||||||
|
int m_filesNotAnalyzed;
|
||||||
|
bool m_success;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERRUNCONTROL_H
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerruncontrolfactory.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerconstants.h"
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzermanager.h>
|
||||||
|
#include <analyzerbase/analyzerruncontrol.h>
|
||||||
|
#include <analyzerbase/analyzerstartparameters.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
|
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
|
||||||
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
|
#include <projectexplorer/gcctoolchain.h>
|
||||||
|
#include <projectexplorer/kit.h>
|
||||||
|
#include <projectexplorer/kitinformation.h>
|
||||||
|
#include <projectexplorer/project.h>
|
||||||
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
#include <projectexplorer/session.h>
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunControlFactory::ClangStaticAnalyzerRunControlFactory(
|
||||||
|
ClangStaticAnalyzerTool *tool,
|
||||||
|
QObject *parent)
|
||||||
|
: IRunControlFactory(parent)
|
||||||
|
, m_tool(tool)
|
||||||
|
{
|
||||||
|
QTC_CHECK(m_tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunControlFactory::canRun(RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode) const
|
||||||
|
{
|
||||||
|
if (runMode != Constants::CLANGSTATICANALYZER_RUN_MODE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Project *project = runConfiguration->target()->project();
|
||||||
|
QTC_ASSERT(project, return false);
|
||||||
|
const Core::Context context = project->projectLanguages();
|
||||||
|
if (!context.contains(ProjectExplorer::Constants::LANG_CXX))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Target *target = runConfiguration->target();
|
||||||
|
QTC_ASSERT(target, return false);
|
||||||
|
Kit *kit = target->kit();
|
||||||
|
QTC_ASSERT(kit, return false);
|
||||||
|
ToolChain *toolChain = ToolChainKitInformation::toolChain(kit);
|
||||||
|
return toolChain && (toolChain->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID
|
||||||
|
|| toolChain->typeId() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID
|
||||||
|
|| toolChain->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID
|
||||||
|
|| toolChain->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunControl *ClangStaticAnalyzerRunControlFactory::create(RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode,
|
||||||
|
QString *errorMessage)
|
||||||
|
{
|
||||||
|
using namespace CppTools;
|
||||||
|
const ProjectInfo projectInfoBeforeBuild = m_tool->projectInfoBeforeBuild();
|
||||||
|
QTC_ASSERT(projectInfoBeforeBuild.isValid(), return 0);
|
||||||
|
|
||||||
|
QTC_ASSERT(runConfiguration, return 0);
|
||||||
|
Target * const target = runConfiguration->target();
|
||||||
|
QTC_ASSERT(target, return 0);
|
||||||
|
Project * const project = target->project();
|
||||||
|
QTC_ASSERT(project, return 0);
|
||||||
|
|
||||||
|
const ProjectInfo projectInfoAfterBuild = CppModelManager::instance()->projectInfo(project);
|
||||||
|
|
||||||
|
if (projectInfoAfterBuild.configurationOrFilesChanged(projectInfoBeforeBuild)) {
|
||||||
|
// If it's more than a release/debug build configuration change, e.g.
|
||||||
|
// a version control checkout, files might be not valid C++ anymore
|
||||||
|
// or even gone, so better stop here.
|
||||||
|
|
||||||
|
m_tool->resetCursorAndProjectInfoBeforeBuild();
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = tr(
|
||||||
|
"The project configuration changed since the start of the Clang Static Analyzer. "
|
||||||
|
"Please re-run with current configuration.");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnalyzerManager::createRunControl(runConfiguration, runMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERRUNCONTROLFACTORY_H
|
||||||
|
#define CLANGSTATICANALYZERRUNCONTROLFACTORY_H
|
||||||
|
|
||||||
|
#include "clangstaticanalyzertool.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/runconfiguration.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunControlFactory : public ProjectExplorer::IRunControlFactory
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ClangStaticAnalyzerRunControlFactory(ClangStaticAnalyzerTool *tool,
|
||||||
|
QObject *parent = 0);
|
||||||
|
|
||||||
|
bool canRun(ProjectExplorer::RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode) const;
|
||||||
|
|
||||||
|
ProjectExplorer::RunControl *create(ProjectExplorer::RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode,
|
||||||
|
QString *errorMessage);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClangStaticAnalyzerTool *m_tool;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERRUNCONTROLFACTORY_H
|
||||||
193
src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
Normal file
193
src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerconstants.h"
|
||||||
|
|
||||||
|
#include <utils/synchronousprocess.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
|
||||||
|
static Q_LOGGING_CATEGORY(LOG, "qtc.clangstaticanalyzer.runner")
|
||||||
|
|
||||||
|
static QString generalProcessError()
|
||||||
|
{
|
||||||
|
return QObject::tr("An error occurred with the clang static analyzer process.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString finishedDueToCrash()
|
||||||
|
{
|
||||||
|
return QObject::tr("Clang static analyzer crashed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static QStringList constructCommandLineArguments(const QString &filePath,
|
||||||
|
const QString &logFile,
|
||||||
|
const QStringList &options)
|
||||||
|
{
|
||||||
|
QStringList arguments = QStringList()
|
||||||
|
<< QLatin1String("--analyze")
|
||||||
|
<< QLatin1String("-o")
|
||||||
|
<< logFile
|
||||||
|
;
|
||||||
|
arguments += options;
|
||||||
|
arguments << QDir::toNativeSeparators(filePath);
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
QString finishedWithBadExitCode(int exitCode)
|
||||||
|
{
|
||||||
|
return QObject::tr("Clang static analyzer finished with exit code: %1.").arg(exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunner::ClangStaticAnalyzerRunner(const QString &clangExecutable,
|
||||||
|
const QString &clangLogFileDir,
|
||||||
|
const Utils::Environment &environment,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_clangExecutable(clangExecutable)
|
||||||
|
, m_clangLogFileDir(clangLogFileDir)
|
||||||
|
{
|
||||||
|
QTC_CHECK(!m_clangExecutable.isEmpty());
|
||||||
|
QTC_CHECK(!m_clangLogFileDir.isEmpty());
|
||||||
|
|
||||||
|
m_process.setProcessChannelMode(QProcess::MergedChannels);
|
||||||
|
m_process.setProcessEnvironment(environment.toProcessEnvironment());
|
||||||
|
m_process.setWorkingDirectory(m_clangLogFileDir); // Current clang-cl puts log file into working dir.
|
||||||
|
connect(&m_process, &QProcess::started,
|
||||||
|
this, &ClangStaticAnalyzerRunner::onProcessStarted);
|
||||||
|
connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||||
|
this, &ClangStaticAnalyzerRunner::onProcessFinished);
|
||||||
|
connect(&m_process, static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
|
||||||
|
this, &ClangStaticAnalyzerRunner::onProcessError);
|
||||||
|
connect(&m_process, &QProcess::readyRead,
|
||||||
|
this, &ClangStaticAnalyzerRunner::onProcessOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunner::~ClangStaticAnalyzerRunner()
|
||||||
|
{
|
||||||
|
Utils::SynchronousProcess::stopProcess(m_process);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunner::run(const QString &filePath, const QStringList &compilerOptions)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_clangExecutable.isEmpty(), return false);
|
||||||
|
QTC_CHECK(!compilerOptions.contains(QLatin1String("-o")));
|
||||||
|
QTC_CHECK(!compilerOptions.contains(filePath));
|
||||||
|
|
||||||
|
m_filePath = filePath;
|
||||||
|
m_processOutput.clear();
|
||||||
|
|
||||||
|
m_logFile = createLogFile(filePath);
|
||||||
|
QTC_ASSERT(!m_logFile.isEmpty(), return false);
|
||||||
|
const QStringList arguments = constructCommandLineArguments(filePath, m_logFile,
|
||||||
|
compilerOptions);
|
||||||
|
m_commandLine = (QStringList(m_clangExecutable) + arguments).join(QLatin1String("\" \""));
|
||||||
|
|
||||||
|
qCDebug(LOG) << "Starting" << m_commandLine;
|
||||||
|
m_process.start(m_clangExecutable, arguments);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerRunner::filePath() const
|
||||||
|
{
|
||||||
|
return m_filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunner::onProcessStarted()
|
||||||
|
{
|
||||||
|
emit started();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunner::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
if (exitStatus == QProcess::NormalExit) {
|
||||||
|
if (exitCode == 0)
|
||||||
|
emit finishedWithSuccess(actualLogFile());
|
||||||
|
else
|
||||||
|
emit finishedWithFailure(finishedWithBadExitCode(exitCode), processCommandlineAndOutput());
|
||||||
|
} else { // == QProcess::CrashExit
|
||||||
|
emit finishedWithFailure(finishedDueToCrash(), processCommandlineAndOutput());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunner::onProcessError(QProcess::ProcessError error)
|
||||||
|
{
|
||||||
|
if (error == QProcess::Crashed)
|
||||||
|
return; // handled by slot of finished()
|
||||||
|
|
||||||
|
emit finishedWithFailure(generalProcessError(), processCommandlineAndOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunner::onProcessOutput()
|
||||||
|
{
|
||||||
|
m_processOutput.append(m_process.readAll());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerRunner::createLogFile(const QString &filePath) const
|
||||||
|
{
|
||||||
|
const QString fileName = QFileInfo(filePath).fileName();
|
||||||
|
const QString fileTemplate = m_clangLogFileDir
|
||||||
|
+ QLatin1String("/report-") + fileName + QLatin1String("-XXXXXX.plist");
|
||||||
|
|
||||||
|
QTemporaryFile temporaryFile;
|
||||||
|
temporaryFile.setAutoRemove(false);
|
||||||
|
temporaryFile.setFileTemplate(fileTemplate);
|
||||||
|
if (temporaryFile.open()) {
|
||||||
|
temporaryFile.close();
|
||||||
|
return temporaryFile.fileName();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerRunner::processCommandlineAndOutput() const
|
||||||
|
{
|
||||||
|
return QObject::tr("Command line: \"%1\"\n"
|
||||||
|
"Process Error: %2\n"
|
||||||
|
"Output:\n%3")
|
||||||
|
.arg(m_commandLine,
|
||||||
|
QString::number(m_process.error()),
|
||||||
|
QString::fromLocal8Bit(m_processOutput));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerRunner::actualLogFile() const
|
||||||
|
{
|
||||||
|
if (QFileInfo(m_logFile).size() == 0) {
|
||||||
|
// Current clang-cl ignores -o, always putting the log file into the working directory.
|
||||||
|
return m_clangLogFileDir + QLatin1Char('/') + QFileInfo(m_filePath).completeBaseName()
|
||||||
|
+ QLatin1String(".plist");
|
||||||
|
}
|
||||||
|
return m_logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
86
src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
Normal file
86
src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERRUNNER_H
|
||||||
|
#define CLANGSTATICANALYZERRUNNER_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QProcess>
|
||||||
|
|
||||||
|
#include <utils/environment.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
QString finishedWithBadExitCode(int exitCode); // exposed for tests
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunner : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerRunner(const QString &clangExecutable,
|
||||||
|
const QString &clangLogFileDir,
|
||||||
|
const Utils::Environment &environment,
|
||||||
|
QObject *parent = 0);
|
||||||
|
~ClangStaticAnalyzerRunner();
|
||||||
|
|
||||||
|
// compilerOptions is expected to contain everything except:
|
||||||
|
// (1) filePath, that is the file to analyze
|
||||||
|
// (2) -o output-file
|
||||||
|
bool run(const QString &filePath, const QStringList &compilerOptions = QStringList());
|
||||||
|
|
||||||
|
QString filePath() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void started();
|
||||||
|
void finishedWithSuccess(const QString &logFilePath);
|
||||||
|
void finishedWithFailure(const QString &errorMessage, const QString &errorDetails);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onProcessStarted();
|
||||||
|
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
|
void onProcessError(QProcess::ProcessError error);
|
||||||
|
void onProcessOutput();
|
||||||
|
|
||||||
|
QString createLogFile(const QString &filePath) const;
|
||||||
|
QString processCommandlineAndOutput() const;
|
||||||
|
QString actualLogFile() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_clangExecutable;
|
||||||
|
QString m_clangLogFileDir;
|
||||||
|
QString m_filePath;
|
||||||
|
QString m_logFile;
|
||||||
|
QString m_commandLine;
|
||||||
|
QProcess m_process;
|
||||||
|
QByteArray m_processOutput;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERRUNNER_H
|
||||||
122
src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.cpp
Normal file
122
src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.cpp
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzersettings.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerconstants.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
|
static const char clangExecutableKey[] = "clangExecutable";
|
||||||
|
static const char simultaneousProcessesKey[] = "simultaneousProcesses";
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerSettings::ClangStaticAnalyzerSettings()
|
||||||
|
: m_simultaneousProcesses(-1)
|
||||||
|
{
|
||||||
|
readSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangStaticAnalyzerSettings *ClangStaticAnalyzerSettings::instance()
|
||||||
|
{
|
||||||
|
static ClangStaticAnalyzerSettings instance;
|
||||||
|
return &instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString clangExecutableFileName()
|
||||||
|
{
|
||||||
|
return QLatin1String(Utils::HostOsInfo::isWindowsHost() ? "clang-cl.exe" : "clang");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerSettings::defaultClangExecutable() const
|
||||||
|
{
|
||||||
|
const QString shippedBinary = Core::ICore::libexecPath() + QLatin1Char('/')
|
||||||
|
+ clangExecutableFileName();
|
||||||
|
if (QFileInfo(shippedBinary).isExecutable())
|
||||||
|
return shippedBinary;
|
||||||
|
return clangExecutableFileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangStaticAnalyzerSettings::clangExecutable(bool *isSet) const
|
||||||
|
{
|
||||||
|
if (m_clangExecutable.isEmpty()) {
|
||||||
|
if (isSet)
|
||||||
|
*isSet = false;
|
||||||
|
return defaultClangExecutable();
|
||||||
|
}
|
||||||
|
if (isSet)
|
||||||
|
*isSet = true;
|
||||||
|
return m_clangExecutable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerSettings::setClangExecutable(const QString &exectuable)
|
||||||
|
{
|
||||||
|
m_clangExecutable = exectuable;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClangStaticAnalyzerSettings::simultaneousProcesses() const
|
||||||
|
{
|
||||||
|
return m_simultaneousProcesses;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerSettings::setSimultaneousProcesses(int processes)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(processes >=1, return);
|
||||||
|
m_simultaneousProcesses = processes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerSettings::readSettings()
|
||||||
|
{
|
||||||
|
QSettings *settings = Core::ICore::settings();
|
||||||
|
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
|
||||||
|
|
||||||
|
setClangExecutable(settings->value(QLatin1String(clangExecutableKey)).toString());
|
||||||
|
|
||||||
|
const int defaultSimultaneousProcesses = qMax(0, QThread::idealThreadCount() / 2);
|
||||||
|
setSimultaneousProcesses(settings->value(QLatin1String(simultaneousProcessesKey),
|
||||||
|
defaultSimultaneousProcesses).toInt());
|
||||||
|
|
||||||
|
settings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerSettings::writeSettings() const
|
||||||
|
{
|
||||||
|
QSettings *settings = Core::ICore::settings();
|
||||||
|
settings->beginGroup(QLatin1String(Constants::SETTINGS_ID));
|
||||||
|
settings->setValue(QLatin1String(clangExecutableKey), m_clangExecutable);
|
||||||
|
settings->setValue(QLatin1String(simultaneousProcessesKey), simultaneousProcesses());
|
||||||
|
settings->endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERSETTINGS_H
|
||||||
|
#define CLANGSTATICANALYZERSETTINGS_H
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static ClangStaticAnalyzerSettings *instance();
|
||||||
|
|
||||||
|
void writeSettings() const;
|
||||||
|
|
||||||
|
QString defaultClangExecutable() const;
|
||||||
|
QString clangExecutable(bool *isSet = nullptr) const;
|
||||||
|
void setClangExecutable(const QString &exectuable);
|
||||||
|
|
||||||
|
int simultaneousProcesses() const;
|
||||||
|
void setSimultaneousProcesses(int processes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClangStaticAnalyzerSettings();
|
||||||
|
void readSettings();
|
||||||
|
|
||||||
|
QString m_clangExecutable;
|
||||||
|
int m_simultaneousProcesses;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERSETTINGS_H
|
||||||
332
src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
Normal file
332
src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
Normal file
@@ -0,0 +1,332 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerconstants.h"
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
#include "clangstaticanalyzerdiagnosticmodel.h"
|
||||||
|
#include "clangstaticanalyzerdiagnosticview.h"
|
||||||
|
#include "clangstaticanalyzerruncontrol.h"
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzermanager.h>
|
||||||
|
#include <coreplugin/coreconstants.h>
|
||||||
|
#include <coreplugin/coreicons.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
#include <projectexplorer/buildconfiguration.h>
|
||||||
|
#include <projectexplorer/projectexplorer.h>
|
||||||
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
#include <projectexplorer/session.h>
|
||||||
|
#include <projectexplorer/target.h>
|
||||||
|
|
||||||
|
#include <utils/checkablemessagebox.h>
|
||||||
|
#include <utils/fancymainwindow.h>
|
||||||
|
|
||||||
|
#include <QDockWidget>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QListView>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QToolButton>
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class DummyRunConfiguration : public RunConfiguration
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DummyRunConfiguration(Target *parent)
|
||||||
|
: RunConfiguration(parent, "ClangStaticAnalyzer.DummyRunConfig")
|
||||||
|
{
|
||||||
|
setDefaultDisplayName(tr("Clang Static Analyzer"));
|
||||||
|
addExtraAspects();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWidget *createConfigurationWidget() override { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
ClangStaticAnalyzerTool::ClangStaticAnalyzerTool(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_diagnosticModel(0)
|
||||||
|
, m_diagnosticFilterModel(0)
|
||||||
|
, m_diagnosticView(0)
|
||||||
|
, m_goBack(0)
|
||||||
|
, m_goNext(0)
|
||||||
|
, m_running(false)
|
||||||
|
{
|
||||||
|
setObjectName(QLatin1String("ClangStaticAnalyzerTool"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *ClangStaticAnalyzerTool::createWidgets()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(!m_diagnosticView, return 0);
|
||||||
|
QTC_ASSERT(!m_diagnosticModel, return 0);
|
||||||
|
QTC_ASSERT(!m_goBack, return 0);
|
||||||
|
QTC_ASSERT(!m_goNext, return 0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Diagnostic View
|
||||||
|
//
|
||||||
|
m_diagnosticView = new ClangStaticAnalyzerDiagnosticView;
|
||||||
|
m_diagnosticView->setFrameStyle(QFrame::NoFrame);
|
||||||
|
m_diagnosticView->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||||
|
m_diagnosticModel = new ClangStaticAnalyzerDiagnosticModel(this);
|
||||||
|
m_diagnosticFilterModel = new ClangStaticAnalyzerDiagnosticFilterModel(this);
|
||||||
|
m_diagnosticFilterModel->setSourceModel(m_diagnosticModel);
|
||||||
|
m_diagnosticView->setModel(m_diagnosticFilterModel);
|
||||||
|
m_diagnosticView->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||||
|
m_diagnosticView->setAutoScroll(false);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDockWidget *issuesDock = AnalyzerManager::createDockWidget(ClangStaticAnalyzerToolId,
|
||||||
|
m_diagnosticView);
|
||||||
|
issuesDock->show();
|
||||||
|
Utils::FancyMainWindow *mw = AnalyzerManager::mainWindow();
|
||||||
|
mw->splitDockWidget(mw->toolBarDockWidget(), issuesDock, Qt::Vertical);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Toolbar widget
|
||||||
|
//
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout;
|
||||||
|
layout->setMargin(0);
|
||||||
|
layout->setSpacing(0);
|
||||||
|
|
||||||
|
QAction *action = 0;
|
||||||
|
QToolButton *button = 0;
|
||||||
|
|
||||||
|
// Go to previous diagnostic
|
||||||
|
action = new QAction(this);
|
||||||
|
action->setDisabled(true);
|
||||||
|
action->setIcon(Core::Icons::PREV.icon());
|
||||||
|
action->setToolTip(tr("Go to previous bug."));
|
||||||
|
connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goBack);
|
||||||
|
button = new QToolButton;
|
||||||
|
button->setDefaultAction(action);
|
||||||
|
layout->addWidget(button);
|
||||||
|
m_goBack = action;
|
||||||
|
|
||||||
|
// Go to next diagnostic
|
||||||
|
action = new QAction(this);
|
||||||
|
action->setDisabled(true);
|
||||||
|
action->setIcon(Core::Icons::NEXT.icon());
|
||||||
|
action->setToolTip(tr("Go to next bug."));
|
||||||
|
connect(action, &QAction::triggered, m_diagnosticView, &DetailedErrorView::goNext);
|
||||||
|
button = new QToolButton;
|
||||||
|
button->setDefaultAction(action);
|
||||||
|
layout->addWidget(button);
|
||||||
|
m_goNext = action;
|
||||||
|
|
||||||
|
layout->addStretch();
|
||||||
|
|
||||||
|
QWidget *toolbarWidget = new QWidget;
|
||||||
|
toolbarWidget->setObjectName(QLatin1String("ClangStaticAnalyzerToolBarWidget"));
|
||||||
|
toolbarWidget->setLayout(layout);
|
||||||
|
return toolbarWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalyzerRunControl *ClangStaticAnalyzerTool::createRunControl(RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(runConfiguration, return 0);
|
||||||
|
QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), return 0);
|
||||||
|
|
||||||
|
// Some projects provides CompilerCallData once a build is finished,
|
||||||
|
// so pass on the updated Project Info unless no configuration change
|
||||||
|
// (defines/includes/files) happened.
|
||||||
|
Project *project = runConfiguration->target()->project();
|
||||||
|
QTC_ASSERT(project, return 0);
|
||||||
|
const CppTools::ProjectInfo projectInfoAfterBuild
|
||||||
|
= CppTools::CppModelManager::instance()->projectInfo(project);
|
||||||
|
QTC_ASSERT(!projectInfoAfterBuild.configurationOrFilesChanged(m_projectInfoBeforeBuild),
|
||||||
|
return 0);
|
||||||
|
m_projectInfoBeforeBuild = CppTools::ProjectInfo();
|
||||||
|
|
||||||
|
auto runControl = new ClangStaticAnalyzerRunControl(runConfiguration, runMode,
|
||||||
|
projectInfoAfterBuild);
|
||||||
|
connect(runControl, &ClangStaticAnalyzerRunControl::starting,
|
||||||
|
this, &ClangStaticAnalyzerTool::onEngineIsStarting);
|
||||||
|
connect(runControl, &ClangStaticAnalyzerRunControl::newDiagnosticsAvailable,
|
||||||
|
this, &ClangStaticAnalyzerTool::onNewDiagnosticsAvailable);
|
||||||
|
connect(runControl, &ClangStaticAnalyzerRunControl::finished,
|
||||||
|
this, &ClangStaticAnalyzerTool::onEngineFinished);
|
||||||
|
return runControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dontStartAfterHintForDebugMode(Project *project)
|
||||||
|
{
|
||||||
|
BuildConfiguration::BuildType buildType = BuildConfiguration::Unknown;
|
||||||
|
if (project) {
|
||||||
|
if (const Target *target = project->activeTarget()) {
|
||||||
|
if (const BuildConfiguration *buildConfig = target->activeBuildConfiguration())
|
||||||
|
buildType = buildConfig->buildType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildType == BuildConfiguration::Release) {
|
||||||
|
const QString wrongMode = ClangStaticAnalyzerTool::tr("Release");
|
||||||
|
const QString toolName = ClangStaticAnalyzerTool::tr("Clang Static Analyzer");
|
||||||
|
const QString title = ClangStaticAnalyzerTool::tr("Run %1 in %2 Mode?").arg(toolName)
|
||||||
|
.arg(wrongMode);
|
||||||
|
const QString message = ClangStaticAnalyzerTool::tr(
|
||||||
|
"<html><head/><body>"
|
||||||
|
"<p>You are trying to run the tool \"%1\" on an application in %2 mode. The tool is "
|
||||||
|
"designed to be used in Debug mode since enabled assertions can reduce the number of "
|
||||||
|
"false positives.</p>"
|
||||||
|
"<p>Do you want to continue and run the tool in %2 mode?</p>"
|
||||||
|
"</body></html>")
|
||||||
|
.arg(toolName).arg(wrongMode);
|
||||||
|
if (Utils::CheckableMessageBox::doNotAskAgainQuestion(Core::ICore::mainWindow(),
|
||||||
|
title, message, Core::ICore::settings(),
|
||||||
|
QLatin1String("ClangStaticAnalyzerCorrectModeWarning")) != QDialogButtonBox::Yes)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::startTool()
|
||||||
|
{
|
||||||
|
AnalyzerManager::showMode();
|
||||||
|
|
||||||
|
Project *project = SessionManager::startupProject();
|
||||||
|
QTC_ASSERT(project, emit finished(false); return);
|
||||||
|
|
||||||
|
if (dontStartAfterHintForDebugMode(project))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_diagnosticModel->clear();
|
||||||
|
setBusyCursor(true);
|
||||||
|
m_diagnosticFilterModel->setProject(project);
|
||||||
|
m_projectInfoBeforeBuild = CppTools::CppModelManager::instance()->projectInfo(project);
|
||||||
|
QTC_ASSERT(m_projectInfoBeforeBuild.isValid(), emit finished(false); return);
|
||||||
|
m_running = true;
|
||||||
|
handleStateUpdate();
|
||||||
|
|
||||||
|
Target * const target = project->activeTarget();
|
||||||
|
QTC_ASSERT(target, return);
|
||||||
|
DummyRunConfiguration *& rc = m_runConfigs[target];
|
||||||
|
if (!rc) {
|
||||||
|
rc = new DummyRunConfiguration(target);
|
||||||
|
connect(project, &Project::aboutToRemoveTarget, this,
|
||||||
|
[this](Target *t) { m_runConfigs.remove(t); });
|
||||||
|
const auto onProjectRemoved = [this](Project *p) {
|
||||||
|
foreach (Target * const t, p->targets())
|
||||||
|
m_runConfigs.remove(t);
|
||||||
|
};
|
||||||
|
connect(SessionManager::instance(), &SessionManager::aboutToRemoveProject, this,
|
||||||
|
onProjectRemoved, Qt::UniqueConnection);
|
||||||
|
}
|
||||||
|
ProjectExplorerPlugin::runRunConfiguration(rc, Constants::CLANGSTATICANALYZER_RUN_MODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
CppTools::ProjectInfo ClangStaticAnalyzerTool::projectInfoBeforeBuild() const
|
||||||
|
{
|
||||||
|
return m_projectInfoBeforeBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::resetCursorAndProjectInfoBeforeBuild()
|
||||||
|
{
|
||||||
|
setBusyCursor(false);
|
||||||
|
m_projectInfoBeforeBuild = CppTools::ProjectInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<Diagnostic> ClangStaticAnalyzerTool::diagnostics() const
|
||||||
|
{
|
||||||
|
return m_diagnosticModel->diagnostics();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::onEngineIsStarting()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_diagnosticModel, return);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_diagnosticModel, return);
|
||||||
|
m_diagnosticModel->addDiagnostics(diagnostics);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::onEngineFinished()
|
||||||
|
{
|
||||||
|
resetCursorAndProjectInfoBeforeBuild();
|
||||||
|
m_running = false;
|
||||||
|
handleStateUpdate();
|
||||||
|
emit finished(static_cast<ClangStaticAnalyzerRunControl *>(sender())->success());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerTool::setBusyCursor(bool busy)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_diagnosticView, return);
|
||||||
|
QCursor cursor(busy ? Qt::BusyCursor : Qt::ArrowCursor);
|
||||||
|
m_diagnosticView->setCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = m_running ? tr("Clang Static Analyzer running.")
|
||||||
|
: 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);
|
||||||
|
}
|
||||||
|
AnalyzerManager::showPermanentStatusMessage(ClangStaticAnalyzerToolId, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#include "clangstaticanalyzertool.moc"
|
||||||
93
src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
Normal file
93
src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERTOOL_H
|
||||||
|
#define CLANGSTATICANALYZERTOOL_H
|
||||||
|
|
||||||
|
#include <analyzerbase/ianalyzertool.h>
|
||||||
|
#include <cpptools/projectinfo.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
namespace Analyzer { class DetailedErrorView; }
|
||||||
|
namespace ProjectExplorer { class Target; }
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerDiagnosticFilterModel;
|
||||||
|
class ClangStaticAnalyzerDiagnosticModel;
|
||||||
|
class ClangStaticAnalyzerDiagnosticView;
|
||||||
|
class Diagnostic;
|
||||||
|
class DummyRunConfiguration;
|
||||||
|
|
||||||
|
const char ClangStaticAnalyzerToolId[] = "ClangStaticAnalyzer";
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerTool : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ClangStaticAnalyzerTool(QObject *parent = 0);
|
||||||
|
CppTools::ProjectInfo projectInfoBeforeBuild() const;
|
||||||
|
void resetCursorAndProjectInfoBeforeBuild();
|
||||||
|
|
||||||
|
// For testing.
|
||||||
|
bool isRunning() const { return m_running; }
|
||||||
|
QList<Diagnostic> diagnostics() const;
|
||||||
|
|
||||||
|
QWidget *createWidgets();
|
||||||
|
Analyzer::AnalyzerRunControl *createRunControl(ProjectExplorer::RunConfiguration *runConfiguration,
|
||||||
|
Core::Id runMode);
|
||||||
|
void startTool();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished(bool success); // For testing.
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEngineIsStarting();
|
||||||
|
void onNewDiagnosticsAvailable(const QList<Diagnostic> &diagnostics);
|
||||||
|
void onEngineFinished();
|
||||||
|
|
||||||
|
void setBusyCursor(bool busy);
|
||||||
|
void handleStateUpdate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CppTools::ProjectInfo m_projectInfoBeforeBuild;
|
||||||
|
|
||||||
|
ClangStaticAnalyzerDiagnosticModel *m_diagnosticModel;
|
||||||
|
ClangStaticAnalyzerDiagnosticFilterModel *m_diagnosticFilterModel;
|
||||||
|
ClangStaticAnalyzerDiagnosticView *m_diagnosticView;
|
||||||
|
|
||||||
|
QAction *m_goBack;
|
||||||
|
QAction *m_goNext;
|
||||||
|
QHash<ProjectExplorer::Target *, DummyRunConfiguration *> m_runConfigs;
|
||||||
|
bool m_running;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERTOOL_H
|
||||||
117
src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp
Normal file
117
src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerunittests.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
#include "clangstaticanalyzertool.h"
|
||||||
|
#include "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include <analyzerbase/analyzermanager.h>
|
||||||
|
#include <cpptools/cppmodelmanager.h>
|
||||||
|
#include <cpptools/cpptoolstestcase.h>
|
||||||
|
#include <projectexplorer/kitinformation.h>
|
||||||
|
#include <projectexplorer/kitmanager.h>
|
||||||
|
#include <projectexplorer/projectexplorer.h>
|
||||||
|
#include <projectexplorer/toolchain.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QEventLoop>
|
||||||
|
#include <QSignalSpy>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
using namespace ProjectExplorer;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
ClangStaticAnalyzerUnitTests::ClangStaticAnalyzerUnitTests(ClangStaticAnalyzerTool *analyzerTool,
|
||||||
|
QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
, m_analyzerTool(analyzerTool)
|
||||||
|
, m_tmpDir(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerUnitTests::initTestCase()
|
||||||
|
{
|
||||||
|
const QList<Kit *> allKits = KitManager::kits();
|
||||||
|
if (allKits.count() != 1)
|
||||||
|
QSKIP("This test requires exactly one kit to be present");
|
||||||
|
const ToolChain * const toolchain = ToolChainKitInformation::toolChain(allKits.first());
|
||||||
|
if (!toolchain)
|
||||||
|
QSKIP("This test requires that there is a kit with a toolchain.");
|
||||||
|
bool hasClangExecutable;
|
||||||
|
clangExecutableFromSettings(toolchain->typeId(), &hasClangExecutable);
|
||||||
|
if (!hasClangExecutable)
|
||||||
|
QSKIP("No clang suitable for analyzing found");
|
||||||
|
|
||||||
|
m_tmpDir = new CppTools::Tests::TemporaryCopiedDir(QLatin1String(":/unit-tests"));
|
||||||
|
QVERIFY(m_tmpDir->isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerUnitTests::cleanupTestCase()
|
||||||
|
{
|
||||||
|
delete m_tmpDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerUnitTests::testProject()
|
||||||
|
{
|
||||||
|
QFETCH(QString, projectFilePath);
|
||||||
|
QFETCH(int, expectedDiagCount);
|
||||||
|
|
||||||
|
CppTools::Tests::ProjectOpenerAndCloser projectManager;
|
||||||
|
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
|
||||||
|
QVERIFY(projectInfo.isValid());
|
||||||
|
AnalyzerManager::selectAction(ClangStaticAnalyzerToolId, /* alsoRunIt = */ true);
|
||||||
|
QSignalSpy waiter(m_analyzerTool, SIGNAL(finished(bool)));
|
||||||
|
QVERIFY(waiter.wait(30000));
|
||||||
|
const QList<QVariant> arguments = waiter.takeFirst();
|
||||||
|
QVERIFY(arguments.first().toBool());
|
||||||
|
QCOMPARE(m_analyzerTool->diagnostics().count(), expectedDiagCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerUnitTests::testProject_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("projectFilePath");
|
||||||
|
QTest::addColumn<int>("expectedDiagCount");
|
||||||
|
|
||||||
|
QTest::newRow("simple qbs project")
|
||||||
|
<< QString(m_tmpDir->absolutePath("simple/simple.qbs")) << 1;
|
||||||
|
QTest::newRow("simple qmake project")
|
||||||
|
<< QString(m_tmpDir->absolutePath("simple/simple.pro")) << 1;
|
||||||
|
|
||||||
|
QTest::newRow("qt-widgets-app qbs project")
|
||||||
|
<< QString(m_tmpDir->absolutePath("qt-widgets-app/qt-widgets-app.qbs")) << 0;
|
||||||
|
QTest::newRow("qt-widgets-app qmake project")
|
||||||
|
<< QString(m_tmpDir->absolutePath("qt-widgets-app/qt-widgets-app.pro")) << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzerPlugin
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERUNITTESTS_H
|
||||||
|
#define CLANGSTATICANALYZERUNITTESTS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTemporaryDir>
|
||||||
|
|
||||||
|
namespace CppTools { namespace Tests { class TemporaryCopiedDir; } }
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
class ClangStaticAnalyzerTool;
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerUnitTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerUnitTests(ClangStaticAnalyzerTool *analyzerTool, QObject *parent = 0);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void initTestCase();
|
||||||
|
void cleanupTestCase();
|
||||||
|
void testProject();
|
||||||
|
void testProject_data();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClangStaticAnalyzerTool * const m_analyzerTool;
|
||||||
|
CppTools::Tests::TemporaryCopiedDir *m_tmpDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzerPlugin
|
||||||
|
|
||||||
|
#endif // Include guard
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>unit-tests/simple/main.cpp</file>
|
||||||
|
<file>unit-tests/simple/simple.qbs</file>
|
||||||
|
<file>unit-tests/simple/simple.pro</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/main.cpp</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/mainwindow.cpp</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/mainwindow.h</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/mainwindow.ui</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/qt-widgets-app.pro</file>
|
||||||
|
<file>unit-tests/qt-widgets-app/qt-widgets-app.qbs</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
103
src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp
Normal file
103
src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "clangstaticanalyzerutils.h"
|
||||||
|
|
||||||
|
#include "clangstaticanalyzerdiagnostic.h"
|
||||||
|
#include "clangstaticanalyzersettings.h"
|
||||||
|
|
||||||
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
|
#include <utils/environment.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
static bool isFileExecutable(const QString &executablePath)
|
||||||
|
{
|
||||||
|
if (executablePath.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const QFileInfo fileInfo(executablePath);
|
||||||
|
return fileInfo.isFile() && fileInfo.isExecutable();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid)
|
||||||
|
{
|
||||||
|
QString exeFromSettings = ClangStaticAnalyzerSettings::instance()->clangExecutable();
|
||||||
|
if (toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
|
||||||
|
exeFromSettings.replace(QLatin1String("clang.exe"), QLatin1String("clang-cl.exe"));
|
||||||
|
return clangExecutable(exeFromSettings, isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString clangExecutable(const QString &fileNameOrPath, bool *isValid)
|
||||||
|
{
|
||||||
|
QString executable = fileNameOrPath;
|
||||||
|
if (executable.isEmpty()) {
|
||||||
|
*isValid = false;
|
||||||
|
return executable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!QFileInfo(executable).isAbsolute()) {
|
||||||
|
const Utils::Environment &environment = Utils::Environment::systemEnvironment();
|
||||||
|
const QString executableFromPath = environment.searchInPath(executable).toString();
|
||||||
|
if (executableFromPath.isEmpty()) {
|
||||||
|
*isValid = false;
|
||||||
|
return executable;
|
||||||
|
}
|
||||||
|
executable = executableFromPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
*isValid = isFileExecutable(executable) && isClangExecutableUsable(executable);
|
||||||
|
return executable;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString createFullLocationString(const Analyzer::DiagnosticLocation &location)
|
||||||
|
{
|
||||||
|
const QString filePath = location.filePath;
|
||||||
|
const QString lineNumber = QString::number(location.line);
|
||||||
|
return filePath + QLatin1Char(':') + lineNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isClangExecutableUsable(const QString &filePath, QString *errorMessage)
|
||||||
|
{
|
||||||
|
const QFileInfo fi(filePath);
|
||||||
|
if (fi.isSymLink() && fi.symLinkTarget().contains(QLatin1String("icecc"))) {
|
||||||
|
if (errorMessage) {
|
||||||
|
*errorMessage = QCoreApplication::translate("ClangStaticAnalyzer",
|
||||||
|
"The chosen file \"%1\" seems to point to an icecc binary not suitable "
|
||||||
|
"for analyzing.\nPlease set a real clang executable.")
|
||||||
|
.arg(filePath);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
52
src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h
Normal file
52
src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CLANGSTATICANALYZERUTILS_H
|
||||||
|
#define CLANGSTATICANALYZERUTILS_H
|
||||||
|
|
||||||
|
#include <coreplugin/id.h>
|
||||||
|
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QString;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
namespace Analyzer { class DiagnosticLocation; }
|
||||||
|
|
||||||
|
namespace ClangStaticAnalyzer {
|
||||||
|
namespace Internal {
|
||||||
|
|
||||||
|
bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0);
|
||||||
|
|
||||||
|
QString clangExecutable(const QString &fileNameOrPath, bool *isValid);
|
||||||
|
QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid);
|
||||||
|
|
||||||
|
QString createFullLocationString(const Analyzer::DiagnosticLocation &location);
|
||||||
|
|
||||||
|
} // namespace Internal
|
||||||
|
} // namespace ClangStaticAnalyzer
|
||||||
|
|
||||||
|
#endif // CLANGSTATICANALYZERUTILS_H
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import qbs
|
||||||
|
|
||||||
|
QtcAutotest {
|
||||||
|
Depends { name: "Qt.widgets" }
|
||||||
|
Depends { name: "AnalyzerBase" }
|
||||||
|
Depends { name: "Utils" }
|
||||||
|
|
||||||
|
property path pluginDir: "../../"
|
||||||
|
cpp.defines: base.concat('SRCDIR="' + sourceDirectory + '"')
|
||||||
|
cpp.includePaths: base.concat(pluginDir + "/..")
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
include(../tests.pri)
|
||||||
|
|
||||||
|
TARGET = tst_clangstaticanalyzerlogfilereader
|
||||||
|
|
||||||
|
DEFINES += SRCDIR=\\\"$$PWD/\\\"
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
tst_clangstaticanalyzerlogfilereader.cpp \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerdiagnostic.cpp \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerlogfilereader.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerdiagnostic.h \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerlogfilereader.h
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import qbs
|
||||||
|
import "../clangstaticanalyzerautotest.qbs" as ClangStaticAnalyzerAutotest
|
||||||
|
|
||||||
|
ClangStaticAnalyzerAutotest {
|
||||||
|
name: "ClangStaticAnalyzerLogFileReader Autotest"
|
||||||
|
|
||||||
|
Group {
|
||||||
|
name: "sources from plugin"
|
||||||
|
prefix: pluginDir + '/'
|
||||||
|
files: [
|
||||||
|
"clangstaticanalyzerdiagnostic.cpp",
|
||||||
|
"clangstaticanalyzerdiagnostic.h",
|
||||||
|
"clangstaticanalyzerlogfilereader.cpp",
|
||||||
|
"clangstaticanalyzerlogfilereader.h",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
files: [
|
||||||
|
"tst_clangstaticanalyzerlogfilereader.cpp"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?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>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
<?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>
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <clangstaticanalyzer/clangstaticanalyzerlogfilereader.h>
|
||||||
|
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
enum { debug = 0 };
|
||||||
|
|
||||||
|
using namespace Analyzer;
|
||||||
|
using namespace ClangStaticAnalyzer::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 ClangStaticAnalyzerLogFileReaderTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void readEmptyFile();
|
||||||
|
void readFileWithNoDiagnostics();
|
||||||
|
void readFileWithDiagnostics();
|
||||||
|
};
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerLogFileReaderTest::readEmptyFile()
|
||||||
|
{
|
||||||
|
const QString filePath = QDir::tempPath() + QLatin1String("/empty.file");
|
||||||
|
QVERIFY(createEmptyFile(filePath));
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
const QList<Diagnostic> diagnostics = LogFileReader::read(filePath, &errorMessage);
|
||||||
|
QVERIFY(!errorMessage.isEmpty());
|
||||||
|
if (debug)
|
||||||
|
qDebug() << errorMessage;
|
||||||
|
QVERIFY(diagnostics.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerLogFileReaderTest::readFileWithNoDiagnostics()
|
||||||
|
{
|
||||||
|
const QString filePath = testFilePath(QLatin1String("/data/noDiagnostics.plist"));
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
const QList<Diagnostic> diagnostics = LogFileReader::read(filePath, &errorMessage);
|
||||||
|
QVERIFY(errorMessage.isEmpty());
|
||||||
|
QVERIFY(diagnostics.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerLogFileReaderTest::readFileWithDiagnostics()
|
||||||
|
{
|
||||||
|
const QString filePath = testFilePath(QLatin1String("/data/someDiagnostics.plist"));
|
||||||
|
|
||||||
|
QString errorMessage;
|
||||||
|
const QList<Diagnostic> diagnostics = LogFileReader::read(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(ClangStaticAnalyzerLogFileReaderTest)
|
||||||
|
|
||||||
|
#include "tst_clangstaticanalyzerlogfilereader.moc"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
include(../tests.pri)
|
||||||
|
|
||||||
|
TARGET = tst_clangstaticanalyzerrunnertest
|
||||||
|
|
||||||
|
DEFINES += SRCDIR=\\\"$$PWD/\\\"
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
tst_clangstaticanalyzerrunner.cpp \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerrunner.cpp
|
||||||
|
HEADERS += \
|
||||||
|
$$PLUGINDIR/clangstaticanalyzerrunner.h
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import qbs
|
||||||
|
import "../clangstaticanalyzerautotest.qbs" as ClangStaticAnalyzerAutotest
|
||||||
|
|
||||||
|
ClangStaticAnalyzerAutotest {
|
||||||
|
name: "ClangStaticAnalyzerRunner Autotest"
|
||||||
|
|
||||||
|
Group {
|
||||||
|
name: "sources from plugin"
|
||||||
|
prefix: pluginDir + '/'
|
||||||
|
files: [
|
||||||
|
"clangstaticanalyzerrunner.cpp",
|
||||||
|
"clangstaticanalyzerrunner.h",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
files: [
|
||||||
|
"tst_clangstaticanalyzerrunner.cpp",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <clangstaticanalyzer/clangstaticanalyzerconstants.h>
|
||||||
|
#include <clangstaticanalyzer/clangstaticanalyzerrunner.h>
|
||||||
|
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace ClangStaticAnalyzer::Internal;
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunnerTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerRunnerTest() {}
|
||||||
|
virtual ~ClangStaticAnalyzerRunnerTest() {}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void runWithTestCodeGeneratedOneIssue();
|
||||||
|
void runWithNonExistentFileToAnalyze();
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool writeFile(const QString &filePath, const QByteArray &source)
|
||||||
|
{
|
||||||
|
Utils::FileSaver saver(filePath);
|
||||||
|
return saver.write(source) && saver.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClangStaticAnalyzerRunnerSignalTester
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClangStaticAnalyzerRunnerSignalTester(ClangStaticAnalyzerRunner *runner);
|
||||||
|
|
||||||
|
bool expectStartedSignal();
|
||||||
|
bool expectFinishWithSuccessSignal();
|
||||||
|
bool expectFinishWithFailureSignal(const QString &expectedErrorMessage = QString());
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSignalSpy m_spyStarted;
|
||||||
|
QSignalSpy m_spyFinishedWithFailure;
|
||||||
|
QSignalSpy m_spyFinishedWithSuccess;
|
||||||
|
};
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunnerSignalTester::ClangStaticAnalyzerRunnerSignalTester(
|
||||||
|
ClangStaticAnalyzerRunner *runner)
|
||||||
|
: m_spyStarted(runner, SIGNAL(started()))
|
||||||
|
, m_spyFinishedWithFailure(runner, SIGNAL(finishedWithFailure(QString,QString)))
|
||||||
|
, m_spyFinishedWithSuccess(runner, SIGNAL(finishedWithSuccess(QString)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunnerSignalTester::expectStartedSignal()
|
||||||
|
{
|
||||||
|
if (m_spyStarted.wait()) {
|
||||||
|
if (m_spyStarted.size() != 1) {
|
||||||
|
qDebug() << "started() emitted more than once.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "started() not emitted.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunnerSignalTester::expectFinishWithSuccessSignal()
|
||||||
|
{
|
||||||
|
if (m_spyFinishedWithSuccess.wait()) {
|
||||||
|
if (m_spyFinishedWithSuccess.size() != 1) {
|
||||||
|
qDebug() << "finishedWithSuccess() emitted more than once.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "finishedWithSuccess() not emitted.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_spyFinishedWithFailure.size() != 0) {
|
||||||
|
qDebug() << "finishedWithFailure() emitted.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangStaticAnalyzerRunnerSignalTester::expectFinishWithFailureSignal(
|
||||||
|
const QString &expectedErrorMessage)
|
||||||
|
{
|
||||||
|
if (m_spyFinishedWithFailure.wait()) {
|
||||||
|
if (m_spyFinishedWithFailure.size() == 1) {
|
||||||
|
const QList<QVariant> args = m_spyFinishedWithFailure.at(0);
|
||||||
|
const QString errorMessage = args.at(0).toString();
|
||||||
|
if (errorMessage == expectedErrorMessage) {
|
||||||
|
if (m_spyFinishedWithSuccess.size() != 0) {
|
||||||
|
qDebug() << "Got expected error, but finishedWithSuccess() was also emitted.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Actual error message:" << errorMessage;
|
||||||
|
qDebug() << "Expected error message:" << expectedErrorMessage;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Finished with more than one failure (expected only one).";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qDebug() << "Not finished with failure, but expected.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunnerTest::runWithTestCodeGeneratedOneIssue()
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
QTemporaryDir temporaryDir(QDir::tempPath() + QLatin1String("/qtc-clangstaticanalyzer-XXXXXX"));
|
||||||
|
QVERIFY(temporaryDir.isValid());
|
||||||
|
ClangStaticAnalyzerRunner runner(QLatin1String("clang"), temporaryDir.path(),
|
||||||
|
Utils::Environment::systemEnvironment());
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunnerSignalTester st(&runner);
|
||||||
|
QVERIFY(runner.run(testFilePath));
|
||||||
|
QVERIFY(st.expectStartedSignal());
|
||||||
|
QVERIFY(st.expectFinishWithSuccessSignal());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClangStaticAnalyzerRunnerTest::runWithNonExistentFileToAnalyze()
|
||||||
|
{
|
||||||
|
QTemporaryDir temporaryDir(QDir::tempPath() + QLatin1String("/qtc-clangstaticanalyzer-XXXXXX"));
|
||||||
|
QVERIFY(temporaryDir.isValid());
|
||||||
|
ClangStaticAnalyzerRunner runner(QLatin1String("clang"), temporaryDir.path(),
|
||||||
|
Utils::Environment::systemEnvironment());
|
||||||
|
|
||||||
|
ClangStaticAnalyzerRunnerSignalTester st(&runner);
|
||||||
|
QVERIFY(runner.run(QLatin1String("not.existing.file.111")));
|
||||||
|
|
||||||
|
QVERIFY(st.expectStartedSignal());
|
||||||
|
QVERIFY(st.expectFinishWithFailureSignal(finishedWithBadExitCode(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(ClangStaticAnalyzerRunnerTest)
|
||||||
|
|
||||||
|
#include "tst_clangstaticanalyzerrunner.moc"
|
||||||
22
src/plugins/clangstaticanalyzer/tests/tests.pri
Normal file
22
src/plugins/clangstaticanalyzer/tests/tests.pri
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
QTC_LIB_DEPENDS += utils
|
||||||
|
QTC_PLUGIN_DEPENDS += analyzerbase
|
||||||
|
|
||||||
|
isEmpty(IDE_SOURCE_TREE): IDE_SOURCE_TREE=$$(QTC_SOURCE)
|
||||||
|
isEmpty(IDE_BUILD_TREE): IDE_BUILD_TREE=$$(QTC_BUILD)
|
||||||
|
isEmpty(IDE_SOURCE_TREE): error(Set QTC_SOURCE environment variable)
|
||||||
|
isEmpty(IDE_BUILD_TREE): error(Set QTC_BUILD environment variable)
|
||||||
|
|
||||||
|
PLUGINDIR = $$PWD/..
|
||||||
|
INCLUDEPATH += $$PLUGINDIR/..
|
||||||
|
|
||||||
|
include($$IDE_SOURCE_TREE/qtcreator.pri)
|
||||||
|
include($$IDE_SOURCE_TREE/tests/auto/qttestrpath.pri)
|
||||||
|
|
||||||
|
QT += testlib
|
||||||
|
QT -= gui
|
||||||
|
|
||||||
|
CONFIG += console
|
||||||
|
CONFIG += testcase
|
||||||
|
CONFIG -= app_bundle
|
||||||
|
|
||||||
|
TEMPLATE = app
|
||||||
6
src/plugins/clangstaticanalyzer/tests/tests.pro
Normal file
6
src/plugins/clangstaticanalyzer/tests/tests.pro
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
TEMPLATE = subdirs
|
||||||
|
CONFIG += ordered
|
||||||
|
|
||||||
|
SUBDIRS = \
|
||||||
|
clangstaticanalyzerrunner \
|
||||||
|
clangstaticanalyzerlogfilereader
|
||||||
8
src/plugins/clangstaticanalyzer/tests/tests.qbs
Normal file
8
src/plugins/clangstaticanalyzer/tests/tests.qbs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import qbs
|
||||||
|
|
||||||
|
Project {
|
||||||
|
references: [
|
||||||
|
"clangstaticanalyzerlogfilereader",
|
||||||
|
"clangstaticanalyzerrunner",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "mainwindow.h"
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = 0);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow" >
|
||||||
|
<property name="geometry" >
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle" >
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QMenuBar" name="menuBar" />
|
||||||
|
<widget class="QToolBar" name="mainToolBar" />
|
||||||
|
<widget class="QWidget" name="centralWidget" />
|
||||||
|
<widget class="QStatusBar" name="statusBar" />
|
||||||
|
</widget>
|
||||||
|
<layoutDefault spacing="6" margin="11" />
|
||||||
|
<pixmapfunction></pixmapfunction>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
QT += core gui
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
TARGET = qt-widgets-app
|
||||||
|
TEMPLATE = app
|
||||||
|
SOURCES += main.cpp mainwindow.cpp
|
||||||
|
HEADERS += mainwindow.h
|
||||||
|
FORMS += mainwindow.ui
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import qbs 1.0
|
||||||
|
|
||||||
|
QtApplication {
|
||||||
|
name : "Qt Widgets Application"
|
||||||
|
|
||||||
|
Depends {
|
||||||
|
name: "Qt"
|
||||||
|
submodules: [ "widgets" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
files : [
|
||||||
|
"main.cpp",
|
||||||
|
"mainwindow.cpp",
|
||||||
|
"mainwindow.h",
|
||||||
|
"mainwindow.ui"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
int main()
|
||||||
|
{
|
||||||
|
int *i = 0;
|
||||||
|
*i = 42;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
CONFIG -= QT
|
||||||
|
|
||||||
|
SOURCES = main.cpp
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import qbs
|
||||||
|
|
||||||
|
CppApplication {
|
||||||
|
files: ["main.cpp"]
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ include(../../qtcreator.pri)
|
|||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
|
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
|
clangstaticanalyzer \
|
||||||
coreplugin \
|
coreplugin \
|
||||||
texteditor \
|
texteditor \
|
||||||
cppeditor \
|
cppeditor \
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Project {
|
|||||||
"bineditor/bineditor.qbs",
|
"bineditor/bineditor.qbs",
|
||||||
"bookmarks/bookmarks.qbs",
|
"bookmarks/bookmarks.qbs",
|
||||||
"clangcodemodel/clangcodemodel.qbs",
|
"clangcodemodel/clangcodemodel.qbs",
|
||||||
|
"clangstaticanalyzer/clangstaticanalyzer.qbs",
|
||||||
"classview/classview.qbs",
|
"classview/classview.qbs",
|
||||||
"clearcase/clearcase.qbs",
|
"clearcase/clearcase.qbs",
|
||||||
"cmakeprojectmanager/cmakeprojectmanager.qbs",
|
"cmakeprojectmanager/cmakeprojectmanager.qbs",
|
||||||
|
|||||||
Reference in New Issue
Block a user