diff --git a/src/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in b/src/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
new file mode 100644
index 0000000000000000000000000000000000000000..8be50b27da55580f34e5002b9bc575bed42dbd8b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/ClangStaticAnalyzer.json.in
@@ -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
+}
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
new file mode 100644
index 0000000000000000000000000000000000000000..cdffb1f1d1ccc1a4f4779387be4ba7d01e37676c
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.pro
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..2562b46b3c1f6b500373e3e55200a4327703d84e
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer.qbs
@@ -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: ["**/*"]
+    }
+}
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer_dependencies.pri b/src/plugins/clangstaticanalyzer/clangstaticanalyzer_dependencies.pri
new file mode 100644
index 0000000000000000000000000000000000000000..b0993923732bba98a493380a4e594128552a0e1d
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer_dependencies.pri
@@ -0,0 +1,10 @@
+QTC_PLUGIN_NAME = ClangStaticAnalyzer
+QTC_LIB_DEPENDS += \
+    extensionsystem \
+    utils
+QTC_PLUGIN_DEPENDS += \
+    analyzerbase \
+    cpptools
+QTC_TEST_DEPENDS += \
+    qbsprojectmanager \
+    qmakeprojectmanager
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzer_global.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzer_global.h
new file mode 100644
index 0000000000000000000000000000000000000000..39fb52397659c6d9a12fbcac4afed448c680774b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzer_global.h
@@ -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
+
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0ffe9ca8c275bbbfce3e17c5b9ca1887f3888acb
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..4655a07eec81e4779d15dce6b0f079cd646d8029
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..800733a33179b30abf80fbcf16effc30b4004048
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconfigwidget.ui
@@ -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>
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerconstants.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconstants.h
new file mode 100644
index 0000000000000000000000000000000000000000..66b1f149fe873e064db3c41b71bb563401675030
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerconstants.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..173e5ee5964adcfb5b21806cdcef365b8e1342f4
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h
new file mode 100644
index 0000000000000000000000000000000000000000..6da02dfaa974d4d18b7ff65b8c817077ed52e8fe
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnostic.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fa0625891a3197b46fe5b5e69cc10cc5cc188fdb
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c93fb9f7791905ea5f64fe31d309bc2bf1962a1
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticmodel.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..69fb87a3bb5f2f68b8653da3b56d336fabfe8cbe
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h
new file mode 100644
index 0000000000000000000000000000000000000000..392294fd86135db33fd34d3211e1c96c50d5a1d2
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerdiagnosticview.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dd0727864fc0a3814cf334e9898c334f080aafd5
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b05ada7aa34a0c0e89516811bd24e150a05ebd1
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerlogfilereader.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..eb9683e3d42c1ca63746ddbaa736e2c403ef067a
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.h
new file mode 100644
index 0000000000000000000000000000000000000000..b663a16487758d41e07dceb0634de367330d3c26
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerplugin.h
@@ -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
+
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4d37154c8585e72450bf1371ebd55382e7dc2d46
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..f30298b69f67859ffcbdfab898e398543551607b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettings.h
@@ -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.
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c0b456345b6b1aad34cbae498be3ad7112f9ff25
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h
new file mode 100644
index 0000000000000000000000000000000000000000..a588a7824d785556f673b0cbe2a1c3624614fe65
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingsmanager.h
@@ -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.
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3ec14f7d2913ff8a35cc675ca0db6f14abf35d74
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.cpp
@@ -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"
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..b68003b25c52b5b799179835fe2c2a7bca0c6dae
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.h
@@ -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.
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui
new file mode 100644
index 0000000000000000000000000000000000000000..c131bbe0c22f9a53538851204da347dba87e47d4
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerprojectsettingswidget.ui
@@ -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>
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..35652728c47f3c35e30a41124cbc5cef2977a66b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
new file mode 100644
index 0000000000000000000000000000000000000000..06cbc7ed9329ce674781db1f981ef254135d561e
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b89ea1cee55c826a8d7d828d4d972a4c8d94c1c9
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f9e5fc81cd7c7204ded8c0703eb0c5e75336658
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrolfactory.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..00e0672d3b487f893d2038dbc4292741f8d17b00
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
new file mode 100644
index 0000000000000000000000000000000000000000..92852d34c2c46d7551d8fe18c26dbee3370013cc
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerrunner.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..803cbb02f09bf4fe0991af1b14c22d4f75348e1d
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f7d80a01fbed81210e0dde0563256c67d14959f
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzersettings.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9fe109d63d6c6d54a44edc80895965fb99e394f0
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.cpp
@@ -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"
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5a748d0cd129da58f3a016c64116543c22aeb82
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzertool.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..12acb811a629bd5d2c854b1ccd168981e9e405d3
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.h
new file mode 100644
index 0000000000000000000000000000000000000000..b49ef5b1d30043c28b5097e163de22ffe299ce00
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.h
@@ -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
+
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.qrc b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..d8a1a8674e866db31d4c1853e81566a27ab132d3
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerunittests.qrc
@@ -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>
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1c7af5176bac1a9d797aac7b46951e75cbe3ee7d
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h
new file mode 100644
index 0000000000000000000000000000000000000000..63f6f6517f96ae8e0c9ba752de0c3a6e5b637554
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerautotest.qbs b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerautotest.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..88dfcb32a138713b31e4f2543039f5905f489fde
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerautotest.qbs
@@ -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 + "/..")
+}
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.pro b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d9dda64f85d69012c909ea7e16669ad3081ae11b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.pro
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.qbs b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..a1ac819f5f640805690be13b9938d823c975ddf2
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/clangstaticanalyzerlogfilereader.qbs
@@ -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"
+    ]
+}
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/noDiagnostics.plist b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/noDiagnostics.plist
new file mode 100644
index 0000000000000000000000000000000000000000..2cccbf770f9479f64213a0917abc2cfe6f7a6b8a
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/noDiagnostics.plist
@@ -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>
\ No newline at end of file
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/someDiagnostics.plist b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/someDiagnostics.plist
new file mode 100644
index 0000000000000000000000000000000000000000..3fa5effad2d634dd1b0d2bdb53497433818c3b1d
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/data/someDiagnostics.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 &apos;foo&apos;</string>
+     <key>message</key>
+     <string>Null pointer value stored to &apos;foo&apos;</string>
+    </dict>
+    <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>35</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>35</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>36</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>36</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
+     <key>kind</key><string>event</string>
+     <key>location</key>
+     <dict>
+      <key>line</key><integer>36</integer>
+      <key>col</key><integer>3</integer>
+      <key>file</key><integer>0</integer>
+     </dict>
+     <key>ranges</key>
+     <array>
+       <array>
+        <dict>
+         <key>line</key><integer>36</integer>
+         <key>col</key><integer>3</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+        <dict>
+         <key>line</key><integer>36</integer>
+         <key>col</key><integer>5</integer>
+         <key>file</key><integer>0</integer>
+        </dict>
+       </array>
+     </array>
+     <key>depth</key><integer>0</integer>
+     <key>extended_message</key>
+     <string>Called function pointer is null (null dereference)</string>
+     <key>message</key>
+     <string>Called function pointer is null (null dereference)</string>
+    </dict>
+   </array>
+   <key>description</key><string>Called function pointer is null (null dereference)</string>
+   <key>category</key><string>Logic error</string>
+   <key>type</key><string>Called function pointer is null (null dereference)</string>
+  <key>issue_context_kind</key><string>function</string>
+  <key>issue_context</key><string>test</string>
+  <key>issue_hash</key><string>3</string>
+  <key>location</key>
+  <dict>
+   <key>line</key><integer>36</integer>
+   <key>col</key><integer>3</integer>
+   <key>file</key><integer>0</integer>
+  </dict>
+  <key>HTMLDiagnostics_files</key>
+  <array>
+   <string>report-6c3c2a.html</string>
+  </array>
+  </dict>
+ </array>
+</dict>
+</plist>
\ No newline at end of file
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8050c514ed218ae4f325869a0af761b759cf638
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerlogfilereader/tst_clangstaticanalyzerlogfilereader.cpp
@@ -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"
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.pro b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.pro
new file mode 100644
index 0000000000000000000000000000000000000000..b19bae409288cb7c7411a46188508584f87a114b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.pro
@@ -0,0 +1,11 @@
+include(../tests.pri)
+
+TARGET = tst_clangstaticanalyzerrunnertest
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+SOURCES += \
+    tst_clangstaticanalyzerrunner.cpp \
+    $$PLUGINDIR/clangstaticanalyzerrunner.cpp
+HEADERS += \
+    $$PLUGINDIR/clangstaticanalyzerrunner.h
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.qbs b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..6b0f9da3f37097f9bf11ec32cf5c74cd54802668
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/clangstaticanalyzerrunner.qbs
@@ -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",
+    ]
+}
diff --git a/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/tst_clangstaticanalyzerrunner.cpp b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/tst_clangstaticanalyzerrunner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..712875c329168238189fd45e9653b99495371bbe
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/clangstaticanalyzerrunner/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"
diff --git a/src/plugins/clangstaticanalyzer/tests/tests.pri b/src/plugins/clangstaticanalyzer/tests/tests.pri
new file mode 100644
index 0000000000000000000000000000000000000000..8975fc8448df84e945c9c486947bef50e23e0489
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/tests.pri
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/tests/tests.pro b/src/plugins/clangstaticanalyzer/tests/tests.pro
new file mode 100644
index 0000000000000000000000000000000000000000..72e7c586e9dc16e5c936de0d9440679ddb717c5b
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/tests.pro
@@ -0,0 +1,6 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = \
+    clangstaticanalyzerrunner \
+    clangstaticanalyzerlogfilereader
diff --git a/src/plugins/clangstaticanalyzer/tests/tests.qbs b/src/plugins/clangstaticanalyzer/tests/tests.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..a6dc94d66cf09a4cfadbc4c9a34e5313eb398296
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/tests/tests.qbs
@@ -0,0 +1,8 @@
+import qbs
+
+Project {
+    references: [
+        "clangstaticanalyzerlogfilereader",
+        "clangstaticanalyzerrunner",
+    ]
+}
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/main.cpp b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b48f94ec827033ef073fb3c7f060837e90b935ec
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/main.cpp
@@ -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();
+}
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.cpp b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..49d64fce7cedf4ed8c5e0124cfe43e90c23c6ab6
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.cpp
@@ -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;
+}
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.h b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce76956bad998e8efedb3b6f7ac77c4da8551018
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.h
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.ui b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.ui
new file mode 100644
index 0000000000000000000000000000000000000000..6050363fa71ed2da04105077f9fef06150d05ee2
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/mainwindow.ui
@@ -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>
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.pro b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.pro
new file mode 100644
index 0000000000000000000000000000000000000000..d9e1f2590b0494c27bc561d9b8ec8a6d8a68c36d
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.pro
@@ -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
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.qbs b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..e641f9bd54dfb731df340ebca94795d8ba9345df
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/qt-widgets-app/qt-widgets-app.qbs
@@ -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"
+    ]
+}
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/simple/main.cpp b/src/plugins/clangstaticanalyzer/unit-tests/simple/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..af917a3a3328bcec2869c195603a20f8b607ecca
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/simple/main.cpp
@@ -0,0 +1,5 @@
+int main()
+{
+    int *i = 0;
+    *i = 42;
+}
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.pro b/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.pro
new file mode 100644
index 0000000000000000000000000000000000000000..fb560c2af612cc4779c1aeba22a1a21ff8e99d20
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.pro
@@ -0,0 +1,3 @@
+CONFIG -= QT
+
+SOURCES = main.cpp
diff --git a/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.qbs b/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.qbs
new file mode 100644
index 0000000000000000000000000000000000000000..f6ae698a0cb6b887b931d41df7b7b12e8d4579f2
--- /dev/null
+++ b/src/plugins/clangstaticanalyzer/unit-tests/simple/simple.qbs
@@ -0,0 +1,5 @@
+import qbs
+
+CppApplication {
+    files: ["main.cpp"]
+}
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index cf1904f263f0b1981e1ce0593aef85873a3dceb9..baa76e50d9045da703c83c4c37dc8afda5f1ae74 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -3,6 +3,7 @@ include(../../qtcreator.pri)
 TEMPLATE  = subdirs
 
 SUBDIRS   = \
+    clangstaticanalyzer \
     coreplugin \
     texteditor \
     cppeditor \
diff --git a/src/plugins/plugins.qbs b/src/plugins/plugins.qbs
index 34d5510893bfff7efe0e96b9673dbd7060384965..6505ce0822ebf381a8e10d8e3ff7f315c96fac36 100644
--- a/src/plugins/plugins.qbs
+++ b/src/plugins/plugins.qbs
@@ -13,6 +13,7 @@ Project {
         "bineditor/bineditor.qbs",
         "bookmarks/bookmarks.qbs",
         "clangcodemodel/clangcodemodel.qbs",
+        "clangstaticanalyzer/clangstaticanalyzer.qbs",
         "classview/classview.qbs",
         "clearcase/clearcase.qbs",
         "cmakeprojectmanager/cmakeprojectmanager.qbs",