From b278dc87ca8662ff98aeabc03ed4293021aab955 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 31 Aug 2015 16:28:26 +0200 Subject: [PATCH] Clang: Add diagnostics Diagnostics are now moved to the clang backend process. Fixits are supported too. Change-Id: I20faacf466bbf78dec479220c3d7b336a47bc453 Reviewed-by: Nikolai Kosjar --- .../clangbackendipc/clangbackendipc-lib.pri | 16 +- .../clangbackendipc/clangbackendipc_global.h | 10 +- src/libs/clangbackendipc/cmbmessages.cpp | 25 ++ .../clangbackendipc/diagnosticcontainer.cpp | 202 ++++++++++++ .../clangbackendipc/diagnosticcontainer.h | 98 ++++++ .../diagnosticschangedmessage.cpp | 112 +++++++ .../diagnosticschangedmessage.h | 79 +++++ src/libs/clangbackendipc/fixitcontainer.cpp | 98 ++++++ src/libs/clangbackendipc/fixitcontainer.h | 70 ++++ .../clangbackendipc/ipcclientdispatcher.cpp | 6 + .../clangbackendipc/ipcclientdispatcher.h | 1 + .../clangbackendipc/ipcclientinterface.cpp | 4 + src/libs/clangbackendipc/ipcclientinterface.h | 3 + src/libs/clangbackendipc/ipcclientproxy.cpp | 6 + src/libs/clangbackendipc/ipcclientproxy.h | 1 + .../clangbackendipc/ipcserverinterface.cpp | 4 + src/libs/clangbackendipc/ipcserverinterface.h | 1 + src/libs/clangbackendipc/ipcserverproxy.cpp | 6 + src/libs/clangbackendipc/ipcserverproxy.h | 1 + .../requestdiagnosticsmessage.cpp | 97 ++++++ .../requestdiagnosticsmessage.h | 71 ++++ .../sourcelocationcontainer.cpp | 111 +++++++ .../clangbackendipc/sourcelocationcontainer.h | 77 +++++ .../clangbackendipc/sourcerangecontainer.cpp | 100 ++++++ .../clangbackendipc/sourcerangecontainer.h | 71 ++++ .../clangbackendipcintegration.cpp | 43 ++- .../clangbackendipcintegration.h | 7 + src/plugins/clangcodemodel/clangcodemodel.pro | 2 + src/plugins/clangcodemodel/clangcodemodel.qbs | 2 + .../clangcodemodel/clangcodemodelplugin.cpp | 11 + .../clangcompletionassistprocessor.cpp | 15 +- .../clangeditordocumentprocessor.cpp | 305 +++++++++++++++--- .../clangeditordocumentprocessor.h | 18 +- src/plugins/clangcodemodel/clangtextmark.cpp | 82 +++++ src/plugins/clangcodemodel/clangtextmark.h | 48 +++ src/plugins/clangcodemodel/clangutils.cpp | 14 + src/plugins/clangcodemodel/constants.h | 2 + .../test/clangcodecompletion_test.cpp | 22 ++ .../cpptools/baseeditordocumentprocessor.cpp | 4 +- src/plugins/debugger/qml/qmlengineutils.cpp | 2 +- src/plugins/glsleditor/glsleditor.cpp | 4 +- src/plugins/qmljseditor/qmljseditor.cpp | 2 +- .../qmljseditor/qmljssemantichighlighter.cpp | 4 +- src/plugins/texteditor/fontsettings.cpp | 2 +- src/plugins/texteditor/textmark.cpp | 14 + src/plugins/texteditor/textmark.h | 2 + .../ipcsource/clangbackendclangipc-source.pri | 15 +- .../clangbackend/ipcsource/clangipcserver.cpp | 39 ++- .../clangbackend/ipcsource/clangipcserver.h | 1 + .../clangbackend/ipcsource/diagnostic.cpp | 178 ++++++++++ src/tools/clangbackend/ipcsource/diagnostic.h | 94 ++++++ .../clangbackend/ipcsource/diagnosticset.cpp | 115 +++++++ .../clangbackend/ipcsource/diagnosticset.h | 84 +++++ .../ipcsource/diagnosticsetiterator.h | 93 ++++++ src/tools/clangbackend/ipcsource/fixit.cpp | 63 ++++ src/tools/clangbackend/ipcsource/fixit.h | 65 ++++ .../clangbackend/ipcsource/projectpart.cpp | 7 + .../clangbackend/ipcsource/projectpart.h | 2 + .../clangbackend/ipcsource/sourcelocation.cpp | 89 +++++ .../clangbackend/ipcsource/sourcelocation.h | 69 ++++ .../clangbackend/ipcsource/sourcerange.cpp | 64 ++++ .../clangbackend/ipcsource/sourcerange.h | 61 ++++ .../ipcsource/translationunit.cpp | 20 +- .../clangbackend/ipcsource/translationunit.h | 7 +- tests/unit/echoserver/echoipcserver.cpp | 6 + tests/unit/echoserver/echoipcserver.h | 1 + tests/unit/unittest/clangipcservertest.cpp | 1 + tests/unit/unittest/clangstringtest.cpp | 21 +- .../unittest/clientserverinprocesstest.cpp | 48 ++- .../unittest/clientserveroutsideprocess.cpp | 5 +- .../unittest/data/diagnostic_diagnostic.cpp | 10 + .../data/diagnostic_diagnosticset.cpp | 5 + tests/unit/unittest/data/diagnostic_fixit.cpp | 4 + .../data/diagnostic_source_location.cpp | 5 + .../unittest/data/diagnostic_source_range.cpp | 9 + tests/unit/unittest/diagnosticsettest.cpp | 118 +++++++ tests/unit/unittest/diagnostictest.cpp | 149 +++++++++ tests/unit/unittest/fixittest.cpp | 114 +++++++ tests/unit/unittest/mockipclient.h | 24 +- tests/unit/unittest/mockipcserver.h | 28 +- .../unittest/readandwritemessageblocktest.cpp | 76 +++-- tests/unit/unittest/sourcelocationtest.cpp | 89 +++++ tests/unit/unittest/sourcerangetest.cpp | 106 ++++++ tests/unit/unittest/unittest.pro | 5 + 84 files changed, 3633 insertions(+), 132 deletions(-) create mode 100644 src/libs/clangbackendipc/diagnosticcontainer.cpp create mode 100644 src/libs/clangbackendipc/diagnosticcontainer.h create mode 100644 src/libs/clangbackendipc/diagnosticschangedmessage.cpp create mode 100644 src/libs/clangbackendipc/diagnosticschangedmessage.h create mode 100644 src/libs/clangbackendipc/fixitcontainer.cpp create mode 100644 src/libs/clangbackendipc/fixitcontainer.h create mode 100644 src/libs/clangbackendipc/requestdiagnosticsmessage.cpp create mode 100644 src/libs/clangbackendipc/requestdiagnosticsmessage.h create mode 100644 src/libs/clangbackendipc/sourcelocationcontainer.cpp create mode 100644 src/libs/clangbackendipc/sourcelocationcontainer.h create mode 100644 src/libs/clangbackendipc/sourcerangecontainer.cpp create mode 100644 src/libs/clangbackendipc/sourcerangecontainer.h create mode 100644 src/plugins/clangcodemodel/clangtextmark.cpp create mode 100644 src/plugins/clangcodemodel/clangtextmark.h create mode 100644 src/tools/clangbackend/ipcsource/diagnostic.cpp create mode 100644 src/tools/clangbackend/ipcsource/diagnostic.h create mode 100644 src/tools/clangbackend/ipcsource/diagnosticset.cpp create mode 100644 src/tools/clangbackend/ipcsource/diagnosticset.h create mode 100644 src/tools/clangbackend/ipcsource/diagnosticsetiterator.h create mode 100644 src/tools/clangbackend/ipcsource/fixit.cpp create mode 100644 src/tools/clangbackend/ipcsource/fixit.h create mode 100644 src/tools/clangbackend/ipcsource/sourcelocation.cpp create mode 100644 src/tools/clangbackend/ipcsource/sourcelocation.h create mode 100644 src/tools/clangbackend/ipcsource/sourcerange.cpp create mode 100644 src/tools/clangbackend/ipcsource/sourcerange.h create mode 100644 tests/unit/unittest/data/diagnostic_diagnostic.cpp create mode 100644 tests/unit/unittest/data/diagnostic_diagnosticset.cpp create mode 100644 tests/unit/unittest/data/diagnostic_fixit.cpp create mode 100644 tests/unit/unittest/data/diagnostic_source_location.cpp create mode 100644 tests/unit/unittest/data/diagnostic_source_range.cpp create mode 100644 tests/unit/unittest/diagnosticsettest.cpp create mode 100644 tests/unit/unittest/diagnostictest.cpp create mode 100644 tests/unit/unittest/fixittest.cpp create mode 100644 tests/unit/unittest/sourcelocationtest.cpp create mode 100644 tests/unit/unittest/sourcerangetest.cpp diff --git a/src/libs/clangbackendipc/clangbackendipc-lib.pri b/src/libs/clangbackendipc/clangbackendipc-lib.pri index eee627f6d72..fdc27dc1ebd 100644 --- a/src/libs/clangbackendipc/clangbackendipc-lib.pri +++ b/src/libs/clangbackendipc/clangbackendipc-lib.pri @@ -37,7 +37,13 @@ SOURCES += $$PWD/ipcserverinterface.cpp \ $$PWD/projectpartcontainer.cpp \ $$PWD/projectpartsdonotexistmessage.cpp \ $$PWD/lineprefixer.cpp \ - $$PWD/clangbackendipcdebugutils.cpp + $$PWD/clangbackendipcdebugutils.cpp \ + $$PWD/diagnosticschangedmessage.cpp \ + $$PWD/diagnosticcontainer.cpp \ + $$PWD/sourcerangecontainer.cpp \ + $$PWD/sourcelocationcontainer.cpp \ + $$PWD/fixitcontainer.cpp \ + $$PWD/requestdiagnosticsmessage.cpp HEADERS += \ $$PWD/ipcserverinterface.h \ @@ -69,6 +75,12 @@ HEADERS += \ $$PWD/container_common.h \ $$PWD/clangbackendipc_global.h \ $$PWD/lineprefixer.h \ - $$PWD/clangbackendipcdebugutils.h + $$PWD/clangbackendipcdebugutils.h \ + $$PWD/diagnosticschangedmessage.h \ + $$PWD/diagnosticcontainer.h \ + $$PWD/sourcerangecontainer.h \ + $$PWD/sourcelocationcontainer.h \ + $$PWD/fixitcontainer.h \ + $$PWD/requestdiagnosticsmessage.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangbackendipc/clangbackendipc_global.h b/src/libs/clangbackendipc/clangbackendipc_global.h index 38b20faf423..5856e23221c 100644 --- a/src/libs/clangbackendipc/clangbackendipc_global.h +++ b/src/libs/clangbackendipc/clangbackendipc_global.h @@ -45,6 +45,14 @@ namespace ClangBackEnd { CMBIPC_EXPORT void registerTypes(); -} +enum class DiagnosticSeverity // one to one mapping of the clang enum numbers +{ + Ignored = 0, + Note = 1, + Warning = 2, + Error = 3, + Fatal = 4 +}; +} #endif // CLANGBACKENDIPC_GLOBAL_H diff --git a/src/libs/clangbackendipc/cmbmessages.cpp b/src/libs/clangbackendipc/cmbmessages.cpp index 540d41ea8b9..1177cadc61f 100644 --- a/src/libs/clangbackendipc/cmbmessages.cpp +++ b/src/libs/clangbackendipc/cmbmessages.cpp @@ -39,7 +39,12 @@ #include "cmbunregisterprojectsforcodecompletionmessage.h" #include "cmbcompletecodemessage.h" #include "cmbcodecompletedmessage.h" +#include "diagnosticcontainer.h" +#include "diagnosticschangedmessage.h" +#include "requestdiagnosticsmessage.h" #include "projectpartsdonotexistmessage.h" +#include "sourcelocationcontainer.h" +#include "sourcerangecontainer.h" #include "translationunitdoesnotexistmessage.h" #include @@ -102,6 +107,26 @@ void Messages::registerMessages() qRegisterMetaType(); qRegisterMetaTypeStreamOperators(); QMetaType::registerComparators(); + + qRegisterMetaType(); + qRegisterMetaTypeStreamOperators(); + QMetaType::registerComparators(); + + qRegisterMetaType(); + qRegisterMetaTypeStreamOperators(); + QMetaType::registerComparators(); + + qRegisterMetaType(); + qRegisterMetaTypeStreamOperators(); + QMetaType::registerComparators(); + + qRegisterMetaType(); + qRegisterMetaTypeStreamOperators(); + QMetaType::registerComparators(); + + qRegisterMetaType(); + qRegisterMetaTypeStreamOperators(); + QMetaType::registerComparators(); } } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/diagnosticcontainer.cpp b/src/libs/clangbackendipc/diagnosticcontainer.cpp new file mode 100644 index 00000000000..2d532b0eca2 --- /dev/null +++ b/src/libs/clangbackendipc/diagnosticcontainer.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "diagnosticcontainer.h" + +#include +#include + +namespace ClangBackEnd { + +DiagnosticContainer::DiagnosticContainer(const Utf8String &text, + const Utf8String &category, + const std::pair &options, + DiagnosticSeverity severity, + const SourceLocationContainer &location, + const QVector &ranges, + const QVector &fixIts, + const QVector &children) + : location_(location), + ranges_(ranges), + text_(text), + category_(category), + enableOption_(options.first), + disableOption_(options.second), + children_(children), + fixIts_(fixIts), + severity_(severity) +{ +} + +const Utf8String &DiagnosticContainer::text() const +{ + return text_; +} + +const Utf8String &DiagnosticContainer::category() const +{ + return category_; +} + +const Utf8String &DiagnosticContainer::enableOption() const +{ + return enableOption_; +} + +const Utf8String &DiagnosticContainer::disableOption() const +{ + return disableOption_; +} + +const SourceLocationContainer &DiagnosticContainer::location() const +{ + return location_; +} + +const QVector &DiagnosticContainer::ranges() const +{ + return ranges_; +} + +DiagnosticSeverity DiagnosticContainer::severity() const +{ + return severity_; +} + +const QVector &DiagnosticContainer::fixIts() const +{ + return fixIts_; +} + +const QVector &DiagnosticContainer::children() const +{ + return children_; +} + +quint32 &DiagnosticContainer::severityAsInt() +{ + return reinterpret_cast(severity_); +} + +QDataStream &operator<<(QDataStream &out, const DiagnosticContainer &container) +{ + out << container.text_; + out << container.category_; + out << container.enableOption_; + out << container.disableOption_; + out << container.location_; + out << quint32(container.severity_); + out << container.ranges_; + out << container.fixIts_; + out << container.children_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, DiagnosticContainer &container) +{ + in >> container.text_; + in >> container.category_; + in >> container.enableOption_; + in >> container.disableOption_; + in >> container.location_; + in >> container.severityAsInt(); + in >> container.ranges_; + in >> container.fixIts_; + in >> container.children_; + + return in; +} + +bool operator==(const DiagnosticContainer &first, const DiagnosticContainer &second) +{ + return first.text_ == second.text_ + && first.location_ == second.location_; +} + +bool operator<(const DiagnosticContainer &first, const DiagnosticContainer &second) +{ + return first.text_ < second.text_ + || (first.text_ == second.text_ && first.location_ < second.location_); +} + +static const char *severityToText(DiagnosticSeverity severity) +{ + switch (severity) { + case DiagnosticSeverity::Ignored: return "Ignored"; + case DiagnosticSeverity::Note: return "Note"; + case DiagnosticSeverity::Warning: return "Warning"; + case DiagnosticSeverity::Error: return "Error"; + case DiagnosticSeverity::Fatal: return "Fatal"; + } + + Q_UNREACHABLE(); +} + +QDebug operator<<(QDebug debug, const DiagnosticContainer &container) +{ + debug.nospace() << "DiagnosticContainer(" + << container.text() << ", " + << container.category() << ", " + << container.enableOption() << ", " + << container.disableOption() << ", " + << container.location() << ", " + << container.ranges() << ", " + << container.fixIts() << ", " + << container.children() + << ")"; + + return debug; +} + +void PrintTo(const DiagnosticContainer &container, ::std::ostream* os) +{ + *os << severityToText(container.severity()) << ": " + << container.text().constData() << ", " + << container.category().constData() << ", " + << container.enableOption().constData() << ", "; + PrintTo(container.location(), os); + *os << "["; + for (const auto &range : container.ranges()) + PrintTo(range, os); + *os << "], "; + *os << "["; + for (const auto &fixIt : container.fixIts()) + PrintTo(fixIt, os); + *os << "], "; + *os << "["; + for (const auto &child : container.children()) + PrintTo(child, os); + *os << "], "; + *os << ")"; +} + +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/diagnosticcontainer.h b/src/libs/clangbackendipc/diagnosticcontainer.h new file mode 100644 index 00000000000..b1829ab19f9 --- /dev/null +++ b/src/libs/clangbackendipc/diagnosticcontainer.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_DIAGNOSTICCONTAINER_H +#define CLANGBACKEND_DIAGNOSTICCONTAINER_H + +#include "sourcerangecontainer.h" +#include "fixitcontainer.h" + +#include + +#include + +namespace ClangBackEnd { + +class CMBIPC_EXPORT DiagnosticContainer +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticContainer &container); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, DiagnosticContainer &container); + friend CMBIPC_EXPORT bool operator==(const DiagnosticContainer &first, const DiagnosticContainer &second); + friend CMBIPC_EXPORT bool operator<(const DiagnosticContainer &first, const DiagnosticContainer &second); + +public: + DiagnosticContainer() = default; + DiagnosticContainer(const Utf8String &text, + const Utf8String &category, + const std::pair &options, + DiagnosticSeverity severity, + const SourceLocationContainer &location, + const QVector &ranges, + const QVector &fixIts, + const QVector &children); + + const Utf8String &text() const; + const Utf8String &category() const; + const Utf8String &enableOption() const; + const Utf8String &disableOption() const; + const SourceLocationContainer &location() const; + const QVector &ranges() const; + DiagnosticSeverity severity() const; + const QVector &fixIts() const; + const QVector &children() const; + +private: + quint32 &severityAsInt(); + +private: + SourceLocationContainer location_; + QVector ranges_; + Utf8String text_; + Utf8String category_; + Utf8String enableOption_; + Utf8String disableOption_; + QVector children_; + QVector fixIts_; + DiagnosticSeverity severity_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticContainer &container); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, DiagnosticContainer &container); +CMBIPC_EXPORT bool operator==(const DiagnosticContainer &first, const DiagnosticContainer &second); +CMBIPC_EXPORT bool operator<(const DiagnosticContainer &first, const DiagnosticContainer &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const DiagnosticContainer &container); +void PrintTo(const DiagnosticContainer &container, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::DiagnosticContainer) + +#endif // CLANGBACKEND_DIAGNOSTICCONTAINER_H diff --git a/src/libs/clangbackendipc/diagnosticschangedmessage.cpp b/src/libs/clangbackendipc/diagnosticschangedmessage.cpp new file mode 100644 index 00000000000..44c385f64b2 --- /dev/null +++ b/src/libs/clangbackendipc/diagnosticschangedmessage.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "diagnosticschangedmessage.h" + +#include "container_common.h" + +#include +#include + +namespace ClangBackEnd { + +DiagnosticsChangedMessage::DiagnosticsChangedMessage(const FileContainer &file, + const QVector &diagnostics, + quint32 documentRevision) + : file_(file), + diagnostics_(diagnostics), + documentRevision_(documentRevision) +{ +} + +const FileContainer &DiagnosticsChangedMessage::file() const +{ + return file_; +} + +const QVector &DiagnosticsChangedMessage::diagnostics() const +{ + return diagnostics_; +} + +quint32 DiagnosticsChangedMessage::documentRevision() const +{ + return documentRevision_; +} + +QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message) +{ + out << message.file_; + out << message.diagnostics_; + out << message.documentRevision_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, DiagnosticsChangedMessage &message) +{ + in >> message.file_; + in >> message.diagnostics_; + in >> message.documentRevision_; + + return in; +} + +bool operator==(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second) +{ + return first.file_ == second.file_ + && first.diagnostics_ == second.diagnostics_; +} + +bool operator<(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second) +{ + return first.file_ < second.file_ + && compareContainer(first.diagnostics_, second.diagnostics_); +} + +QDebug operator<<(QDebug debug, const DiagnosticsChangedMessage &message) +{ + debug.nospace() << "DiagnosticsChangedMessage(" + << message.file_ << QStringLiteral(", ") + << message.documentRevision_ + << ")"; + + return debug; +} + +void PrintTo(const DiagnosticsChangedMessage &message, ::std::ostream* os) +{ + *os << "DiagnosticsChangedMessage("; + PrintTo(message.file(), os); + *os << ")"; +} + +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/diagnosticschangedmessage.h b/src/libs/clangbackendipc/diagnosticschangedmessage.h new file mode 100644 index 00000000000..17485c26896 --- /dev/null +++ b/src/libs/clangbackendipc/diagnosticschangedmessage.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_DIAGNOSTICSCHANGEDMESSAGE_H +#define CLANGBACKEND_DIAGNOSTICSCHANGEDMESSAGE_H + +#include "clangbackendipc_global.h" +#include "diagnosticcontainer.h" +#include "filecontainer.h" + +#include + +namespace ClangBackEnd { + +class CMBIPC_EXPORT DiagnosticsChangedMessage +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, DiagnosticsChangedMessage &message); + friend CMBIPC_EXPORT bool operator==(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second); + friend CMBIPC_EXPORT bool operator<(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second); + friend CMBIPC_EXPORT QDebug operator<<(QDebug debug, const DiagnosticsChangedMessage &message); + friend void PrintTo(const DiagnosticsChangedMessage &message, ::std::ostream* os); + +public: + DiagnosticsChangedMessage() = default; + DiagnosticsChangedMessage(const FileContainer &file, + const QVector &diagnostics, + quint32 documentRevision); + + const FileContainer &file() const; + const QVector &diagnostics() const; + quint32 documentRevision() const; + +private: + FileContainer file_; + QVector diagnostics_; + quint32 documentRevision_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const DiagnosticsChangedMessage &message); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, DiagnosticsChangedMessage &message); +CMBIPC_EXPORT bool operator==(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second); +CMBIPC_EXPORT bool operator<(const DiagnosticsChangedMessage &first, const DiagnosticsChangedMessage &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const DiagnosticsChangedMessage &message); +void PrintTo(const DiagnosticsChangedMessage &message, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::DiagnosticsChangedMessage) + +#endif // CLANGBACKEND_DIAGNOSTICSCHANGEDMESSAGE_H diff --git a/src/libs/clangbackendipc/fixitcontainer.cpp b/src/libs/clangbackendipc/fixitcontainer.cpp new file mode 100644 index 00000000000..4eaca0e4185 --- /dev/null +++ b/src/libs/clangbackendipc/fixitcontainer.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "fixitcontainer.h" + +#include + +namespace ClangBackEnd { + +FixItContainer::FixItContainer(const Utf8String &text, + const SourceRangeContainer &range) + : range_(range), + text_(text) +{ +} + +const Utf8String &FixItContainer::text() const +{ + return text_; +} + +const SourceRangeContainer &FixItContainer::range() const +{ + return range_; +} + +QDataStream &operator<<(QDataStream &out, const FixItContainer &container) +{ + out << container.text_; + out << container.range_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, FixItContainer &container) +{ + in >> container.text_; + in >> container.range_; + + return in; +} + +bool operator==(const FixItContainer &first, const FixItContainer &second) +{ + return first.text_ == second.text_ && first.range_ == second.range_; +} + +bool operator<(const FixItContainer &first, const FixItContainer &second) +{ + return first.range_ < second.range_; +} + +QDebug operator<<(QDebug debug, const FixItContainer &container) +{ + debug.nospace() << "FixItContainer(" + << container.text() << ", " + << container.range() + << ")"; + + return debug; +} + +void PrintTo(const FixItContainer &container, ::std::ostream* os) +{ + *os << "FixIt(" << container.text().constData() << ", "; + *os<< ")"; + PrintTo(container.range(), os); +} + +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/fixitcontainer.h b/src/libs/clangbackendipc/fixitcontainer.h new file mode 100644 index 00000000000..5959f4befed --- /dev/null +++ b/src/libs/clangbackendipc/fixitcontainer.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_FIXITCONTAINER_H +#define CLANGBACKEND_FIXITCONTAINER_H + +#include "sourcerangecontainer.h" + +namespace ClangBackEnd { + +class CMBIPC_EXPORT FixItContainer +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const FixItContainer &container); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, FixItContainer &container); + friend CMBIPC_EXPORT bool operator==(const FixItContainer &first, const FixItContainer &second); + friend CMBIPC_EXPORT bool operator<(const FixItContainer &first, const FixItContainer &second); + +public: + FixItContainer() = default; + FixItContainer(const Utf8String &text, + const SourceRangeContainer &range); + + const Utf8String &text() const; + const SourceRangeContainer &range() const; + +private: + SourceRangeContainer range_; + Utf8String text_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const FixItContainer &container); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, FixItContainer &container); +CMBIPC_EXPORT bool operator==(const FixItContainer &first, const FixItContainer &second); +CMBIPC_EXPORT bool operator<(const FixItContainer &first, const FixItContainer &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const FixItContainer &container); +void PrintTo(const FixItContainer &container, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::FixItContainer) + +#endif // CLANGBACKEND_FIXITCONTAINER_H diff --git a/src/libs/clangbackendipc/ipcclientdispatcher.cpp b/src/libs/clangbackendipc/ipcclientdispatcher.cpp index 09ea31221c7..bd9c7eb7f24 100644 --- a/src/libs/clangbackendipc/ipcclientdispatcher.cpp +++ b/src/libs/clangbackendipc/ipcclientdispatcher.cpp @@ -74,5 +74,11 @@ void IpcClientDispatcher::projectPartsDoNotExist(const ProjectPartsDoNotExistMes client->projectPartsDoNotExist(message); } +void IpcClientDispatcher::diagnosticsChanged(const DiagnosticsChangedMessage &message) +{ + for (auto *client : clients) + client->diagnosticsChanged(message); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/ipcclientdispatcher.h b/src/libs/clangbackendipc/ipcclientdispatcher.h index 463d2ebe2f1..7d8329e4165 100644 --- a/src/libs/clangbackendipc/ipcclientdispatcher.h +++ b/src/libs/clangbackendipc/ipcclientdispatcher.h @@ -48,6 +48,7 @@ public: void codeCompleted(const CodeCompletedMessage &message) override; void translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) override; void projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message) override; + void diagnosticsChanged(const DiagnosticsChangedMessage &message) override; private: QVector clients; diff --git a/src/libs/clangbackendipc/ipcclientinterface.cpp b/src/libs/clangbackendipc/ipcclientinterface.cpp index 8b6a94e6ccd..28d2410662d 100644 --- a/src/libs/clangbackendipc/ipcclientinterface.cpp +++ b/src/libs/clangbackendipc/ipcclientinterface.cpp @@ -34,6 +34,7 @@ #include "cmbechomessage.h" #include "projectpartsdonotexistmessage.h" #include "translationunitdoesnotexistmessage.h" +#include "diagnosticschangedmessage.h" #include #include @@ -48,6 +49,7 @@ void IpcClientInterface::dispatch(const QVariant &message) static const int codeCompletedMessageType = QMetaType::type("ClangBackEnd::CodeCompletedMessage"); static const int translationUnitDoesNotExistMessage = QMetaType::type("ClangBackEnd::TranslationUnitDoesNotExistMessage"); static const int projectPartsDoNotExistMessage = QMetaType::type("ClangBackEnd::ProjectPartsDoNotExistMessage"); + static const int diagnosticsChangedMessage = QMetaType::type("ClangBackEnd::DiagnosticsChangedMessage"); int type = message.userType(); @@ -61,6 +63,8 @@ void IpcClientInterface::dispatch(const QVariant &message) translationUnitDoesNotExist(message.value()); else if (type == projectPartsDoNotExistMessage) projectPartsDoNotExist(message.value()); + else if (type == diagnosticsChangedMessage) + diagnosticsChanged(message.value()); else qWarning() << "Unknown IpcClientMessage"; } diff --git a/src/libs/clangbackendipc/ipcclientinterface.h b/src/libs/clangbackendipc/ipcclientinterface.h index 412d67a242a..4c3acff829a 100644 --- a/src/libs/clangbackendipc/ipcclientinterface.h +++ b/src/libs/clangbackendipc/ipcclientinterface.h @@ -45,6 +45,8 @@ class CompleteCodeMessage; class CodeCompletedMessage; class TranslationUnitDoesNotExistMessage; class ProjectPartsDoNotExistMessage; +class DiagnosticsChangedMessage; +class RequestDiagnosticsMessage; class CMBIPC_EXPORT IpcClientInterface : public IpcInterface { @@ -56,6 +58,7 @@ public: virtual void codeCompleted(const CodeCompletedMessage &message) = 0; virtual void translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) = 0; virtual void projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message) = 0; + virtual void diagnosticsChanged(const DiagnosticsChangedMessage &message) = 0; }; } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/ipcclientproxy.cpp b/src/libs/clangbackendipc/ipcclientproxy.cpp index 4b419a84f77..f7319e208d9 100644 --- a/src/libs/clangbackendipc/ipcclientproxy.cpp +++ b/src/libs/clangbackendipc/ipcclientproxy.cpp @@ -34,6 +34,7 @@ #include "cmbcodecompletedmessage.h" #include "cmbechomessage.h" #include "cmbregistertranslationunitsforcodecompletionmessage.h" +#include "diagnosticschangedmessage.h" #include "ipcserverinterface.h" #include "projectpartsdonotexistmessage.h" #include "translationunitdoesnotexistmessage.h" @@ -98,6 +99,11 @@ void IpcClientProxy::projectPartsDoNotExist(const ProjectPartsDoNotExistMessage writeMessageBlock.write(QVariant::fromValue(message)); } +void IpcClientProxy::diagnosticsChanged(const DiagnosticsChangedMessage &message) +{ + writeMessageBlock.write(QVariant::fromValue(message)); +} + void IpcClientProxy::readMessages() { for (const QVariant &message : readMessageBlock.readAll()) diff --git a/src/libs/clangbackendipc/ipcclientproxy.h b/src/libs/clangbackendipc/ipcclientproxy.h index c95fb1e429d..77b53c7cd2d 100644 --- a/src/libs/clangbackendipc/ipcclientproxy.h +++ b/src/libs/clangbackendipc/ipcclientproxy.h @@ -62,6 +62,7 @@ public: void codeCompleted(const CodeCompletedMessage &message) override; void translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) override; void projectPartsDoNotExist(const ProjectPartsDoNotExistMessage &message) override; + void diagnosticsChanged(const DiagnosticsChangedMessage &message) override; void readMessages(); diff --git a/src/libs/clangbackendipc/ipcserverinterface.cpp b/src/libs/clangbackendipc/ipcserverinterface.cpp index 1fab6de0f68..0e8ab5c2372 100644 --- a/src/libs/clangbackendipc/ipcserverinterface.cpp +++ b/src/libs/clangbackendipc/ipcserverinterface.cpp @@ -35,6 +35,7 @@ #include "cmbregistertranslationunitsforcodecompletionmessage.h" #include "cmbunregisterprojectsforcodecompletionmessage.h" #include "cmbunregistertranslationunitsforcodecompletionmessage.h" +#include "requestdiagnosticsmessage.h" #include #include @@ -49,6 +50,7 @@ void IpcServerInterface::dispatch(const QVariant &message) static const int registerProjectPartsForCodeCompletionMessageType = QMetaType::type("ClangBackEnd::RegisterProjectPartsForCodeCompletionMessage"); static const int unregisterProjectPartsForCodeCompletionMessageType = QMetaType::type("ClangBackEnd::UnregisterProjectPartsForCodeCompletionMessage"); static const int completeCodeMessageType = QMetaType::type("ClangBackEnd::CompleteCodeMessage"); + static const int requestDiagnosticsMessageType = QMetaType::type("ClangBackEnd::RequestDiagnosticsMessage"); int type = message.userType(); @@ -64,6 +66,8 @@ void IpcServerInterface::dispatch(const QVariant &message) unregisterProjectPartsForCodeCompletion(message.value()); else if (type == completeCodeMessageType) completeCode(message.value()); + else if (type == requestDiagnosticsMessageType) + requestDiagnostics(message.value()); else qWarning() << "Unknown IpcServerMessage"; } diff --git a/src/libs/clangbackendipc/ipcserverinterface.h b/src/libs/clangbackendipc/ipcserverinterface.h index 257d95466f8..6252443584d 100644 --- a/src/libs/clangbackendipc/ipcserverinterface.h +++ b/src/libs/clangbackendipc/ipcserverinterface.h @@ -50,6 +50,7 @@ public: virtual void registerProjectPartsForCodeCompletion(const RegisterProjectPartsForCodeCompletionMessage &message) = 0; virtual void unregisterProjectPartsForCodeCompletion(const UnregisterProjectPartsForCodeCompletionMessage &message) = 0; virtual void completeCode(const CompleteCodeMessage &message) = 0; + virtual void requestDiagnostics(const RequestDiagnosticsMessage &message) = 0; void addClient(IpcClientInterface *client); void removeClient(IpcClientInterface *client); diff --git a/src/libs/clangbackendipc/ipcserverproxy.cpp b/src/libs/clangbackendipc/ipcserverproxy.cpp index 6a9446e51b9..5917fd975ae 100644 --- a/src/libs/clangbackendipc/ipcserverproxy.cpp +++ b/src/libs/clangbackendipc/ipcserverproxy.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -95,5 +96,10 @@ void IpcServerProxy::completeCode(const CompleteCodeMessage &message) writeMessageBlock.write(QVariant::fromValue(message)); } +void IpcServerProxy::requestDiagnostics(const ClangBackEnd::RequestDiagnosticsMessage &message) +{ + writeMessageBlock.write(QVariant::fromValue(message)); +} + } // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/ipcserverproxy.h b/src/libs/clangbackendipc/ipcserverproxy.h index 98cee2abdaa..5adbaf468ed 100644 --- a/src/libs/clangbackendipc/ipcserverproxy.h +++ b/src/libs/clangbackendipc/ipcserverproxy.h @@ -61,6 +61,7 @@ public: void registerProjectPartsForCodeCompletion(const RegisterProjectPartsForCodeCompletionMessage &message) override; void unregisterProjectPartsForCodeCompletion(const UnregisterProjectPartsForCodeCompletionMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; + void requestDiagnostics(const RequestDiagnosticsMessage &message) override; void readMessages(); diff --git a/src/libs/clangbackendipc/requestdiagnosticsmessage.cpp b/src/libs/clangbackendipc/requestdiagnosticsmessage.cpp new file mode 100644 index 00000000000..5ff6bf4783d --- /dev/null +++ b/src/libs/clangbackendipc/requestdiagnosticsmessage.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "requestdiagnosticsmessage.h" + +#include +#include + +namespace ClangBackEnd { + +RequestDiagnosticsMessage::RequestDiagnosticsMessage(const FileContainer &file, + quint32 documentRevision) + : file_(file), + documentRevision_(documentRevision) +{ +} + +const FileContainer RequestDiagnosticsMessage::file() const +{ + return file_; +} + +quint32 RequestDiagnosticsMessage::documentRevision() const +{ + return documentRevision_; +} + +QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &message) +{ + out << message.file_; + out << message.documentRevision_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, RequestDiagnosticsMessage &message) +{ + in >> message.file_; + in >> message.documentRevision_; + + return in; +} + +bool operator==(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second) +{ + return first.file_ == second.file_ && first.documentRevision_ == second.documentRevision_; +} + +bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second) +{ + return first.file_ < second.file_; +} + +QDebug operator<<(QDebug debug, const RequestDiagnosticsMessage &message) +{ + debug.nospace() << "RequestDiagnosticsMessage(" + << message.file() << ", " + << message.documentRevision() + << ")"; + + return debug; +} + +void PrintTo(const RequestDiagnosticsMessage &message, ::std::ostream* os) +{ + *os << message.file().filePath().constData() + << "(" << message.file().projectPartId().constData() << ")"; +} + +} // namespace ClangBackEnd diff --git a/src/libs/clangbackendipc/requestdiagnosticsmessage.h b/src/libs/clangbackendipc/requestdiagnosticsmessage.h new file mode 100644 index 00000000000..87c3b41e684 --- /dev/null +++ b/src/libs/clangbackendipc/requestdiagnosticsmessage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_REQUESTDIAGNOSTICSMESSAGE_H +#define CLANGBACKEND_REQUESTDIAGNOSTICSMESSAGE_H + +#include "filecontainer.h" + +namespace ClangBackEnd { + +class CMBIPC_EXPORT RequestDiagnosticsMessage +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &message); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, RequestDiagnosticsMessage &message); + friend CMBIPC_EXPORT bool operator==(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second); + friend CMBIPC_EXPORT bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second); + friend CMBIPC_EXPORT QDebug operator<<(QDebug debug, const RequestDiagnosticsMessage &message); + friend void PrintTo(const RequestDiagnosticsMessage &message, ::std::ostream* os); + +public: + RequestDiagnosticsMessage() = default; + RequestDiagnosticsMessage(const FileContainer &file, quint32 documentRevision); + + const FileContainer file() const; + quint32 documentRevision() const; + +private: + FileContainer file_; + quint32 documentRevision_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const RequestDiagnosticsMessage &message); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, RequestDiagnosticsMessage &message); +CMBIPC_EXPORT bool operator==(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second); +CMBIPC_EXPORT bool operator<(const RequestDiagnosticsMessage &first, const RequestDiagnosticsMessage &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const RequestDiagnosticsMessage &message); +void PrintTo(const RequestDiagnosticsMessage &message, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::RequestDiagnosticsMessage) + +#endif // CLANGBACKEND_REQUESTDIAGNOSTICSMESSAGE_H diff --git a/src/libs/clangbackendipc/sourcelocationcontainer.cpp b/src/libs/clangbackendipc/sourcelocationcontainer.cpp new file mode 100644 index 00000000000..1da7ad060e1 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationcontainer.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "sourcelocationcontainer.h" + +#include +#include + +namespace ClangBackEnd { + +SourceLocationContainer::SourceLocationContainer(const Utf8String &filePath, + uint line, + uint offset) + : filePath_(filePath), + line_(line), + offset_(offset) +{ +} + +const Utf8String &SourceLocationContainer::filePath() const +{ + return filePath_; +} + +uint SourceLocationContainer::line() const +{ + return line_; +} + + +uint SourceLocationContainer::offset() const +{ + return offset_; +} + +QDataStream &operator<<(QDataStream &out, const SourceLocationContainer &container) +{ + out << container.filePath_; + out << container.line_; + out << container.offset_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, SourceLocationContainer &container) +{ + in >> container.filePath_; + in >> container.line_; + in >> container.offset_; + + return in; +} + +bool operator==(const SourceLocationContainer &first, const SourceLocationContainer &second) +{ + return first.offset_ == second.offset_ && first.filePath_ == second.filePath_; +} + +bool operator<(const SourceLocationContainer &first, const SourceLocationContainer &second) +{ + return first.filePath_ < second.filePath_ + || (first.filePath_ == second.filePath_ && first.offset_ < second.offset_); +} + +QDebug operator<<(QDebug debug, const SourceLocationContainer &container) +{ + debug.nospace() << "SourceLocationContainer(" + << container.filePath() << ", " + << container.line() << ", " + << container.offset() + << ")"; + return debug; +} + +void PrintTo(const SourceLocationContainer &container, ::std::ostream* os) +{ + *os << "[" + << container.filePath().constData() << ", " + << container.line() << ", " + << container.offset() + << "]"; +} +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/sourcelocationcontainer.h b/src/libs/clangbackendipc/sourcelocationcontainer.h new file mode 100644 index 00000000000..bfe446ec051 --- /dev/null +++ b/src/libs/clangbackendipc/sourcelocationcontainer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_SOURCELOCATIONCONTAINER_H +#define CLANGBACKEND_SOURCELOCATIONCONTAINER_H + +#include + +#include + +#include + +namespace ClangBackEnd { + +class CMBIPC_EXPORT SourceLocationContainer +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const SourceLocationContainer &container); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, SourceLocationContainer &container); + friend CMBIPC_EXPORT bool operator==(const SourceLocationContainer &first, const SourceLocationContainer &second); + friend CMBIPC_EXPORT bool operator<(const SourceLocationContainer &first, const SourceLocationContainer &second); + +public: + SourceLocationContainer() = default; + SourceLocationContainer(const Utf8String &filePath, + uint line, + uint offset); + + const Utf8String &filePath() const; + uint line() const; + uint offset() const; + +private: + Utf8String filePath_; + uint line_; + uint offset_; +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const SourceLocationContainer &container); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, SourceLocationContainer &container); +CMBIPC_EXPORT bool operator==(const SourceLocationContainer &first, const SourceLocationContainer &second); +CMBIPC_EXPORT bool operator<(const SourceLocationContainer &first, const SourceLocationContainer &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceLocationContainer &container); +void PrintTo(const SourceLocationContainer &container, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::SourceLocationContainer) + +#endif // CLANGBACKEND_SOURCELOCATIONCONTAINER_H diff --git a/src/libs/clangbackendipc/sourcerangecontainer.cpp b/src/libs/clangbackendipc/sourcerangecontainer.cpp new file mode 100644 index 00000000000..42c619b1d4e --- /dev/null +++ b/src/libs/clangbackendipc/sourcerangecontainer.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "sourcerangecontainer.h" + +#include + +namespace ClangBackEnd { +SourceRangeContainer::SourceRangeContainer(SourceLocationContainer start, + SourceLocationContainer end) + : start_(start), + end_(end) +{ +} + +SourceLocationContainer SourceRangeContainer::start() const +{ + return start_; +} + +SourceLocationContainer SourceRangeContainer::end() const +{ + return end_; +} + +QDataStream &operator<<(QDataStream &out, const SourceRangeContainer &container) +{ + out << container.start_; + out << container.end_; + + return out; +} + +QDataStream &operator>>(QDataStream &in, SourceRangeContainer &container) +{ + in >> container.start_; + in >> container.end_; + + return in; +} + +bool operator==(const SourceRangeContainer &first, const SourceRangeContainer &second) +{ + return first.start_ == second.start_ && first.end_ == second.end_; +} + +bool operator<(const SourceRangeContainer &first, const SourceRangeContainer &second) +{ + return first.start_ < second.start_ + || (first.start_ == second.start_ && first.end_ < second.end_); +} + +QDebug operator<<(QDebug debug, const SourceRangeContainer &container) +{ + debug.nospace() << "SourceRangeContainer(" + << container.start() << ", " + << container.end() + << ")"; + + return debug; +} + +void PrintTo(const SourceRangeContainer &container, ::std::ostream* os) +{ + *os << "["; + PrintTo(container.start(), os); + *os << ", "; + PrintTo(container.end(), os); + *os<< "]"; +} + +} // namespace ClangBackEnd + diff --git a/src/libs/clangbackendipc/sourcerangecontainer.h b/src/libs/clangbackendipc/sourcerangecontainer.h new file mode 100644 index 00000000000..e1f31a52552 --- /dev/null +++ b/src/libs/clangbackendipc/sourcerangecontainer.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_SOURCERANGECONTAINER_H +#define CLANGBACKEND_SOURCERANGECONTAINER_H + +#include "sourcelocationcontainer.h" + +namespace ClangBackEnd { + +class CMBIPC_EXPORT SourceRangeContainer +{ + friend CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const SourceRangeContainer &container); + friend CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, SourceRangeContainer &container); + friend CMBIPC_EXPORT bool operator==(const SourceRangeContainer &first, const SourceRangeContainer &second); + friend CMBIPC_EXPORT bool operator<(const SourceRangeContainer &first, const SourceRangeContainer &second); + +public: + SourceRangeContainer() = default; + SourceRangeContainer(SourceLocationContainer start, + SourceLocationContainer end); + + SourceLocationContainer start() const; + SourceLocationContainer end() const; + +private: + SourceLocationContainer start_; + SourceLocationContainer end_; + +}; + +CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const SourceRangeContainer &container); +CMBIPC_EXPORT QDataStream &operator>>(QDataStream &in, SourceRangeContainer &container); +CMBIPC_EXPORT bool operator==(const SourceRangeContainer &first, const SourceRangeContainer &second); +CMBIPC_EXPORT bool operator<(const SourceRangeContainer &first, const SourceRangeContainer &second); + +CMBIPC_EXPORT QDebug operator<<(QDebug debug, const SourceRangeContainer &container); +void PrintTo(const SourceRangeContainer &container, ::std::ostream* os); + +} // namespace ClangBackEnd + +Q_DECLARE_METATYPE(ClangBackEnd::SourceRangeContainer) + +#endif // CLANGBACKEND_SOURCERANGECONTAINER_H diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp index 0ffe78ad9eb..614ed11c8bc 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp @@ -31,6 +31,7 @@ #include "clangbackendipcintegration.h" #include "clangcompletionassistprocessor.h" +#include "clangeditordocumentprocessor.h" #include "clangmodelmanagersupport.h" #include "clangutils.h" #include "pchmanager.h" @@ -46,6 +47,8 @@ #include #include +#include + #include #include @@ -57,6 +60,8 @@ #include #include #include +#include +#include #include #include @@ -152,6 +157,20 @@ void IpcReceiver::codeCompleted(const CodeCompletedMessage &message) } } +void IpcReceiver::diagnosticsChanged(const DiagnosticsChangedMessage &message) +{ + qCDebug(log) << "<<< DiagnosticsChangedMessage with" << message.diagnostics().size() << "items"; + + auto processor = ClangEditorDocumentProcessor::get(message.file().filePath()); + + if (processor && processor->projectPart()) { + const QString diagnosticsProjectPartId = message.file().projectPartId(); + const QString documentProjectPartId = processor->projectPart()->id(); + if (diagnosticsProjectPartId == documentProjectPartId) + processor->updateCodeWarnings(message.diagnostics(), message.documentRevision()); + } +} + void IpcReceiver::translationUnitDoesNotExist(const TranslationUnitDoesNotExistMessage &message) { QTC_CHECK(!"Got TranslationUnitDoesNotExistMessage"); @@ -177,6 +196,7 @@ public: void registerProjectPartsForCodeCompletion(const ClangBackEnd::RegisterProjectPartsForCodeCompletionMessage &message) override; void unregisterProjectPartsForCodeCompletion(const ClangBackEnd::UnregisterProjectPartsForCodeCompletionMessage &message) override; void completeCode(const ClangBackEnd::CompleteCodeMessage &message) override; + void requestDiagnostics(const ClangBackEnd::RequestDiagnosticsMessage &message) override; private: ClangBackEnd::ConnectionClient &m_connection; @@ -218,6 +238,12 @@ void IpcSender::completeCode(const CompleteCodeMessage &message) m_connection.serverProxy().completeCode(message); } +void IpcSender::requestDiagnostics(const RequestDiagnosticsMessage &message) +{ + QTC_CHECK(m_connection.isConnected()); + m_connection.serverProxy().requestDiagnostics(message); +} + IpcCommunicator::IpcCommunicator() : m_connection(&m_ipcReceiver) , m_ipcSender(new IpcSender(m_connection)) @@ -300,6 +326,7 @@ static QStringList projectPartMessageLine(const CppTools::ProjectPart::Ptr &proj CppTools::ProjectFile::Unclassified); // No language option if (PchInfo::Ptr pchInfo = PchManager::instance()->pchInfo(projectPart)) options += ClangCodeModel::Utils::createPCHInclusionOptions(pchInfo->fileName()); + return options; } @@ -339,12 +366,16 @@ void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArra const bool hasUnsavedContent = true; // TODO: Send new only if changed - registerFilesForCodeCompletion({ - ClangBackEnd::FileContainer(filePath, - projectPartId, - Utf8String::fromByteArray(contents), - hasUnsavedContent) - }); + registerFilesForCodeCompletion({{filePath, + projectPartId, + Utf8String::fromByteArray(contents), + hasUnsavedContent}}); +} + +void IpcCommunicator::requestDiagnostics(const FileContainer &fileContainer, uint documentRevision) +{ + registerFilesForCodeCompletion({fileContainer}); + m_ipcSender->requestDiagnostics({fileContainer, documentRevision}); } void IpcCommunicator::updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document) diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.h b/src/plugins/clangcodemodel/clangbackendipcintegration.h index 60535879cd4..778b947a939 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.h +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.h @@ -47,6 +47,10 @@ class IEditor; class IDocument; } +namespace ClangBackEnd { +class DiagnosticsChangedMessage; +} + namespace TextEditor { class TextEditorWidget; } @@ -75,6 +79,7 @@ private: void alive() override; void echo(const ClangBackEnd::EchoMessage &message) override; void codeCompleted(const ClangBackEnd::CodeCompletedMessage &message) override; + void diagnosticsChanged(const ClangBackEnd::DiagnosticsChangedMessage &message) override; void translationUnitDoesNotExist(const ClangBackEnd::TranslationUnitDoesNotExistMessage &message) override; void projectPartsDoNotExist(const ClangBackEnd::ProjectPartsDoNotExistMessage &message) override; @@ -95,6 +100,7 @@ public: virtual void registerProjectPartsForCodeCompletion(const ClangBackEnd::RegisterProjectPartsForCodeCompletionMessage &message) = 0; virtual void unregisterProjectPartsForCodeCompletion(const ClangBackEnd::UnregisterProjectPartsForCodeCompletionMessage &message) = 0; virtual void completeCode(const ClangBackEnd::CompleteCodeMessage &message) = 0; + virtual void requestDiagnostics(const ClangBackEnd::RequestDiagnosticsMessage &message) = 0; }; class IpcCommunicator : public QObject @@ -123,6 +129,7 @@ public: void updateUnsavedFileIfNotCurrentDocument(Core::IDocument *document); void updateUnsavedFileFromCppEditorDocument(const QString &filePath); void updateUnsavedFile(const QString &filePath, const QByteArray &contents); + void requestDiagnostics(const ClangBackEnd::FileContainer &fileContainer, uint documentRevision); public: // for tests IpcSenderInterface *setIpcSender(IpcSenderInterface *ipcSender); diff --git a/src/plugins/clangcodemodel/clangcodemodel.pro b/src/plugins/clangcodemodel/clangcodemodel.pro index b4758730d88..e62ce4823c6 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.pro +++ b/src/plugins/clangcodemodel/clangcodemodel.pro @@ -29,6 +29,7 @@ SOURCES += \ clangmodelmanagersupport.cpp \ clangprojectsettings.cpp \ clangprojectsettingspropertiespage.cpp \ + clangtextmark.cpp \ clangutils.cpp \ completionchunkstotextconverter.cpp \ cppcreatemarkers.cpp \ @@ -67,6 +68,7 @@ HEADERS += \ clangmodelmanagersupport.h \ clangprojectsettings.h \ clangprojectsettingspropertiespage.h \ + clangtextmark.h \ clangutils.h \ completionchunkstotextconverter.h \ constants.h \ diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index cc41d8ebd2d..499798e61e2 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -145,6 +145,8 @@ QtcPlugin { "clangprojectsettingspropertiespage.cpp", "clangprojectsettingspropertiespage.h", "clangprojectsettingspropertiespage.ui", + "clangtextmark.cpp", + "clangtextmark.h", "clangutils.cpp", "clangutils.h", "clangbackendipcintegration.cpp", diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index c6c42855a93..f935b2ca5a2 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -31,6 +31,7 @@ #include "clangcodemodelplugin.h" #include "clangprojectsettingspropertiespage.h" +#include "constants.h" #include "pchmanager.h" #include "utils.h" @@ -44,9 +45,19 @@ #include #include +#include + namespace ClangCodeModel { namespace Internal { +void initializeTextMarks() +{ + TextEditor::TextMark::setCategoryColor(Core::Id(Constants::CLANG_WARNING), + Utils::Theme::ProjectExplorer_TaskWarn_TextMarkColor); + TextEditor::TextMark::setCategoryColor(Core::Id(Constants::CLANG_ERROR), + Utils::Theme::ProjectExplorer_TaskError_TextMarkColor); +} + bool ClangCodeModelPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index eadb4a37ce2..99e3ff1f1e2 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -669,11 +669,10 @@ void ClangCompletionAssistProcessor::sendFileContent(const QString &projectPartI const UnsavedFileContentInfo info = unsavedFileContent(customFileContent); IpcCommunicator &ipcCommunicator = m_interface->ipcCommunicator(); - ipcCommunicator.registerFilesForCodeCompletion( - {ClangBackEnd::FileContainer(m_interface->fileName(), - projectPartId, - Utf8String::fromByteArray(info.unsavedContent), - info.isDocumentModified)}); + ipcCommunicator.registerFilesForCodeCompletion({{m_interface->fileName(), + projectPartId, + Utf8String::fromByteArray(info.unsavedContent), + info.isDocumentModified}}); } void ClangCompletionAssistProcessor::sendCompletionRequest(int position, @@ -686,7 +685,11 @@ void ClangCompletionAssistProcessor::sendCompletionRequest(int position, const QString filePath = m_interface->fileName(); const QString projectPartId = Utils::projectPartIdForFile(filePath); sendFileContent(projectPartId, customFileContent); - m_interface->ipcCommunicator().completeCode(this, filePath, line, column, projectPartId); + m_interface->ipcCommunicator().completeCode(this, + filePath, + uint(line), + uint(column), + projectPartId); } TextEditor::IAssistProposal *ClangCompletionAssistProcessor::createProposal() const diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index f8a4191513b..ab586c1a350 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -36,43 +36,24 @@ #include "diagnostic.h" #include "pchinfo.h" +#include +#include + #include #include +#include + #include #include #include +#include + namespace { typedef CPlusPlus::Document::DiagnosticMessage CppToolsDiagnostic; -QList toCppToolsDiagnostics( - const QString &filePath, - const QList &diagnostics) -{ - using namespace ClangCodeModel; - - QList converted; - foreach (const ClangCodeModel::Diagnostic &d, diagnostics) { - if (d.location().fileName() != filePath) - continue; - - // TODO: retrieve fix-its for this diagnostic - - int level; - switch (d.severity()) { - case Diagnostic::Fatal: level = CppToolsDiagnostic::Fatal; break; - case Diagnostic::Error: level = CppToolsDiagnostic::Error; break; - case Diagnostic::Warning: level = CppToolsDiagnostic::Warning; break; - default: continue; - } - converted.append(CppToolsDiagnostic(level, d.location().fileName(), d.location().line(), - d.location().column(), d.spelling(), d.length())); - } - - return converted; -} QList toTextEditorBlocks( const QList &ranges) @@ -135,6 +116,8 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor() void ClangEditorDocumentProcessor::run() { + requestDiagnostics(); + // Run clang parser disconnect(&m_parserWatcher, &QFutureWatcher::finished, this, &ClangEditorDocumentProcessor::onParserFinished); @@ -189,6 +172,15 @@ CppTools::ProjectPart::Ptr ClangEditorDocumentProcessor::projectPart() const return m_projectPart; } +void ClangEditorDocumentProcessor::updateCodeWarnings(const QVector &diagnostics, + uint documentRevision) +{ + if (documentRevision == revision()) { + const auto codeWarnings = generateDiagnosticHints(diagnostics); + emit codeWarningsUpdated(revision(), codeWarnings); + } +} + ClangEditorDocumentProcessor *ClangEditorDocumentProcessor::get(const QString &filePath) { return qobject_cast(BaseEditorDocumentProcessor::get(filePath)); @@ -200,6 +192,8 @@ void ClangEditorDocumentProcessor::updateProjectPartAndTranslationUnitForComplet QTC_ASSERT(projectPart, return); updateTranslationUnitForCompletion(*projectPart.data()); + requestDiagnostics(*projectPart.data()); + m_projectPart = projectPart; } @@ -212,11 +206,6 @@ void ClangEditorDocumentProcessor::onParserFinished() const auto ifdefoutBlocks = toTextEditorBlocks(m_parser.ifdefedOutBlocks()); emit ifdefedOutBlocksUpdated(revision(), ifdefoutBlocks); - // Emit code warnings - const auto diagnostics = toCppToolsDiagnostics(filePath(), m_parser.diagnostics()); - const auto codeWarnings = toTextEditorSelections(diagnostics, textDocument()); - emit codeWarningsUpdated(revision(), codeWarnings); - // Run semantic highlighter m_semanticHighlighter.run(); @@ -229,23 +218,261 @@ void ClangEditorDocumentProcessor::onProjectPartsRemoved(const QStringList &proj m_projectPart.clear(); } -void ClangEditorDocumentProcessor::updateTranslationUnitForCompletion( - CppTools::ProjectPart &projectPart) +void ClangEditorDocumentProcessor::updateTranslationUnitForCompletion(CppTools::ProjectPart &projectPart) { QTC_ASSERT(m_modelManagerSupport, return); IpcCommunicator &ipcCommunicator = m_modelManagerSupport->ipcCommunicator(); if (m_projectPart) { if (projectPart.id() != m_projectPart->id()) { - auto container1 = {ClangBackEnd::FileContainer(filePath(), m_projectPart->id())}; - ipcCommunicator.unregisterFilesForCodeCompletion(container1); + auto container1 = ClangBackEnd::FileContainer(filePath(), m_projectPart->id()); + ipcCommunicator.unregisterFilesForCodeCompletion({container1}); - auto container2 = {ClangBackEnd::FileContainer(filePath(), projectPart.id())}; - ipcCommunicator.registerFilesForCodeCompletion(container2); + auto container2 = ClangBackEnd::FileContainer(filePath(), projectPart.id()); + ipcCommunicator.registerFilesForCodeCompletion({container2}); } } else { - auto container = {ClangBackEnd::FileContainer(filePath(), projectPart.id())}; - ipcCommunicator.registerFilesForCodeCompletion(container); + auto container = ClangBackEnd::FileContainer(filePath(), projectPart.id()); + ipcCommunicator.registerFilesForCodeCompletion({container}); + } +} + +namespace { +bool isWarningOrNote(ClangBackEnd::DiagnosticSeverity severity) +{ + using ClangBackEnd::DiagnosticSeverity; + switch (severity) { + case DiagnosticSeverity::Ignored: + case DiagnosticSeverity::Note: + case DiagnosticSeverity::Warning: return true; + case DiagnosticSeverity::Error: + case DiagnosticSeverity::Fatal: return false; + } + + Q_UNREACHABLE(); +} + +bool isHelpfulChildDiagnostic(const ClangBackEnd::DiagnosticContainer &parentDiagnostic, + const ClangBackEnd::DiagnosticContainer &childDiagnostic) +{ + auto parentLocation = parentDiagnostic.location(); + auto childLocation = childDiagnostic.location(); + + return parentLocation == childLocation; +} + +QString diagnosticText(const ClangBackEnd::DiagnosticContainer &diagnostic) +{ + QString text = diagnostic.category().toString() + + QStringLiteral(" ") + + diagnostic.text().toString(); + if (!diagnostic.enableOption().isEmpty()) { + text += QStringLiteral(" (clang option: ") + + diagnostic.enableOption().toString() + + QStringLiteral(" disable with: ") + + diagnostic.disableOption().toString() + + QStringLiteral(")"); + } + + for (auto &&childDiagnostic : diagnostic.children()) { + if (isHelpfulChildDiagnostic(diagnostic, childDiagnostic)) + text += QStringLiteral("\n ") + childDiagnostic.text().toString(); + } + + return text; +} + +template +std::vector +filterDiagnostics(const QVector &diagnostics, + const Condition &condition) +{ + std::vector filteredDiagnostics; + + std::copy_if(diagnostics.cbegin(), + diagnostics.cend(), + std::back_inserter(filteredDiagnostics), + condition); + + return filteredDiagnostics; +} + +std::vector +filterInterestingWarningDiagnostics(const QVector &diagnostics, + QString &&documentFilePath) +{ + auto isLocalWarning = [documentFilePath] (const ClangBackEnd::DiagnosticContainer &diagnostic) { + return isWarningOrNote(diagnostic.severity()) + && diagnostic.location().filePath() == documentFilePath; + }; + + return filterDiagnostics(diagnostics, isLocalWarning); +} + +std::vector +filterInterestingErrorsDiagnostics(const QVector &diagnostics, + QString &&documentFilePath) +{ + auto isLocalWarning = [documentFilePath] (const ClangBackEnd::DiagnosticContainer &diagnostic) { + return !isWarningOrNote(diagnostic.severity()) + && diagnostic.location().filePath() == documentFilePath; + }; + + return filterDiagnostics(diagnostics, isLocalWarning); +} + +QTextEdit::ExtraSelection createExtraSelections(const QTextCharFormat &mainformat, + const QTextCursor &cursor, + const QString &diagnosticText) +{ + QTextEdit::ExtraSelection extraSelection; + + extraSelection.format = mainformat; + extraSelection.cursor = cursor; + extraSelection.format.setToolTip(diagnosticText); + + return extraSelection; +} + +void addRangeSelections(const ClangBackEnd::DiagnosticContainer &diagnostic, + QTextDocument *textDocument, + const QTextCharFormat &rangeFormat, + const QString &diagnosticText, + QList &extraSelections) +{ + for (auto &&range : diagnostic.ranges()) { + QTextCursor cursor(textDocument); + cursor.setPosition(int(range.start().offset())); + cursor.setPosition(int(range.end().offset()), QTextCursor::KeepAnchor); + + auto extraSelection = createExtraSelections(rangeFormat, cursor, diagnosticText); + + extraSelections.push_back(std::move(extraSelection)); + } +} + +QTextCursor createSelectionCursor(QTextDocument *textDocument, uint position) +{ + QTextCursor cursor(textDocument); + cursor.setPosition(int(position)); + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + + if (!cursor.hasSelection()) { + cursor.setPosition(int(position) - 1); + cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, 2); + } + + return cursor; +} + +void addSelections(const std::vector &diagnostics, + QTextDocument *textDocument, + const QTextCharFormat &mainFormat, + const QTextCharFormat &rangeFormat, + QList &extraSelections) +{ + for (auto &&diagnostic : diagnostics) { + auto cursor = createSelectionCursor(textDocument, diagnostic.location().offset()); + + auto text = diagnosticText(diagnostic); + auto extraSelection = createExtraSelections(mainFormat, cursor, text); + + addRangeSelections(diagnostic, textDocument, rangeFormat, text, extraSelections); + + extraSelections.push_back(std::move(extraSelection)); + } +} + +void addWarningSelections(const std::vector &diagnostics, + QTextDocument *textDocument, + QList &extraSelections) +{ + QTextCharFormat warningFormat; + warningFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); + warningFormat.setUnderlineColor(QColor(180, 180, 0, 255)); + + QTextCharFormat warningRangeFormat; + warningRangeFormat.setUnderlineStyle(QTextCharFormat::DotLine); + warningRangeFormat.setUnderlineColor(QColor(180, 180, 0, 255)); + + addSelections(diagnostics, textDocument, warningFormat, warningRangeFormat, extraSelections); +} + +void addErrorSelections(const std::vector &diagnostics, + QTextDocument *textDocument, + QList &extraSelections) +{ + QTextCharFormat errorFormat; + errorFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); + errorFormat.setUnderlineColor(QColor(255, 0, 0, 255)); + + QTextCharFormat errorRangeFormat; + errorRangeFormat.setUnderlineStyle(QTextCharFormat::DotLine); + errorRangeFormat.setUnderlineColor(QColor(255, 0, 0, 255)); + + addSelections(diagnostics, textDocument, errorFormat, errorRangeFormat, extraSelections); +} + +} // anonymous namespace + +QList +ClangEditorDocumentProcessor::generateDiagnosticHints(const QVector &allDiagnostics) +{ + const auto warningDiagnostic = filterInterestingWarningDiagnostics(allDiagnostics, filePath()); + const auto errorDiagnostic = filterInterestingErrorsDiagnostics(allDiagnostics, filePath()); + + m_clangTextMarks.clear(); + m_clangTextMarks.reserve(warningDiagnostic.size() + errorDiagnostic.size()); + + addClangTextMarks(warningDiagnostic); + addClangTextMarks(errorDiagnostic); + + QList extraSelections; + extraSelections.reserve(int(warningDiagnostic.size() + errorDiagnostic.size())); + + addWarningSelections(warningDiagnostic, textDocument(), extraSelections); + addErrorSelections(errorDiagnostic, textDocument(), extraSelections); + + return extraSelections; +} + +void ClangEditorDocumentProcessor::addClangTextMarks(const std::vector &diagnostics) +{ + QTC_ASSERT(m_clangTextMarks.size() + diagnostics.size() <= m_clangTextMarks.capacity(), return); + + for (auto &&diagnostic : diagnostics) { + m_clangTextMarks.emplace_back(filePath(), + diagnostic.location().line(), + diagnostic.severity()); + + ClangTextMark &textMark = m_clangTextMarks.back(); + + textMark.setBaseTextDocument(baseTextDocument()); + + baseTextDocument()->addMark(&textMark); + } +} + +void ClangEditorDocumentProcessor::requestDiagnostics(CppTools::ProjectPart &projectPart) +{ + if (!m_projectPart || projectPart.id() != m_projectPart->id()) { + IpcCommunicator &ipcCommunicator = m_modelManagerSupport->ipcCommunicator(); + + ipcCommunicator.requestDiagnostics({filePath(), projectPart.id()}, + revision()); + } +} + +void ClangEditorDocumentProcessor::requestDiagnostics() +{ + // Get diagnostics + if (m_projectPart) { + auto &ipcCommunicator = m_modelManagerSupport->ipcCommunicator(); + ipcCommunicator.requestDiagnostics({filePath(), + m_projectPart->id(), + baseTextDocument()->plainText(), + true}, + revision()); } } diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 4d8564685ca..f1c918f146e 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -32,6 +32,7 @@ #define CLANGEDITORDOCUMENTPROCESSOR_H #include "clangeditordocumentparser.h" +#include "clangtextmark.h" #include #include @@ -40,6 +41,12 @@ #include #include +#include + +namespace ClangBackEnd { +class DiagnosticContainer; +} + namespace ClangCodeModel { namespace Internal { @@ -65,6 +72,9 @@ public: CppTools::ProjectPart::Ptr projectPart() const; + void updateCodeWarnings(const QVector &diagnostics, + uint documentRevision); + public: static ClangEditorDocumentProcessor *get(const QString &filePath); @@ -75,9 +85,15 @@ private slots: private: void updateProjectPartAndTranslationUnitForCompletion(); void updateTranslationUnitForCompletion(CppTools::ProjectPart &projectPart); + QList + generateDiagnosticHints(const QVector &diagnostics); + void addClangTextMarks(const std::vector &diagnostics); + void requestDiagnostics(CppTools::ProjectPart &projectPart); + void requestDiagnostics(); +private: QPointer m_modelManagerSupport; - + std::vector m_clangTextMarks; ClangEditorDocumentParser m_parser; CppTools::ProjectPart::Ptr m_projectPart; QFutureWatcher m_parserWatcher; diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp new file mode 100644 index 00000000000..e6692487637 --- /dev/null +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "clangtextmark.h" + +#include "constants.h" + +#include + +#include +#include + +#include + +namespace ClangCodeModel { + +namespace { + +bool isWarningOrNote(ClangBackEnd::DiagnosticSeverity severity) +{ + using ClangBackEnd::DiagnosticSeverity; + switch (severity) { + case DiagnosticSeverity::Ignored: + case DiagnosticSeverity::Note: + case DiagnosticSeverity::Warning: return true; + default: return false; + } + + Q_UNREACHABLE(); +} + +Core::Id cartegoryForSeverity(ClangBackEnd::DiagnosticSeverity severity) +{ + return isWarningOrNote(severity) ? Constants::CLANG_WARNING : Constants::CLANG_ERROR; +} + +const QIcon &iconForSeverity(ClangBackEnd::DiagnosticSeverity severity) +{ + static const QIcon errorIcon{QLatin1String(Core::Constants::ICON_ERROR)}; + static const QIcon warningIcon{QLatin1String(Core::Constants::ICON_WARNING)}; + + return isWarningOrNote(severity) ? warningIcon : errorIcon; +} + +} // anonymous namespace + +ClangTextMark::ClangTextMark(const QString &fileName, int lineNumber, ClangBackEnd::DiagnosticSeverity severity) + : TextEditor::TextMark(fileName, lineNumber, cartegoryForSeverity(severity)) +{ + setPriority(TextEditor::TextMark::HighPriority); + setIcon(iconForSeverity(severity)); +} + +} // namespace ClangCodeModel + diff --git a/src/plugins/clangcodemodel/clangtextmark.h b/src/plugins/clangcodemodel/clangtextmark.h new file mode 100644 index 00000000000..fe55a9d56d3 --- /dev/null +++ b/src/plugins/clangcodemodel/clangtextmark.h @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGCODEMODEL_CLANGTEXTMARK_H +#define CLANGCODEMODEL_CLANGTEXTMARK_H + +#include + +#include + +namespace ClangCodeModel { + +class ClangTextMark : public TextEditor::TextMark +{ +public: + ClangTextMark(const QString &fileName, int lineNumber, ClangBackEnd::DiagnosticSeverity severity); +}; + +} // namespace ClangCodeModel + +#endif // CLANGCODEMODEL_CLANGTEXTMARK_H diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index b76d1c86fe7..acd6129631f 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -135,6 +135,8 @@ public: optionsBuilder.addHeaderPathOptions(); optionsBuilder.addProjectConfigFileInclude(); + optionsBuilder.addDiagnosticOptions(); + optionsBuilder.addExtraOptions(); return optionsBuilder.options(); @@ -199,6 +201,18 @@ private: add(QLatin1String("-fretain-comments-from-system-headers")); // TODO: -Xclang -ferror-limit -Xclang 0 ? } + + void addDiagnosticOptions() + { + add(QStringLiteral("-Weverything")); + add(QStringLiteral("-Wno-c++98-compat")); + add(QStringLiteral("-Wno-c++98-compat-pedantic")); + add(QStringLiteral("-fmessage-length=0")); + add(QStringLiteral("-fdiagnostics-show-note-include-stack")); + add(QStringLiteral("-fmacro-backtrace-limit=0")); + add(QStringLiteral("-fretain-comments-from-system-headers")); + add(QStringLiteral("-ferror-limit=1000")); + } }; /** diff --git a/src/plugins/clangcodemodel/constants.h b/src/plugins/clangcodemodel/constants.h index 8bdb3f9b337..4cd0cf81d78 100644 --- a/src/plugins/clangcodemodel/constants.h +++ b/src/plugins/clangcodemodel/constants.h @@ -56,6 +56,8 @@ static const QLatin1Char kNewLine('\n'); static const QLatin1Char kHorizontalTab('\t'); const char CLANG_MODELMANAGERSUPPORT_ID[] = "ClangCodeMode.ClangCodeMode"; +const char CLANG_ERROR[] = "Clang.Error"; +const char CLANG_WARNING[] = "Clang.Warning"; } } diff --git a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp index 462feddaa0a..13760035d23 100644 --- a/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp +++ b/src/plugins/clangcodemodel/test/clangcodecompletion_test.cpp @@ -352,6 +352,11 @@ QString toString(const CompleteCodeMessage &) return QLatin1String("CompleteCodeMessage\n"); } +QString toString(const RequestDiagnosticsMessage &) +{ + return QStringLiteral("RequestDiagnosticsMessage\n"); +} + class IpcSenderSpy : public IpcSenderInterface { public: @@ -373,6 +378,10 @@ public: void completeCode(const CompleteCodeMessage &message) override { senderLog.append(toString(message)); } + void requestDiagnostics(const RequestDiagnosticsMessage &message) override + { senderLog.append(toString(message)); } + + public: QString senderLog; }; @@ -1105,14 +1114,27 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart() LogOutput( "RegisterTranslationUnitForCodeCompletionMessage\n" " Path: myheader.h ProjectPart: \n" + "RegisterTranslationUnitForCodeCompletionMessage\n" + " Path: myheader.h ProjectPart: \n" + "RequestDiagnosticsMessage\n" "RegisterProjectPartsForCodeCompletionMessage\n" " ProjectPartContainer id: qt-widgets-app.pro qt-widgets-app\n" "RegisterTranslationUnitForCodeCompletionMessage\n" + " Path: myheader.h ProjectPart: \n" + "RequestDiagnosticsMessage\n" + "RegisterTranslationUnitForCodeCompletionMessage\n" + " Path: myheader.h ProjectPart: \n" + "RequestDiagnosticsMessage\n" + "RegisterTranslationUnitForCodeCompletionMessage\n" " Path: ui_mainwindow.h ProjectPart: \n" "RegisterTranslationUnitForCodeCompletionMessage\n" " Path: myheader.h ProjectPart: \n" "RegisterTranslationUnitForCodeCompletionMessage\n" " Path: mainwindow.cpp ProjectPart: qt-widgets-app.pro qt-widgets-app\n" + "RegisterTranslationUnitForCodeCompletionMessage\n" + " Path: mainwindow.cpp ProjectPart: qt-widgets-app.pro qt-widgets-app\n" + "RequestDiagnosticsMessage\n" + ))); spy.senderLog.clear(); diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp index d627ab3cb76..182261686fa 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.cpp +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -78,12 +78,12 @@ QList BaseEditorDocumentProcessor::toTextEditorSelect { // Format for errors QTextCharFormat errorFormat; - errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + errorFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); errorFormat.setUnderlineColor(Qt::red); // Format for warnings QTextCharFormat warningFormat; - warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + warningFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); warningFormat.setUnderlineColor(Qt::darkYellow); QList result; diff --git a/src/plugins/debugger/qml/qmlengineutils.cpp b/src/plugins/debugger/qml/qmlengineutils.cpp index bdd36e24e4a..55dc00813dc 100644 --- a/src/plugins/debugger/qml/qmlengineutils.cpp +++ b/src/plugins/debugger/qml/qmlengineutils.cpp @@ -272,7 +272,7 @@ QStringList highlightExceptionCode(int lineNumber, const QString &filePath, cons // set up the format for the errors QTextCharFormat errorFormat; - errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + errorFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); errorFormat.setUnderlineColor(Qt::red); foreach (IEditor *editor, editors) { diff --git a/src/plugins/glsleditor/glsleditor.cpp b/src/plugins/glsleditor/glsleditor.cpp index bef941344dc..b7fac825e0d 100644 --- a/src/plugins/glsleditor/glsleditor.cpp +++ b/src/plugins/glsleditor/glsleditor.cpp @@ -237,11 +237,11 @@ void GlslEditorWidget::updateDocumentNow() createRanges(ast); QTextCharFormat errorFormat; - errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + errorFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); errorFormat.setUnderlineColor(Qt::red); QTextCharFormat warningFormat; - warningFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + warningFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline); warningFormat.setUnderlineColor(Qt::darkYellow); QList sels; diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index a926efc45c6..df7f849cb93 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -199,7 +199,7 @@ static void appendExtraSelectionsForMessages( else sel.format.setUnderlineColor(Qt::red); - sel.format.setUnderlineStyle(QTextCharFormat::WaveUnderline); + sel.format.setUnderlineStyle(QTextCharFormat::SingleUnderline); sel.format.setToolTip(d.message); selections->append(sel); diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp index 08a24a072aa..fb5900548e4 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp @@ -391,7 +391,7 @@ protected: else format.setUnderlineColor(Qt::red); - format.setUnderlineStyle(QTextCharFormat::WaveUnderline); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); format.setToolTip(d.message); collectRanges(begin, length, format); @@ -428,7 +428,7 @@ protected: else if (d.severity == Severity::Hint) format.setUnderlineColor(Qt::darkGreen); - format.setUnderlineStyle(QTextCharFormat::WaveUnderline); + format.setUnderlineStyle(QTextCharFormat::SingleUnderline); format.setToolTip(d.message); collectRanges(begin, length, format); diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp index daf50dc5657..ef8933ac62f 100644 --- a/src/plugins/texteditor/fontsettings.cpp +++ b/src/plugins/texteditor/fontsettings.cpp @@ -170,7 +170,7 @@ QTextCharFormat FontSettings::toTextCharFormat(TextStyle category) const } if (category == C_OCCURRENCES_UNUSED) { - tf.setUnderlineStyle(QTextCharFormat::WaveUnderline); + tf.setUnderlineStyle(QTextCharFormat::SingleUnderline); tf.setUnderlineColor(f.foreground()); tf.setToolTip(QCoreApplication::translate("FontSettings_C_OCCURRENCES_UNUSED", "Unused variable")); diff --git a/src/plugins/texteditor/textmark.cpp b/src/plugins/texteditor/textmark.cpp index 7525c1a9908..e3a692e7355 100644 --- a/src/plugins/texteditor/textmark.cpp +++ b/src/plugins/texteditor/textmark.cpp @@ -65,6 +65,20 @@ TextMark::~TextMark() m_baseTextDocument = 0; } +TextMark::TextMark(TextMark &&other) + : m_baseTextDocument(std::move(other.m_baseTextDocument)), + m_fileName(std::move(other.m_fileName)), + m_lineNumber(std::move(other.m_lineNumber)), + m_priority(std::move(other.m_priority)), + m_visible(std::move(other.m_visible)), + m_icon(std::move(other.m_icon)), + m_color(std::move(other.m_color)), + m_category(std::move(other.m_category)), + m_widthFactor(std::move(other.m_widthFactor)) +{ + other.m_baseTextDocument = nullptr; +} + QString TextMark::fileName() const { return m_fileName; diff --git a/src/plugins/texteditor/textmark.h b/src/plugins/texteditor/textmark.h index 0d68ae3232b..468196138dd 100644 --- a/src/plugins/texteditor/textmark.h +++ b/src/plugins/texteditor/textmark.h @@ -57,6 +57,8 @@ public: TextMark(const QString &fileName, int lineNumber, Core::Id category); virtual ~TextMark(); + TextMark(TextMark &&other); + // determine order on markers on the same line. enum Priority { diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index 4e8800de028..1a5c23d495c 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -16,7 +16,13 @@ HEADERS += $$PWD/clangipcserver.h \ $$PWD/translationunitfilenotexitexception.h \ $$PWD/translationunitdoesnotexistexception.h \ $$PWD/projectpartsdonotexistexception.h \ - $$PWD/codecompletionchunkconverter.h + $$PWD/codecompletionchunkconverter.h \ + $$PWD/diagnosticset.h \ + $$PWD/diagnostic.h \ + $$PWD/sourcelocation.h \ + $$PWD/sourcerange.h \ + $$PWD/fixit.h \ + $$PWD/diagnosticsetiterator.h SOURCES += $$PWD/clangipcserver.cpp \ $$PWD/codecompleter.cpp \ @@ -34,4 +40,9 @@ SOURCES += $$PWD/clangipcserver.cpp \ $$PWD/translationunitfilenotexitexception.cpp \ $$PWD/translationunitdoesnotexistexception.cpp \ $$PWD/projectpartsdonotexistexception.cpp \ - $$PWD/codecompletionchunkconverter.cpp + $$PWD/codecompletionchunkconverter.cpp \ + $$PWD/diagnosticset.cpp \ + $$PWD/diagnostic.cpp \ + $$PWD/sourcelocation.cpp \ + $$PWD/sourcerange.cpp \ + $$PWD/fixit.cpp diff --git a/src/tools/clangbackend/ipcsource/clangipcserver.cpp b/src/tools/clangbackend/ipcsource/clangipcserver.cpp index 8bd9ff316ed..53ea4be867c 100644 --- a/src/tools/clangbackend/ipcsource/clangipcserver.cpp +++ b/src/tools/clangbackend/ipcsource/clangipcserver.cpp @@ -30,6 +30,15 @@ #include "clangipcserver.h" +#include "codecompleter.h" +#include "diagnosticset.h" +#include "projectpartsdonotexistexception.h" +#include "translationunitdoesnotexistexception.h" +#include "translationunitfilenotexitexception.h" +#include "translationunitisnullexception.h" +#include "translationunitparseerrorexception.h" +#include "translationunits.h" + #include #include #include @@ -37,17 +46,11 @@ #include #include #include +#include +#include #include #include -#include "codecompleter.h" -#include "projectpartsdonotexistexception.h" -#include "translationunitdoesnotexistexception.h" -#include "translationunitfilenotexitexception.h" -#include "translationunitisnullexception.h" -#include "translationunitparseerrorexception.h" -#include "translationunits.h" - #include #include @@ -135,4 +138,24 @@ void ClangIpcServer::completeCode(const ClangBackEnd::CompleteCodeMessage &messa } } +void ClangIpcServer::requestDiagnostics(const RequestDiagnosticsMessage &message) +{ + TIME_SCOPE_DURATION("ClangIpcServer::requestDiagnostics"); + + try { + auto translationUnit = translationUnits.translationUnit(message.file().filePath(), + message.file().projectPartId()); + + client()->diagnosticsChanged(DiagnosticsChangedMessage(translationUnit.fileContainer(), + translationUnit.diagnostics().toDiagnosticContainers(), + message.documentRevision())); + } catch (const TranslationUnitDoesNotExistException &exception) { + client()->translationUnitDoesNotExist(TranslationUnitDoesNotExistMessage(exception.fileContainer())); + } catch (const ProjectPartDoNotExistException &exception) { + client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds())); + } catch (const std::exception &exception) { + qWarning() << "Error in ClangIpcServer::requestDiagnostics:" << exception.what(); + } +} + } diff --git a/src/tools/clangbackend/ipcsource/clangipcserver.h b/src/tools/clangbackend/ipcsource/clangipcserver.h index b25da5f8f24..1716ade4630 100644 --- a/src/tools/clangbackend/ipcsource/clangipcserver.h +++ b/src/tools/clangbackend/ipcsource/clangipcserver.h @@ -56,6 +56,7 @@ public: void registerProjectPartsForCodeCompletion(const RegisterProjectPartsForCodeCompletionMessage &message) override; void unregisterProjectPartsForCodeCompletion(const UnregisterProjectPartsForCodeCompletionMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; + void requestDiagnostics(const RequestDiagnosticsMessage &message) override; private: ProjectParts projects; diff --git a/src/tools/clangbackend/ipcsource/diagnostic.cpp b/src/tools/clangbackend/ipcsource/diagnostic.cpp new file mode 100644 index 00000000000..f0220e79581 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/diagnostic.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "diagnostic.h" + +#include "clangstring.h" +#include "diagnosticset.h" +#include "fixit.h" +#include "sourcelocation.h" +#include "sourcerange.h" + +#include +#include + +namespace ClangBackEnd { + +Diagnostic::Diagnostic(CXDiagnostic cxDiagnostic) + : cxDiagnostic(cxDiagnostic) +{ +} + +Diagnostic::~Diagnostic() +{ + clang_disposeDiagnostic(cxDiagnostic); +} + +Diagnostic::Diagnostic(Diagnostic &&other) + : cxDiagnostic(std::move(other.cxDiagnostic)) +{ + other.cxDiagnostic = nullptr; +} + +Diagnostic &Diagnostic::operator=(Diagnostic &&other) +{ + if (this != &other) { + clang_disposeDiagnostic(cxDiagnostic); + cxDiagnostic = std::move(other.cxDiagnostic); + other.cxDiagnostic = nullptr; + } + + return *this; +} + +bool Diagnostic::isNull() const +{ + return cxDiagnostic == nullptr; +} + +Utf8String Diagnostic::text() const +{ + return ClangString(clang_formatDiagnostic(cxDiagnostic, 0)); +} + +Utf8String Diagnostic::category() const +{ + return ClangString(clang_getDiagnosticCategoryText(cxDiagnostic)); +} + +std::pair Diagnostic::options() const +{ + CXString disableString; + + const Utf8String enableOption = ClangString(clang_getDiagnosticOption(cxDiagnostic, &disableString)); + const Utf8String disableOption = ClangString(disableString); + + return {enableOption, disableOption}; +} + +SourceLocation Diagnostic::location() const +{ + return SourceLocation(clang_getDiagnosticLocation(cxDiagnostic)); +} + +DiagnosticSeverity Diagnostic::severity() const +{ + return static_cast(clang_getDiagnosticSeverity(cxDiagnostic)); +} + +std::vector Diagnostic::ranges() const +{ + std::vector ranges; + + const uint rangesCount = clang_getDiagnosticNumRanges(cxDiagnostic); + + ranges.reserve(rangesCount); + + for (uint index = 0; index < rangesCount; ++index) + ranges.push_back(SourceRange(clang_getDiagnosticRange(cxDiagnostic, index))); + + return ranges; +} + +std::vector Diagnostic::fixIts() const +{ + std::vector fixIts; + + const uint fixItsCount = clang_getDiagnosticNumFixIts(cxDiagnostic); + + fixIts.reserve(fixItsCount); + + for (uint index = 0; index < fixItsCount; ++index) + fixIts.push_back(FixIt(cxDiagnostic, index)); + + return fixIts; +} + +DiagnosticSet Diagnostic::childDiagnostics() const +{ + return DiagnosticSet(clang_getChildDiagnostics(cxDiagnostic)); +} + +DiagnosticContainer Diagnostic::toDiagnosticContainer() const +{ + return DiagnosticContainer(text(), + category(), + options(), + severity(), + location().toSourceLocationContainer(), + getSourceRangeContainers(), + getFixItContainers(), + childDiagnostics().toDiagnosticContainers()); +} + +QVector Diagnostic::getSourceRangeContainers() const +{ + auto rangeVector = ranges(); + + QVector sourceRangeContainers; + sourceRangeContainers.reserve(rangeVector.size()); + + for (auto &&sourceRange : rangeVector) + sourceRangeContainers.push_back(sourceRange.toSourceRangeContainer()); + + return sourceRangeContainers; +} + +QVector Diagnostic::getFixItContainers() const +{ + auto fixItVector = fixIts(); + + QVector fixItContainers; + fixItContainers.reserve(fixItVector.size()); + + for (auto &&fixIt : fixItVector) + fixItContainers.push_back(fixIt.toFixItContainer()); + + return fixItContainers; +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/diagnostic.h b/src/tools/clangbackend/ipcsource/diagnostic.h new file mode 100644 index 00000000000..db0950c7527 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/diagnostic.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_DIAGNOSTIC_H +#define CLANGBACKEND_DIAGNOSTIC_H + +#include + +#include + +class Utf8String; + +namespace ClangBackEnd { + +class SourceLocation; +class SourceRange; +class FixIt; +class DiagnosticSet; +class DiagnosticContainer; +class SourceRangeContainer; +class FixItContainer; + +class Diagnostic +{ + friend class DiagnosticSet; + friend class DiagnosticSetIterator; + friend bool operator==(Diagnostic first, Diagnostic second); + +public: + ~Diagnostic(); + + Diagnostic(const Diagnostic &) = delete; + const Diagnostic &operator=(const Diagnostic &) = delete; + + Diagnostic(Diagnostic &&other); + Diagnostic &operator=(Diagnostic &&other); + + bool isNull() const; + + Utf8String text() const; + Utf8String category() const; + std::pair options() const; + SourceLocation location() const; + DiagnosticSeverity severity() const; + std::vector ranges() const; + std::vector fixIts() const; + DiagnosticSet childDiagnostics() const; + + DiagnosticContainer toDiagnosticContainer() const; + +private: + Diagnostic(CXDiagnostic cxDiagnostic); + QVector getSourceRangeContainers() const; + QVector getFixItContainers() const; + +private: + CXDiagnostic cxDiagnostic; +}; + +inline bool operator==(Diagnostic first, Diagnostic second) +{ + return first.cxDiagnostic == second.cxDiagnostic; +} + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_DIAGNOSTIC_H diff --git a/src/tools/clangbackend/ipcsource/diagnosticset.cpp b/src/tools/clangbackend/ipcsource/diagnosticset.cpp new file mode 100644 index 00000000000..44f4071a8c1 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/diagnosticset.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "diagnosticset.h" + +#include "diagnostic.h" + +#include + +#include + +namespace ClangBackEnd { + +DiagnosticSet::DiagnosticSet(CXDiagnosticSet cxDiagnosticSet) + : cxDiagnosticSet(cxDiagnosticSet) +{ +} + +DiagnosticSet::~DiagnosticSet() +{ + clang_disposeDiagnosticSet(cxDiagnosticSet); +} + +DiagnosticSet::DiagnosticSet(DiagnosticSet &&other) + : cxDiagnosticSet(std::move(other.cxDiagnosticSet)) +{ + other.cxDiagnosticSet = nullptr; +} + +DiagnosticSet &DiagnosticSet::operator=(DiagnosticSet &&other) +{ + if (this != &other) { + clang_disposeDiagnosticSet(cxDiagnosticSet); + cxDiagnosticSet = std::move(other.cxDiagnosticSet); + other.cxDiagnosticSet = nullptr; + } + + return *this; +} + +Diagnostic DiagnosticSet::front() const +{ + return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, 0)); +} + +Diagnostic DiagnosticSet::back() const +{ + return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, size() - 1)); +} + +DiagnosticSet::ConstIterator DiagnosticSet::begin() const +{ + return DiagnosticSetIterator(cxDiagnosticSet, 0); +} + +DiagnosticSet::ConstIterator DiagnosticSet::end() const +{ + return DiagnosticSetIterator(cxDiagnosticSet, size()); +} + +QVector DiagnosticSet::toDiagnosticContainers() const +{ + QVector diagnosticContainers; + diagnosticContainers.reserve(size()); + + for (const Diagnostic &diagnostic : *this) + diagnosticContainers.push_back(diagnostic.toDiagnosticContainer()); + + return diagnosticContainers; +} + +uint DiagnosticSet::size() const +{ + return clang_getNumDiagnosticsInSet(cxDiagnosticSet); +} + +bool DiagnosticSet::isNull() const +{ + return cxDiagnosticSet == nullptr; +} + +Diagnostic DiagnosticSet::at(uint index) const +{ + return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, index)); +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/diagnosticset.h b/src/tools/clangbackend/ipcsource/diagnosticset.h new file mode 100644 index 00000000000..bc9b8431e66 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/diagnosticset.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_DIAGNOSTICSET_H +#define CLANGBACKEND_DIAGNOSTICSET_H + +#include "diagnostic.h" +#include "diagnosticsetiterator.h" + +#include + +#include + +namespace ClangBackEnd { + +class DiagnosticSetIterator; + +class DiagnosticSet +{ + friend class TranslationUnit; + friend class Diagnostic; + +public: + using ConstIterator = DiagnosticSetIterator; + +public: + ~DiagnosticSet(); + + DiagnosticSet(const DiagnosticSet &) = delete; + const DiagnosticSet &operator=(const DiagnosticSet &) = delete; + + DiagnosticSet(DiagnosticSet &&other); + DiagnosticSet &operator=(DiagnosticSet &&other); + + uint size() const; + bool isNull() const; + + Diagnostic at(uint index) const; + + Diagnostic front() const; + Diagnostic back() const; + + ConstIterator begin() const; + ConstIterator end() const; + + QVector toDiagnosticContainers() const; + +private: + DiagnosticSet(CXDiagnosticSet cxDiagnosticSet); + +private: + CXDiagnosticSet cxDiagnosticSet; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_DIAGNOSTICSET_H diff --git a/src/tools/clangbackend/ipcsource/diagnosticsetiterator.h b/src/tools/clangbackend/ipcsource/diagnosticsetiterator.h new file mode 100644 index 00000000000..aaed744986b --- /dev/null +++ b/src/tools/clangbackend/ipcsource/diagnosticsetiterator.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef DIAGNOSTICSETITERATOR_H +#define DIAGNOSTICSETITERATOR_H + +#include + +#include + +namespace ClangBackEnd { + +using uint = unsigned int; + +class DiagnosticSet; +class Diagnostic; + +class DiagnosticSetIterator : public std::iterator +{ +public: + DiagnosticSetIterator(CXDiagnosticSet cxDiagnosticSet, uint index) + : cxDiagnosticSet(cxDiagnosticSet), + index(index) + {} + + DiagnosticSetIterator(const DiagnosticSetIterator &other) + : cxDiagnosticSet(other.cxDiagnosticSet), + index(other.index) + {} + + DiagnosticSetIterator& operator++() + { + ++index; + return *this; + } + + DiagnosticSetIterator operator++(int) + { + uint oldIndex = index++; + return DiagnosticSetIterator(cxDiagnosticSet, oldIndex); + } + + bool operator==(const DiagnosticSetIterator &other) + { + return index == other.index && cxDiagnosticSet == other.cxDiagnosticSet; + } + + bool operator!=(const DiagnosticSetIterator &other) + { + return index != other.index || cxDiagnosticSet != other.cxDiagnosticSet; + } + + Diagnostic operator*() + { + return Diagnostic(clang_getDiagnosticInSet(cxDiagnosticSet, index)); + } + +private: + CXDiagnosticSet cxDiagnosticSet; + uint index; +}; + +} + +#endif // DIAGNOSTICSETITERATOR_H + diff --git a/src/tools/clangbackend/ipcsource/fixit.cpp b/src/tools/clangbackend/ipcsource/fixit.cpp new file mode 100644 index 00000000000..1c263194036 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/fixit.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "fixit.h" + +#include "clangstring.h" + +#include + +namespace ClangBackEnd { + +const Utf8String &FixIt::text() const +{ + return text_; +} + +const SourceRange &FixIt::range() const +{ + return sourceRange; +} + +FixItContainer FixIt::toFixItContainer() const +{ + return FixItContainer(text_, sourceRange.toSourceRangeContainer()); +} + +FixIt::FixIt(CXDiagnostic cxDiagnostic, uint index) +{ + CXSourceRange cxSourceRange; + + text_ = ClangString(clang_getDiagnosticFixIt(cxDiagnostic, index, &cxSourceRange)); + sourceRange = SourceRange(cxSourceRange); +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/fixit.h b/src/tools/clangbackend/ipcsource/fixit.h new file mode 100644 index 00000000000..cc9436263e4 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/fixit.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_FIXIT_H +#define CLANGBACKEND_FIXIT_H + +#include "sourcerange.h" + +#include + +#include + +namespace ClangBackEnd { + +class FixItContainer; + +using uint = unsigned int; + +class FixIt +{ + friend class Diagnostic; +public: + const Utf8String &text() const; + const SourceRange &range() const; + + FixItContainer toFixItContainer() const; + +private: + FixIt(CXDiagnostic cxDiagnostic, uint index); + +private: + SourceRange sourceRange; + Utf8String text_; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_FIXIT_H diff --git a/src/tools/clangbackend/ipcsource/projectpart.cpp b/src/tools/clangbackend/ipcsource/projectpart.cpp index ed240c2fa4b..d03dd833a05 100644 --- a/src/tools/clangbackend/ipcsource/projectpart.cpp +++ b/src/tools/clangbackend/ipcsource/projectpart.cpp @@ -76,6 +76,13 @@ ProjectPart::ProjectPart(const Utf8String &projectPartId) { } +ProjectPart::ProjectPart(const Utf8String &projectPartId, + std::initializer_list arguments) + : d(std::make_shared(projectPartId)) +{ + setArguments(arguments); +} + ProjectPart::ProjectPart(const ProjectPartContainer &projectContainer) : d(std::make_shared(projectContainer.projectPartId())) { diff --git a/src/tools/clangbackend/ipcsource/projectpart.h b/src/tools/clangbackend/ipcsource/projectpart.h index 5c318be7f5f..c87dc8d8467 100644 --- a/src/tools/clangbackend/ipcsource/projectpart.h +++ b/src/tools/clangbackend/ipcsource/projectpart.h @@ -49,6 +49,8 @@ class ProjectPart { public: ProjectPart(const Utf8String &projectPartId); + ProjectPart(const Utf8String &projectPartId, + std::initializer_list arguments); ProjectPart(const ProjectPartContainer &projectContainer); ~ProjectPart(); diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.cpp b/src/tools/clangbackend/ipcsource/sourcelocation.cpp new file mode 100644 index 00000000000..8a7cd0d8716 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/sourcelocation.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "sourcelocation.h" + +#include "clangstring.h" + +#include + +#include +#include + +namespace ClangBackEnd { + +const Utf8String &SourceLocation::filePath() const +{ + return filePath_; +} + +uint SourceLocation::line() const +{ + return line_; +} + +uint SourceLocation::column() const +{ + return column_; +} + +uint SourceLocation::offset() const +{ + return offset_; +} + +SourceLocationContainer SourceLocation::toSourceLocationContainer() const +{ + return SourceLocationContainer(filePath_, line_, offset_); +} + +SourceLocation::SourceLocation(CXSourceLocation cxSourceLocation) +{ + CXFile cxFile; + + clang_getFileLocation(cxSourceLocation, + &cxFile, + &line_, + &column_, + &offset_); + + filePath_ = ClangString(clang_getFileName(cxFile)); +} + +void PrintTo(const SourceLocation &sourceLocation, std::ostream *os) +{ + *os << sourceLocation.filePath().constData() + << ", line: " << sourceLocation.line() + << ", column: "<< sourceLocation.column() + << ", offset: "<< sourceLocation.offset(); +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/sourcelocation.h b/src/tools/clangbackend/ipcsource/sourcelocation.h new file mode 100644 index 00000000000..3ee500623b8 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/sourcelocation.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_SOURCELOCATION_H +#define CLANGBACKEND_SOURCELOCATION_H + +#include + +#include + +namespace ClangBackEnd { + +class SourceLocationContainer; + +class SourceLocation +{ + friend class Diagnostic; + friend class SourceRange; + +public: + const Utf8String &filePath() const; + uint line() const; + uint column() const; + uint offset() const; + + SourceLocationContainer toSourceLocationContainer() const; + +private: + SourceLocation(CXSourceLocation cxSourceLocation); + +private: + Utf8String filePath_; + uint line_; + uint column_; + uint offset_; +}; + +void PrintTo(const SourceLocation &sourceLocation, ::std::ostream* os); + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_SOURCELOCATION_H diff --git a/src/tools/clangbackend/ipcsource/sourcerange.cpp b/src/tools/clangbackend/ipcsource/sourcerange.cpp new file mode 100644 index 00000000000..4ea26ba1fed --- /dev/null +++ b/src/tools/clangbackend/ipcsource/sourcerange.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "sourcerange.h" + +#include + +namespace ClangBackEnd { + +SourceRange::SourceRange() + : cxSourceRange(clang_getNullRange()) +{ +} + +SourceLocation SourceRange::start() const +{ + return SourceLocation(clang_getRangeStart(cxSourceRange)); +} + +SourceLocation SourceRange::end() const +{ + return SourceLocation(clang_getRangeEnd(cxSourceRange)); +} + +SourceRangeContainer SourceRange::toSourceRangeContainer() const +{ + return SourceRangeContainer(start().toSourceLocationContainer(), + end().toSourceLocationContainer()); +} + +SourceRange::SourceRange(CXSourceRange cxSourceRange) + : cxSourceRange(cxSourceRange) +{ +} + +} // namespace ClangBackEnd + diff --git a/src/tools/clangbackend/ipcsource/sourcerange.h b/src/tools/clangbackend/ipcsource/sourcerange.h new file mode 100644 index 00000000000..cec9f6fa658 --- /dev/null +++ b/src/tools/clangbackend/ipcsource/sourcerange.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#ifndef CLANGBACKEND_SOURCERANGE_H +#define CLANGBACKEND_SOURCERANGE_H + +#include "sourcelocation.h" + +namespace ClangBackEnd { + +class SourceRangeContainer; + +class SourceRange +{ + friend class Diagnostic; + friend class FixIt; + +public: + SourceRange(); + SourceLocation start() const; + SourceLocation end() const; + + SourceRangeContainer toSourceRangeContainer() const; + +private: + SourceRange(CXSourceRange cxSourceRange); + +private: + CXSourceRange cxSourceRange; +}; + +} // namespace ClangBackEnd + +#endif // CLANGBACKEND_SOURCERANGE_H diff --git a/src/tools/clangbackend/ipcsource/translationunit.cpp b/src/tools/clangbackend/ipcsource/translationunit.cpp index 9581cb57508..7d0a0735c8b 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.cpp +++ b/src/tools/clangbackend/ipcsource/translationunit.cpp @@ -31,6 +31,7 @@ #include "translationunit.h" #include "codecompleter.h" +#include "diagnosticset.h" #include "projectpart.h" #include "translationunitfilenotexitexception.h" #include "translationunitisnullexception.h" @@ -99,7 +100,7 @@ void TranslationUnit::reset() d.reset(); } -void TranslationUnit::reparse() +void TranslationUnit::reparse() const { cxTranslationUnit(); @@ -143,11 +144,25 @@ const Utf8String &TranslationUnit::projectPartId() const return d->projectPart.projectPartId(); } +FileContainer TranslationUnit::fileContainer() const +{ + checkIfNull(); + + return FileContainer(d->filePath, d->projectPart.projectPartId()); +} + const time_point &TranslationUnit::lastChangeTimePoint() const { return d->lastChangeTimePoint; } +DiagnosticSet TranslationUnit::diagnostics() const +{ + reparse(); + + return DiagnosticSet(clang_getDiagnosticSetFromTU(cxTranslationUnit())); +} + void TranslationUnit::checkIfNull() const { if (isNull()) @@ -215,8 +230,7 @@ void TranslationUnit::reparseTranslationUnit() const int TranslationUnit::defaultOptions() { return CXTranslationUnit_CacheCompletionResults - | CXTranslationUnit_PrecompiledPreamble - | CXTranslationUnit_SkipFunctionBodies; + | CXTranslationUnit_PrecompiledPreamble; } uint TranslationUnit::unsavedFilesCount() const diff --git a/src/tools/clangbackend/ipcsource/translationunit.h b/src/tools/clangbackend/ipcsource/translationunit.h index 803e5e9c27b..904590d934e 100644 --- a/src/tools/clangbackend/ipcsource/translationunit.h +++ b/src/tools/clangbackend/ipcsource/translationunit.h @@ -46,6 +46,8 @@ class TranslationUnitData; class CodeCompleter; class UnsavedFiles; class ProjectPart; +class DiagnosticSet; +class FileContainer; using time_point = std::chrono::steady_clock::time_point; @@ -73,7 +75,7 @@ public: bool isNull() const; void reset(); - void reparse(); + void reparse() const; CXIndex index() const; CXTranslationUnit cxTranslationUnit() const; @@ -82,9 +84,12 @@ public: const Utf8String &filePath() const; const Utf8String &projectPartId() const; + FileContainer fileContainer() const; const time_point &lastChangeTimePoint() const; + DiagnosticSet diagnostics() const; + private: void checkIfNull() const; void checkIfFileExists() const; diff --git a/tests/unit/echoserver/echoipcserver.cpp b/tests/unit/echoserver/echoipcserver.cpp index afd2939c729..6642bff9c73 100644 --- a/tests/unit/echoserver/echoipcserver.cpp +++ b/tests/unit/echoserver/echoipcserver.cpp @@ -39,6 +39,7 @@ #include "cmbunregisterprojectsforcodecompletionmessage.h" #include "cmbunregistertranslationunitsforcodecompletionmessage.h" #include "connectionserver.h" +#include "requestdiagnosticsmessage.h" #include #include @@ -82,6 +83,11 @@ void EchoIpcServer::completeCode(const CompleteCodeMessage &message) echoMessage(QVariant::fromValue(message)); } +void EchoIpcServer::requestDiagnostics(const RequestDiagnosticsMessage &message) +{ + echoMessage(QVariant::fromValue(message)); +} + void EchoIpcServer::echoMessage(const QVariant &message) { client()->echo(EchoMessage(message)); diff --git a/tests/unit/echoserver/echoipcserver.h b/tests/unit/echoserver/echoipcserver.h index 98138aaaf57..2c82bbc3f67 100644 --- a/tests/unit/echoserver/echoipcserver.h +++ b/tests/unit/echoserver/echoipcserver.h @@ -45,6 +45,7 @@ public: void registerProjectPartsForCodeCompletion(const RegisterProjectPartsForCodeCompletionMessage &message) override; void unregisterProjectPartsForCodeCompletion(const UnregisterProjectPartsForCodeCompletionMessage &message) override; void completeCode(const CompleteCodeMessage &message) override; + void requestDiagnostics(const RequestDiagnosticsMessage &message) override; private: void echoMessage(const QVariant &message); diff --git a/tests/unit/unittest/clangipcservertest.cpp b/tests/unit/unittest/clangipcservertest.cpp index cda99a2fcbc..466ca354b17 100644 --- a/tests/unit/unittest/clangipcservertest.cpp +++ b/tests/unit/unittest/clangipcservertest.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include diff --git a/tests/unit/unittest/clangstringtest.cpp b/tests/unit/unittest/clangstringtest.cpp index 33d4a785ad3..0467de693df 100644 --- a/tests/unit/unittest/clangstringtest.cpp +++ b/tests/unit/unittest/clangstringtest.cpp @@ -58,7 +58,7 @@ TEST(ClangString, ConvertNullStringToUtf8String) ASSERT_THAT(Utf8String(ClangString(cxString)), Utf8String()); } -TEST(ClangString, MoveClangString) +TEST(ClangString, MoveContructor) { ClangString text(CXString{ "text", 0}); @@ -68,4 +68,23 @@ TEST(ClangString, MoveClangString) ASSERT_FALSE(text2.isNull()); } +TEST(ClangString, MoveAssigment) +{ + ClangString text(CXString{ "text", 0}); + + ClangString text2 = std::move(text); + text = std::move(text2); + + ASSERT_TRUE(text2.isNull()); + ASSERT_FALSE(text.isNull()); +} + +TEST(ClangString, MoveSelfAssigment) +{ + ClangString text(CXString{ "text", 0}); + + text = std::move(text); + + ASSERT_FALSE(text.isNull()); +} } diff --git a/tests/unit/unittest/clientserverinprocesstest.cpp b/tests/unit/unittest/clientserverinprocesstest.cpp index c39325d91e3..943c1809130 100644 --- a/tests/unit/unittest/clientserverinprocesstest.cpp +++ b/tests/unit/unittest/clientserverinprocesstest.cpp @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -110,7 +112,7 @@ TEST_F(ClientServerInProcess, SendAliveMessage) TEST_F(ClientServerInProcess, SendRegisterTranslationUnitForCodeCompletionMessage) { ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), - Utf8StringLiteral("pathToProjectPart.pro")); + Utf8StringLiteral("projectId")); ClangBackEnd::RegisterTranslationUnitForCodeCompletionMessage message({fileContainer}); EXPECT_CALL(mockIpcServer, registerTranslationUnitsForCodeCompletion(message)) @@ -122,7 +124,7 @@ TEST_F(ClientServerInProcess, SendRegisterTranslationUnitForCodeCompletionMessag TEST_F(ClientServerInProcess, SendUnregisterTranslationUnitsForCodeCompletionMessage) { - ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProjectPart.pro")); + ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("projectId")); ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionMessage message({fileContainer}); EXPECT_CALL(mockIpcServer, unregisterTranslationUnitsForCodeCompletion(message)) @@ -143,6 +145,20 @@ TEST_F(ClientServerInProcess, SendCompleteCodeMessage) scheduleServerMessages(); } +TEST_F(ClientServerInProcess, SendRequestDiagnosticsMessage) +{ + ClangBackEnd::RequestDiagnosticsMessage message({Utf8StringLiteral("foo.cpp"), + Utf8StringLiteral("projectId")}, + 1); + + EXPECT_CALL(mockIpcServer, requestDiagnostics(message)) + .Times(1); + + serverProxy.requestDiagnostics(message); + scheduleServerMessages(); +} + + TEST_F(ClientServerInProcess, SendCodeCompletedMessage) { ClangBackEnd::CodeCompletions codeCompletions({Utf8StringLiteral("newFunction()")}); @@ -181,7 +197,7 @@ TEST_F(ClientServerInProcess, SendUnregisterProjectPartsForCodeCompletionMessage TEST_F(ClientServerInProcess, SendTranslationUnitDoesNotExistMessage) { ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), - Utf8StringLiteral("pathToProjectPart.pro")); + Utf8StringLiteral("projectId")); ClangBackEnd::TranslationUnitDoesNotExistMessage message(fileContainer); EXPECT_CALL(mockIpcClient, translationUnitDoesNotExist(message)) @@ -194,7 +210,7 @@ TEST_F(ClientServerInProcess, SendTranslationUnitDoesNotExistMessage) TEST_F(ClientServerInProcess, SendProjectPartDoesNotExistMessage) { - ClangBackEnd::ProjectPartsDoNotExistMessage message({Utf8StringLiteral("pathToProjectPart.pro")}); + ClangBackEnd::ProjectPartsDoNotExistMessage message({Utf8StringLiteral("projectId")}); EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(message)) .Times(1); @@ -202,6 +218,30 @@ TEST_F(ClientServerInProcess, SendProjectPartDoesNotExistMessage) clientProxy.projectPartsDoNotExist(message); scheduleClientMessages(); } + +TEST_F(ClientServerInProcess, SendDiagnosticsChangedMessage) +{ + ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), + Utf8StringLiteral("projectId")); + ClangBackEnd::DiagnosticContainer container(Utf8StringLiteral("don't do that"), + Utf8StringLiteral("warning"), + {Utf8StringLiteral("-Wpadded"), Utf8StringLiteral("-Wno-padded")}, + ClangBackEnd::DiagnosticSeverity::Warning, + {Utf8StringLiteral("foo.cpp"), 20u, 103u}, + {{{Utf8StringLiteral("foo.cpp"), 20u, 103u}, {Utf8StringLiteral("foo.cpp"), 20u, 110u}}}, + {}, + {}); + ClangBackEnd::DiagnosticsChangedMessage message(fileContainer, + {container}, + 1); + + EXPECT_CALL(mockIpcClient, diagnosticsChanged(message)) + .Times(1); + + clientProxy.diagnosticsChanged(message); + scheduleClientMessages(); +} + ClientServerInProcess::ClientServerInProcess() : serverProxy(&mockIpcClient, &buffer), clientProxy(&mockIpcServer, &buffer) diff --git a/tests/unit/unittest/clientserveroutsideprocess.cpp b/tests/unit/unittest/clientserveroutsideprocess.cpp index d3c4867f832..a52ec551431 100644 --- a/tests/unit/unittest/clientserveroutsideprocess.cpp +++ b/tests/unit/unittest/clientserveroutsideprocess.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -113,7 +114,7 @@ TEST_F(ClientServerOutsideProcess, RestartProcessAfterTermination) TEST_F(ClientServerOutsideProcess, SendRegisterTranslationUnitForCodeCompletionMessage) { - ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo"), Utf8StringLiteral("pathToProjectPart.pro")); + ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("projectId")); ClangBackEnd::RegisterTranslationUnitForCodeCompletionMessage registerTranslationUnitForCodeCompletionMessage({fileContainer}); EchoMessage echoMessage(QVariant::fromValue(registerTranslationUnitForCodeCompletionMessage)); @@ -126,7 +127,7 @@ TEST_F(ClientServerOutsideProcess, SendRegisterTranslationUnitForCodeCompletionM TEST_F(ClientServerOutsideProcess, SendUnregisterTranslationUnitsForCodeCompletionMessage) { - FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("bar.pro")); + FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("projectId")); ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionMessage unregisterTranslationUnitsForCodeCompletionMessage ({fileContainer}); EchoMessage echoMessage(QVariant::fromValue(unregisterTranslationUnitsForCodeCompletionMessage)); diff --git a/tests/unit/unittest/data/diagnostic_diagnostic.cpp b/tests/unit/unittest/data/diagnostic_diagnostic.cpp new file mode 100644 index 00000000000..a1525b85d51 --- /dev/null +++ b/tests/unit/unittest/data/diagnostic_diagnostic.cpp @@ -0,0 +1,10 @@ +class X { + X(X&&) noexcept; +}; + +X::X(X&&) = default; + +int function() +{ +} + diff --git a/tests/unit/unittest/data/diagnostic_diagnosticset.cpp b/tests/unit/unittest/data/diagnostic_diagnosticset.cpp new file mode 100644 index 00000000000..20ea8ffe1e4 --- /dev/null +++ b/tests/unit/unittest/data/diagnostic_diagnosticset.cpp @@ -0,0 +1,5 @@ +int function() +{ + +} + diff --git a/tests/unit/unittest/data/diagnostic_fixit.cpp b/tests/unit/unittest/data/diagnostic_fixit.cpp new file mode 100644 index 00000000000..8b7eb2c657c --- /dev/null +++ b/tests/unit/unittest/data/diagnostic_fixit.cpp @@ -0,0 +1,4 @@ +int function() +{ + return 3 +} diff --git a/tests/unit/unittest/data/diagnostic_source_location.cpp b/tests/unit/unittest/data/diagnostic_source_location.cpp new file mode 100644 index 00000000000..20ea8ffe1e4 --- /dev/null +++ b/tests/unit/unittest/data/diagnostic_source_location.cpp @@ -0,0 +1,5 @@ +int function() +{ + +} + diff --git a/tests/unit/unittest/data/diagnostic_source_range.cpp b/tests/unit/unittest/data/diagnostic_source_range.cpp new file mode 100644 index 00000000000..ae0ee72f593 --- /dev/null +++ b/tests/unit/unittest/data/diagnostic_source_range.cpp @@ -0,0 +1,9 @@ +class XXX +{ + +}; + +int function(XXX i) +{ + i + 20; +} diff --git a/tests/unit/unittest/diagnosticsettest.cpp b/tests/unit/unittest/diagnosticsettest.cpp new file mode 100644 index 00000000000..e476a895ff8 --- /dev/null +++ b/tests/unit/unittest/diagnosticsettest.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +using ::ClangBackEnd::DiagnosticSet; +using ::ClangBackEnd::TranslationUnit; +using ::ClangBackEnd::ProjectPart; +using ::ClangBackEnd::UnsavedFiles; + +namespace { + +class DiagnosticSet : public ::testing::Test +{ +protected: + ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}}; + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnosticset.cpp"), + unsavedFiles, + projectPart}; +}; + +TEST_F(DiagnosticSet, SetHasContent) +{ + const auto set = translationUnit.diagnostics(); + + ASSERT_THAT(set.size(), 1); +} + +TEST_F(DiagnosticSet, MoveConstructor) +{ + auto set = translationUnit.diagnostics(); + + const auto set2 = std::move(set); + + ASSERT_TRUE(set.isNull()); + ASSERT_FALSE(set2.isNull()); +} + +TEST_F(DiagnosticSet, MoveAssigment) +{ + auto set = translationUnit.diagnostics(); + + auto set2 = std::move(set); + set = std::move(set2); + + ASSERT_TRUE(set2.isNull()); + ASSERT_FALSE(set.isNull()); +} + +TEST_F(DiagnosticSet, MoveSelfAssigment) +{ + auto set = translationUnit.diagnostics(); + + set = std::move(set); + + ASSERT_FALSE(set.isNull()); +} + +TEST_F(DiagnosticSet, FirstElementEqualBegin) +{ + auto set = translationUnit.diagnostics(); + + ASSERT_TRUE(set.front() == *set.begin()); +} + +TEST_F(DiagnosticSet, BeginIsUnequalEnd) +{ + auto set = translationUnit.diagnostics(); + + ASSERT_TRUE(set.begin() != set.end()); +} + +TEST_F(DiagnosticSet, BeginPlusOneIsEqualEnd) +{ + auto set = translationUnit.diagnostics(); + + ASSERT_TRUE(++set.begin() == set.end()); +} + +} diff --git a/tests/unit/unittest/diagnostictest.cpp b/tests/unit/unittest/diagnostictest.cpp new file mode 100644 index 00000000000..a57aba9919a --- /dev/null +++ b/tests/unit/unittest/diagnostictest.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +using ClangBackEnd::DiagnosticSet; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::Diagnostic; +using ClangBackEnd::SourceLocation; +using ClangBackEnd::DiagnosticSeverity; +using testing::PrintToString; + +namespace { + +MATCHER_P4(IsSourceLocation, filePath, line, column, offset, + std::string(negation ? "isn't" : "is") + + " source location with file path "+ PrintToString(filePath) + + ", line " + PrintToString(line) + + ", column " + PrintToString(column) + + " and offset " + PrintToString(offset) + ) +{ + if (!arg.filePath().endsWith(filePath) + || arg.line() != line + || arg.column() != column + || arg.offset() != offset) + return false; + + return true; +} + +class Diagnostic : public ::testing::Test +{ +protected: + ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-std=c++11")}}; + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_diagnostic.cpp"), + unsavedFiles, + projectPart}; + DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; + ::Diagnostic diagnostic{diagnosticSet.back()}; +}; + +TEST_F(Diagnostic, MoveContructor) +{ + const auto diagnostic2 = std::move(diagnostic); + + ASSERT_TRUE(diagnostic.isNull()); + ASSERT_FALSE(diagnostic2.isNull()); +} + +TEST_F(Diagnostic, MoveAssigment) +{ + auto diagnostic2 = std::move(diagnostic); + diagnostic = std::move(diagnostic2); + + ASSERT_TRUE(diagnostic2.isNull()); + ASSERT_FALSE(diagnostic.isNull()); +} + +TEST_F(Diagnostic, MoveSelfAssigment) +{ + diagnostic = std::move(diagnostic); + + ASSERT_FALSE(diagnostic.isNull()); +} + +TEST_F(Diagnostic, Text) +{ + ASSERT_THAT(diagnostic.text(), Utf8StringLiteral("warning: control reaches end of non-void function")); +} + +TEST_F(Diagnostic, Category) +{ + ASSERT_THAT(diagnostic.category(), Utf8StringLiteral("Semantic Issue")); +} + +TEST_F(Diagnostic, EnableOption) +{ + ASSERT_THAT(diagnostic.options().first, Utf8StringLiteral("-Wreturn-type")); +} + +TEST_F(Diagnostic, DisableOption) +{ + ASSERT_THAT(diagnostic.options().second, Utf8StringLiteral("-Wno-return-type")); +} + +TEST_F(Diagnostic, Severity) +{ + ASSERT_THAT(diagnostic.severity(), DiagnosticSeverity::Warning); +} + +TEST_F(Diagnostic, ChildDiagnosticsSize) +{ + auto diagnostic = diagnosticSet.front(); + + ASSERT_THAT(diagnostic.childDiagnostics().size(), 1); +} + +TEST_F(Diagnostic, ChildDiagnosticsText) +{ + auto childDiagnostic = diagnosticSet.front().childDiagnostics().front(); + + ASSERT_THAT(childDiagnostic.text(), Utf8StringLiteral("note: previous declaration is here")); +} + +} diff --git a/tests/unit/unittest/fixittest.cpp b/tests/unit/unittest/fixittest.cpp new file mode 100644 index 00000000000..88e5d34587b --- /dev/null +++ b/tests/unit/unittest/fixittest.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +using ClangBackEnd::DiagnosticSet; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::Diagnostic; +using ClangBackEnd::FixIt; +using testing::PrintToString; + +namespace { + +MATCHER_P4(IsSourceLocation, filePath, line, column, offset, + std::string(negation ? "isn't" : "is") + + " source location with file path "+ PrintToString(filePath) + + ", line " + PrintToString(line) + + ", column " + PrintToString(column) + + " and offset " + PrintToString(offset) + ) +{ + if (!arg.filePath().endsWith(filePath) + || arg.line() != line + || arg.column() != column + || arg.offset() != offset) + return false; + + return true; +} + +class FixIt : public ::testing::Test +{ +protected: + ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_fixit.cpp"), + unsavedFiles, + projectPart}; + DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; + Diagnostic diagnostic{diagnosticSet.front()}; + ::FixIt fixIt{diagnostic.fixIts().front()}; +}; + +TEST_F(FixIt, Size) +{ + ASSERT_THAT(diagnostic.fixIts().size(), 1); +} + +TEST_F(FixIt, Text) +{ + ASSERT_THAT(fixIt.text(), Utf8StringLiteral(";")); +} + + +TEST_F(FixIt, Start) +{ + ASSERT_THAT(fixIt.range().start(), IsSourceLocation(Utf8StringLiteral("diagnostic_fixit.cpp"), + 3u, + 13u, + 29u)); +} + +TEST_F(FixIt, End) +{ + ASSERT_THAT(fixIt.range().end(), IsSourceLocation(Utf8StringLiteral("diagnostic_fixit.cpp"), + 3u, + 13u, + 29u)); +} + +} diff --git a/tests/unit/unittest/mockipclient.h b/tests/unit/unittest/mockipclient.h index 90d58404560..75c24dc9e3f 100644 --- a/tests/unit/unittest/mockipclient.h +++ b/tests/unit/unittest/mockipclient.h @@ -39,17 +39,19 @@ #include "gtest-qt-printing.h" class MockIpcClient : public ClangBackEnd::IpcClientInterface { - public: - MOCK_METHOD0(alive, - void()); - MOCK_METHOD1(echo, - void(const ClangBackEnd::EchoMessage &message)); - MOCK_METHOD1(codeCompleted, - void(const ClangBackEnd::CodeCompletedMessage &message)); - MOCK_METHOD1(translationUnitDoesNotExist, - void(const ClangBackEnd::TranslationUnitDoesNotExistMessage &message)); - MOCK_METHOD1(projectPartsDoNotExist, - void(const ClangBackEnd::ProjectPartsDoNotExistMessage &message)); +public: + MOCK_METHOD0(alive, + void()); + MOCK_METHOD1(echo, + void(const ClangBackEnd::EchoMessage &message)); + MOCK_METHOD1(codeCompleted, + void(const ClangBackEnd::CodeCompletedMessage &message)); + MOCK_METHOD1(translationUnitDoesNotExist, + void(const ClangBackEnd::TranslationUnitDoesNotExistMessage &message)); + MOCK_METHOD1(projectPartsDoNotExist, + void(const ClangBackEnd::ProjectPartsDoNotExistMessage &message)); + MOCK_METHOD1(diagnosticsChanged, + void(const ClangBackEnd::DiagnosticsChangedMessage &message)); }; #endif // MOCKIPCLIENT_H diff --git a/tests/unit/unittest/mockipcserver.h b/tests/unit/unittest/mockipcserver.h index ccf4561d00b..01012f94337 100644 --- a/tests/unit/unittest/mockipcserver.h +++ b/tests/unit/unittest/mockipcserver.h @@ -39,19 +39,21 @@ #include "gtest-qt-printing.h" class MockIpcServer : public ClangBackEnd::IpcServerInterface { - public: - MOCK_METHOD0(end, - void()); - MOCK_METHOD1(registerTranslationUnitsForCodeCompletion, - void(const ClangBackEnd::RegisterTranslationUnitForCodeCompletionMessage &message)); - MOCK_METHOD1(unregisterTranslationUnitsForCodeCompletion, - void(const ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionMessage &message)); - MOCK_METHOD1(registerProjectPartsForCodeCompletion, - void(const ClangBackEnd::RegisterProjectPartsForCodeCompletionMessage &message)); - MOCK_METHOD1(unregisterProjectPartsForCodeCompletion, - void(const ClangBackEnd::UnregisterProjectPartsForCodeCompletionMessage &message)); - MOCK_METHOD1(completeCode, - void(const ClangBackEnd::CompleteCodeMessage &message)); +public: + MOCK_METHOD0(end, + void()); + MOCK_METHOD1(registerTranslationUnitsForCodeCompletion, + void(const ClangBackEnd::RegisterTranslationUnitForCodeCompletionMessage &message)); + MOCK_METHOD1(unregisterTranslationUnitsForCodeCompletion, + void(const ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionMessage &message)); + MOCK_METHOD1(registerProjectPartsForCodeCompletion, + void(const ClangBackEnd::RegisterProjectPartsForCodeCompletionMessage &message)); + MOCK_METHOD1(unregisterProjectPartsForCodeCompletion, + void(const ClangBackEnd::UnregisterProjectPartsForCodeCompletionMessage &message)); + MOCK_METHOD1(completeCode, + void(const ClangBackEnd::CompleteCodeMessage &message)); + MOCK_METHOD1(requestDiagnostics, + void(const ClangBackEnd::RequestDiagnosticsMessage &message)); }; #endif // MOCKIPCSERVER_H diff --git a/tests/unit/unittest/readandwritemessageblocktest.cpp b/tests/unit/unittest/readandwritemessageblocktest.cpp index b1a3c5a5cf3..e3ae0a20198 100644 --- a/tests/unit/unittest/readandwritemessageblocktest.cpp +++ b/tests/unit/unittest/readandwritemessageblocktest.cpp @@ -30,17 +30,22 @@ #include #include -#include #include #include +#include #include #include +#include +#include +#include #include +#include #include #include #include #include + #include #include @@ -51,10 +56,10 @@ using namespace testing; namespace CodeModelBackeEndTest { -class ReadAndWriteMessageBlockTest : public ::testing::Test +class ReadAndWriteMessageBlock : public ::testing::Test { protected: - ReadAndWriteMessageBlockTest(); + ReadAndWriteMessageBlock(); virtual void SetUp() override; virtual void TearDown() override; @@ -74,39 +79,39 @@ protected: char lastCharacter = 0; }; -ReadAndWriteMessageBlockTest::ReadAndWriteMessageBlockTest() +ReadAndWriteMessageBlock::ReadAndWriteMessageBlock() : writeMessageBlock(&buffer), readMessageBlock(&buffer) { } -void ReadAndWriteMessageBlockTest::SetUp() +void ReadAndWriteMessageBlock::SetUp() { buffer.open(QIODevice::ReadWrite); writeMessageBlock = ClangBackEnd::WriteMessageBlock(&buffer); readMessageBlock = ClangBackEnd::ReadMessageBlock(&buffer); } -void ReadAndWriteMessageBlockTest::TearDown() +void ReadAndWriteMessageBlock::TearDown() { buffer.close(); } -TEST_F(ReadAndWriteMessageBlockTest, WriteMessageAndTestSize) +TEST_F(ReadAndWriteMessageBlock, WriteMessageAndTestSize) { writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); ASSERT_EQ(46, buffer.size()); } -TEST_F(ReadAndWriteMessageBlockTest, WriteSecondMessageAndTestSize) +TEST_F(ReadAndWriteMessageBlock, WriteSecondMessageAndTestSize) { writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); ASSERT_EQ(46, buffer.size()); } -TEST_F(ReadAndWriteMessageBlockTest, WriteTwoMessagesAndTestCount) +TEST_F(ReadAndWriteMessageBlock, WriteTwoMessagesAndTestCount) { writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); @@ -114,7 +119,7 @@ TEST_F(ReadAndWriteMessageBlockTest, WriteTwoMessagesAndTestCount) ASSERT_EQ(2, writeMessageBlock.counter()); } -TEST_F(ReadAndWriteMessageBlockTest, ReadThreeMessagesAndTestCount) +TEST_F(ReadAndWriteMessageBlock, ReadThreeMessagesAndTestCount) { writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); writeMessageBlock.write(QVariant::fromValue(ClangBackEnd::EndMessage())); @@ -124,17 +129,17 @@ TEST_F(ReadAndWriteMessageBlockTest, ReadThreeMessagesAndTestCount) ASSERT_EQ(3, readMessageBlock.readAll().count()); } -TEST_F(ReadAndWriteMessageBlockTest, CompareEndMessage) +TEST_F(ReadAndWriteMessageBlock, CompareEndMessage) { CompareMessage(ClangBackEnd::EndMessage()); } -TEST_F(ReadAndWriteMessageBlockTest, CompareAliveMessage) +TEST_F(ReadAndWriteMessageBlock, CompareAliveMessage) { CompareMessage(ClangBackEnd::AliveMessage()); } -TEST_F(ReadAndWriteMessageBlockTest, CompareRegisterTranslationUnitForCodeCompletionMessage) +TEST_F(ReadAndWriteMessageBlock, CompareRegisterTranslationUnitForCodeCompletionMessage) { ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro")); QVector fileContainers({fileContainer}); @@ -142,26 +147,51 @@ TEST_F(ReadAndWriteMessageBlockTest, CompareRegisterTranslationUnitForCodeComple CompareMessage(ClangBackEnd::RegisterTranslationUnitForCodeCompletionMessage(fileContainers)); } -TEST_F(ReadAndWriteMessageBlockTest, CompareUnregisterFileForCodeCompletionMessage) +TEST_F(ReadAndWriteMessageBlock, CompareUnregisterFileForCodeCompletionMessage) { ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro")); CompareMessage(ClangBackEnd::UnregisterTranslationUnitsForCodeCompletionMessage({fileContainer})); } -TEST_F(ReadAndWriteMessageBlockTest, CompareCompleteCodeMessage) +TEST_F(ReadAndWriteMessageBlock, CompareCompleteCodeMessage) { CompareMessage(ClangBackEnd::CompleteCodeMessage(Utf8StringLiteral("foo.cpp"), 24, 33, Utf8StringLiteral("do what I want"))); } -TEST_F(ReadAndWriteMessageBlockTest, CompareCodeCompletedMessage) +TEST_F(ReadAndWriteMessageBlock, CompareCodeCompletedMessage) { ClangBackEnd::CodeCompletions codeCompletions({Utf8StringLiteral("newFunction()")}); CompareMessage(ClangBackEnd::CodeCompletedMessage(codeCompletions, 1)); } -TEST_F(ReadAndWriteMessageBlockTest, GetInvalidMessageForAPartialBuffer) +TEST_F(ReadAndWriteMessageBlock, CompareDiagnosticsChangedMessage) +{ + ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), + Utf8StringLiteral("projectId")); + ClangBackEnd::DiagnosticContainer container(Utf8StringLiteral("don't do that"), + Utf8StringLiteral("warning"), + {Utf8StringLiteral("-Wpadded"), Utf8StringLiteral("-Wno-padded")}, + ClangBackEnd::DiagnosticSeverity::Warning, + {Utf8StringLiteral("foo.cpp"), 20u, 103u}, + {{{Utf8StringLiteral("foo.cpp"), 20u, 103u}, {Utf8StringLiteral("foo.cpp"), 20u, 110u}}}, + {}, + {}); + + CompareMessage(ClangBackEnd::DiagnosticsChangedMessage(fileContainer, + {container}, + 1)); +} + +TEST_F(ReadAndWriteMessageBlock, RequestDiagnosticsMessage) +{ + ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("pathToProject.pro")); + + CompareMessage(ClangBackEnd::RequestDiagnosticsMessage(fileContainer, 1)); +} + +TEST_F(ReadAndWriteMessageBlock, GetInvalidMessageForAPartialBuffer) { writeCodeCompletedMessage(); popLastCharacterFromBuffer(); @@ -170,7 +200,7 @@ TEST_F(ReadAndWriteMessageBlockTest, GetInvalidMessageForAPartialBuffer) readPartialMessage(); } -TEST_F(ReadAndWriteMessageBlockTest, ReadMessageAfterInterruption) +TEST_F(ReadAndWriteMessageBlock, ReadMessageAfterInterruption) { const QVariant writeMessage = writeCodeCompletedMessage(); popLastCharacterFromBuffer(); @@ -181,7 +211,7 @@ TEST_F(ReadAndWriteMessageBlockTest, ReadMessageAfterInterruption) ASSERT_EQ(readMessageBlock.read(), writeMessage); } -QVariant ReadAndWriteMessageBlockTest::writeCodeCompletedMessage() +QVariant ReadAndWriteMessageBlock::writeCodeCompletedMessage() { ClangBackEnd::CodeCompletedMessage message(ClangBackEnd::CodeCompletions({Utf8StringLiteral("newFunction()")}), 1); const QVariant writeMessage = QVariant::fromValue(message); @@ -190,19 +220,19 @@ QVariant ReadAndWriteMessageBlockTest::writeCodeCompletedMessage() return writeMessage; } -void ReadAndWriteMessageBlockTest::popLastCharacterFromBuffer() +void ReadAndWriteMessageBlock::popLastCharacterFromBuffer() { auto &internalBuffer = buffer.buffer(); lastCharacter = internalBuffer.at(internalBuffer.size() - 1); internalBuffer.chop(1); } -void ReadAndWriteMessageBlockTest::pushLastCharacterToBuffer() +void ReadAndWriteMessageBlock::pushLastCharacterToBuffer() { buffer.buffer().push_back(lastCharacter); } -void ReadAndWriteMessageBlockTest::readPartialMessage() +void ReadAndWriteMessageBlock::readPartialMessage() { QVariant readMessage = readMessageBlock.read(); @@ -210,7 +240,7 @@ void ReadAndWriteMessageBlockTest::readPartialMessage() } template -void ReadAndWriteMessageBlockTest::CompareMessage(const Type &message) +void ReadAndWriteMessageBlock::CompareMessage(const Type &message) { const QVariant writeMessage = QVariant::fromValue(message); writeMessageBlock.write(writeMessage); diff --git a/tests/unit/unittest/sourcelocationtest.cpp b/tests/unit/unittest/sourcelocationtest.cpp new file mode 100644 index 00000000000..73d747a748a --- /dev/null +++ b/tests/unit/unittest/sourcelocationtest.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +using ClangBackEnd::Diagnostic; +using ClangBackEnd::DiagnosticSet; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::SourceLocation; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::UnsavedFiles; +using testing::EndsWith; + +namespace { + +class SourceLocation : public ::testing::Test +{ +protected: + ProjectPart projectPart{Utf8StringLiteral("projectPartId")}; + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_location.cpp"), + unsavedFiles, + projectPart}; + DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; + Diagnostic diagnostic{diagnosticSet.front()}; + ::SourceLocation sourceLocation{diagnostic.location()}; + +}; + +TEST_F(SourceLocation, FilePath) +{ + ASSERT_THAT(sourceLocation.filePath().constData(), EndsWith("diagnostic_source_location.cpp")); +} + +TEST_F(SourceLocation, Line) +{ + ASSERT_THAT(sourceLocation.line(), 4); +} + +TEST_F(SourceLocation, Column) +{ + ASSERT_THAT(sourceLocation.column(), 1); +} + +TEST_F(SourceLocation, Offset) +{ + ASSERT_THAT(sourceLocation.offset(), 18); +} + +} diff --git a/tests/unit/unittest/sourcerangetest.cpp b/tests/unit/unittest/sourcerangetest.cpp new file mode 100644 index 00000000000..9d77e51d633 --- /dev/null +++ b/tests/unit/unittest/sourcerangetest.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://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 http://www.qt.io/terms-conditions. For further information +** use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "gtest-qt-printing.h" + +using ClangBackEnd::DiagnosticSet; +using ClangBackEnd::TranslationUnit; +using ClangBackEnd::ProjectPart; +using ClangBackEnd::UnsavedFiles; +using ClangBackEnd::Diagnostic; +using ClangBackEnd::SourceRange; +using testing::PrintToString; + +namespace { + +MATCHER_P4(IsSourceLocation, filePath, line, column, offset, + std::string(negation ? "isn't" : "is") + + " source location with file path "+ PrintToString(filePath) + + ", line " + PrintToString(line) + + ", column " + PrintToString(column) + + " and offset " + PrintToString(offset) + ) +{ + if (!arg.filePath().endsWith(filePath) + || arg.line() != line + || arg.column() != column + || arg.offset() != offset) { + return false; + } + + return true; +} + +class SourceRange : public ::testing::Test +{ +protected: + ProjectPart projectPart{Utf8StringLiteral("projectPartId"), {Utf8StringLiteral("-pedantic")}}; + UnsavedFiles unsavedFiles; + TranslationUnit translationUnit{Utf8StringLiteral(TESTDATA_DIR"/diagnostic_source_range.cpp"), + unsavedFiles, + projectPart}; + DiagnosticSet diagnosticSet{translationUnit.diagnostics()}; + Diagnostic diagnostic{diagnosticSet.front()}; + ::SourceRange sourceRange{diagnostic.ranges().front()}; +}; + +TEST_F(SourceRange, Size) +{ + ASSERT_THAT(diagnostic.ranges().size(), 2); +} + +TEST_F(SourceRange, Start) +{ + ASSERT_THAT(sourceRange.start(), IsSourceLocation(Utf8StringLiteral("diagnostic_source_range.cpp"), + 8u, + 5u, + 43u)); +} + +TEST_F(SourceRange, End) +{ + ASSERT_THAT(sourceRange.end(), IsSourceLocation(Utf8StringLiteral("diagnostic_source_range.cpp"), + 8u, + 6u, + 44u)); +} +} diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 4dc5c9e358a..baedfa5df5d 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -31,10 +31,15 @@ SOURCES += \ codecompletiontest.cpp \ completionchunkstotextconvertertest.cpp \ createtablesqlstatementbuildertest.cpp \ + diagnosticsettest.cpp \ + diagnostictest.cpp \ + fixittest.cpp \ lineprefixertest.cpp \ main.cpp \ projecttest.cpp \ readandwritemessageblocktest.cpp \ + sourcelocationtest.cpp \ + sourcerangetest.cpp \ spydummy.cpp \ sqlitecolumntest.cpp \ sqlitedatabasebackendtest.cpp \