diff --git a/dist/clangformat/README.md b/dist/clangformat/README.md index ae714aad9ee..05fd065c019 100644 --- a/dist/clangformat/README.md +++ b/dist/clangformat/README.md @@ -57,7 +57,8 @@ For Windows: 3. Set shortcuts for convenience: In Menu: Tools > Options > Environment > Keyboard * ClangFormat / FormatFile - e.g. Alt+C, F - * ClangFormat / FormatSelectedText - e.g. Alt+C, S + * ClangFormat / FormatAtCursor - e.g. Alt+C, C + * ClangFormat / DisableFormattingSelectedText - e.g. Alt+C, D Due to several issues outlined below the FormatFile action might be of limited use. diff --git a/doc/src/editors/creator-beautifier.qdoc b/doc/src/editors/creator-beautifier.qdoc index c47f9fb5121..52662b53c9c 100644 --- a/doc/src/editors/creator-beautifier.qdoc +++ b/doc/src/editors/creator-beautifier.qdoc @@ -174,7 +174,13 @@ \endlist In addition to the \uicontrol {Format Current File} command, ClangFormat - and Uncrustify provide the \uicontrol {Format Selected Text} command. If you + and Uncrustify provide additional commands. + ClangFormat provides the \uicontrol {Format at Cursor} command. If you + select it when no text is selected, the syntactic entity under the cursor + is formatted. The \uicontrol {Disable Formatting for Selected Text} command + wraps selected lines within \c {// clang-format off} and + \c {// clang-format on}. + Uncrustify provides the \uicontrol {Format Selected Text} command. If you select it when no text is selected, the whole file is formatted by default. To disable this behavior, deselect the \uicontrol {Format entire file if no text was selected} check box. diff --git a/scripts/deployqt.py b/scripts/deployqt.py index 8e7fa8ba47a..5559587f990 100755 --- a/scripts/deployqt.py +++ b/scripts/deployqt.py @@ -223,8 +223,6 @@ def deploy_libclang(install_dir, llvm_install_dir, chrpath_bin): os.path.join(install_dir, 'bin'))) deployinfo.append((os.path.join(llvm_install_dir, 'bin', 'clang.exe'), clangbindirtarget)) - deployinfo.append((os.path.join(llvm_install_dir, 'bin', 'clang-cl.exe'), - clangbindirtarget)) resourcetarget = os.path.join(clanglibdirtarget, 'clang') else: libsources = glob(os.path.join(llvm_install_dir, 'lib', 'libclang.so*')) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index be1678de459..181b7ac657f 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -1258,9 +1258,7 @@ class Dumper(DumperBase): if not skipEventReporting: self.eventState = state if state == lldb.eStateExited: - if self.isShuttingDown_: - self.reportState("inferiorshutdownok") - else: + if not self.isShuttingDown_: self.reportState("inferiorexited") self.report('exited={status="%s",desc="%s"}' % (self.process.GetExitStatus(), self.process.GetExitDescription())) @@ -1290,7 +1288,7 @@ class Dumper(DumperBase): return if self.isInterrupting_: self.isInterrupting_ = False - self.reportState("stopped") + self.reportState("inferiorstopok") elif self.ignoreStops > 0: self.ignoreStops -= 1 self.process.Continue() diff --git a/share/qtcreator/qml-type-descriptions/qbs.qmltypes b/share/qtcreator/qml-type-descriptions/qbs.qmltypes index 20d36bf5326..718baa6a04b 100644 --- a/share/qtcreator/qml-type-descriptions/qbs.qmltypes +++ b/share/qtcreator/qml-type-descriptions/qbs.qmltypes @@ -20,7 +20,7 @@ Module { prototype: "QQuickItem" Property { name: "condition"; type: "bool" } Property { name: "limitToSubProject"; type: "bool" } - Property { name: "multiplexConfigurationId"; type: "string" } + Property { name: "multiplexConfigurationIds"; type: "string"; isList: true } Property { name: "name"; type: "string" } Property { name: "productTypes"; type: "string"; isList: true } Property { name: "profiles"; type: "string"; isList: true } @@ -49,6 +49,7 @@ Module { Property { name: "condition"; type: "bool" } Property { name: "fileTags"; type: "string"; isList: true } Property { name: "patterns"; type: "string"; isList: true } + Property { name: "priority"; type: "int" } } Component { name: "Group" @@ -118,6 +119,14 @@ Module { Property { name: "type"; type: "string"; isList: true } Property { name: "version"; type: "string" } } + Component { + name: "Profile" + exports: [ "qbs/Profile 1.0" ] + prototype: "QQuickItem" + Property { name: "baseProfile"; type: "string" } + Property { name: "condition"; type: "bool" } + Property { name: "name"; type: "string" } + } Component { name: "Project" exports: [ "qbs/Project 1.0" ] diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp index 875c80d3781..fb1bad0603d 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.cpp @@ -157,7 +157,7 @@ void sortFilterImports(const QStringList &imports, QStringList *workingImports, namespace QmlDesigner { -static NodeInstanceServer *nodeInstanceServerInstance = 0; +static NodeInstanceServer *nodeInstanceServerInstance = nullptr; static void notifyPropertyChangeCallBackFunction(QObject *object, const PropertyName &propertyName) { @@ -170,11 +170,7 @@ static void (*notifyPropertyChangeCallBackPointer)(QObject *, const PropertyName NodeInstanceServer::NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) : NodeInstanceServerInterface(), m_childrenChangeEventFilter(new Internal::ChildrenChangeEventFilter(this)), - m_nodeInstanceClient(nodeInstanceClient), - m_timer(0), - m_renderTimerInterval(16), - m_slowRenderTimer(false), - m_slowRenderTimerInterval(200) + m_nodeInstanceClient(nodeInstanceClient) { qmlRegisterType("QmlDesigner", 1, 0, "DummyContextObject"); @@ -184,10 +180,6 @@ NodeInstanceServer::NodeInstanceServer(NodeInstanceClientInterface *nodeInstance Internal::QmlPrivateGate::registerFixResourcePathsForObjectCallBack(); } -NodeInstanceServer::~NodeInstanceServer() -{ -} - QList NodeInstanceServer::createInstances(const QVector &containerVector) { Q_ASSERT(declarativeView() || quickView()); @@ -247,7 +239,7 @@ ServerNodeInstance NodeInstanceServer::instanceForObject(QObject *object) const bool NodeInstanceServer::hasInstanceForObject(QObject *object) const { - if (object == 0) + if (object == nullptr) return false; return m_objectInstanceHash.contains(object) && m_objectInstanceHash.value(object).isValid(); @@ -671,7 +663,7 @@ QQmlContext *NodeInstanceServer::context() const if (engine()) return rootContext(); - return 0; + return nullptr; } QQmlContext *NodeInstanceServer::rootContext() const @@ -979,7 +971,7 @@ void NodeInstanceServer::setInstanceAuxiliaryData(const PropertyValueContainer & } } if (auxiliaryContainer.name().endsWith("@NodeInstance")) { - PropertyName propertyName = auxiliaryContainer.name().left(auxiliaryContainer.name().count() - 12); + PropertyName propertyName = auxiliaryContainer.name().left(auxiliaryContainer.name().count() - 13); if (!auxiliaryContainer.value().isNull()) { setInstancePropertyVariant(PropertyValueContainer(auxiliaryContainer.instanceId(), propertyName, diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h index c7a0e58b32f..c777c0a7a19 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/nodeinstanceserver.h @@ -71,7 +71,6 @@ public: typedef QPair > DummyPair; explicit NodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient); - ~NodeInstanceServer(); void createInstances(const CreateInstancesCommand &command); void changeFileUrl(const ChangeFileUrlCommand &command); @@ -214,10 +213,10 @@ private: QPointer m_childrenChangeEventFilter; QUrl m_fileUrl; NodeInstanceClientInterface *m_nodeInstanceClient; - int m_timer; - int m_renderTimerInterval; - bool m_slowRenderTimer; - int m_slowRenderTimerInterval; + int m_timer = 0; + int m_renderTimerInterval = 16; + bool m_slowRenderTimer = false; + int m_slowRenderTimerInterval = 200; QVector m_changedPropertyList; QByteArray m_importCode; QPointer m_dummyContextObject; diff --git a/src/libs/3rdparty/cplusplus/Lexer.cpp b/src/libs/3rdparty/cplusplus/Lexer.cpp index e62c9412a4e..079ae0ca6e6 100644 --- a/src/libs/3rdparty/cplusplus/Lexer.cpp +++ b/src/libs/3rdparty/cplusplus/Lexer.cpp @@ -211,7 +211,7 @@ void Lexer::scan_helper(Token *tok) _state = 0; scanCppComment(originalKind); return; - } else if (isRawStringLiteral(s._tokenKind)) { + } else if (!control() && isRawStringLiteral(s._tokenKind)) { tok->f.kind = s._tokenKind; if (scanUntilRawStringLiteralEndSimple()) _state = 0; @@ -755,13 +755,17 @@ void Lexer::scanRawStringLiteral(Token *tok, unsigned char hint) yyinp(); } else if (_yychar == ')') { yyinp(); - if (delimLength == -1) - break; + if (delimLength == -1) { + tok->f.kind = T_ERROR; + return; + } closingDelimCandidate = _currentChar; } else { if (delimLength == -1) { - if (_yychar == '\\' || std::isspace(_yychar)) - break; + if (_yychar == '\\' || std::isspace(_yychar)) { + tok->f.kind = T_ERROR; + return; + } yyinp(); } else { if (!closingDelimCandidate) { @@ -804,7 +808,7 @@ void Lexer::scanRawStringLiteral(Token *tok, unsigned char hint) else tok->f.kind = T_RAW_STRING_LITERAL; - if (!closed) + if (!control() && !closed) s._tokenKind = tok->f.kind; } diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index f7bd2674aec..6c7d00b7d87 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -175,6 +175,7 @@ HEADERS += \ $$PWD/requestsourcerangesforquerymessage.h \ $$PWD/stringcachefwd.h \ $$PWD/stringcachealgorithms.h \ - $$PWD/projectmanagementserverinterface.h + $$PWD/projectmanagementserverinterface.h \ + $$PWD/refactoringdatabaseinitializer.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangsupport/followsymbolmessage.cpp b/src/libs/clangsupport/followsymbolmessage.cpp index 929199bef5b..cafd22aa4bc 100644 --- a/src/libs/clangsupport/followsymbolmessage.cpp +++ b/src/libs/clangsupport/followsymbolmessage.cpp @@ -36,8 +36,7 @@ QDebug operator<<(QDebug debug, const FollowSymbolMessage &message) debug.nospace() << "FollowSymbolMessage(" << message.m_fileContainer << ", " << message.m_ticketNumber - << ", " << message.m_sourceRange - << ", " << message.m_failedToFollow; + << ", " << message.m_sourceRange; debug.nospace() << ")"; @@ -50,7 +49,6 @@ std::ostream &operator<<(std::ostream &os, const FollowSymbolMessage &message) << message.m_fileContainer << ", " << message.m_ticketNumber << ", " << message.m_sourceRange << ", " - << message.m_failedToFollow << ", " << ")"; return os; diff --git a/src/libs/clangsupport/followsymbolmessage.h b/src/libs/clangsupport/followsymbolmessage.h index ad8f7348f39..3893a6e49c3 100644 --- a/src/libs/clangsupport/followsymbolmessage.h +++ b/src/libs/clangsupport/followsymbolmessage.h @@ -39,12 +39,10 @@ public: FollowSymbolMessage() = default; FollowSymbolMessage(const FileContainer &fileContainer, const SourceRangeContainer &range, - bool failedToFollow, quint64 ticketNumber) : m_fileContainer(fileContainer) , m_sourceRange(range) , m_ticketNumber(ticketNumber) - , m_failedToFollow(failedToFollow) { } const FileContainer &fileContainer() const @@ -57,11 +55,6 @@ public: return m_sourceRange; } - bool failedToFollow() const - { - return m_failedToFollow; - } - quint64 ticketNumber() const { return m_ticketNumber; @@ -72,7 +65,6 @@ public: out << message.m_fileContainer; out << message.m_sourceRange; out << message.m_ticketNumber; - out << message.m_failedToFollow; return out; } @@ -81,7 +73,6 @@ public: in >> message.m_fileContainer; in >> message.m_sourceRange; in >> message.m_ticketNumber; - in >> message.m_failedToFollow; return in; } @@ -89,8 +80,7 @@ public: { return first.m_ticketNumber == second.m_ticketNumber && first.m_fileContainer == second.m_fileContainer - && first.m_sourceRange == second.m_sourceRange - && first.m_failedToFollow == second.m_failedToFollow; + && first.m_sourceRange == second.m_sourceRange; } friend CMBIPC_EXPORT QDebug operator<<(QDebug debug, const FollowSymbolMessage &message); @@ -99,7 +89,6 @@ private: FileContainer m_fileContainer; SourceRangeContainer m_sourceRange; quint64 m_ticketNumber = 0; - bool m_failedToFollow = false; }; DECLARE_MESSAGE(FollowSymbolMessage); diff --git a/src/libs/clangsupport/highlightingmarkcontainer.cpp b/src/libs/clangsupport/highlightingmarkcontainer.cpp index ab679c8d890..ec460a14a6f 100644 --- a/src/libs/clangsupport/highlightingmarkcontainer.cpp +++ b/src/libs/clangsupport/highlightingmarkcontainer.cpp @@ -65,6 +65,8 @@ QDebug operator<<(QDebug debug, const HighlightingMarkContainer &container) << container.column() << ", " << container.length() << ", " << highlightingTypeToCStringLiteral(container.types().mainHighlightingType) << ", " + << container.isIdentifier() << ", " + << container.isIncludeDirectivePath() << ")"; return debug; @@ -94,7 +96,9 @@ std::ostream &operator<<(std::ostream &os, const HighlightingMarkContainer &cont << container.line() << ", " << container.column() << ", " << container.length() << ", " - << container.types() + << container.types() << ", " + << container.isIdentifier() << ", " + << container.isIncludeDirectivePath() << ")"; return os; diff --git a/src/libs/clangsupport/highlightingmarkcontainer.h b/src/libs/clangsupport/highlightingmarkcontainer.h index 0bc3ab0b555..8b6e585e501 100644 --- a/src/libs/clangsupport/highlightingmarkcontainer.h +++ b/src/libs/clangsupport/highlightingmarkcontainer.h @@ -44,11 +44,14 @@ class HighlightingMarkContainer { public: HighlightingMarkContainer() = default; - HighlightingMarkContainer(uint line, uint column, uint length, HighlightingTypes types) + HighlightingMarkContainer(uint line, uint column, uint length, HighlightingTypes types, + bool isIdentifier = false, bool isIncludeDirectivePath = false) : line_(line), column_(column), length_(length), - types_(types) + types_(types), + isIdentifier_(isIdentifier), + isIncludeDirectivePath_(isIncludeDirectivePath) { } @@ -80,12 +83,29 @@ public: return types_; } + bool isInvalid() const + { + return line_ == 0 && column_ == 0 && length_ == 0; + } + + bool isIdentifier() const + { + return isIdentifier_; + } + + bool isIncludeDirectivePath() const + { + return isIncludeDirectivePath_; + } + friend QDataStream &operator<<(QDataStream &out, const HighlightingMarkContainer &container) { out << container.line_; out << container.column_; out << container.length_; out << container.types_; + out << container.isIdentifier_; + out << container.isIncludeDirectivePath_; return out; } @@ -96,6 +116,8 @@ public: in >> container.column_; in >> container.length_; in >> container.types_; + in >> container.isIdentifier_; + in >> container.isIncludeDirectivePath_; return in; } @@ -105,7 +127,9 @@ public: return first.line_ == second.line_ && first.column_ == second.column_ && first.length_ == second.length_ - && first.types_ == second.types_; + && first.types_ == second.types_ + && first.isIdentifier_ == second.isIdentifier_ + && first.isIncludeDirectivePath_ == second.isIncludeDirectivePath_; } private: @@ -113,6 +137,8 @@ private: uint column_ = 0; uint length_ = 0; HighlightingTypes types_; + bool isIdentifier_ = false; + bool isIncludeDirectivePath_ = false; }; inline QDataStream &operator<<(QDataStream &out, HighlightingType highlightingType) diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h new file mode 100644 index 00000000000..29f41d621e9 --- /dev/null +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include +#include + +namespace ClangBackEnd { + +template +class RefactoringDatabaseInitializer +{ +public: + RefactoringDatabaseInitializer(DatabaseType &database) + : database(database) + { + Sqlite::ImmediateTransaction transaction{database}; + + createSymbolsTable(); + createLocationsTable(); + createSourcesTable(); + + transaction.commit(); + } + + void createSymbolsTable() + { + Sqlite::Table table; + table.setUseIfNotExists(true); + table.setName("symbols"); + table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text); + table.addColumn("symbolName", Sqlite::ColumnType::Text); + table.addIndex({usrColumn}); + + table.initialize(database); + } + + void createLocationsTable() + { + Sqlite::Table table; + table.setUseIfNotExists(true); + table.setName("locations"); + table.addColumn("symbolId", Sqlite::ColumnType::Integer); + table.addColumn("line", Sqlite::ColumnType::Integer); + table.addColumn("column", Sqlite::ColumnType::Integer); + const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); + table.addIndex({sourceIdColumn}); + + table.initialize(database); + } + + void createSourcesTable() + { + Sqlite::Table table; + table.setUseIfNotExists(true); + table.setName("sources"); + table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("sourcePath", Sqlite::ColumnType::Text); + + table.initialize(database); + } + +public: + DatabaseType &database; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/requestfollowsymbolmessage.cpp b/src/libs/clangsupport/requestfollowsymbolmessage.cpp index 9d31139840a..dcb0b5cd2ef 100644 --- a/src/libs/clangsupport/requestfollowsymbolmessage.cpp +++ b/src/libs/clangsupport/requestfollowsymbolmessage.cpp @@ -42,7 +42,6 @@ QDebug operator<<(QDebug debug, const RequestFollowSymbolMessage &message) debug.nospace() << message.m_ticketNumber << ", "; debug.nospace() << message.m_line << ", "; debug.nospace() << message.m_column << ", "; - debug.nospace() << message.m_resolveTarget << ", "; debug.nospace() << ")"; @@ -57,7 +56,6 @@ std::ostream &operator<<(std::ostream &os, const RequestFollowSymbolMessage &mes << message.m_ticketNumber << ", " << message.m_line << ", " << message.m_column << ", " - << message.m_resolveTarget << ", " << ")"; return os; diff --git a/src/libs/clangsupport/requestfollowsymbolmessage.h b/src/libs/clangsupport/requestfollowsymbolmessage.h index a9c37e101a5..1305abfba81 100644 --- a/src/libs/clangsupport/requestfollowsymbolmessage.h +++ b/src/libs/clangsupport/requestfollowsymbolmessage.h @@ -40,14 +40,12 @@ public: RequestFollowSymbolMessage(const FileContainer &fileContainer, const QVector &dependentFiles, quint32 line, - quint32 column, - bool resolveTarget = true) + quint32 column) : m_fileContainer(fileContainer) , m_ticketNumber(++ticketCounter) , m_line(line) , m_column(column) , m_dependentFiles(dependentFiles) - , m_resolveTarget(resolveTarget) { } @@ -71,11 +69,6 @@ public: return m_column; } - bool resolveTarget() const - { - return m_resolveTarget; - } - quint64 ticketNumber() const { return m_ticketNumber; @@ -88,7 +81,6 @@ public: out << message.m_ticketNumber; out << message.m_line; out << message.m_column; - out << message.m_resolveTarget; return out; } @@ -100,7 +92,6 @@ public: in >> message.m_ticketNumber; in >> message.m_line; in >> message.m_column; - in >> message.m_resolveTarget; return in; } @@ -112,7 +103,6 @@ public: && first.m_line == second.m_line && first.m_column == second.m_column && first.m_fileContainer == second.m_fileContainer - && first.m_resolveTarget == second.m_resolveTarget && first.m_dependentFiles == second.m_dependentFiles; } @@ -124,7 +114,6 @@ private: quint32 m_line = 0; quint32 m_column = 0; QVector m_dependentFiles; - bool m_resolveTarget = true; static CMBIPC_EXPORT quint64 ticketCounter; }; diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index ecdff0fbaee..aa265593c5a 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -108,16 +108,6 @@ OpenMode Database::openMode() const return m_openMode; } -int Database::changesCount() -{ - return m_databaseBackend.changesCount(); -} - -int Database::totalChangesCount() -{ - return m_databaseBackend.totalChangesCount(); -} - void Database::execute(Utils::SmallStringView sqlStatement) { m_databaseBackend.execute(sqlStatement); diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 8bbdbb7de2e..125bccaf24a 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -31,6 +31,7 @@ #include +#include #include namespace Sqlite { @@ -38,11 +39,13 @@ namespace Sqlite { class SQLITE_EXPORT Database { template - friend class SqliteAbstractTransaction; - friend class SqliteStatement; - friend class SqliteBackend; + friend class AbstractTransaction; + friend class Statement; + friend class Backend; public: + using MutexType = std::mutex; + Database(); Database(Utils::PathString &&databaseFilePath); @@ -70,21 +73,34 @@ public: void setOpenMode(OpenMode openMode); OpenMode openMode() const; - int changesCount(); - int totalChangesCount(); - void execute(Utils::SmallStringView sqlStatement); DatabaseBackend &backend(); + int64_t lastInsertedRowId() const + { + return m_databaseBackend.lastInsertedRowId(); + } + + int changesCount() + { + return m_databaseBackend.changesCount(); + } + + int totalChangesCount() + { + return m_databaseBackend.totalChangesCount(); + } + private: void initializeTables(); - + std::mutex &databaseMutex() { return m_databaseMutex; } private: + Utils::PathString m_databaseFilePath; DatabaseBackend m_databaseBackend; std::vector m_sqliteTables; - Utils::PathString m_databaseFilePath; + std::mutex m_databaseMutex; JournalMode m_journalMode = JournalMode::Wal; OpenMode m_openMode = OpenMode::ReadWrite; bool m_isOpen = false; diff --git a/src/libs/sqlite/sqlitedatabasebackend.cpp b/src/libs/sqlite/sqlitedatabasebackend.cpp index bef03ea9865..5c4fc95e732 100644 --- a/src/libs/sqlite/sqlitedatabasebackend.cpp +++ b/src/libs/sqlite/sqlitedatabasebackend.cpp @@ -31,6 +31,7 @@ #include "sqlitestatement.h" #include "sqlitewritestatement.h" +#include #include #include @@ -109,7 +110,7 @@ void DatabaseBackend::open(Utils::SmallStringView databaseFilePath, OpenMode mod cacheTextEncoding(); } -sqlite3 *DatabaseBackend::sqliteDatabaseHandle() +sqlite3 *DatabaseBackend::sqliteDatabaseHandle() const { checkDatabaseHandleIsNotNull(); return m_databaseHandle; @@ -156,16 +157,21 @@ Utils::SmallStringVector DatabaseBackend::columnNames(Utils::SmallStringView tab return statement.columnNames(); } -int DatabaseBackend::changesCount() +int DatabaseBackend::changesCount() const { return sqlite3_changes(sqliteDatabaseHandle()); } -int DatabaseBackend::totalChangesCount() +int DatabaseBackend::totalChangesCount() const { return sqlite3_total_changes(sqliteDatabaseHandle()); } +int64_t DatabaseBackend::lastInsertedRowId() const +{ + return sqlite3_last_insert_rowid(sqliteDatabaseHandle()); +} + void DatabaseBackend::execute(Utils::SmallStringView sqlStatement) { ReadWriteStatement statement(sqlStatement, m_database); @@ -230,24 +236,29 @@ void DatabaseBackend::cacheTextEncoding() void DatabaseBackend::checkForOpenDatabaseWhichCanBeClosed() { if (m_databaseHandle == nullptr) - throwException("SqliteDatabaseBackend::close: database is not open so it can not be closed."); + throw DatabaseIsAlreadyClosed("SqliteDatabaseBackend::close: database is not open so it can not be closed."); } void DatabaseBackend::checkDatabaseClosing(int resultCode) { switch (resultCode) { case SQLITE_OK: return; - default: throwException("SqliteDatabaseBackend::close: unknown error happens at closing!"); + case SQLITE_BUSY: throw DatabaseIsBusy("SqliteDatabaseBackend::close: database is busy because of e.g. unfinalized statements and will stay open!"); + default: throwUnknowError("SqliteDatabaseBackend::close: unknown error happens at closing!"); } } void DatabaseBackend::checkCanOpenDatabase(Utils::SmallStringView databaseFilePath) { if (databaseFilePath.isEmpty()) - throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", "database file path is empty!"); + throw DatabaseFilePathIsEmpty("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because the file path is empty!"); + + if (!QFileInfo::exists(QFileInfo(QString(databaseFilePath)).path())) + throw WrongFilePath("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because of wrong file path!", + Utils::SmallString(databaseFilePath)); if (databaseIsOpen()) - throw Exception("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened:", "database is already open!"); + throw DatabaseIsAlreadyOpen("SqliteDatabaseBackend::SqliteDatabaseBackend: database cannot be opened because it is already open!"); } void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode) @@ -262,16 +273,16 @@ void DatabaseBackend::checkDatabaseCouldBeOpened(int resultCode) } void DatabaseBackend::checkPragmaValue(Utils::SmallStringView databaseValue, - Utils::SmallStringView expectedValue) + Utils::SmallStringView expectedValue) { if (databaseValue != expectedValue) - throwException("SqliteDatabaseBackend::setPragmaValue: pragma value is not set!"); + throw PragmaValueNotSet("SqliteDatabaseBackend::setPragmaValue: pragma value is not set!"); } -void DatabaseBackend::checkDatabaseHandleIsNotNull() +void DatabaseBackend::checkDatabaseHandleIsNotNull() const { if (m_databaseHandle == nullptr) - throwException("SqliteDatabaseBackend: database is not open!"); + throwDatabaseIsNotOpen("SqliteDatabaseBackend: database is not open!"); } void DatabaseBackend::checkIfMultithreadingIsActivated(int resultCode) @@ -392,6 +403,16 @@ void DatabaseBackend::throwException(const char *whatHasHappens) const throw Exception(whatHasHappens); } +void DatabaseBackend::throwUnknowError(const char *whatHasHappens) const +{ + throw UnknowError(whatHasHappens); +} + +void DatabaseBackend::throwDatabaseIsNotOpen(const char *whatHasHappens) const +{ + throw DatabaseIsNotOpen(whatHasHappens); +} + template Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) { @@ -399,7 +420,7 @@ Type DatabaseBackend::toValue(Utils::SmallStringView sqlStatement) statement.next(); - return statement.value(0); + return statement.fetchValue(0); } } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitedatabasebackend.h b/src/libs/sqlite/sqlitedatabasebackend.h index 7e5b9aad02a..6ff56b11b22 100644 --- a/src/libs/sqlite/sqlitedatabasebackend.h +++ b/src/libs/sqlite/sqlitedatabasebackend.h @@ -58,7 +58,7 @@ public: void close(); void closeWithoutException(); - sqlite3* sqliteDatabaseHandle(); + sqlite3* sqliteDatabaseHandle() const; void setJournalMode(JournalMode journalMode); JournalMode journalMode(); @@ -68,8 +68,10 @@ public: Utils::SmallStringVector columnNames(Utils::SmallStringView tableName); - int changesCount(); - int totalChangesCount(); + int changesCount() const; + int totalChangesCount() const; + + int64_t lastInsertedRowId() const; void execute(Utils::SmallStringView sqlStatement); @@ -95,7 +97,7 @@ protected: void checkCanOpenDatabase(Utils::SmallStringView databaseFilePath); void checkDatabaseCouldBeOpened(int resultCode); void checkPragmaValue(Utils::SmallStringView databaseValue, Utils::SmallStringView expectedValue); - void checkDatabaseHandleIsNotNull(); + void checkDatabaseHandleIsNotNull() const; void checkIfMultithreadingIsActivated(int resultCode); void checkIfLoogingIsActivated(int resultCode); void checkMmapSizeIsSet(int resultCode); @@ -110,8 +112,9 @@ protected: Q_NORETURN static void throwExceptionStatic(const char *whatHasHappens); - Q_NORETURN void throwException(const char *whatHasHappens) const; - + [[noreturn]] void throwException(const char *whatHasHappens) const; + [[noreturn]] void throwUnknowError(const char *whatHasHappens) const; + [[noreturn]] void throwDatabaseIsNotOpen(const char *whatHasHappens) const; private: Database &m_database; diff --git a/src/libs/sqlite/sqliteexception.h b/src/libs/sqlite/sqliteexception.h index 3ce2c20e9b9..319141d2573 100644 --- a/src/libs/sqlite/sqliteexception.h +++ b/src/libs/sqlite/sqliteexception.h @@ -48,4 +48,211 @@ private: Utils::SmallString m_sqliteErrorMessage; }; +class StatementIsBusy : public Exception +{ +public: + StatementIsBusy(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) + { + } +}; + +class DatabaseIsBusy : public Exception +{ +public: + DatabaseIsBusy(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class StatementHasError : public Exception +{ +public: + StatementHasError(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) + { + } +}; + +class StatementIsMisused : public Exception +{ +public: + StatementIsMisused(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) + { + } +}; + +class ContraintPreventsModification : public Exception +{ +public: + ContraintPreventsModification(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) + { + } +}; + +class NoValuesToFetch : public Exception +{ +public: + NoValuesToFetch(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class InvalidColumnFetched : public Exception +{ +public: + InvalidColumnFetched(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class BindingIndexIsOutOfRange : public Exception +{ +public: + BindingIndexIsOutOfRange(const char *whatErrorHasHappen, + Utils::SmallString &&sqliteErrorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(sqliteErrorMessage)) + { + } +}; + +class WrongBingingName : public Exception +{ +public: + WrongBingingName(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class DatabaseIsNotOpen : public Exception +{ +public: + DatabaseIsNotOpen(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class DatabaseCannotBeOpened : public Exception +{ +public: + DatabaseCannotBeOpened(const char *whatErrorHasHappen, + Utils::SmallString &&errorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(errorMessage)) + { + } +}; + +class DatabaseFilePathIsEmpty : public DatabaseCannotBeOpened +{ +public: + DatabaseFilePathIsEmpty(const char *whatErrorHasHappen) + : DatabaseCannotBeOpened(whatErrorHasHappen) + { + } +}; + +class DatabaseIsAlreadyOpen : public DatabaseCannotBeOpened +{ +public: + DatabaseIsAlreadyOpen(const char *whatErrorHasHappen) + : DatabaseCannotBeOpened(whatErrorHasHappen) + { + } +}; + +class DatabaseCannotBeClosed : public Exception +{ +public: + DatabaseCannotBeClosed(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class DatabaseIsAlreadyClosed : public DatabaseCannotBeClosed +{ +public: + DatabaseIsAlreadyClosed(const char *whatErrorHasHappen) + : DatabaseCannotBeClosed(whatErrorHasHappen) + { + } +}; + +class WrongFilePath : public DatabaseCannotBeOpened +{ +public: + WrongFilePath(const char *whatErrorHasHappen, + Utils::SmallString &&errorMessage = Utils::SmallString()) + : DatabaseCannotBeOpened(whatErrorHasHappen, std::move(errorMessage)) + { + } +}; + +class PragmaValueNotSet : public Exception +{ +public: + PragmaValueNotSet(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class NotReadOnlySqlStatement : public Exception +{ +public: + NotReadOnlySqlStatement(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class NotWriteSqlStatement : public Exception +{ +public: + NotWriteSqlStatement(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class DeadLock : public Exception +{ +public: + DeadLock(const char *whatErrorHasHappen) + : Exception(whatErrorHasHappen) + { + } +}; + +class UnknowError : public Exception +{ +public: + UnknowError(const char *whatErrorHasHappen, + Utils::SmallString &&errorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(errorMessage)) + { + } +}; + +class BindingTooBig : public Exception +{ +public: + BindingTooBig(const char *whatErrorHasHappen, + Utils::SmallString &&errorMessage = Utils::SmallString()) + : Exception(whatErrorHasHappen, std::move(errorMessage)) + { + } +}; + } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadstatement.cpp b/src/libs/sqlite/sqlitereadstatement.cpp index ec9e59c4a37..9af95f1cffa 100644 --- a/src/libs/sqlite/sqlitereadstatement.cpp +++ b/src/libs/sqlite/sqlitereadstatement.cpp @@ -39,7 +39,7 @@ ReadStatement::ReadStatement(Utils::SmallStringView sqlStatement, void ReadStatement::checkIsReadOnlyStatement() { if (!isReadOnlyStatement()) - throwException("SqliteStatement::SqliteReadStatement: is not read only statement!"); + throw NotReadOnlySqlStatement("SqliteStatement::SqliteReadStatement: is not read only statement!"); } } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h index c20221c34f9..828d1f7c377 100644 --- a/src/libs/sqlite/sqlitereadstatement.h +++ b/src/libs/sqlite/sqlitereadstatement.h @@ -34,21 +34,8 @@ class SQLITE_EXPORT ReadStatement final : private Statement public: explicit ReadStatement(Utils::SmallStringView sqlStatement, Database &database); - using Statement::next; - using Statement::reset; using Statement::value; - using Statement::structValues; - using Statement::tupleValues; - using Statement::text; using Statement::values; - using Statement::columnCount; - using Statement::columnNames; - using Statement::bind; - using Statement::bindValues; - using Statement::bindNameValues; - using Statement::bindingIndexForName; - using Statement::setBindingColumnNames; - using Statement::bindingColumnNames; using Statement::toValue; using Statement::database; diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h index 4b982525e7f..8645a6eae8a 100644 --- a/src/libs/sqlite/sqlitereadwritestatement.h +++ b/src/libs/sqlite/sqlitereadwritestatement.h @@ -36,22 +36,9 @@ class SQLITE_EXPORT ReadWriteStatement final : private Statement public: ReadWriteStatement(Utils::SmallStringView sqlStatement, Database &database); - using Statement::next; using Statement::execute; - using Statement::reset; - using Statement::bind; - using Statement::bindValues; - using Statement::bindNameValues; - using Statement::bindingIndexForName; - using Statement::setBindingColumnNames; - using Statement::bindingColumnNames; using Statement::value; - using Statement::text; using Statement::values; - using Statement::structValues; - using Statement::tupleValues; - using Statement::columnCount; - using Statement::columnNames; using Statement::toValue; using Statement::database; using Statement::write; diff --git a/src/libs/sqlite/sqlitestatement.cpp b/src/libs/sqlite/sqlitestatement.cpp index 709822ef95e..0e70b5aaca6 100644 --- a/src/libs/sqlite/sqlitestatement.cpp +++ b/src/libs/sqlite/sqlitestatement.cpp @@ -95,19 +95,26 @@ private: void Statement::waitForUnlockNotify() const { UnlockNotification unlockNotification; - int resultCode = sqlite3_unlock_notify(sqliteDatabaseHandle(), UnlockNotification::unlockNotifyCallBack, &unlockNotification); + int resultCode = sqlite3_unlock_notify(sqliteDatabaseHandle(), + UnlockNotification::unlockNotifyCallBack, + &unlockNotification); - if (resultCode == SQLITE_OK) - unlockNotification.wait(); - else - throwException("SqliteStatement::waitForUnlockNotify: database is in a dead lock!"); + if (resultCode == SQLITE_LOCKED) + throw DeadLock("SqliteStatement::waitForUnlockNotify: database is in a dead lock!"); + + unlockNotification.wait(); } void Statement::reset() const { int resultCode = sqlite3_reset(m_compiledStatement.get()); - if (resultCode != SQLITE_OK) - throwException("SqliteStatement::reset: can't reset statement!"); + switch (resultCode) { + case SQLITE_OK: return; + case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!"); + case SQLITE_ERROR : throwStatementHasError("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!"); + case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::stepStatement: was called inappropriately!"); + case SQLITE_CONSTRAINT: throwConstraintPreventsModification("SqliteStatement::stepStatement: contraint prevent insert or update!"); + } m_isReadyToFetchValues = false; } @@ -159,30 +166,30 @@ Utils::SmallStringVector Statement::columnNames() const void Statement::bind(int index, int value) { - int resultCode = sqlite3_bind_int(m_compiledStatement.get(), index, value); - if (resultCode != SQLITE_OK) - throwException("SqliteStatement::bind: cant' bind 32 bit integer!"); + int resultCode = sqlite3_bind_int(m_compiledStatement.get(), index, value); + checkForBindingError(resultCode); } void Statement::bind(int index, long long value) { - int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value); - if (resultCode != SQLITE_OK) - throwException("SqliteStatement::bind: cant' bind 64 bit integer!"); + int resultCode = sqlite3_bind_int64(m_compiledStatement.get(), index, value); + checkForBindingError(resultCode); } void Statement::bind(int index, double value) { int resultCode = sqlite3_bind_double(m_compiledStatement.get(), index, value); - if (resultCode != SQLITE_OK) - throwException("SqliteStatement::bind: cant' bind double!"); + checkForBindingError(resultCode); } void Statement::bind(int index, Utils::SmallStringView text) { - int resultCode = sqlite3_bind_text(m_compiledStatement.get(), index, text.data(), int(text.size()), SQLITE_TRANSIENT); - if (resultCode != SQLITE_OK) - throwException("SqliteStatement::bind: cant' bind double!"); + int resultCode = sqlite3_bind_text(m_compiledStatement.get(), + index, + text.data(), + int(text.size()), + SQLITE_STATIC); + checkForBindingError(resultCode); } template @@ -250,13 +257,13 @@ bool Statement::checkForStepError(int resultCode) const switch (resultCode) { case SQLITE_ROW: return true; case SQLITE_DONE: return false; - case SQLITE_BUSY: throwException("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!"); - case SQLITE_ERROR : throwException("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!"); - case SQLITE_MISUSE: throwException("SqliteStatement::stepStatement: was called inappropriately!"); - case SQLITE_CONSTRAINT: throwException("SqliteStatement::stepStatement: contraint prevent insert or update!"); + case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::stepStatement: database engine was unable to acquire the database locks!"); + case SQLITE_ERROR : throwStatementHasError("SqliteStatement::stepStatement: run-time error (such as a constraint violation) has occurred!"); + case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::stepStatement: was called inappropriately!"); + case SQLITE_CONSTRAINT: throwConstraintPreventsModification("SqliteStatement::stepStatement: contraint prevent insert or update!"); } - throwException("SqliteStatement::stepStatement: unknown error has happened"); + throwUnknowError("SqliteStatement::stepStatement: unknown error has happened"); Q_UNREACHABLE(); } @@ -265,12 +272,24 @@ void Statement::checkForPrepareError(int resultCode) const { switch (resultCode) { case SQLITE_OK: return; - case SQLITE_BUSY: throwException("SqliteStatement::prepareStatement: database engine was unable to acquire the database locks!"); - case SQLITE_ERROR : throwException("SqliteStatement::prepareStatement: run-time error (such as a constraint violation) has occurred!"); - case SQLITE_MISUSE: throwException("SqliteStatement::prepareStatement: was called inappropriately!"); + case SQLITE_BUSY: throwStatementIsBusy("SqliteStatement::prepareStatement: database engine was unable to acquire the database locks!"); + case SQLITE_ERROR : throwStatementHasError("SqliteStatement::prepareStatement: run-time error (such as a constraint violation) has occurred!"); + case SQLITE_MISUSE: throwStatementIsMisused("SqliteStatement::prepareStatement: was called inappropriately!"); } - throwException("SqliteStatement::prepareStatement: unknown error has happened"); + throwUnknowError("SqliteStatement::prepareStatement: unknown error has happened"); +} + +void Statement::checkForBindingError(int resultCode) const +{ + switch (resultCode) { + case SQLITE_OK: return; + case SQLITE_TOOBIG: throwBingingTooBig("SqliteStatement::bind: string or blob are over size limits(SQLITE_LIMIT_LENGTH)!"); + case SQLITE_RANGE : throwBindingIndexIsOutOfRange("SqliteStatement::bind: binding index is out of range!"); + case SQLITE_NOMEM: throw std::bad_alloc(); + } + + throwUnknowError("SqliteStatement::bind: unknown error has happened"); } void Statement::setIfIsReadyToFetchValues(int resultCode) const @@ -285,33 +304,27 @@ void Statement::setIfIsReadyToFetchValues(int resultCode) const void Statement::checkIfIsReadyToFetchValues() const { if (!m_isReadyToFetchValues) - throwException("SqliteStatement::value: there are no values to fetch!"); + throwNoValuesToFetch("SqliteStatement::value: there are no values to fetch!"); } void Statement::checkColumnsAreValid(const std::vector &columns) const { for (int column : columns) { if (column < 0 || column >= m_columnCount) - throwException("SqliteStatement::values: column index out of bound!"); + throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!"); } } void Statement::checkColumnIsValid(int column) const { if (column < 0 || column >= m_columnCount) - throwException("SqliteStatement::values: column index out of bound!"); -} - -void Statement::checkBindingIndex(int index) const -{ - if (index <= 0 || index > m_bindingParameterCount) - throwException("SqliteStatement::bind: binding index is out of bound!"); + throwInvalidColumnFetched("SqliteStatement::values: column index out of bound!"); } void Statement::checkBindingName(int index) const { if (index <= 0 || index > m_bindingParameterCount) - throwException("SqliteStatement::bind: binding name are not exists in this statement!"); + throwWrongBingingName("SqliteStatement::bind: binding name are not exists in this statement!"); } void Statement::setBindingParameterCount() @@ -345,9 +358,57 @@ bool Statement::isReadOnlyStatement() const return sqlite3_stmt_readonly(m_compiledStatement.get()); } -void Statement::throwException(const char *whatHasHappened) const +void Statement::throwStatementIsBusy(const char *whatHasHappened) const { - throw Exception(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); + throw StatementIsBusy(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); +} + +void Statement::throwStatementHasError(const char *whatHasHappened) const +{ + throw StatementHasError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); +} + +void Statement::throwStatementIsMisused(const char *whatHasHappened) const +{ + throw StatementIsMisused(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); +} + +void Statement::throwConstraintPreventsModification(const char *whatHasHappened) const +{ + throw ContraintPreventsModification(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); +} + +void Statement::throwNoValuesToFetch(const char *whatHasHappened) const +{ + throw NoValuesToFetch(whatHasHappened); +} + +void Statement::throwInvalidColumnFetched(const char *whatHasHappened) const +{ + throw InvalidColumnFetched(whatHasHappened); +} + +void Statement::throwBindingIndexIsOutOfRange(const char *whatHasHappened) const +{ + throw BindingIndexIsOutOfRange(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); +} + +void Statement::throwWrongBingingName(const char *whatHasHappened) const +{ + throw WrongBingingName(whatHasHappened); +} + +void Statement::throwUnknowError(const char *whatHasHappened) const +{ + if (sqliteDatabaseHandle()) + throw UnknowError(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); + else + throw UnknowError(whatHasHappened); +} + +void Statement::throwBingingTooBig(const char *whatHasHappened) const +{ + throw BindingTooBig(whatHasHappened, sqlite3_errmsg(sqliteDatabaseHandle())); } QString Statement::columnName(int column) const @@ -384,8 +445,7 @@ static StringType convertToTextForColumn(sqlite3_stmt *sqlStatment, int column) Q_UNREACHABLE(); } -template<> -int Statement::value(int column) const +int Statement::fetchIntValue(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); @@ -393,13 +453,23 @@ int Statement::value(int column) const } template<> -long Statement::value(int column) const +int Statement::fetchValue(int column) const { - return long(value(column)); + return fetchIntValue(column); +} + +long Statement::fetchLongValue(int column) const +{ + return long(fetchValue(column)); } template<> -long long Statement::value(int column) const +long Statement::fetchValue(int column) const +{ + return fetchLongValue(column); +} + +long long Statement::fetchLongLongValue(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); @@ -407,27 +477,48 @@ long long Statement::value(int column) const } template<> -double Statement::value(int column) const +long long Statement::fetchValue(int column) const +{ + return fetchLongLongValue(column); +} + +double Statement::fetchDoubleValue(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); return sqlite3_column_double(m_compiledStatement.get(), column); } +template<> +double Statement::fetchValue(int column) const +{ + return fetchDoubleValue(column); +} + template -StringType Statement::value(int column) const +StringType Statement::fetchValue(int column) const { checkIfIsReadyToFetchValues(); checkColumnIsValid(column); return convertToTextForColumn(m_compiledStatement.get(), column); } -template SQLITE_EXPORT Utils::SmallString Statement::value(int column) const; -template SQLITE_EXPORT Utils::PathString Statement::value(int column) const; +Utils::SmallString Statement::fetchSmallStringValue(int column) const +{ + return fetchValue(column); +} + +Utils::PathString Statement::fetchPathStringValue(int column) const +{ + return fetchValue(column); +} + +template SQLITE_EXPORT Utils::SmallString Statement::fetchValue(int column) const; +template SQLITE_EXPORT Utils::PathString Statement::fetchValue(int column) const; Utils::SmallString Statement::text(int column) const { - return value(column); + return fetchValue(column); } template @@ -437,7 +528,7 @@ ContainerType Statement::columnValues(const std::vector &columnIndices) con ContainerType valueContainer; valueContainer.reserve(columnIndices.size()); for (int columnIndex : columnIndices) - valueContainer.push_back(value(columnIndex)); + valueContainer.push_back(fetchValue(columnIndex)); return valueContainer; } @@ -449,7 +540,7 @@ Type Statement::toValue(Utils::SmallStringView sqlStatement, Database &database) statement.next(); - return statement.value(0); + return statement.fetchValue(0); } template SQLITE_EXPORT int Statement::toValue(Utils::SmallStringView sqlStatement, Database &database); diff --git a/src/libs/sqlite/sqlitestatement.h b/src/libs/sqlite/sqlitestatement.h index 0e73de836f8..3e93b7ba8d6 100644 --- a/src/libs/sqlite/sqlitestatement.h +++ b/src/libs/sqlite/sqlitestatement.h @@ -31,6 +31,8 @@ #include +#include + #include #include #include @@ -58,16 +60,22 @@ protected: void execute() const; void reset() const; + int fetchIntValue(int column) const; + long fetchLongValue(int column) const; + long long fetchLongLongValue(int column) const; + double fetchDoubleValue(int column) const; + Utils::SmallString fetchSmallStringValue(int column) const; + Utils::PathString fetchPathStringValue(int column) const; template - Type value(int column) const; + Type fetchValue(int column) const; Utils::SmallString text(int column) const; int columnCount() const; Utils::SmallStringVector columnNames() const; - void bind(int index, int value); - void bind(int index, long long value); - void bind(int index, double value); - void bind(int index, Utils::SmallStringView value); + void bind(int index, int fetchValue); + void bind(int index, long long fetchValue); + void bind(int index, double fetchValue); + void bind(int index, Utils::SmallStringView fetchValue); void bind(int index, uint value) { @@ -84,164 +92,86 @@ protected: } template - void bindValues(ValueType... values) + void bindValues(const ValueType&... values) { bindValuesByIndex(1, values...); } template - void write(ValueType... values) + void write(const ValueType&... values) { bindValuesByIndex(1, values...); execute(); } template - void bindNameValues(ValueType... values) + void bindNameValues(const ValueType&... values) { bindValuesByName(values...); } template - void writeNamed(ValueType... values) + void writeNamed(const ValueType&... values) { bindValuesByName(values...); execute(); } template - void bind(Utils::SmallStringView name, Type value); + void bind(Utils::SmallStringView name, Type fetchValue); int bindingIndexForName(Utils::SmallStringView name) const; void setBindingColumnNames(const Utils::SmallStringVector &bindingColumnNames); const Utils::SmallStringVector &bindingColumnNames() const; - template - std::vector> tupleValues(std::size_t reserveSize) + template + std::vector values(std::size_t reserveSize) { - using Container = std::vector>; - Container resultValues; + std::vector resultValues; resultValues.reserve(reserveSize); while (next()) - emplaceTupleValues(resultValues); + emplaceBackValues(resultValues); reset(); return resultValues; } - template - std::vector> tupleValues(std::size_t reserveSize, const QueryTypes&... queryValues) + std::vector values(std::size_t reserveSize, const QueryTypes&... queryValues) { - using Container = std::vector>; - Container resultValues; + std::vector resultValues; resultValues.reserve(reserveSize); bindValues(queryValues...); while (next()) - emplaceTupleValues(resultValues); + emplaceBackValues(resultValues); reset(); return resultValues; } - template - std::vector> tupleValues(std::size_t reserveSize, - const std::vector> &queryTuples) - { - using Container = std::vector>; - Container resultValues; - resultValues.reserve(reserveSize); - - for (const auto &queryTuple : queryTuples) { - bindTupleValues(queryTuple); - - while (next()) - emplaceTupleValues(resultValues); - - reset(); - } - - return resultValues; - } - - template - std::vector> tupleValues(std::size_t reserveSize, - const std::vector &queryValues) - { - using Container = std::vector>; - Container resultValues; - resultValues.reserve(reserveSize); - - for (const QueryElementType &queryValue : queryValues) { - bindValues(queryValue); - - while (next()) - emplaceTupleValues(resultValues); - - reset(); - } - - return resultValues; - } - - template - std::vector structValues(std::size_t reserveSize) - { - using Container = std::vector; - Container resultValues; - resultValues.reserve(reserveSize); - - while (next()) - pushBackStructValues(resultValues); - - reset(); - - return resultValues; - } - - template - std::vector structValues(std::size_t reserveSize, const QueryTypes&... queryValues) - { - using Container = std::vector; - Container resultValues; - resultValues.reserve(reserveSize); - - bindValues(queryValues...); - - while (next()) - pushBackStructValues(resultValues); - - reset(); - - return resultValues; - } - - template - std::vector structValues(std::size_t reserveSize, + std::vector values(std::size_t reserveSize, const std::vector &queryValues) { - using Container = std::vector; - Container resultValues; + std::vector resultValues; resultValues.reserve(reserveSize); for (const QueryElementType &queryValue : queryValues) { bindValues(queryValue); while (next()) - pushBackStructValues(resultValues); + emplaceBackValues(resultValues); reset(); } @@ -250,9 +180,9 @@ protected: } template - std::vector structValues(std::size_t reserveSize, + std::vector values(std::size_t reserveSize, const std::vector> &queryTuples) { using Container = std::vector; @@ -263,62 +193,7 @@ protected: bindTupleValues(queryTuple); while (next()) - pushBackStructValues(resultValues); - - reset(); - } - - return resultValues; - } - - template - std::vector values(std::size_t reserveSize) - { - std::vector resultValues; - resultValues.reserve(reserveSize); - - while (next()) - resultValues.push_back(value(0)); - - reset(); - - return resultValues; - } - - template - std::vector values(std::size_t reserveSize, - const std::vector> &queryTuples) - { - std::vector resultValues; - resultValues.reserve(reserveSize); - - for (const auto &queryTuple : queryTuples) { - bindTupleValues(queryTuple); - - while (next()) - resultValues.push_back(value(0)); - - reset(); - } - - return resultValues; - } - - template - std::vector values(std::size_t reserveSize, - const std::vector &queryValues) - { - std::vector resultValues; - resultValues.reserve(reserveSize); - - for (const ElementType &queryValue : queryValues) { - bindValues(queryValue); - - while (next()) - resultValues.push_back(value(0)); + emplaceBackValues(resultValues); reset(); } @@ -327,20 +202,20 @@ protected: } template - std::vector values(std::size_t reserveSize, const QueryTypes&... queryValues) + Utils::optional value( const QueryTypes&... queryValues) { - std::vector resultValues; - resultValues.reserve(reserveSize); + Utils::optional resultValue; bindValues(queryValues...); - while (next()) - resultValues.push_back(value(0)); + if (next()) + resultValue = assignValue, ResultTypeCount>(); reset(); - return resultValues; + return resultValue; } template @@ -352,20 +227,28 @@ protected: sqlite3 *sqliteDatabaseHandle() const; TextEncoding databaseTextEncoding(); - bool checkForStepError(int resultCode) const; void checkForPrepareError(int resultCode) const; + void checkForBindingError(int resultCode) const; void setIfIsReadyToFetchValues(int resultCode) const; void checkIfIsReadyToFetchValues() const; void checkColumnsAreValid(const std::vector &columns) const; void checkColumnIsValid(int column) const; - void checkBindingIndex(int index) const; void checkBindingName(int index) const; void setBindingParameterCount(); void setBindingColumnNamesFromStatement(); void setColumnCount(); bool isReadOnlyStatement() const; - Q_NORETURN void throwException(const char *whatHasHappened) const; + [[noreturn]] void throwStatementIsBusy(const char *whatHasHappened) const; + [[noreturn]] void throwStatementHasError(const char *whatHasHappened) const; + [[noreturn]] void throwStatementIsMisused(const char *whatHasHappened) const; + [[noreturn]] void throwConstraintPreventsModification(const char *whatHasHappened) const; + [[noreturn]] void throwNoValuesToFetch(const char *whatHasHappened) const; + [[noreturn]] void throwInvalidColumnFetched(const char *whatHasHappened) const; + [[noreturn]] void throwBindingIndexIsOutOfRange(const char *whatHasHappened) const; + [[noreturn]] void throwWrongBingingName(const char *whatHasHappened) const; + [[noreturn]] void throwUnknowError(const char *whatHasHappened) const; + [[noreturn]] void throwBingingTooBig(const char *whatHasHappened) const; template ContainerType columnValues(const std::vector &columnIndices) const; @@ -379,58 +262,97 @@ protected: DatabaseBackend &databaseBackend); private: + class ValueGetter + { + public: + ValueGetter(Statement &statement, int column) + : statement(statement), + column(column) + {} + + operator int() + { + return statement.fetchIntValue(column); + } + + operator long() + { + return statement.fetchLongValue(column); + } + + operator long long() + { + return statement.fetchLongLongValue(column); + } + + operator double() + { + return statement.fetchDoubleValue(column); + } + + operator Utils::SmallString() + { + return statement.fetchSmallStringValue(column); + } + + operator Utils::PathString() + { + return statement.fetchPathStringValue(column); + } + + Statement &statement; + int column; + }; + template - void emplaceTupleValues(ContainerType &container, std::integer_sequence) + void emplaceBackValues(ContainerType &container, std::integer_sequence) { - container.emplace_back(value(ColumnIndices)...); + container.emplace_back(ValueGetter(*this, ColumnIndices)...); } - template - void emplaceTupleValues(ContainerType &container) + template + void emplaceBackValues(ContainerType &container) { - emplaceTupleValues(container, std::make_integer_sequence{}); + emplaceBackValues(container, std::make_integer_sequence{}); } - template - void pushBackStructValues(ContainerType &container, std::integer_sequence) + ResultOptionalType assignValue(std::integer_sequence) { - using ResultType = typename ContainerType::value_type; - container.push_back(ResultType{value(ColumnIndices)...}); + return ResultOptionalType(Utils::in_place, ValueGetter(*this, ColumnIndices)...); } - template - void pushBackStructValues(ContainerType &container) + template + ResultOptionalType assignValue() { - pushBackStructValues(container, std::make_integer_sequence{}); + return assignValue(std::make_integer_sequence{}); } template - void bindValuesByIndex(int index, ValueType value) + void bindValuesByIndex(int index, const ValueType &value) { bind(index, value); } template - void bindValuesByIndex(int index, ValueType value, ValueTypes... values) + void bindValuesByIndex(int index, const ValueType &value, const ValueTypes&... values) { bind(index, value); bindValuesByIndex(index + 1, values...); } template - void bindValuesByName(Utils::SmallStringView name, ValueType value) + void bindValuesByName(Utils::SmallStringView name, const ValueType &value) { bind(bindingIndexForName(name), value); } template - void bindValuesByName(Utils::SmallStringView name, ValueType value, ValueTypes... values) + void bindValuesByName(Utils::SmallStringView name, const ValueType &value, const ValueTypes&... values) { bind(bindingIndexForName(name), value); bindValuesByName(values...); @@ -469,10 +391,10 @@ extern template SQLITE_EXPORT long long Statement::toValue(Utils::Sma extern template SQLITE_EXPORT double Statement::toValue(Utils::SmallStringView sqlStatement, Database &database); extern template SQLITE_EXPORT Utils::SmallString Statement::toValue(Utils::SmallStringView sqlStatement, Database &database); -template <> SQLITE_EXPORT int Statement::value(int column) const; -template <> SQLITE_EXPORT long Statement::value(int column) const; -template <> SQLITE_EXPORT long long Statement::value(int column) const; -template <> SQLITE_EXPORT double Statement::value(int column) const; -extern template SQLITE_EXPORT Utils::SmallString Statement::value(int column) const; -extern template SQLITE_EXPORT Utils::PathString Statement::value(int column) const; +template <> SQLITE_EXPORT int Statement::fetchValue(int column) const; +template <> SQLITE_EXPORT long Statement::fetchValue(int column) const; +template <> SQLITE_EXPORT long long Statement::fetchValue(int column) const; +template <> SQLITE_EXPORT double Statement::fetchValue(int column) const; +extern template SQLITE_EXPORT Utils::SmallString Statement::fetchValue(int column) const; +extern template SQLITE_EXPORT Utils::PathString Statement::fetchValue(int column) const; } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetransaction.h b/src/libs/sqlite/sqlitetransaction.h index 183923cfa60..d271728baea 100644 --- a/src/libs/sqlite/sqlitetransaction.h +++ b/src/libs/sqlite/sqlitetransaction.h @@ -27,6 +27,8 @@ #include "sqliteglobal.h" +#include + namespace Sqlite { class DatabaseBackend; @@ -50,11 +52,13 @@ public: protected: AbstractTransaction(Database &database) - : m_database(database) + : m_databaseLock(database.databaseMutex()), + m_database(database) { } private: + std::lock_guard m_databaseLock; Database &m_database; bool m_isAlreadyCommited = false; }; diff --git a/src/libs/sqlite/sqlitewritestatement.cpp b/src/libs/sqlite/sqlitewritestatement.cpp index 7878a284d37..26c8522b8a5 100644 --- a/src/libs/sqlite/sqlitewritestatement.cpp +++ b/src/libs/sqlite/sqlitewritestatement.cpp @@ -37,7 +37,7 @@ WriteStatement::WriteStatement(Utils::SmallStringView sqlStatement, void WriteStatement::checkIsWritableStatement() { if (isReadOnlyStatement()) - throwException("SqliteStatement::SqliteWriteStatement: is not a writable statement!"); + throw NotWriteSqlStatement("SqliteStatement::SqliteWriteStatement: is not a writable statement!"); } } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitewritestatement.h b/src/libs/sqlite/sqlitewritestatement.h index c673bbae201..ec00ae4e8f1 100644 --- a/src/libs/sqlite/sqlitewritestatement.h +++ b/src/libs/sqlite/sqlitewritestatement.h @@ -35,13 +35,6 @@ public: explicit WriteStatement(Utils::SmallStringView sqlStatement, Database &database); using Statement::execute; - using Statement::reset; - using Statement::bind; - using Statement::bindValues; - using Statement::bindNameValues; - using Statement::bindingIndexForName; - using Statement::setBindingColumnNames; - using Statement::bindingColumnNames; using Statement::database; using Statement::write; using Statement::writeNamed; diff --git a/src/libs/utils/camelhumpmatcher.cpp b/src/libs/utils/camelhumpmatcher.cpp index 4ede263d0d4..0661499c7a3 100644 --- a/src/libs/utils/camelhumpmatcher.cpp +++ b/src/libs/utils/camelhumpmatcher.cpp @@ -72,6 +72,7 @@ QRegularExpression CamelHumpMatcher::createCamelHumpRegExp( const QLatin1String lowercaseWordFirst("(?<=\\b|[A-Z0-9_])"); const QLatin1String uppercaseWordContinuation("[a-z0-9_]*"); const QLatin1String lowercaseWordContinuation("(?:[a-zA-Z0-9]*_)?"); + const QLatin1String upperSnakeWordContinuation("[A-Z0-9]*_"); for (const QChar &c : pattern) { if (!c.isLetter()) { if (c == question) @@ -90,7 +91,9 @@ QRegularExpression CamelHumpMatcher::createCamelHumpRegExp( keyRegExp += '|' + lowercaseWordFirst + QRegularExpression::escape(c.toLower()) + ')'; } else { keyRegExp += ")|" + lowercaseWordContinuation; - keyRegExp += '(' + QRegularExpression::escape(c.toLower()) + ')'; + keyRegExp += '(' + QRegularExpression::escape(c.toLower()) + ")|"; + keyRegExp += upperSnakeWordContinuation; + keyRegExp += '(' + QRegularExpression::escape(c.toUpper()) + ')'; } keyRegExp += ')'; } else { diff --git a/src/libs/utils/optional.h b/src/libs/utils/optional.h index 1960297de43..e4f943259f7 100644 --- a/src/libs/utils/optional.h +++ b/src/libs/utils/optional.h @@ -41,6 +41,8 @@ namespace Utils { using std::experimental::optional; // --> Utils::nullopt using std::experimental::nullopt; +// --> Utils::in_place +using std::experimental::in_place; // TODO: make_optional is a copy, since there is no sensible way to import functions in C++ template diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index 3a86d2435ce..5b30662592c 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -322,22 +322,22 @@ public: reverse_iterator rbegin() noexcept { - return reverse_iterator(end() - static_cast(1)); + return reverse_iterator(end()); } reverse_iterator rend() noexcept { - return reverse_iterator(begin() - static_cast(1)); + return reverse_iterator(begin()); } const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end() - static_cast(1)); + return const_reverse_iterator(end()); } const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin() - static_cast(1)); + return const_reverse_iterator(begin()); } const_iterator begin() const noexcept diff --git a/src/libs/utils/smallstringliteral.h b/src/libs/utils/smallstringliteral.h index 9ed2ce91145..eedcf45d139 100644 --- a/src/libs/utils/smallstringliteral.h +++ b/src/libs/utils/smallstringliteral.h @@ -80,12 +80,12 @@ public: const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end() - static_cast(1)); + return const_reverse_iterator(end()); } const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin() - static_cast(1)); + return const_reverse_iterator(begin()); } constexpr static diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h index e2c3f7ea92d..3d479195f17 100644 --- a/src/libs/utils/smallstringview.h +++ b/src/libs/utils/smallstringview.h @@ -97,6 +97,12 @@ public: return m_size == 0; } + constexpr + size_type empty() const noexcept + { + return m_size == 0; + } + constexpr const_iterator begin() const noexcept { @@ -111,12 +117,12 @@ public: const_reverse_iterator rbegin() const noexcept { - return const_reverse_iterator(end() - static_cast(1)); + return const_reverse_iterator(end()); } const_reverse_iterator rend() const noexcept { - return const_reverse_iterator(begin() - static_cast(1)); + return const_reverse_iterator(begin()); } operator std::string() const diff --git a/src/libs/utils/stylehelper.cpp b/src/libs/utils/stylehelper.cpp index fd270a5a860..b70ea7b07c4 100644 --- a/src/libs/utils/stylehelper.cpp +++ b/src/libs/utils/stylehelper.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include // Clamps float color values within (0, 255) @@ -397,7 +398,9 @@ void StyleHelper::drawIconWithShadow(const QIcon &icon, const QRect &rect, QPainter *p, QIcon::Mode iconMode, int dipRadius, const QColor &color, const QPoint &dipOffset) { QPixmap cache; - QString pixmapName = QString::fromLatin1("icon %0 %1 %2").arg(icon.cacheKey()).arg(iconMode).arg(rect.height()); + const int devicePixelRatio = p->device()->devicePixelRatio(); + QString pixmapName = QString::fromLatin1("icon %0 %1 %2 %3") + .arg(icon.cacheKey()).arg(iconMode).arg(rect.height()).arg(devicePixelRatio); if (!QPixmapCache::find(pixmapName, cache)) { // High-dpi support: The in parameters (rect, radius, offset) are in @@ -405,9 +408,8 @@ void StyleHelper::drawIconWithShadow(const QIcon &icon, const QRect &rect, // return a high-dpi pixmap, which will in that case have a devicePixelRatio // different than 1. The shadow drawing caluculations are done in device // pixels. - QWindow *window = QApplication::allWidgets().first()->windowHandle(); + QWindow *window = dynamic_cast(p->device())->window()->windowHandle(); QPixmap px = icon.pixmap(window, rect.size(), iconMode); - int devicePixelRatio = qCeil(px.devicePixelRatio()); int radius = dipRadius * devicePixelRatio; QPoint offset = dipOffset * devicePixelRatio; cache = QPixmap(px.size() + QSize(radius * 2, radius * 2)); @@ -415,7 +417,8 @@ void StyleHelper::drawIconWithShadow(const QIcon &icon, const QRect &rect, QPainter cachePainter(&cache); if (iconMode == QIcon::Disabled) { - const bool hasDisabledState = icon.availableSizes(QIcon::Disabled).contains(px.size()); + const bool hasDisabledState = + icon.availableSizes().count() == icon.availableSizes(QIcon::Disabled).count(); if (!hasDisabledState) px = disabledSideBarIcon(icon.pixmap(window, rect.size())); } else if (creatorTheme()->flag(Theme::ToolBarIconShadow)) { diff --git a/src/plugins/texteditor/convenience.cpp b/src/libs/utils/textutils.cpp similarity index 97% rename from src/plugins/texteditor/convenience.cpp rename to src/libs/utils/textutils.cpp index f18511d518e..65b7093c5a6 100644 --- a/src/plugins/texteditor/convenience.cpp +++ b/src/libs/utils/textutils.cpp @@ -23,14 +23,14 @@ ** ****************************************************************************/ -#include "convenience.h" +#include "textutils.h" #include #include #include -namespace TextEditor { -namespace Convenience { +namespace Utils { +namespace Text { bool convertPosition(const QTextDocument *document, int pos, int *line, int *column) { @@ -121,5 +121,5 @@ QTextCursor wordStartCursor(const QTextCursor &textCursor) return cursor; } -} // Util -} // TextEditor +} // Text +} // Utils diff --git a/src/plugins/texteditor/convenience.h b/src/libs/utils/textutils.h similarity index 64% rename from src/plugins/texteditor/convenience.h rename to src/libs/utils/textutils.h index f4302cd5f31..9e818842711 100644 --- a/src/plugins/texteditor/convenience.h +++ b/src/libs/utils/textutils.h @@ -25,30 +25,28 @@ #pragma once -#include "texteditor_global.h" +#include "utils_global.h" #include -QT_BEGIN_NAMESPACE -class QTextDocument; -class QTextCursor; -QT_END_NAMESPACE +QT_FORWARD_DECLARE_CLASS(QTextDocument) +QT_FORWARD_DECLARE_CLASS(QTextCursor) -namespace TextEditor { -namespace Convenience { +namespace Utils { +namespace Text { // line is 1-based, column is 0-based -TEXTEDITOR_EXPORT bool convertPosition(const QTextDocument *document, - int pos, - int *line, int *column); +QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document, + int pos, + int *line, int *column); -TEXTEDITOR_EXPORT QString textAt(QTextCursor tc, int pos, int length); +QTCREATOR_UTILS_EXPORT QString textAt(QTextCursor tc, int pos, int length); -TEXTEDITOR_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint column, uint length); +QTCREATOR_UTILS_EXPORT QTextCursor selectAt(QTextCursor textCursor, uint line, uint column, uint length); -TEXTEDITOR_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); +QTCREATOR_UTILS_EXPORT QTextCursor flippedCursor(const QTextCursor &cursor); -TEXTEDITOR_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor); +QTCREATOR_UTILS_EXPORT QTextCursor wordStartCursor(const QTextCursor &cursor); -} // Util -} // TextEditor +} // Text +} // Utils diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index c6d30f4712b..c181a8e25ae 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -115,7 +115,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/utilsicons.cpp \ $$PWD/guard.cpp \ $$PWD/highlightingitemdelegate.cpp \ - $$PWD/camelhumpmatcher.cpp + $$PWD/camelhumpmatcher.cpp \ + $$PWD/textutils.cpp win32:SOURCES += $$PWD/consoleprocess_win.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp @@ -244,7 +245,8 @@ HEADERS += \ $$PWD/../3rdparty/optional/optional.hpp \ $$PWD/qtcfallthrough.h \ $$PWD/highlightingitemdelegate.h \ - $$PWD/camelhumpmatcher.h + $$PWD/camelhumpmatcher.h \ + $$PWD/textutils.h FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index c6e7f7c0395..56b1b31e608 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -232,6 +232,8 @@ Project { "textfieldcombobox.h", "textfileformat.cpp", "textfileformat.h", + "textutils.cpp", + "textutils.h", "treemodel.cpp", "treemodel.h", "treeviewcombobox.cpp", diff --git a/src/plugins/android/androidrunner.cpp b/src/plugins/android/androidrunner.cpp index eb676d9bc8d..5eaaaf5241d 100644 --- a/src/plugins/android/androidrunner.cpp +++ b/src/plugins/android/androidrunner.cpp @@ -293,6 +293,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunControl *runControl, const AndroidRu QTC_ASSERT(server.listen(QHostAddress::LocalHost) || server.listen(QHostAddress::LocalHostIPv6), qDebug() << tr("No free ports available on host for QML debugging.")); + m_qmlServer.setScheme(urlTcpScheme()); m_qmlServer.setHost(server.serverAddress().toString()); m_qmlServer.setPort(server.serverPort()); } diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index bb3b10ee92b..3d89d3018d3 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -213,7 +213,7 @@ QString AndroidToolChain::makeCommand(const Environment &env) const if (HostOsInfo::isWindowsHost()) { FileName tmp = env.searchInPath(QLatin1String("ma-make.exe"), extraDirectories); if (!tmp.isEmpty()) - return QString(); + return tmp.toString(); tmp = env.searchInPath(QLatin1String("mingw32-make"), extraDirectories); return tmp.isEmpty() ? QLatin1String("mingw32-make") : tmp.toString(); } diff --git a/src/plugins/android/images/androiddevice.png b/src/plugins/android/images/androiddevice.png index f72af6020b1..fd68e6aa3aa 100644 Binary files a/src/plugins/android/images/androiddevice.png and b/src/plugins/android/images/androiddevice.png differ diff --git a/src/plugins/android/images/androiddevice@2x.png b/src/plugins/android/images/androiddevice@2x.png index 1a2116ba3e7..b76fa151776 100644 Binary files a/src/plugins/android/images/androiddevice@2x.png and b/src/plugins/android/images/androiddevice@2x.png differ diff --git a/src/plugins/baremetal/images/baremetaldevice.png b/src/plugins/baremetal/images/baremetaldevice.png index 34ac48c118a..cc7f96a7fdb 100644 Binary files a/src/plugins/baremetal/images/baremetaldevice.png and b/src/plugins/baremetal/images/baremetaldevice.png differ diff --git a/src/plugins/baremetal/images/baremetaldevice@2x.png b/src/plugins/baremetal/images/baremetaldevice@2x.png index d1341f90ee6..f99932ab5e4 100644 Binary files a/src/plugins/baremetal/images/baremetaldevice@2x.png and b/src/plugins/baremetal/images/baremetaldevice@2x.png differ diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp index 0dcfbf7c0ef..ec0065ed954 100644 --- a/src/plugins/beautifier/beautifierplugin.cpp +++ b/src/plugins/beautifier/beautifierplugin.cpp @@ -45,12 +45,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include #include @@ -169,7 +169,7 @@ QString sourceData(TextEditorWidget *editor, int startPos, int endPos) { return (startPos < 0) ? editor->toPlainText() - : Convenience::textAt(editor->textCursor(), startPos, (endPos - startPos)); + : Utils::Text::textAt(editor->textCursor(), startPos, (endPos - startPos)); } bool isAutoFormatApplicable(const Core::IDocument *document, @@ -496,6 +496,18 @@ QString BeautifierPlugin::msgFormatSelectedText() return tr("Format &Selected Text"); } +QString BeautifierPlugin::msgFormatAtCursor() +{ + //: Menu entry + return tr("&Format at Cursor"); +} + +QString BeautifierPlugin::msgDisableFormattingSelectedText() +{ + //: Menu entry + return tr("&Disable Formatting for Selected Text"); +} + QString BeautifierPlugin::msgCommandPromptDialogTitle(const QString &command) { //: File dialog title for path chooser when choosing binary diff --git a/src/plugins/beautifier/beautifierplugin.h b/src/plugins/beautifier/beautifierplugin.h index 14d6674ab8a..f298063f0ae 100644 --- a/src/plugins/beautifier/beautifierplugin.h +++ b/src/plugins/beautifier/beautifierplugin.h @@ -80,6 +80,8 @@ public: static QString msgCannotGetConfigurationFile(const QString &command); static QString msgFormatCurrentFile(); static QString msgFormatSelectedText(); + static QString msgFormatAtCursor(); + static QString msgDisableFormattingSelectedText(); static QString msgCommandPromptDialogTitle(const QString &command); static void showError(const QString &error); diff --git a/src/plugins/beautifier/clangformat/clangformat.cpp b/src/plugins/beautifier/clangformat/clangformat.cpp index 13f7caab24f..97298ffc39e 100644 --- a/src/plugins/beautifier/clangformat/clangformat.cpp +++ b/src/plugins/beautifier/clangformat/clangformat.cpp @@ -48,6 +48,7 @@ #include #include +#include namespace Beautifier { namespace Internal { @@ -82,11 +83,19 @@ bool ClangFormat::initialize() menu->addAction(cmd); connect(m_formatFile, &QAction::triggered, this, &ClangFormat::formatFile); - m_formatRange = new QAction(BeautifierPlugin::msgFormatSelectedText(), this); + m_formatRange = new QAction(BeautifierPlugin::msgFormatAtCursor(), this); cmd = Core::ActionManager::registerAction(m_formatRange, - Constants::ClangFormat::ACTION_FORMATSELECTED); + Constants::ClangFormat::ACTION_FORMATATCURSOR); menu->addAction(cmd); - connect(m_formatRange, &QAction::triggered, this, &ClangFormat::formatSelectedText); + connect(m_formatRange, &QAction::triggered, this, &ClangFormat::formatAtCursor); + + m_disableFormattingSelectedText + = new QAction(BeautifierPlugin::msgDisableFormattingSelectedText(), this); + cmd = Core::ActionManager::registerAction( + m_disableFormattingSelectedText, Constants::ClangFormat::ACTION_DISABLEFORMATTINGSELECTED); + menu->addAction(cmd); + connect(m_disableFormattingSelectedText, &QAction::triggered, + this, &ClangFormat::disableFormattingSelectedText); Core::ActionManager::actionContainer(Constants::MENU_ID)->addMenu(menu); @@ -113,7 +122,7 @@ void ClangFormat::formatFile() m_beautifierPlugin->formatCurrentFile(command()); } -void ClangFormat::formatSelectedText() +void ClangFormat::formatAtCursor() { const TextEditor::TextEditorWidget *widget = TextEditor::TextEditorWidget::currentTextEditorWidget(); @@ -125,11 +134,53 @@ void ClangFormat::formatSelectedText() const int offset = tc.selectionStart(); const int length = tc.selectionEnd() - offset; m_beautifierPlugin->formatCurrentFile(command(offset, length)); - } else if (m_settings->formatEntireFileFallback()) { - formatFile(); + } else { + // Pretend that the current line was selected. + // Note that clang-format will extend the range to the next bigger + // syntactic construct if needed. + const QTextBlock block = tc.block(); + const int offset = block.position(); + const int length = block.length(); + m_beautifierPlugin->formatCurrentFile(command(offset, length)); } } +void ClangFormat::disableFormattingSelectedText() +{ + TextEditor::TextEditorWidget *widget = TextEditor::TextEditorWidget::currentTextEditorWidget(); + if (!widget) + return; + + const QTextCursor tc = widget->textCursor(); + if (!tc.hasSelection()) + return; + + // Insert start marker + const QTextBlock selectionStartBlock = tc.document()->findBlock(tc.selectionStart()); + QTextCursor insertCursor(tc.document()); + insertCursor.beginEditBlock(); + insertCursor.setPosition(selectionStartBlock.position()); + insertCursor.insertText("// clang-format off\n"); + const int positionToRestore = tc.position(); + + // Insert end marker + QTextBlock selectionEndBlock = tc.document()->findBlock(tc.selectionEnd()); + insertCursor.setPosition(selectionEndBlock.position() + selectionEndBlock.length() - 1); + insertCursor.insertText("\n// clang-format on"); + insertCursor.endEditBlock(); + + // Reset the cursor position in order to clear the selection. + QTextCursor restoreCursor(tc.document()); + restoreCursor.setPosition(positionToRestore); + widget->setTextCursor(restoreCursor); + + // The indentation of these markers might be undesired, so reformat. + // This is not optimal because two undo steps will be needed to remove the markers. + const int reformatTextLength = insertCursor.position() - selectionStartBlock.position(); + m_beautifierPlugin->formatCurrentFile(command(selectionStartBlock.position(), + reformatTextLength)); +} + Command ClangFormat::command() const { Command command; diff --git a/src/plugins/beautifier/clangformat/clangformat.h b/src/plugins/beautifier/clangformat/clangformat.h index 86037fac0cc..34cccb5fbcc 100644 --- a/src/plugins/beautifier/clangformat/clangformat.h +++ b/src/plugins/beautifier/clangformat/clangformat.h @@ -54,10 +54,12 @@ public: private: void formatFile(); - void formatSelectedText(); + void formatAtCursor(); + void disableFormattingSelectedText(); BeautifierPlugin *m_beautifierPlugin; QAction *m_formatFile = nullptr; QAction *m_formatRange = nullptr; + QAction *m_disableFormattingSelectedText = nullptr; ClangFormatSettings *m_settings; Command command(int offset, int length) const; }; diff --git a/src/plugins/beautifier/clangformat/clangformatconstants.h b/src/plugins/beautifier/clangformat/clangformatconstants.h index 837d3323069..2c94b347a51 100644 --- a/src/plugins/beautifier/clangformat/clangformatconstants.h +++ b/src/plugins/beautifier/clangformat/clangformatconstants.h @@ -33,7 +33,8 @@ namespace ClangFormat { const char DISPLAY_NAME[] = QT_TRANSLATE_NOOP("Beautifier::Internal::ClangFormat::ClangFormat", "ClangFormat"); const char ACTION_FORMATFILE[] = "ClangFormat.FormatFile"; -const char ACTION_FORMATSELECTED[] = "ClangFormat.FormatSelectedText"; +const char ACTION_FORMATATCURSOR[] = "ClangFormat.FormatAtCursor"; +const char ACTION_DISABLEFORMATTINGSELECTED[] = "ClangFormat.DisableFormattingSelectedText"; const char MENU_ID[] = "ClangFormat.Menu"; const char OPTION_ID[] = "ClangFormat"; const char SETTINGS_NAME[] = "clangformat"; diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp index ddac14461f1..d9f881dc415 100644 --- a/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp +++ b/src/plugins/beautifier/clangformat/clangformatoptionspage.cpp @@ -78,7 +78,6 @@ void ClangFormatOptionsPageWidget::restore() const int fallbackStyleIndex = ui->fallbackStyle->findText(m_settings->fallbackStyle()); if (fallbackStyleIndex != -1) ui->fallbackStyle->setCurrentIndex(fallbackStyleIndex); - ui->formatEntireFileFallback->setChecked(m_settings->formatEntireFileFallback()); ui->configurations->setSettings(m_settings); ui->configurations->setCurrentConfiguration(m_settings->customStyle()); @@ -96,7 +95,6 @@ void ClangFormatOptionsPageWidget::apply() m_settings->setPredefinedStyle(ui->predefinedStyle->currentText()); m_settings->setFallbackStyle(ui->fallbackStyle->currentText()); m_settings->setCustomStyle(ui->configurations->currentConfiguration()); - m_settings->setFormatEntireFileFallback(ui->formatEntireFileFallback->isChecked()); m_settings->save(); // update since not all MIME types are accepted (invalids or duplicates) diff --git a/src/plugins/beautifier/clangformat/clangformatoptionspage.ui b/src/plugins/beautifier/clangformat/clangformatoptionspage.ui index c40b28c0417..7d060611b4b 100644 --- a/src/plugins/beautifier/clangformat/clangformatoptionspage.ui +++ b/src/plugins/beautifier/clangformat/clangformatoptionspage.ui @@ -20,6 +20,19 @@ Options + + + + Use customized style: + + + true + + + + + + @@ -62,29 +75,6 @@ - - - - Use customized style: - - - true - - - - - - - - - - For action Format Selected Text. - - - Format entire file if no text was selected - - - diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.cpp b/src/plugins/beautifier/clangformat/clangformatsettings.cpp index f4c2189181b..6369c60510f 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.cpp +++ b/src/plugins/beautifier/clangformat/clangformatsettings.cpp @@ -43,7 +43,6 @@ const char USE_PREDEFINED_STYLE[] = "usePredefinedStyle"; const char PREDEFINED_STYLE[] = "predefinedStyle"; const char FALLBACK_STYLE[] = "fallbackStyle"; const char CUSTOM_STYLE[] = "customStyle"; -const char FORMAT_ENTIRE_FILE_FALLBACK[] = "formatEntireFileFallback"; } ClangFormatSettings::ClangFormatSettings() : @@ -54,7 +53,6 @@ ClangFormatSettings::ClangFormatSettings() : m_settings.insert(PREDEFINED_STYLE, "LLVM"); m_settings.insert(FALLBACK_STYLE, "Default"); m_settings.insert(CUSTOM_STYLE, QVariant()); - m_settings.insert(FORMAT_ENTIRE_FILE_FALLBACK, QVariant(true)); read(); } @@ -215,16 +213,6 @@ void ClangFormatSettings::setCustomStyle(const QString &customStyle) m_settings.insert(CUSTOM_STYLE, QVariant(customStyle)); } -bool ClangFormatSettings::formatEntireFileFallback() const -{ - return m_settings.value(FORMAT_ENTIRE_FILE_FALLBACK).toBool(); -} - -void ClangFormatSettings::setFormatEntireFileFallback(bool formatEntireFileFallback) -{ - m_settings.insert(FORMAT_ENTIRE_FILE_FALLBACK, QVariant(formatEntireFileFallback)); -} - QStringList ClangFormatSettings::predefinedStyles() const { return {"LLVM", "Google", "Chromium", "Mozilla", "WebKit", "File"}; diff --git a/src/plugins/beautifier/clangformat/clangformatsettings.h b/src/plugins/beautifier/clangformat/clangformatsettings.h index b8a62be6bdc..4fca7ddc248 100644 --- a/src/plugins/beautifier/clangformat/clangformatsettings.h +++ b/src/plugins/beautifier/clangformat/clangformatsettings.h @@ -54,9 +54,6 @@ public: QString customStyle() const; void setCustomStyle(const QString &customStyle); - bool formatEntireFileFallback() const; - void setFormatEntireFileFallback(bool formatEntireFileFallback); - QStringList predefinedStyles() const; QStringList fallbackStyles() const; diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp index 065ea0fe4b3..ff1cf8f0750 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.cpp +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.cpp @@ -275,7 +275,6 @@ CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message) result.endLine = static_cast(end.line()); result.endColumn = static_cast(end.column()); result.fileName = start.filePath(); - result.failedToFollow = message.failedToFollow(); return result; } @@ -748,14 +747,12 @@ QFuture IpcCommunicator::requestFollowSymbol( const FileContainer &curFileContainer, const QVector &dependentFiles, quint32 line, - quint32 column, - bool resolveTarget) + quint32 column) { const RequestFollowSymbolMessage message(curFileContainer, dependentFiles, line, - column, - resolveTarget); + column); m_ipcSender->requestFollowSymbol(message); return m_ipcReceiver.addExpectedRequestFollowSymbolMessage(message.ticketNumber()); diff --git a/src/plugins/clangcodemodel/clangbackendipcintegration.h b/src/plugins/clangcodemodel/clangbackendipcintegration.h index 94be668114e..63c9d768017 100644 --- a/src/plugins/clangcodemodel/clangbackendipcintegration.h +++ b/src/plugins/clangcodemodel/clangbackendipcintegration.h @@ -169,8 +169,7 @@ public: QFuture requestFollowSymbol(const FileContainer &curFileContainer, const QVector &dependentFiles, quint32 line, - quint32 column, - bool resolveTarget); + quint32 column); void completeCode(ClangCompletionAssistProcessor *assistProcessor, const QString &filePath, quint32 line, quint32 column, diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index 13d8f5531d8..e60ac37ec6c 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #include #include @@ -52,6 +51,7 @@ #include #include +#include #include #include @@ -556,10 +556,7 @@ ClangCompletionAssistProcessor::extractLineColumn(int position) return {-1, -1}; int line = -1, column = -1; - TextEditor::Convenience::convertPosition(m_interface->textDocument(), - position, - &line, - &column); + ::Utils::Text::convertPosition(m_interface->textDocument(), position, &line, &column); const QTextBlock block = m_interface->textDocument()->findBlock(position); column += ClangCodeModel::Utils::extraUtf8CharsShift(block.text(), column) + 1; return {line, column}; diff --git a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp index 1dd003c7c11..eb43f6556ee 100644 --- a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp +++ b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp @@ -33,11 +33,11 @@ #include -#include #include #include #include +#include #include #include #include @@ -176,7 +176,7 @@ void addErrorSelections(const QVector &diagno ClangBackEnd::SourceLocationContainer toSourceLocation(QTextDocument *textDocument, int position) { int line, column; - if (TextEditor::Convenience::convertPosition(textDocument, position, &line, &column)) + if (Utils::Text::convertPosition(textDocument, position, &line, &column)) return ClangBackEnd::SourceLocationContainer(Utf8String(), line, column); return ClangBackEnd::SourceLocationContainer(); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 593d3cb9c72..81053cef60e 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -47,7 +47,6 @@ #include #include -#include #include #include #include @@ -56,6 +55,7 @@ #include +#include #include #include @@ -225,6 +225,12 @@ toTextEditorBlocks(QTextDocument *textDocument, } } +const QVector +&ClangEditorDocumentProcessor::highlightingMarks() const +{ + return m_highlightingMarks; +} + void ClangEditorDocumentProcessor::updateHighlighting( const QVector &highlightingMarks, const QVector &skippedPreprocessorRanges, @@ -234,6 +240,7 @@ void ClangEditorDocumentProcessor::updateHighlighting( const auto skippedPreprocessorBlocks = toTextEditorBlocks(textDocument(), skippedPreprocessorRanges); emit ifdefedOutBlocksUpdated(documentRevision, skippedPreprocessorBlocks); + m_highlightingMarks = highlightingMarks; m_semanticHighlighter.setHighlightingRunner( [highlightingMarks]() { auto *reporter = new HighlightingMarksReporter(highlightingMarks); @@ -246,10 +253,8 @@ void ClangEditorDocumentProcessor::updateHighlighting( static int currentLine(const TextEditor::AssistInterface &assistInterface) { int line, column; - TextEditor::Convenience::convertPosition(assistInterface.textDocument(), - assistInterface.position(), - &line, - &column); + ::Utils::Text::convertPosition(assistInterface.textDocument(), assistInterface.position(), + &line, &column); return line; } @@ -315,10 +320,10 @@ static QFuture defaultCursorInfoFuture() static bool convertPosition(const QTextCursor &textCursor, int *line, int *column) { - const bool converted = TextEditor::Convenience::convertPosition(textCursor.document(), - textCursor.position(), - line, - column); + const bool converted = ::Utils::Text::convertPosition(textCursor.document(), + textCursor.position(), + line, + column); QTC_CHECK(converted); return converted; } @@ -376,7 +381,7 @@ static QVector prioritizeByBaseName(const QString &curPath, } QFuture -ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column, bool resolveTarget) +ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column) { QVector dependentFiles; CppTools::CppModelManager *modelManager = CppTools::CppModelManager::instance(); @@ -390,8 +395,7 @@ ClangEditorDocumentProcessor::requestFollowSymbol(int line, int column, bool res return m_ipcCommunicator.requestFollowSymbol(simpleFileContainer(), dependentFiles, static_cast(line), - static_cast(column), - resolveTarget); + static_cast(column)); } ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index 6255608dc23..d7f7f966f50 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -86,14 +86,14 @@ public: void setParserConfig(const CppTools::BaseEditorDocumentParser::Configuration config) override; QFuture cursorInfo(const CppTools::CursorInfoParams ¶ms) override; - QFuture requestFollowSymbol(int line, - int column, - bool resolveTarget) override; + QFuture requestFollowSymbol(int line, int column) override; ClangBackEnd::FileContainer fileContainerWithArguments() const; void clearDiagnosticsWithFixIts(); + const QVector &highlightingMarks() const; + public: static ClangEditorDocumentProcessor *get(const QString &filePath); @@ -122,6 +122,7 @@ private: QTimer m_updateTranslationUnitTimer; unsigned m_parserRevision; + QVector m_highlightingMarks; CppTools::SemanticHighlighter m_semanticHighlighter; CppTools::BuiltinEditorDocumentProcessor m_builtinProcessor; }; diff --git a/src/plugins/clangcodemodel/clangfollowsymbol.cpp b/src/plugins/clangcodemodel/clangfollowsymbol.cpp index ede9cac8245..66db810e4a4 100644 --- a/src/plugins/clangcodemodel/clangfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangfollowsymbol.cpp @@ -23,14 +23,78 @@ ** ****************************************************************************/ -#include "clangfollowsymbol.h" #include "clangeditordocumentprocessor.h" -#include "texteditor/texteditor.h" -#include "texteditor/convenience.h" +#include "clangfollowsymbol.h" + +#include + +#include + +#include +#include namespace ClangCodeModel { namespace Internal { +// Returns invalid Mark if it is not found at (line, column) +static bool findMark(const QVector &marks, + uint line, + uint column, + ClangBackEnd::HighlightingMarkContainer &mark) +{ + mark = Utils::findOrDefault(marks, + [line, column](const ClangBackEnd::HighlightingMarkContainer &curMark) { + if (curMark.line() != line) + return false; + if (curMark.column() == column) + return true; + if (curMark.column() < column && curMark.column() + curMark.length() >= column) + return true; + return false; + }); + if (mark.isInvalid()) + return false; + return true; +} + +static int getMarkPos(QTextCursor cursor, const ClangBackEnd::HighlightingMarkContainer &mark) +{ + cursor.setPosition(0); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, mark.line() - 1); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, mark.column() - 1); + return cursor.position(); +} + +static TextEditor::TextEditorWidget::Link linkAtCursor(QTextCursor cursor, + const QString &filePath, + uint line, + uint column, + ClangEditorDocumentProcessor *processor) +{ + using Link = TextEditor::TextEditorWidget::Link; + + const QVector &marks + = processor->highlightingMarks(); + ClangBackEnd::HighlightingMarkContainer mark; + if (!findMark(marks, line, column, mark)) + return Link(); + + cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor); + const QString tokenStr = cursor.selectedText(); + + Link token(filePath, mark.line(), mark.column()); + token.linkTextStart = getMarkPos(cursor, mark); + token.linkTextEnd = token.linkTextStart + mark.length(); + if (mark.isIncludeDirectivePath()) { + if (tokenStr != "include" && tokenStr != "#" && tokenStr != "<") + return token; + return Link(); + } + if (mark.isIdentifier() || tokenStr == "operator") + return token; + return Link(); +} + TextEditor::TextEditorWidget::Link ClangFollowSymbol::findLink( const CppTools::CursorInEditor &data, bool resolveTarget, @@ -39,42 +103,39 @@ TextEditor::TextEditorWidget::Link ClangFollowSymbol::findLink( CppTools::SymbolFinder *, bool) { - Link link; - int lineNumber = 0, positionInBlock = 0; - QTextCursor cursor = TextEditor::Convenience::wordStartCursor(data.cursor()); - TextEditor::Convenience::convertPosition(cursor.document(), cursor.position(), &lineNumber, - &positionInBlock); - const unsigned line = lineNumber; - const unsigned column = positionInBlock + 1; + QTextCursor cursor = Utils::Text::wordStartCursor(data.cursor()); + Utils::Text::convertPosition(cursor.document(), cursor.position(), &lineNumber, + &positionInBlock); + + const uint line = lineNumber; + const uint column = positionInBlock + 1; - if (!resolveTarget) - return link; ClangEditorDocumentProcessor *processor = ClangEditorDocumentProcessor::get( data.filePath().toString()); if (!processor) - return link; + return Link(); + + if (!resolveTarget) + return linkAtCursor(cursor, data.filePath().toString(), line, column, processor); QFuture info = processor->requestFollowSymbol(static_cast(line), - static_cast(column), - resolveTarget); + static_cast(column)); + if (info.isCanceled()) - return link; + return Link(); while (!info.isFinished()) { if (info.isCanceled()) - return link; + return Link(); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } CppTools::SymbolInfo result = info.result(); - if (result.failedToFollow) - return link; - // We did not fail but the result is empty if (result.fileName.isEmpty()) - return link; + return Link(); return Link(result.fileName, result.startLine, result.startColumn - 1); } diff --git a/src/plugins/clangcodemodel/clanghighlightingmarksreporter.cpp b/src/plugins/clangcodemodel/clanghighlightingmarksreporter.cpp index 6090b73f415..747070a317a 100644 --- a/src/plugins/clangcodemodel/clanghighlightingmarksreporter.cpp +++ b/src/plugins/clangcodemodel/clanghighlightingmarksreporter.cpp @@ -158,8 +158,15 @@ void HighlightingMarksReporter::run_internal() if (isCanceled()) return; - for (const auto &highlightingMark : m_highlightingMarks) + using ClangBackEnd::HighlightingType; + + for (const auto &highlightingMark : m_highlightingMarks) { + const HighlightingType mainType = highlightingMark.types().mainHighlightingType; + if (mainType == HighlightingType::StringLiteral) + continue; + reportChunkWise(toHighlightingResult(highlightingMark)); + } if (isCanceled()) return; diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 547f27276bc..c5d85045c51 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -31,6 +31,7 @@ #include "clangfollowsymbol.h" #include +#include #include #include #include @@ -72,6 +73,8 @@ ModelManagerSupportClang::ModelManagerSupportClang() if (useClangFollowSymbol()) m_followSymbol.reset(new ClangFollowSymbol); + else + m_followSymbol.reset(new CppTools::FollowSymbolUnderCursor); Core::EditorManager *editorManager = Core::EditorManager::instance(); connect(editorManager, &Core::EditorManager::editorOpened, @@ -106,9 +109,9 @@ CppTools::CppCompletionAssistProvider *ModelManagerSupportClang::completionAssis return &m_completionAssistProvider; } -CppTools::FollowSymbolInterface *ModelManagerSupportClang::followSymbolInterface() +CppTools::FollowSymbolInterface &ModelManagerSupportClang::followSymbolInterface() { - return m_followSymbol.get(); + return *m_followSymbol; } CppTools::BaseEditorDocumentProcessor *ModelManagerSupportClang::editorDocumentProcessor( diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 8728704e1c6..78e5cd5694a 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -42,12 +42,11 @@ QT_END_NAMESPACE namespace Core { class IDocument; } namespace TextEditor { class TextEditorWidget; } +namespace CppTools { class FollowSymbolInterface; } namespace ClangCodeModel { namespace Internal { -class ClangFollowSymbol; - class ModelManagerSupportClang: public QObject, public CppTools::ModelManagerSupport @@ -61,7 +60,7 @@ public: CppTools::CppCompletionAssistProvider *completionAssistProvider() override; CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) override; - CppTools::FollowSymbolInterface *followSymbolInterface() override; + CppTools::FollowSymbolInterface &followSymbolInterface() override; IpcCommunicator &ipcCommunicator(); QString dummyUiHeaderOnDiskDirPath() const; @@ -105,7 +104,7 @@ private: UiHeaderOnDiskManager m_uiHeaderOnDiskManager; IpcCommunicator m_ipcCommunicator; ClangCompletionAssistProvider m_completionAssistProvider; - std::unique_ptr m_followSymbol; + std::unique_ptr m_followSymbol; }; class ModelManagerSupportProviderClang : public CppTools::ModelManagerSupportProvider diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index e436ec275fb..0058ee4023b 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -70,46 +70,21 @@ QStringList createClangOptions(const ProjectPart::Ptr &pPart, const QString &fil return createClangOptions(pPart, fileKind); } -class LibClangOptionsBuilder : public ClangCompilerOptionsBuilder +class LibClangOptionsBuilder final : public ClangCompilerOptionsBuilder { public: - static QStringList build(const ProjectPart::Ptr &projectPart, ProjectFile::Kind fileKind) - { - if (projectPart.isNull()) - return QStringList(); - - LibClangOptionsBuilder optionsBuilder(*projectPart.data()); - - optionsBuilder.addWordWidth(); - optionsBuilder.addTargetTriple(); - optionsBuilder.addLanguageOption(fileKind); - optionsBuilder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true); - optionsBuilder.enableExceptions(); - - optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - optionsBuilder.addDefineFloat128ForMingw(); - optionsBuilder.addToolchainAndProjectDefines(); - optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015(); - - optionsBuilder.addPredefinedMacrosAndHeaderPathsOptions(); - optionsBuilder.addWrappedQtHeadersIncludePath(); - optionsBuilder.addHeaderPathOptions(); - optionsBuilder.addDummyUiHeaderOnDiskIncludePath(); - optionsBuilder.addProjectConfigFileInclude(); - - optionsBuilder.addMsvcCompatibilityVersion(); - - optionsBuilder.addExtraOptions(); - - return optionsBuilder.options(); - } - -private: - LibClangOptionsBuilder(const CppTools::ProjectPart &projectPart) + LibClangOptionsBuilder(const ProjectPart &projectPart) : ClangCompilerOptionsBuilder(projectPart, CLANG_VERSION, CLANG_RESOURCE_DIR) { } + void addExtraOptions() final + { + addDummyUiHeaderOnDiskIncludePath(); + ClangCompilerOptionsBuilder::addExtraOptions(); + } + +private: void addDummyUiHeaderOnDiskIncludePath() { const QString path = ModelManagerSupportClang::instance()->dummyUiHeaderOnDiskDirPath(); @@ -125,7 +100,9 @@ private: */ QStringList createClangOptions(const ProjectPart::Ptr &pPart, ProjectFile::Kind fileKind) { - return LibClangOptionsBuilder::build(pPart, fileKind); + if (!pPart) + return QStringList(); + return LibClangOptionsBuilder(*pPart).build(fileKind, CompilerOptionsBuilder::PchUsage::None); } ProjectPart::Ptr projectPartForFile(const QString &filePath) diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp index 046c5f769fc..8327f85a221 100644 --- a/src/plugins/clangpchmanager/projectupdater.cpp +++ b/src/plugins/clangpchmanager/projectupdater.cpp @@ -108,35 +108,9 @@ HeaderAndSources ProjectUpdater::headerAndSourcesFromProjectPart( QStringList ProjectUpdater::compilerArguments(CppTools::ProjectPart *projectPart) { - using CppTools::ClangCompilerOptionsBuilder; - - ClangCompilerOptionsBuilder builder(*projectPart, CLANG_VERSION, CLANG_RESOURCE_DIR); - - builder.addWordWidth(); - builder.addTargetTriple(); - builder.addLanguageOption(CppTools::ProjectFile::CXXHeader); - builder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true); - builder.enableExceptions(); - - builder.addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - builder.addDefineFloat128ForMingw(); - builder.addToolchainAndProjectDefines(); - builder.undefineCppLanguageFeatureMacrosForMsvc2015(); - - builder.addPredefinedMacrosAndHeaderPathsOptions(); - builder.addWrappedQtHeadersIncludePath(); - builder.addPrecompiledHeaderOptions(ClangCompilerOptionsBuilder::PchUsage::None); - builder.addHeaderPathOptions(); - builder.addProjectConfigFileInclude(); - - builder.addMsvcCompatibilityVersion(); - - builder.add("-fmessage-length=0"); - builder.add("-fmacro-backtrace-limit=0"); - builder.add("-w"); - builder.add("-ferror-limit=100000"); - - return builder.options(); + using ClangCOBuilder = CppTools::ClangCompilerOptionsBuilder; + ClangCOBuilder builder(*projectPart, CLANG_VERSION, CLANG_RESOURCE_DIR); + return builder.build(CppTools::ProjectFile::CXXHeader, ClangCOBuilder::PchUsage::None); } ClangBackEnd::V2::ProjectPartContainer ProjectUpdater::toProjectPartContainer( diff --git a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp index d4e210c04e8..14d8a1620ec 100644 --- a/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp +++ b/src/plugins/clangrefactoring/clangqueryprojectsfindfilter.cpp @@ -155,31 +155,8 @@ Utils::SmallStringVector ClangQueryProjectsFindFilter::compilerArguments(CppTool ClangCompilerOptionsBuilder builder(*projectPart, CLANG_VERSION, CLANG_RESOURCE_DIR); - builder.addWordWidth(); - builder.addTargetTriple(); - builder.addLanguageOption(fileKind); - builder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true); - builder.enableExceptions(); - - builder.addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - builder.addDefineFloat128ForMingw(); - builder.addToolchainAndProjectDefines(); - builder.undefineCppLanguageFeatureMacrosForMsvc2015(); - - builder.addPredefinedMacrosAndHeaderPathsOptions(); - builder.addWrappedQtHeadersIncludePath(); - builder.addPrecompiledHeaderOptions(ClangCompilerOptionsBuilder::PchUsage::None); - builder.addHeaderPathOptions(); - builder.addProjectConfigFileInclude(); - - builder.addMsvcCompatibilityVersion(); - - builder.add("-fmessage-length=0"); - builder.add("-fmacro-backtrace-limit=0"); - builder.add("-w"); - builder.add("-ferror-limit=1000000"); - - return Utils::SmallStringVector(builder.options()); + return Utils::SmallStringVector(builder.build(fileKind, + ClangCompilerOptionsBuilder::PchUsage::None)); } QWidget *ClangQueryProjectsFindFilter::widget() const diff --git a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp index ea17409faca..a2638212d65 100644 --- a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp +++ b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp @@ -96,6 +96,7 @@ void ClangRefactoringPlugin::extensionsInitialized() ExtensionSystem::IPlugin::ShutdownFlag ClangRefactoringPlugin::aboutToShutdown() { ExtensionSystem::PluginManager::removeObject(&d->qtCreatorfindFilter); + CppTools::CppModelManager::setRefactoringEngine(nullptr); d->refactoringClient.setRefactoringConnectionClient(nullptr); d->refactoringClient.setRefactoringEngine(nullptr); diff --git a/src/plugins/clangrefactoring/refactoringengine.cpp b/src/plugins/clangrefactoring/refactoringengine.cpp index aba069d93e3..696e38c468c 100644 --- a/src/plugins/clangrefactoring/refactoringengine.cpp +++ b/src/plugins/clangrefactoring/refactoringengine.cpp @@ -64,12 +64,10 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, QString filePath = data.filePath().toString(); QTextCursor textCursor = data.cursor(); - Utils::SmallStringVector commandLine{ClangCompilerOptionsBuilder::build( - projectPart, + ClangCompilerOptionsBuilder clangCOBuilder{*projectPart, CLANG_VERSION, CLANG_RESOURCE_DIR}; + Utils::SmallStringVector commandLine{clangCOBuilder.build( fileKindInProjectPart(projectPart, filePath), - CppTools::getPchUsage(), - CLANG_VERSION, - CLANG_RESOURCE_DIR)}; + CppTools::getPchUsage())}; commandLine.push_back(filePath); @@ -84,6 +82,11 @@ void RefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, server.requestSourceLocationsForRenamingMessage(std::move(message)); } +void RefactoringEngine::startGlobalRenaming(const CppTools::CursorInEditor &) +{ + // TODO: implement +} + bool RefactoringEngine::isUsable() const { return server.isUsable(); diff --git a/src/plugins/clangrefactoring/refactoringengine.h b/src/plugins/clangrefactoring/refactoringengine.h index a5fe5fc6417..83e67bfe27a 100644 --- a/src/plugins/clangrefactoring/refactoringengine.h +++ b/src/plugins/clangrefactoring/refactoringengine.h @@ -42,6 +42,7 @@ public: void startLocalRenaming(const CppTools::CursorInEditor &data, CppTools::ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback) override; + void startGlobalRenaming(const CppTools::CursorInEditor &data) override; bool isUsable() const override; void setUsable(bool isUsable); diff --git a/src/plugins/clangrefactoring/sourcelocations.h b/src/plugins/clangrefactoring/sourcelocations.h index fe2d3dace94..9ae4241c01a 100644 --- a/src/plugins/clangrefactoring/sourcelocations.h +++ b/src/plugins/clangrefactoring/sourcelocations.h @@ -39,24 +39,25 @@ class SourceLocations public: struct Location { - qint64 sourceId; - qint64 line; - qint64 column; + Location(qint64 sourceId, qint64 line, qint64 column) + : sourceId(sourceId), line(line), column(column) + {} + + qint64 sourceId; + qint64 line; + qint64 column; }; struct Source { + Source(qint64 sourceId, Utils::PathString &&sourcePath) + : sourceId(sourceId), sourcePath(std::move(sourcePath)) + {} + qint64 sourceId; Utils::PathString sourcePath; }; - enum LocationGetter - { - SourceId = 0, - Line, - Column - }; - std::vector locations; std::unordered_map sources; }; diff --git a/src/plugins/clangrefactoring/symbolquery.h b/src/plugins/clangrefactoring/symbolquery.h index 778156410a4..19faf972294 100644 --- a/src/plugins/clangrefactoring/symbolquery.h +++ b/src/plugins/clangrefactoring/symbolquery.h @@ -52,7 +52,7 @@ public: const std::size_t reserveSize = 128; - auto locations = locationsStatement.template structValues( + auto locations = locationsStatement.template values( reserveSize, filePath, line, @@ -62,7 +62,7 @@ public: ReadStatement &sourcesStatement = m_statementFactory.selectSourcePathForId; - auto sources = sourcesStatement.template structValues( + auto sources = sourcesStatement.template values( reserveSize, sourceIds); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp index 0cb7c976ee1..c9ff00558db 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp @@ -167,7 +167,7 @@ static QList validTargets(Project *project) const ToolChain * const toolchain = ToolChainKitInformation::toolChain(kit, ProjectExplorer::Constants::CXX_LANGUAGE_ID); QTC_ASSERT(toolchain, return false); bool hasClangExecutable; - clangExecutableFromSettings(toolchain->typeId(), &hasClangExecutable); + clangExecutableFromSettings(&hasClangExecutable); if (!hasClangExecutable) { qWarning("Project \"%s\": Skipping target \"%s\" since no suitable clang was found for the toolchain.", qPrintable(projectFileName), diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp index 0cfafa08e11..94468e913e4 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerruncontrol.cpp @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include @@ -161,8 +161,7 @@ static void prependTargetTripleIfNotIncludedAndNotEmpty(QStringList *arguments, } // Removes (1) inputFile (2) -o . -QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStringList &arguments, - bool isMsvc) +QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStringList &arguments) { QStringList newArguments; @@ -174,9 +173,6 @@ QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStri } else if (argument == QLatin1String("-o")) { skip = true; continue; - } else if (isMsvc && argument == QLatin1String("-target")) { - skip = true; - continue; } else if (QDir::fromNativeSeparators(argument) == inputFile) { continue; // TODO: Let it in? } @@ -188,55 +184,11 @@ QStringList inputAndOutputArgumentsRemoved(const QString &inputFile, const QStri return newArguments; } -static QString createLanguageOptionMsvc(ProjectFile::Kind fileKind) -{ - switch (fileKind) { - case ProjectFile::CHeader: - case ProjectFile::CSource: - return QLatin1String("/TC"); - break; - case ProjectFile::CXXHeader: - case ProjectFile::CXXSource: - return QLatin1String("/TP"); - break; - default: - break; - } - return QString(); -} - -class ClangStaticAnalyzerOptionsBuilder : public CompilerOptionsBuilder +class ClangStaticAnalyzerOptionsBuilder final : public ClangCompilerOptionsBuilder { public: - static QStringList build(const CppTools::ProjectPart &projectPart, - CppTools::ProjectFile::Kind fileKind, - PchUsage pchUsage) - { - ClangStaticAnalyzerOptionsBuilder optionsBuilder(projectPart); - - optionsBuilder.addWordWidth(); - optionsBuilder.addTargetTriple(); - optionsBuilder.addLanguageOption(fileKind); - optionsBuilder.addOptionsForLanguage(false); - optionsBuilder.enableExceptions(); - - optionsBuilder.addDefineFloat128ForMingw(); - optionsBuilder.addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - const Core::Id type = projectPart.toolchainType; - if (type != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) - optionsBuilder.addMacros(projectPart.toolChainMacros); - optionsBuilder.addMacros(projectPart.projectMacros); - optionsBuilder.undefineClangVersionMacrosForMsvc(); - optionsBuilder.undefineCppLanguageFeatureMacrosForMsvc2015(); - optionsBuilder.addHeaderPathOptions(); - optionsBuilder.addPrecompiledHeaderOptions(pchUsage); - optionsBuilder.addMsvcCompatibilityVersion(); - - return optionsBuilder.options(); - } - ClangStaticAnalyzerOptionsBuilder(const CppTools::ProjectPart &projectPart) - : CompilerOptionsBuilder(projectPart) + : ClangCompilerOptionsBuilder(projectPart) , m_isMsvcToolchain(m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) , m_isMinGWToolchain(m_projectPart.toolchainType @@ -244,91 +196,28 @@ public: { } -public: - bool excludeHeaderPath(const QString &headerPath) const override + bool excludeHeaderPath(const QString &headerPath) const final { - if (CompilerOptionsBuilder::excludeHeaderPath(headerPath)) - return true; if (m_isMinGWToolchain && headerPath.contains(m_projectPart.toolChainTargetTriple)) return true; - return false; + return ClangCompilerOptionsBuilder::excludeHeaderPath(headerPath); } - void undefineClangVersionMacrosForMsvc() + void addPredefinedHeaderPathsOptions() final { - if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { - static QStringList macroNames { - "__clang__", - "__clang_major__", - "__clang_minor__", - "__clang_patchlevel__", - "__clang_version__" - }; - - foreach (const QString ¯oName, macroNames) - add(QLatin1String("/U") + macroName); + add("-undef"); + if (m_isMsvcToolchain) { + // exclude default clang path to use msvc includes + add("-nostdinc"); + add("-nostdlibinc"); } } -private: - void addTargetTriple() override - { - // For MSVC toolchains we use clang-cl.exe, so there is nothing to do here since - // 1) clang-cl.exe does not understand the "-triple" option - // 2) clang-cl.exe already hardcodes the right triple value (even if built with mingw) - if (!m_isMsvcToolchain) - CompilerOptionsBuilder::addTargetTriple(); - } + void addExtraOptions() final {} - void addLanguageOption(ProjectFile::Kind fileKind) override + void addWrappedQtHeadersIncludePath() final { - if (m_isMsvcToolchain) - add(createLanguageOptionMsvc(fileKind)); - else - CompilerOptionsBuilder::addLanguageOption(fileKind); - } - - void addOptionsForLanguage(bool checkForBorlandExtensions) override - { - if (m_isMsvcToolchain) - return; - CompilerOptionsBuilder::addOptionsForLanguage(checkForBorlandExtensions); - } - - QString includeOption() const override - { - if (m_isMsvcToolchain) - return QLatin1String("/FI"); - return CompilerOptionsBuilder::includeOption(); - } - - QString includeDirOption() const override - { - if (m_isMsvcToolchain) - return QLatin1String("/I"); - return CompilerOptionsBuilder::includeDirOption(); - } - - QString defineOption() const override - { - if (m_isMsvcToolchain) - return QLatin1String("/D"); - return CompilerOptionsBuilder::defineOption(); - } - - QString undefineOption() const override - { - if (m_isMsvcToolchain) - return QLatin1String("/U"); - return CompilerOptionsBuilder::undefineOption(); - } - - void enableExceptions() override - { - if (m_isMsvcToolchain) - add(QLatin1String("/EHsc")); - else - CompilerOptionsBuilder::enableExceptions(); + // Empty, analyzer doesn't need them } private: @@ -383,7 +272,7 @@ static QStringList tweakedArguments(const ProjectPart &projectPart, { const bool isMsvc = projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID; - QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments, isMsvc); + QStringList newArguments = inputAndOutputArgumentsRemoved(filePath, arguments); prependWordWidthArgumentIfNotIncluded(&newArguments, projectPart.toolChainWordWidth); if (!isMsvc) prependTargetTripleIfNotIncludedAndNotEmpty(&newArguments, targetTriple); @@ -434,7 +323,7 @@ static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QVectorselectedForBuilding) + if (!projectPart->selectedForBuilding || !projectPart.data()) continue; foreach (const ProjectFile &file, projectPart->files) { @@ -445,7 +334,7 @@ static AnalyzeUnits unitsToAnalyzeFromProjectParts(const QVectortypeId(), &hasClangExecutable); + clangExecutableFromSettings(&hasClangExecutable); if (!hasClangExecutable) QSKIP("No clang suitable for analyzing found"); diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp index 073adac6798..7a433aac49f 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.cpp @@ -50,7 +50,7 @@ static bool isFileExecutable(const QString &executablePath) namespace ClangStaticAnalyzer { namespace Internal { -QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid) +QString clangExecutableFromSettings(bool *isValid) { QString executable = ClangStaticAnalyzerSettings::instance()->clangExecutable(); if (executable.isEmpty()) { @@ -62,14 +62,6 @@ QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid) const Qt::CaseSensitivity caseSensitivity = Utils::HostOsInfo::fileNameCaseSensitivity(); const bool hasSuffix = executable.endsWith(hostExeSuffix, caseSensitivity); - if (toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { - if (hasSuffix) - executable.chop(hostExeSuffix.length()); - executable.append(QLatin1String("-cl")); - if (hasSuffix) - executable.append(hostExeSuffix); - } - const QFileInfo fileInfo = QFileInfo(executable); if (fileInfo.isAbsolute()) { if (!hasSuffix) diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h index e170d8b7f01..c18317237c6 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerutils.h @@ -41,7 +41,7 @@ namespace Internal { bool isClangExecutableUsable(const QString &filePath, QString *errorMessage = 0); -QString clangExecutableFromSettings(Core::Id toolchainType, bool *isValid); +QString clangExecutableFromSettings(bool *isValid); QString createFullLocationString(const Debugger::DiagnosticLocation &location); diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index 86d9e0945f6..67ae9387af0 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include #include @@ -72,12 +73,22 @@ BuildDirManager::~BuildDirManager() = default; const Utils::FileName BuildDirManager::workDirectory() const { const Utils::FileName bdir = m_buildConfiguration->buildDirectory(); - if (bdir.exists()) + const CMakeTool *cmake = CMakeKitInformation::cmakeTool(m_buildConfiguration->target()->kit()); + if (bdir.exists()) { return bdir; + } else { + if (cmake && cmake->autoCreateBuildDirectory()) { + if (!QDir().mkpath(bdir.toString())) + emitErrorOccured(tr("Failed to create build directory \"%1\".").arg(bdir.toUserOutput())); + return bdir; + } + } if (!m_tempDir) { m_tempDir.reset(new Utils::TemporaryDirectory("qtc-cmake-XXXXXXXX")); - if (!m_tempDir->isValid()) - emitErrorOccured(tr("Failed to create temporary directory \"%1\".").arg(m_tempDir->path())); + if (!m_tempDir->isValid()) { + emitErrorOccured(tr("Failed to create temporary directory \"%1\".") + .arg(QDir::toNativeSeparators(m_tempDir->path()))); + } } return Utils::FileName::fromString(m_tempDir->path()); } diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index c0531ebf379..8985a0799e3 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -378,6 +378,33 @@ void CMakeBuildSettingsWidget::updateSelection(const QModelIndex ¤t, const m_editButton->setEnabled(currentModelIndex.flags().testFlag(Qt::ItemIsEditable)); } +QAction *CMakeBuildSettingsWidget::createForceAction(int type, const QModelIndex &idx) +{ + ConfigModel::DataItem::Type t = static_cast(type); + QString typeString; + switch (type) { + case ConfigModel::DataItem::BOOLEAN: + typeString = tr("bool", "display string for cmake type BOOLEAN"); + break; + case ConfigModel::DataItem::FILE: + typeString = tr("file", "display string for cmake type FILE"); + break; + case ConfigModel::DataItem::DIRECTORY: + typeString = tr("directory", "display string for cmake type DIRECTORY"); + break; + case ConfigModel::DataItem::STRING: + typeString = tr("string", "display string for cmake type STRING"); + break; + case ConfigModel::DataItem::UNKNOWN: + return nullptr; + } + QAction *forceAction = new QAction(tr("Force to %1").arg(typeString), nullptr); + forceAction->setEnabled(m_configModel->canForceTo(idx, t)); + connect(forceAction, &QAction::triggered, + this, [this, idx, t]() { m_configModel->forceTo(idx, t); }); + return forceAction; +} + bool CMakeBuildSettingsWidget::eventFilter(QObject *target, QEvent *event) { // handle context menu events: @@ -392,10 +419,15 @@ bool CMakeBuildSettingsWidget::eventFilter(QObject *target, QEvent *event) QMenu *menu = new QMenu(this); connect(menu, &QMenu::triggered, menu, &QMenu::deleteLater); - QAction *forceToStringAction = new QAction(tr("Force to String"), nullptr); - forceToStringAction->setEnabled(m_configModel->canForceToString(idx)); - menu->addAction(forceToStringAction); - connect(forceToStringAction, &QAction::triggered, this, [this, idx]() { m_configModel->forceToString(idx); }); + QAction *action = nullptr; + if ((action = createForceAction(ConfigModel::DataItem::BOOLEAN, idx))) + menu->addAction(action); + if ((action = createForceAction(ConfigModel::DataItem::FILE, idx))) + menu->addAction(action); + if ((action = createForceAction(ConfigModel::DataItem::DIRECTORY, idx))) + menu->addAction(action); + if ((action = createForceAction(ConfigModel::DataItem::STRING, idx))) + menu->addAction(action); menu->move(e->globalPos()); menu->show(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h index a15cfe6e0aa..e6e4b1e21c2 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.h @@ -65,6 +65,7 @@ private: void updateFromKit(); void updateSelection(const QModelIndex ¤t, const QModelIndex &previous); + QAction *createForceAction(int type, const QModelIndex &idx); bool eventFilter(QObject *target, QEvent *event); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 211f564cc83..57de95ad1fa 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -152,7 +152,7 @@ void CMakeProject::updateProjectData(CMakeBuildConfiguration *bc) } updateApplicationAndDeploymentTargets(); - t->updateDefaultRunConfigurations(); + updateTargetRunConfigurations(t); createGeneratedCodeModelSupport(); @@ -448,6 +448,34 @@ QStringList CMakeProject::filesGeneratedFrom(const QString &sourceFile) const } } +void CMakeProject::updateTargetRunConfigurations(Target *t) +{ + // *Update* existing runconfigurations (no need to update new ones!): + QHash buildTargetHash; + const QList buildTargetList = buildTargets(); + foreach (const CMakeBuildTarget &bt, buildTargetList) { + if (bt.targetType != ExecutableType || bt.executable.isEmpty()) + continue; + + buildTargetHash.insert(bt.title, &bt); + } + + foreach (RunConfiguration *rc, t->runConfigurations()) { + auto cmakeRc = qobject_cast(rc); + if (!cmakeRc) + continue; + + auto btIt = buildTargetHash.constFind(cmakeRc->title()); + if (btIt != buildTargetHash.constEnd()) { + cmakeRc->setExecutable(btIt.value()->executable.toString()); + cmakeRc->setBaseWorkingDirectory(btIt.value()->workingDirectory); + } + } + + // create new and remove obsolete RCs using the factories + t->updateDefaultRunConfigurations(); +} + void CMakeProject::updateApplicationAndDeploymentTargets() { Target *t = activeTarget(); diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index 8083cf9dec1..1d3e047683f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -123,6 +123,7 @@ private: void createGeneratedCodeModelSupport(); QStringList filesGeneratedFrom(const QString &sourceFile) const final; + void updateTargetRunConfigurations(ProjectExplorer::Target *t); void updateApplicationAndDeploymentTargets(); ProjectExplorer::Target *m_connectedTarget = nullptr; diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 8381323759d..9f1b7538924 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -66,13 +66,13 @@ public: CMakeToolTreeItem *cmakeToolItem(const Core::Id &id) const; CMakeToolTreeItem *cmakeToolItem(const QModelIndex &index) const; - QModelIndex addCMakeTool(const QString &name, const FileName &executable, const bool autoRun, const bool isAutoDetected); + QModelIndex addCMakeTool(const QString &name, const FileName &executable, const bool autoRun, const bool autoCreate, const bool isAutoDetected); void addCMakeTool(const CMakeTool *item, bool changed); TreeItem *autoGroupItem() const; TreeItem *manualGroupItem() const; void reevaluateChangedFlag(CMakeToolTreeItem *item) const; void updateCMakeTool(const Core::Id &id, const QString &displayName, const FileName &executable, - bool autoRun); + bool autoRun, bool autoCreate); void removeCMakeTool(const Core::Id &id); void apply(); @@ -95,16 +95,18 @@ public: m_name(item->displayName()), m_executable(item->cmakeExecutable()), m_isAutoRun(item->isAutoRun()), + m_autoCreateBuildDirectory(item->autoCreateBuildDirectory()), m_autodetected(item->isAutoDetected()), m_changed(changed) {} CMakeToolTreeItem(const QString &name, const Utils::FileName &executable, - bool autoRun, bool autodetected) : + bool autoRun, bool autoCreate, bool autodetected) : m_id(Core::Id::fromString(QUuid::createUuid().toString())), m_name(name), m_executable(executable), m_isAutoRun(autoRun), + m_autoCreateBuildDirectory(autoCreate), m_autodetected(autodetected), m_changed(true) {} @@ -143,6 +145,7 @@ public: QString m_name; FileName m_executable; bool m_isAutoRun = true; + bool m_autoCreateBuildDirectory = false; bool m_autodetected = false; bool m_changed = true; }; @@ -166,9 +169,10 @@ CMakeToolItemModel::CMakeToolItemModel() } QModelIndex CMakeToolItemModel::addCMakeTool(const QString &name, const FileName &executable, - const bool autoRun, const bool isAutoDetected) + const bool autoRun, const bool autoCreate, + const bool isAutoDetected) { - CMakeToolTreeItem *item = new CMakeToolTreeItem(name, executable, autoRun, isAutoDetected); + CMakeToolTreeItem *item = new CMakeToolTreeItem(name, executable, autoRun, autoCreate, isAutoDetected); if (isAutoDetected) autoGroupItem()->appendChild(item); else @@ -219,7 +223,8 @@ void CMakeToolItemModel::reevaluateChangedFlag(CMakeToolTreeItem *item) const } void CMakeToolItemModel::updateCMakeTool(const Core::Id &id, const QString &displayName, - const FileName &executable, bool autoRun) + const FileName &executable, bool autoRun, + bool autoCreate) { CMakeToolTreeItem *treeItem = cmakeToolItem(id); QTC_ASSERT(treeItem, return); @@ -227,6 +232,7 @@ void CMakeToolItemModel::updateCMakeTool(const Core::Id &id, const QString &disp treeItem->m_name = displayName; treeItem->m_executable = executable; treeItem->m_isAutoRun = autoRun; + treeItem->m_autoCreateBuildDirectory = autoCreate; reevaluateChangedFlag(treeItem); } @@ -262,6 +268,7 @@ void CMakeToolItemModel::apply() cmake->setDisplayName(item->m_name); cmake->setCMakeExecutable(item->m_executable); cmake->setAutorun(item->m_isAutoRun); + cmake->setAutoCreateBuildDirectory(item->m_autoCreateBuildDirectory); } else { toRegister.append(item); } @@ -329,6 +336,7 @@ private: CMakeToolItemModel *m_model; QLineEdit *m_displayNameLineEdit; QCheckBox *m_autoRunCheckBox; + QCheckBox *m_autoCreateBuildDirectoryCheckBox; PathChooser *m_binaryChooser; Core::Id m_id; bool m_loadingItem; @@ -349,11 +357,16 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) m_autoRunCheckBox->setText(tr("Autorun CMake")); m_autoRunCheckBox->setToolTip(tr("Automatically run CMake after changes to CMake project files.")); + m_autoCreateBuildDirectoryCheckBox = new QCheckBox; + m_autoCreateBuildDirectoryCheckBox->setText(tr("Auto-create build directories")); + m_autoCreateBuildDirectoryCheckBox->setToolTip(tr("Automatically create build directories for CMake projects.")); + QFormLayout *formLayout = new QFormLayout(this); formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); formLayout->addRow(new QLabel(tr("Name:")), m_displayNameLineEdit); formLayout->addRow(new QLabel(tr("Path:")), m_binaryChooser); formLayout->addRow(m_autoRunCheckBox); + formLayout->addRow(m_autoCreateBuildDirectoryCheckBox); connect(m_binaryChooser, &PathChooser::rawPathChanged, this, &CMakeToolItemConfigWidget::store); @@ -361,13 +374,16 @@ CMakeToolItemConfigWidget::CMakeToolItemConfigWidget(CMakeToolItemModel *model) this, &CMakeToolItemConfigWidget::store); connect(m_autoRunCheckBox, &QCheckBox::toggled, this, &CMakeToolItemConfigWidget::store); + connect(m_autoCreateBuildDirectoryCheckBox, &QCheckBox::toggled, + this, &CMakeToolItemConfigWidget::store); } void CMakeToolItemConfigWidget::store() const { if (!m_loadingItem && m_id.isValid()) m_model->updateCMakeTool(m_id, m_displayNameLineEdit->text(), m_binaryChooser->fileName(), - m_autoRunCheckBox->checkState() == Qt::Checked); + m_autoRunCheckBox->checkState() == Qt::Checked, + m_autoCreateBuildDirectoryCheckBox->checkState() == Qt::Checked); } void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item) @@ -387,6 +403,7 @@ void CMakeToolItemConfigWidget::load(const CMakeToolTreeItem *item) m_binaryChooser->setFileName(item->m_executable); m_autoRunCheckBox->setChecked(item->m_isAutoRun); + m_autoCreateBuildDirectoryCheckBox->setChecked(item->m_autoCreateBuildDirectory); m_id = item->m_id; m_loadingItem = false; @@ -492,7 +509,8 @@ void CMakeToolConfigWidget::cloneCMakeTool() QModelIndex newItem = m_model.addCMakeTool(tr("Clone of %1").arg(m_currentItem->m_name), m_currentItem->m_executable, - m_currentItem->m_isAutoRun, false); + m_currentItem->m_isAutoRun, + m_currentItem->m_autoCreateBuildDirectory, false); m_cmakeToolsView->setCurrentIndex(newItem); } @@ -500,7 +518,7 @@ void CMakeToolConfigWidget::cloneCMakeTool() void CMakeToolConfigWidget::addCMakeTool() { QModelIndex newItem = m_model.addCMakeTool(m_model.uniqueDisplayName(tr("New CMake")), - FileName(), true, false); + FileName(), true, false, false); m_cmakeToolsView->setCurrentIndex(newItem); } diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 1a107ccd554..9c071dacb85 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -46,6 +46,7 @@ const char CMAKE_INFORMATION_ID[] = "Id"; const char CMAKE_INFORMATION_COMMAND[] = "Binary"; const char CMAKE_INFORMATION_DISPLAYNAME[] = "DisplayName"; const char CMAKE_INFORMATION_AUTORUN[] = "AutoRun"; +const char CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY[] = "AutoCreateBuildDirectory"; const char CMAKE_INFORMATION_AUTODETECTED[] = "AutoDetected"; @@ -68,6 +69,7 @@ CMakeTool::CMakeTool(const QVariantMap &map, bool fromSdk) : m_isAutoDetected(fr m_id = Core::Id::fromSetting(map.value(CMAKE_INFORMATION_ID)); m_displayName = map.value(CMAKE_INFORMATION_DISPLAYNAME).toString(); m_isAutoRun = map.value(CMAKE_INFORMATION_AUTORUN, true).toBool(); + m_autoCreateBuildDirectory = map.value(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, false).toBool(); //loading a CMakeTool from SDK is always autodetection if (!fromSdk) @@ -102,6 +104,15 @@ void CMakeTool::setAutorun(bool autoRun) CMakeToolManager::notifyAboutUpdate(this); } +void CMakeTool::setAutoCreateBuildDirectory(bool autoBuildDir) +{ + if (m_autoCreateBuildDirectory == autoBuildDir) + return; + + m_autoCreateBuildDirectory = autoBuildDir; + CMakeToolManager::notifyAboutUpdate(this); +} + bool CMakeTool::isValid() const { if (!m_id.isValid()) @@ -142,6 +153,7 @@ QVariantMap CMakeTool::toMap() const data.insert(CMAKE_INFORMATION_ID, m_id.toSetting()); data.insert(CMAKE_INFORMATION_COMMAND, m_executable.toString()); data.insert(CMAKE_INFORMATION_AUTORUN, m_isAutoRun); + data.insert(CMAKE_INFORMATION_AUTO_CREATE_BUILD_DIRECTORY, m_autoCreateBuildDirectory); data.insert(CMAKE_INFORMATION_AUTODETECTED, m_isAutoDetected); return data; } @@ -162,6 +174,11 @@ bool CMakeTool::isAutoRun() const return m_isAutoRun; } +bool CMakeTool::autoCreateBuildDirectory() const +{ + return m_autoCreateBuildDirectory; +} + QList CMakeTool::supportedGenerators() const { readInformation(QueryType::GENERATORS); diff --git a/src/plugins/cmakeprojectmanager/cmaketool.h b/src/plugins/cmakeprojectmanager/cmaketool.h index 5851c75bfc7..95556cefd70 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.h +++ b/src/plugins/cmakeprojectmanager/cmaketool.h @@ -90,9 +90,11 @@ public: void setCMakeExecutable(const Utils::FileName &executable); void setAutorun(bool autoRun); + void setAutoCreateBuildDirectory(bool autoBuildDir); Utils::FileName cmakeExecutable() const; bool isAutoRun() const; + bool autoCreateBuildDirectory() const; QList supportedGenerators() const; TextEditor::Keywords keywords(); bool hasServerMode() const; @@ -127,6 +129,7 @@ private: bool m_isAutoRun = true; bool m_isAutoDetected = false; + bool m_autoCreateBuildDirectory = false; mutable bool m_didAttemptToRun = false; mutable bool m_didRun = false; diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index f87ffb967da..ff43d0cc63e 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -135,23 +135,23 @@ bool ConfigModel::hasCMakeChanges() const return Utils::contains(m_configuration, [](const InternalDataItem &i) { return i.isCMakeChanged; }); } -bool ConfigModel::canForceToString(const QModelIndex &idx) const +bool ConfigModel::canForceTo(const QModelIndex &idx, const ConfigModel::DataItem::Type type) const { if (idx.model() != const_cast(this) || idx.column() != 1) return false; Utils::TreeItem *item = itemForIndex(idx); auto cmti = dynamic_cast(item); - return cmti && (cmti->dataItem->type != DataItem::STRING); + return cmti && (cmti->dataItem->type != type); } -void ConfigModel::forceToString(const QModelIndex &idx) +void ConfigModel::forceTo(const QModelIndex &idx, const ConfigModel::DataItem::Type type) { - QTC_ASSERT(canForceToString(idx), return); + QTC_ASSERT(canForceTo(idx, type), return); Utils::TreeItem *item = itemForIndex(idx); auto cmti = dynamic_cast(item); - cmti->dataItem->type = DataItem::STRING; - const QModelIndex valueIdx = idx.sibling(1, idx.column()); + cmti->dataItem->type = type; + const QModelIndex valueIdx = idx.sibling(idx.row(), 1); emit dataChanged(valueIdx, valueIdx); } diff --git a/src/plugins/cmakeprojectmanager/configmodel.h b/src/plugins/cmakeprojectmanager/configmodel.h index adf6edc87e3..626d487ac63 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.h +++ b/src/plugins/cmakeprojectmanager/configmodel.h @@ -73,8 +73,8 @@ public: bool hasChanges() const; bool hasCMakeChanges() const; - bool canForceToString(const QModelIndex &idx) const; - void forceToString(const QModelIndex &idx); + bool canForceTo(const QModelIndex &idx, const DataItem::Type type) const; + void forceTo(const QModelIndex &idx, const DataItem::Type type); static DataItem dataItemFromIndex(const QModelIndex &idx); diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index e5a612d5949..aa9b9fbbc25 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -207,7 +207,7 @@ const char TR_CLEAR_MENU[] = QT_TRANSLATE_NOOP("Core", "Clear Menu"); const char DEFAULT_BUILD_DIRECTORY[] = "../%{JS: Util.asciify(\"build-%{CurrentProject:Name}-%{CurrentKit:FileSystemName}-%{CurrentBuild:Name}\")}"; -const int TARGET_ICON_SIZE = 32; +const int MODEBAR_ICON_SIZE = 34; const int DEFAULT_MAX_LINE_COUNT = 100000; } // namespace Constants diff --git a/src/plugins/coreplugin/fancyactionbar.cpp b/src/plugins/coreplugin/fancyactionbar.cpp index 6cbaeea716b..206e5e4d6ed 100644 --- a/src/plugins/coreplugin/fancyactionbar.cpp +++ b/src/plugins/coreplugin/fancyactionbar.cpp @@ -178,7 +178,7 @@ void FancyToolButton::paintEvent(QPaintEvent *event) const QIcon::Mode iconMode = isEnabled() ? ((isDown() || isChecked()) ? QIcon::Active : QIcon::Normal) : QIcon::Disabled; - QRect iconRect(0, 0, Constants::TARGET_ICON_SIZE, Constants::TARGET_ICON_SIZE); + QRect iconRect(0, 0, Constants::MODEBAR_ICON_SIZE, Constants::MODEBAR_ICON_SIZE); // draw popup texts if (isTitledAction) { @@ -203,7 +203,7 @@ void FancyToolButton::paintEvent(QPaintEvent *event) painter.setFont(normalFont); QPoint textOffset = centerRect.center() - QPoint(iconRect.width()/2, iconRect.height()/2); - textOffset = textOffset - QPoint(0, lineHeight + 4); + textOffset = textOffset - QPoint(0, lineHeight + 3); QRectF r(0, textOffset.y(), rect().width(), lineHeight); painter.setPen(creatorTheme()->color(isEnabled() ? Theme::PanelTextColorLight @@ -218,8 +218,8 @@ void FancyToolButton::paintEvent(QPaintEvent *event) // draw build configuration name textOffset = iconRect.center() + QPoint(iconRect.width()/2, iconRect.height()/2); QRectF buildConfigRect[2]; - buildConfigRect[0] = QRectF(0, textOffset.y() + 5, rect().width(), lineHeight); - buildConfigRect[1] = QRectF(0, textOffset.y() + 5 + lineHeight, rect().width(), lineHeight); + buildConfigRect[0] = QRectF(0, textOffset.y() + 4, rect().width(), lineHeight); + buildConfigRect[1] = QRectF(0, textOffset.y() + 4 + lineHeight, rect().width(), lineHeight); painter.setFont(boldFont); QVector splitBuildConfiguration(2); const QString buildConfiguration = defaultAction()->property("subtitle").toString(); diff --git a/src/plugins/coreplugin/fancytabwidget.cpp b/src/plugins/coreplugin/fancytabwidget.cpp index a87041ef579..cc0da7b7533 100644 --- a/src/plugins/coreplugin/fancytabwidget.cpp +++ b/src/plugins/coreplugin/fancytabwidget.cpp @@ -25,6 +25,7 @@ #include "fancytabwidget.h" #include "fancyactionbar.h" +#include "coreconstants.h" #include #include @@ -324,7 +325,10 @@ void FancyTabBar::paintTab(QPainter *painter, int tabIndex) const tabIconRect.adjust(0, 4, 0, -textHeight); const QIcon::Mode iconMode = enabled ? (selected ? QIcon::Active : QIcon::Normal) : QIcon::Disabled; - StyleHelper::drawIconWithShadow(tab->icon, tabIconRect, painter, iconMode); + QRect iconRect(0, 0, Core::Constants::MODEBAR_ICON_SIZE, Core::Constants::MODEBAR_ICON_SIZE); + iconRect.moveCenter(tabIconRect.center()); + iconRect = iconRect.intersected(tabIconRect); + StyleHelper::drawIconWithShadow(tab->icon, iconRect, painter, iconMode); } painter->setOpacity(1.0); //FIXME: was 0.7 before? diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index 3db6a08f26a..9eee8dee632 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -210,8 +210,6 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : this, &SearchResultWidget::handleReplaceButton); connect(m_replaceButton, &QAbstractButton::clicked, this, &SearchResultWidget::handleReplaceButton); - connect(m_replaceTextEdit, &QLineEdit::textChanged, - this, &SearchResultWidget::handleReplaceEditTextChanged); } SearchResultWidget::~SearchResultWidget() @@ -306,7 +304,6 @@ void SearchResultWidget::setSupportsReplace(bool replaceSupported, const QString void SearchResultWidget::setTextToReplace(const QString &textToReplace) { - m_replaceText = textToReplace; m_replaceTextEdit->setText(textToReplace); } @@ -409,6 +406,7 @@ void SearchResultWidget::goToPrevious() void SearchResultWidget::restart() { m_replaceTextEdit->setEnabled(false); + m_replaceButton->setEnabled(false); m_searchResultTreeView->clear(); m_count = 0; Id sizeWarningId(SIZE_WARNING_ID); @@ -418,7 +416,6 @@ void SearchResultWidget::restart() m_searchAgainButton->setVisible(false); m_messageWidget->setVisible(false); updateMatchesFoundLabel(); - handleReplaceEditTextChanged(); emit restarted(); } @@ -439,6 +436,7 @@ void SearchResultWidget::finishSearch(bool canceled) m_infoBar.removeInfo(sizeWarningId); m_infoBar.enableInfo(sizeWarningId); m_replaceTextEdit->setEnabled(m_count > 0); + m_replaceButton->setEnabled(m_count > 0); m_preserveCaseCheck->setEnabled(m_count > 0); m_cancelButton->setVisible(false); m_messageWidget->setVisible(canceled); @@ -463,15 +461,6 @@ void SearchResultWidget::cancelAfterSizeWarning() emit paused(false); } -void SearchResultWidget::handleReplaceEditTextChanged() -{ - const bool enabled = m_replaceTextEdit->text() != m_replaceText; - m_replaceButton->setEnabled(enabled); - m_replaceButton->setToolTip(enabled - ? QString() - : tr("Cannot replace because replacement text is unchanged.")); -} - void SearchResultWidget::handleJumpToSearchResult(const SearchResultItem &item) { emit activated(item); diff --git a/src/plugins/coreplugin/find/searchresultwidget.h b/src/plugins/coreplugin/find/searchresultwidget.h index bf4b9055440..5309ed69e1e 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.h +++ b/src/plugins/coreplugin/find/searchresultwidget.h @@ -115,7 +115,6 @@ private: void setShowReplaceUI(bool visible); void continueAfterSizeWarning(); void cancelAfterSizeWarning(); - void handleReplaceEditTextChanged(); QList checkedItems() const; void updateMatchesFoundLabel(); @@ -142,7 +141,6 @@ private: bool m_isShowingReplaceUI = false; bool m_searchAgainSupported = false; bool m_replaceSupported = false; - QString m_replaceText; }; } // Internal diff --git a/src/plugins/coreplugin/images/mode_Design.png b/src/plugins/coreplugin/images/mode_Design.png index 268376e5fe7..9f155db22ad 100644 Binary files a/src/plugins/coreplugin/images/mode_Design.png and b/src/plugins/coreplugin/images/mode_Design.png differ diff --git a/src/plugins/coreplugin/images/mode_Design@2x.png b/src/plugins/coreplugin/images/mode_Design@2x.png index 85e08c360b8..ce1baa8c7af 100644 Binary files a/src/plugins/coreplugin/images/mode_Design@2x.png and b/src/plugins/coreplugin/images/mode_Design@2x.png differ diff --git a/src/plugins/coreplugin/images/mode_Edit.png b/src/plugins/coreplugin/images/mode_Edit.png index 494f84baa77..fecee991add 100644 Binary files a/src/plugins/coreplugin/images/mode_Edit.png and b/src/plugins/coreplugin/images/mode_Edit.png differ diff --git a/src/plugins/coreplugin/images/mode_Edit@2x.png b/src/plugins/coreplugin/images/mode_Edit@2x.png index d223679dc36..032d37a2223 100644 Binary files a/src/plugins/coreplugin/images/mode_Edit@2x.png and b/src/plugins/coreplugin/images/mode_Edit@2x.png differ diff --git a/src/plugins/coreplugin/images/mode_design_mask.png b/src/plugins/coreplugin/images/mode_design_mask.png index 3225507f81a..42013edf352 100644 Binary files a/src/plugins/coreplugin/images/mode_design_mask.png and b/src/plugins/coreplugin/images/mode_design_mask.png differ diff --git a/src/plugins/coreplugin/images/mode_design_mask@2x.png b/src/plugins/coreplugin/images/mode_design_mask@2x.png index f4eced6284d..2aef9018a8a 100644 Binary files a/src/plugins/coreplugin/images/mode_design_mask@2x.png and b/src/plugins/coreplugin/images/mode_design_mask@2x.png differ diff --git a/src/plugins/coreplugin/images/mode_edit_mask.png b/src/plugins/coreplugin/images/mode_edit_mask.png index 8e2a971f15f..51197249c0a 100644 Binary files a/src/plugins/coreplugin/images/mode_edit_mask.png and b/src/plugins/coreplugin/images/mode_edit_mask.png differ diff --git a/src/plugins/coreplugin/images/mode_edit_mask@2x.png b/src/plugins/coreplugin/images/mode_edit_mask@2x.png index d683f154e0e..389ac6dc4e3 100644 Binary files a/src/plugins/coreplugin/images/mode_edit_mask@2x.png and b/src/plugins/coreplugin/images/mode_edit_mask@2x.png differ diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index 2b68cf74218..0bc3391ce81 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -13,7 +13,6 @@ HEADERS += \ cppeditorplugin.h \ cppeditorwidget.h \ cppelementevaluator.h \ - cppfollowsymbolundercursor.h \ cppfunctiondecldeflink.h \ cpphighlighter.h \ cpphoverhandler.h \ @@ -27,11 +26,8 @@ HEADERS += \ cppquickfix.h \ cppquickfixassistant.h \ cppquickfixes.h \ - cpprefactoringengine.h \ cpptypehierarchy.h \ cppuseselectionsupdater.h \ - cppvirtualfunctionassistprovider.h \ - cppvirtualfunctionproposalitem.h \ resourcepreviewhoverhandler.h SOURCES += \ @@ -43,7 +39,6 @@ SOURCES += \ cppeditorplugin.cpp \ cppeditorwidget.cpp \ cppelementevaluator.cpp \ - cppfollowsymbolundercursor.cpp \ cppfunctiondecldeflink.cpp \ cpphighlighter.cpp \ cpphoverhandler.cpp \ @@ -57,11 +52,8 @@ SOURCES += \ cppquickfix.cpp \ cppquickfixassistant.cpp \ cppquickfixes.cpp \ - cpprefactoringengine.cpp \ cpptypehierarchy.cpp \ cppuseselectionsupdater.cpp \ - cppvirtualfunctionassistprovider.cpp \ - cppvirtualfunctionproposalitem.cpp \ resourcepreviewhoverhandler.cpp FORMS += \ diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index a5c017665a0..5d8b17adb41 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -41,8 +41,6 @@ QtcPlugin { "cppeditorplugin.h", "cppelementevaluator.cpp", "cppelementevaluator.h", - "cppfollowsymbolundercursor.cpp", - "cppfollowsymbolundercursor.h", "cppfunctiondecldeflink.cpp", "cppfunctiondecldeflink.h", "cpphighlighter.cpp", @@ -70,16 +68,10 @@ QtcPlugin { "cppquickfixassistant.h", "cppquickfixes.cpp", "cppquickfixes.h", - "cpprefactoringengine.cpp", - "cpprefactoringengine.h", "cpptypehierarchy.cpp", "cpptypehierarchy.h", "cppuseselectionsupdater.cpp", "cppuseselectionsupdater.h", - "cppvirtualfunctionassistprovider.cpp", - "cppvirtualfunctionassistprovider.h", - "cppvirtualfunctionproposalitem.cpp", - "cppvirtualfunctionproposalitem.h", "resourcepreviewhoverhandler.cpp", "resourcepreviewhoverhandler.h", ] diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index e11b2c8143d..c14bb541bef 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -30,14 +30,12 @@ #include "cppeditorconstants.h" #include "cppeditordocument.h" #include "cppeditorplugin.h" -#include "cppfollowsymbolundercursor.h" #include "cppfunctiondecldeflink.h" #include "cpphighlighter.h" #include "cpplocalrenaming.h" #include "cppminimizableinfobars.h" #include "cpppreprocessordialog.h" #include "cppquickfixassistant.h" -#include "cpprefactoringengine.h" #include "cppuseselectionsupdater.h" #include @@ -63,6 +61,7 @@ #include #include #include +#include #include #include @@ -70,7 +69,6 @@ #include #include #include -#include #include #include #include @@ -82,7 +80,9 @@ #include #include #include +#include #include +#include #include #include @@ -94,6 +94,7 @@ #include #include #include +#include enum { UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200 }; @@ -130,8 +131,6 @@ public: CppLocalRenaming m_localRenaming; CppUseSelectionsUpdater m_useSelectionsUpdater; CppSelectionChanger m_cppSelectionChanger; - FollowSymbolUnderCursor m_builtinFollowSymbol; - CppRefactoringEngine m_builtinRefactoringEngine; }; CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q) @@ -179,9 +178,11 @@ void CppEditorWidget::finalizeInitialization() &CppLocalRenaming::updateSelectionsForVariableUnderCursor); connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, this, - [this] (SemanticInfo::LocalUseMap localUses) { - d->m_lastSemanticInfo.localUsesUpdated = true; - d->m_lastSemanticInfo.localUses = localUses; + [this] (SemanticInfo::LocalUseMap localUses, bool success) { + if (success) { + d->m_lastSemanticInfo.localUsesUpdated = true; + d->m_lastSemanticInfo.localUses = localUses; + } }); connect(document(), &QTextDocument::contentsChange, @@ -362,7 +363,7 @@ void CppEditorWidget::findUsages() } } -void CppEditorWidget::renameUsages(const QString &replacement) +void CppEditorWidget::renameUsagesInternal(const QString &replacement) { if (!d->m_modelManager) return; @@ -477,7 +478,7 @@ ProjectPart *CppEditorWidget::projectPart() const namespace { using ClangBackEnd::V2::SourceLocationContainer; -using TextEditor::Convenience::selectAt; +using Utils::Text::selectAt; QTextCharFormat occurrencesTextCharFormat() { @@ -523,7 +524,7 @@ void CppEditorWidget::renameSymbolUnderCursor() using ClangBackEnd::SourceLocationsContainer; ProjectPart *projPart = projectPart(); - if (!refactoringEngine()->isUsable() || !projPart) + if (!refactoringEngine().isUsable() || !projPart) return; d->m_useSelectionsUpdater.abortSchedule(); @@ -546,13 +547,15 @@ void CppEditorWidget::renameSymbolUnderCursor() setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, selections); d->m_localRenaming.updateSelectionsForVariableUnderCursor(selections); } - if (!d->m_localRenaming.start()) // Rename local symbol - renameUsages(); // Rename non-local symbol or macro + if (!d->m_localRenaming.start()) { + refactoringEngine().startGlobalRenaming( + CppTools::CursorInEditor{textCursor(), textDocument()->filePath(), this}); + } } }; viewport()->setCursor(Qt::BusyCursor); - refactoringEngine()->startLocalRenaming(CppTools::CursorInEditor{textCursor(), + refactoringEngine().startLocalRenaming(CppTools::CursorInEditor{textCursor(), textDocument()->filePath(), this}, projPart, @@ -647,17 +650,8 @@ CppEditorWidget::Link CppEditorWidget::findLinkAt(const QTextCursor &cursor, return Link(); const Utils::FileName &filePath = textDocument()->filePath(); - if (!resolveTarget) { - // TODO: get that part also from clang - return d->m_builtinFollowSymbol.findLink(CppTools::CursorInEditor{cursor, filePath, this}, - resolveTarget, - d->m_modelManager->snapshot(), - d->m_lastSemanticInfo.doc, - d->m_modelManager->symbolFinder(), - inNextSplit); - } - return followSymbolInterface()->findLink(CppTools::CursorInEditor{cursor, filePath, this}, + return followSymbolInterface().findLink(CppTools::CursorInEditor{cursor, filePath, this}, resolveTarget, d->m_modelManager->snapshot(), d->m_lastSemanticInfo.doc, @@ -690,19 +684,14 @@ RefactorMarkers CppEditorWidget::refactorMarkersWithoutClangMarkers() const return clearedRefactorMarkers; } -RefactoringEngineInterface *CppEditorWidget::refactoringEngine() const +RefactoringEngineInterface &CppEditorWidget::refactoringEngine() const { - RefactoringEngineInterface *engine = CppTools::CppModelManager::refactoringEngine(); - return engine ? engine - : static_cast(&d->m_builtinRefactoringEngine); + return CppTools::CppModelManager::refactoringEngine(); } -CppTools::FollowSymbolInterface *CppEditorWidget::followSymbolInterface() const +CppTools::FollowSymbolInterface &CppEditorWidget::followSymbolInterface() const { - CppTools::FollowSymbolInterface *followSymbol - = CppTools::CppModelManager::instance()->followSymbolInterface(); - return followSymbol ? followSymbol - : static_cast(&d->m_builtinFollowSymbol); + return CppTools::CppModelManager::instance()->followSymbolInterface(); } bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const @@ -765,6 +754,20 @@ static void addRefactoringActions(QMenu *menu, AssistInterface *iface) } } +class ProgressIndicatorMenuItem : public QWidgetAction +{ + Q_OBJECT + +public: + ProgressIndicatorMenuItem(QObject *parent) : QWidgetAction(parent) {} + +protected: + QWidget *createWidget(QWidget *parent = nullptr) override + { + return new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small, parent); + } +}; + QMenu *CppEditorWidget::createRefactorMenu(QWidget *parent) const { auto *menu = new QMenu(tr("&Refactor"), parent); @@ -774,8 +777,30 @@ QMenu *CppEditorWidget::createRefactorMenu(QWidget *parent) const // updateSemanticInfo(m_semanticHighlighter->semanticInfo(currentSource())); if (isSemanticInfoValidExceptLocalUses()) { - d->m_useSelectionsUpdater.update(CppUseSelectionsUpdater::CallType::Synchronous); - addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + d->m_useSelectionsUpdater.abortSchedule(); + + const CppUseSelectionsUpdater::RunnerInfo runnerInfo = d->m_useSelectionsUpdater.update(); + switch (runnerInfo) { + case CppUseSelectionsUpdater::RunnerInfo::AlreadyUpToDate: + addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + break; + case CppUseSelectionsUpdater::RunnerInfo::Started: { + // Update the refactor menu once we get the results. + auto *progressIndicatorMenuItem = new ProgressIndicatorMenuItem(menu); + menu->addAction(progressIndicatorMenuItem); + + connect(&d->m_useSelectionsUpdater, &CppUseSelectionsUpdater::finished, + menu, [=] (SemanticInfo::LocalUseMap, bool success) { + QTC_CHECK(success); + menu->removeAction(progressIndicatorMenuItem); + addRefactoringActions(menu, createAssistInterface(QuickFix, ExplicitlyInvoked)); + }); + break; + } + case CppUseSelectionsUpdater::RunnerInfo::FailedToStart: + case CppUseSelectionsUpdater::RunnerInfo::Invalid: + QTC_CHECK(false && "Unexpected CppUseSelectionsUpdater runner result"); + } } return menu; @@ -925,7 +950,7 @@ void CppEditorWidget::onRefactorMarkerClicked(const RefactorMarker &marker) applyDeclDefLinkChanges(true); } else if (isClangFixItAvailableMarker(marker)) { int line, column; - if (Convenience::convertPosition(document(), marker.cursor.position(), &line, &column)) { + if (Utils::Text::convertPosition(document(), marker.cursor.position(), &line, &column)) { setTextCursor(marker.cursor); invokeAssist(TextEditor::QuickFix); } @@ -1048,5 +1073,13 @@ void CppEditorWidget::showPreProcessorWidget() } } +void CppEditorWidget::invokeTextEditorWidgetAssist(TextEditor::AssistKind assistKind, + TextEditor::IAssistProvider *provider) +{ + invokeAssist(assistKind, provider); +} + } // namespace Internal } // namespace CppEditor + +#include "cppeditorwidget.moc" diff --git a/src/plugins/cppeditor/cppeditorwidget.h b/src/plugins/cppeditor/cppeditorwidget.h index d67b1f4b8c4..166ff10557d 100644 --- a/src/plugins/cppeditor/cppeditorwidget.h +++ b/src/plugins/cppeditor/cppeditorwidget.h @@ -27,6 +27,8 @@ #include +#include + #include namespace CppTools { @@ -45,7 +47,8 @@ class CppEditorDocument; class CppEditorWidgetPrivate; class FunctionDeclDefLink; -class CppEditorWidget : public TextEditor::TextEditorWidget +class CppEditorWidget : public TextEditor::TextEditorWidget, + public CppTools::CppEditorWidgetInterface { Q_OBJECT @@ -74,11 +77,10 @@ public: void selectAll() override; void switchDeclarationDefinition(bool inNextSplit); - void showPreProcessorWidget(); + void showPreProcessorWidget() override; void findUsages(); void renameSymbolUnderCursor(); - void renameUsages(const QString &replacement = QString()); bool selectBlockUp() override; bool selectBlockDown() override; @@ -86,9 +88,10 @@ public: static void updateWidgetHighlighting(QWidget *widget, bool highlight); static bool isWidgetHighlighted(QWidget *widget); - void updateSemanticInfo(); + void updateSemanticInfo() override; + void invokeTextEditorWidgetAssist(TextEditor::AssistKind assistKind, + TextEditor::IAssistProvider *provider) override; - CppTools::FollowSymbolInterface *followSymbolInterface() const; protected: bool event(QEvent *e) override; void contextMenuEvent(QContextMenuEvent *) override; @@ -102,6 +105,8 @@ protected: void slotCodeStyleSettingsChanged(const QVariant &) override; + void renameUsagesInternal(const QString &replacement) override; + private: void updateFunctionDeclDefLink(); void updateFunctionDeclDefLinkNow(); @@ -133,7 +138,8 @@ private: TextEditor::RefactorMarkers refactorMarkersWithoutClangMarkers() const; - CppTools::RefactoringEngineInterface *refactoringEngine() const; + CppTools::FollowSymbolInterface &followSymbolInterface() const; + CppTools::RefactoringEngineInterface &refactoringEngine() const; CppTools::ProjectPart *projectPart() const; diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index 75b5913f17b..dcb182435d4 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -32,9 +32,9 @@ #include #include #include -#include #include +#include #include #include @@ -63,7 +63,7 @@ bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int { if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { int line, column; - if (Convenience::convertPosition(editorWidget->document(), pos, &line, &column)) + if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) return processor->hasDiagnosticsAt(line, column); } @@ -77,7 +77,7 @@ void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, { if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { int line, column; - if (Convenience::convertPosition(editorWidget->document(), position, &line, &column)) { + if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) { auto layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(2); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index fc4ed5a2ac6..9f51f15febb 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -29,12 +29,12 @@ #include "cppeditordocument.h" #include "cppfunctiondecldeflink.h" #include "cppquickfixassistant.h" -#include "cppvirtualfunctionassistprovider.h" #include "cppinsertvirtualmethods.h" #include #include +#include #include #include #include diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.cpp b/src/plugins/cppeditor/cppuseselectionsupdater.cpp index a254ed7eae7..da7a7a1d92a 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.cpp +++ b/src/plugins/cppeditor/cppuseselectionsupdater.cpp @@ -29,7 +29,7 @@ #include "cppeditordocument.h" #include -#include +#include #include #include @@ -66,21 +66,21 @@ void CppUseSelectionsUpdater::abortSchedule() m_timer.stop(); } -void CppUseSelectionsUpdater::update(CallType callType) +CppUseSelectionsUpdater::RunnerInfo CppUseSelectionsUpdater::update(CallType callType) { auto *cppEditorWidget = qobject_cast(m_editorWidget); - QTC_ASSERT(cppEditorWidget, return); + QTC_ASSERT(cppEditorWidget, return RunnerInfo::FailedToStart); auto *cppEditorDocument = qobject_cast(cppEditorWidget->textDocument()); - QTC_ASSERT(cppEditorDocument, return); + QTC_ASSERT(cppEditorDocument, return RunnerInfo::FailedToStart); CppTools::CursorInfoParams params; params.semanticInfo = cppEditorWidget->semanticInfo(); - params.textCursor = TextEditor::Convenience::wordStartCursor(cppEditorWidget->textCursor()); + params.textCursor = Utils::Text::wordStartCursor(cppEditorWidget->textCursor()); if (callType == CallType::Asynchronous) { if (isSameIdentifierAsBefore(params.textCursor)) - return; + return RunnerInfo::AlreadyUpToDate; if (m_runnerWatcher) m_runnerWatcher->cancel(); @@ -93,25 +93,28 @@ void CppUseSelectionsUpdater::update(CallType callType) m_runnerWordStartPosition = params.textCursor.position(); m_runnerWatcher->setFuture(cppEditorDocument->cursorInfo(params)); + return RunnerInfo::Started; } else { // synchronous case abortSchedule(); const int startRevision = cppEditorDocument->document()->revision(); QFuture future = cppEditorDocument->cursorInfo(params); if (future.isCanceled()) - return; + return RunnerInfo::Invalid; // QFuture::waitForFinished seems to block completely, not even // allowing to process events from QLocalSocket. while (!future.isFinished()) { if (future.isCanceled()) - return; + return RunnerInfo::Invalid; - QTC_ASSERT(startRevision == cppEditorDocument->document()->revision(), return); + QTC_ASSERT(startRevision == cppEditorDocument->document()->revision(), + return RunnerInfo::Invalid); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } processResults(future.result()); + return RunnerInfo::Invalid; } } @@ -134,18 +137,25 @@ void CppUseSelectionsUpdater::processResults(const CursorInfo &result) updateUnusedSelections(result.unusedVariablesRanges); emit selectionsForVariableUnderCursorUpdated(localVariableSelections); - emit finished(result.localUses); + emit finished(result.localUses, true); } void CppUseSelectionsUpdater::onFindUsesFinished() { - QTC_ASSERT(m_runnerWatcher, return); - if (m_runnerWatcher->isCanceled()) + QTC_ASSERT(m_runnerWatcher, + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return); + + if (m_runnerWatcher->isCanceled()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; - if (m_runnerRevision != m_editorWidget->document()->revision()) + } + if (m_runnerRevision != m_editorWidget->document()->revision()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; + } if (m_runnerWordStartPosition - != TextEditor::Convenience::wordStartCursor(m_editorWidget->textCursor()).position()) { + != Utils::Text::wordStartCursor(m_editorWidget->textCursor()).position()) { + emit finished(CppTools::SemanticInfo::LocalUseMap(), false); return; } diff --git a/src/plugins/cppeditor/cppuseselectionsupdater.h b/src/plugins/cppeditor/cppuseselectionsupdater.h index 7e10eeb680c..ec18b222f45 100644 --- a/src/plugins/cppeditor/cppuseselectionsupdater.h +++ b/src/plugins/cppeditor/cppuseselectionsupdater.h @@ -50,10 +50,11 @@ public: void abortSchedule(); enum class CallType { Synchronous, Asynchronous }; - void update(CallType callType = CallType::Asynchronous); + enum class RunnerInfo { AlreadyUpToDate, Started, FailedToStart, Invalid }; // For async case. + RunnerInfo update(CallType callType = CallType::Asynchronous); signals: - void finished(CppTools::SemanticInfo::LocalUseMap localUses); + void finished(CppTools::SemanticInfo::LocalUseMap localUses, bool success); void selectionsForVariableUnderCursorUpdated(const QList &); private: diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 9c45cea0559..1f7576c49b1 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -28,10 +28,10 @@ #include "cppeditorplugin.h" #include "cppeditortestcase.h" #include "cppelementevaluator.h" -#include "cppfollowsymbolundercursor.h" -#include "cppvirtualfunctionassistprovider.h" -#include "cppvirtualfunctionproposalitem.h" +#include +#include +#include #include #include @@ -327,10 +327,8 @@ F2TestCase::F2TestCase(CppEditorAction action, switch (action) { case FollowSymbolUnderCursorAction: { CppEditorWidget *widget = initialTestFile->m_editorWidget; - FollowSymbolInterface* delegate = widget->followSymbolInterface(); - if (!delegate) - QFAIL("No follow symbol interface"); - auto* builtinFollowSymbol = dynamic_cast(delegate); + FollowSymbolInterface &delegate = CppModelManager::instance()->followSymbolInterface(); + auto* builtinFollowSymbol = dynamic_cast(&delegate); if (!builtinFollowSymbol) { if (filePaths.size() > 1) QSKIP("Clang FollowSymbol does not currently support multiple files (except cpp+header)"); diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h index 342979dae35..1ac31a6ebc8 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.h +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -76,7 +76,7 @@ public: virtual void setParserConfig(const BaseEditorDocumentParser::Configuration config); virtual QFuture cursorInfo(const CursorInfoParams ¶ms) = 0; - virtual QFuture requestFollowSymbol(int line, int column, bool resolveTarget) = 0; + virtual QFuture requestFollowSymbol(int line, int column) = 0; public: using HeaderErrorDiagnosticWidgetCreator = std::function; diff --git a/src/plugins/cpptools/builtincursorinfo.cpp b/src/plugins/cpptools/builtincursorinfo.cpp index 8902fa05ca9..17f40c7d26d 100644 --- a/src/plugins/cpptools/builtincursorinfo.cpp +++ b/src/plugins/cpptools/builtincursorinfo.cpp @@ -32,12 +32,11 @@ #include "cppsemanticinfo.h" #include "cpptoolsreuse.h" -#include - #include #include #include +#include #include #include @@ -346,8 +345,7 @@ QFuture BuiltinCursorInfo::run(const CursorInfoParams &cursorInfoPar const QTextCursor &textCursor = cursorInfoParams.textCursor; int line, column; - TextEditor::Convenience::convertPosition(textCursor.document(), textCursor.position(), - &line, &column); + Utils::Text::convertPosition(textCursor.document(), textCursor.position(), &line, &column); CanonicalSymbol canonicalSymbol(document, snapshot); QString expression; Scope *scope = canonicalSymbol.getScopeAndExpression(textCursor, &expression); diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.cpp b/src/plugins/cpptools/builtineditordocumentprocessor.cpp index 95f4932e085..bfdabe53629 100644 --- a/src/plugins/cpptools/builtineditordocumentprocessor.cpp +++ b/src/plugins/cpptools/builtineditordocumentprocessor.cpp @@ -33,7 +33,6 @@ #include "cpptoolsreuse.h" #include "cppworkingcopy.h" -#include #include #include #include @@ -41,6 +40,7 @@ #include #include +#include #include #include @@ -105,7 +105,7 @@ CppTools::CheckSymbols *createHighlighter(const CPlusPlus::Document::Ptr &doc, typedef TextEditor::HighlightingResult Result; QList macroUses; - using TextEditor::Convenience::convertPosition; + using Utils::Text::convertPosition; // Get macro definitions foreach (const CPlusPlus::Macro& macro, doc->definedMacros()) { diff --git a/src/plugins/cpptools/builtineditordocumentprocessor.h b/src/plugins/cpptools/builtineditordocumentprocessor.h index 7d3d96f992f..800bff085a6 100644 --- a/src/plugins/cpptools/builtineditordocumentprocessor.h +++ b/src/plugins/cpptools/builtineditordocumentprocessor.h @@ -52,7 +52,7 @@ public: bool isParserRunning() const override; QFuture cursorInfo(const CursorInfoParams ¶ms) override; - QFuture requestFollowSymbol(int, int, bool) override + QFuture requestFollowSymbol(int, int) override { return QFuture(); } private: diff --git a/src/plugins/cpptools/clangcompileroptionsbuilder.cpp b/src/plugins/cpptools/clangcompileroptionsbuilder.cpp index 160bf6b4c6c..0b2209cc628 100644 --- a/src/plugins/cpptools/clangcompileroptionsbuilder.cpp +++ b/src/plugins/cpptools/clangcompileroptionsbuilder.cpp @@ -26,7 +26,6 @@ #include "clangcompileroptionsbuilder.h" #include - #include #include @@ -37,6 +36,15 @@ namespace CppTools { static QString creatorResourcePath() { +#ifndef UNIT_TESTS + return Core::ICore::instance()->resourcePath(); +#else + return QString(); +#endif +} + +static QString creatorLibexecPath() +{ #ifndef UNIT_TESTS return Core::ICore::instance()->libexecPath(); #else @@ -44,40 +52,31 @@ static QString creatorResourcePath() #endif } -QStringList ClangCompilerOptionsBuilder::build(const CppTools::ProjectPart *projectPart, - CppTools::ProjectFile::Kind fileKind, - PchUsage pchUsage, - const QString &clangVersion, - const QString &clangResourceDirectory) +QStringList ClangCompilerOptionsBuilder::build(CppTools::ProjectFile::Kind fileKind, + PchUsage pchUsage) { - if (projectPart) { - ClangCompilerOptionsBuilder builder(*projectPart, clangVersion, clangResourceDirectory); + addWordWidth(); + addTargetTriple(); + addLanguageOption(fileKind); + addOptionsForLanguage(/*checkForBorlandExtensions*/ true); + enableExceptions(); - builder.addWordWidth(); - builder.addTargetTriple(); - builder.addLanguageOption(fileKind); - builder.addOptionsForLanguage(/*checkForBorlandExtensions*/ true); - builder.enableExceptions(); + addDefineFloat128ForMingw(); + addToolchainAndProjectMacros(); + undefineClangVersionMacrosForMsvc(); + undefineCppLanguageFeatureMacrosForMsvc2015(); - builder.addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - builder.addDefineFloat128ForMingw(); - builder.addToolchainAndProjectDefines(); - builder.undefineCppLanguageFeatureMacrosForMsvc2015(); + addPredefinedHeaderPathsOptions(); + addWrappedQtHeadersIncludePath(); + addPrecompiledHeaderOptions(pchUsage); + addHeaderPathOptions(); + addProjectConfigFileInclude(); - builder.addPredefinedMacrosAndHeaderPathsOptions(); - builder.addWrappedQtHeadersIncludePath(); - builder.addPrecompiledHeaderOptions(pchUsage); - builder.addHeaderPathOptions(); - builder.addProjectConfigFileInclude(); + addMsvcCompatibilityVersion(); - builder.addMsvcCompatibilityVersion(); + addExtraOptions(); - builder.addExtraOptions(); - - return builder.options(); - } - - return QStringList(); + return options(); } ClangCompilerOptionsBuilder::ClangCompilerOptionsBuilder(const CppTools::ProjectPart &projectPart, @@ -91,47 +90,35 @@ ClangCompilerOptionsBuilder::ClangCompilerOptionsBuilder(const CppTools::Project bool ClangCompilerOptionsBuilder::excludeHeaderPath(const QString &path) const { - if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID) { - if (path.contains("lib/gcc/i686-apple-darwin")) - return true; + if (m_projectPart.toolchainType == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID + && path.contains("lib/gcc/i686-apple-darwin")) { + return true; } return CompilerOptionsBuilder::excludeHeaderPath(path); } -void ClangCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptions() +void ClangCompilerOptionsBuilder::addPredefinedHeaderPathsOptions() { - if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) - addPredefinedMacrosAndHeaderPathsOptionsForMsvc(); - else - addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc(); -} - -void ClangCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptionsForMsvc() -{ - add("-nostdinc"); add("-undef"); -} + add("-nostdinc"); + add("-nostdlibinc"); -void ClangCompilerOptionsBuilder::addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc() -{ - static const QString resourceDir = clangIncludeDirectory(); - if (QTC_GUARD(!resourceDir.isEmpty())) { - add("-nostdlibinc"); - add("-I" + QDir::toNativeSeparators(resourceDir)); - add("-undef"); - } + if (m_projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) + add(includeDirOption() + clangIncludeDirectory()); } void ClangCompilerOptionsBuilder::addWrappedQtHeadersIncludePath() { - static const QString wrappedQtHeadersPath = creatorResourcePath() - + "/cplusplus/wrappedQtHeaders"; + static const QString resourcePath = creatorResourcePath(); + static QString wrappedQtHeadersPath = resourcePath + "/cplusplus/wrappedQtHeaders"; + QDir dir(wrappedQtHeadersPath); + QTC_ASSERT(QDir(wrappedQtHeadersPath).exists(), return;); if (m_projectPart.qtVersion != CppTools::ProjectPart::NoQt) { const QString wrappedQtCoreHeaderPath = wrappedQtHeadersPath + "/QtCore"; - add("-I" + QDir::toNativeSeparators(wrappedQtHeadersPath)); - add("-I" + QDir::toNativeSeparators(wrappedQtCoreHeaderPath)); + add(includeDirOption() + QDir::toNativeSeparators(wrappedQtHeadersPath)); + add(includeDirOption() + QDir::toNativeSeparators(wrappedQtCoreHeaderPath)); } } @@ -154,12 +141,26 @@ void ClangCompilerOptionsBuilder::addExtraOptions() QString ClangCompilerOptionsBuilder::clangIncludeDirectory() const { - QDir dir(creatorResourcePath() + "/clang/lib/clang/" + m_clangVersion + "/include"); - + QDir dir(creatorLibexecPath() + "/clang/lib/clang/" + m_clangVersion + "/include"); if (!dir.exists() || !QFileInfo(dir, "stdint.h").exists()) dir = QDir(m_clangResourceDirectory); + return QDir::toNativeSeparators(dir.canonicalPath()); +} - return dir.canonicalPath(); +void ClangCompilerOptionsBuilder::undefineClangVersionMacrosForMsvc() +{ + if (m_projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { + static QStringList macroNames { + "__clang__", + "__clang_major__", + "__clang_minor__", + "__clang_patchlevel__", + "__clang_version__" + }; + + foreach (const QString ¯oName, macroNames) + add(undefineOption() + macroName); + } } } // namespace CppTools diff --git a/src/plugins/cpptools/clangcompileroptionsbuilder.h b/src/plugins/cpptools/clangcompileroptionsbuilder.h index 4dadb6bed96..fbe2a5baad2 100644 --- a/src/plugins/cpptools/clangcompileroptionsbuilder.h +++ b/src/plugins/cpptools/clangcompileroptionsbuilder.h @@ -34,33 +34,24 @@ namespace CppTools { class CPPTOOLS_EXPORT ClangCompilerOptionsBuilder : public CompilerOptionsBuilder { public: - static QStringList build(const ProjectPart *projectPart, - ProjectFile::Kind fileKind, - PchUsage pchUsage, - const QString &clangVersion, - const QString &clangResourceDirectory); + QStringList build(ProjectFile::Kind fileKind, + PchUsage pchUsage); ClangCompilerOptionsBuilder(const ProjectPart &projectPart, - const QString &clangVersion, - const QString &clangResourceDirectory); + const QString &clangVersion = QString(), + const QString &clangResourceDirectory = QString()); + + virtual void addPredefinedHeaderPathsOptions(); + virtual void addExtraOptions(); bool excludeHeaderPath(const QString &path) const override; - void addPredefinedMacrosAndHeaderPathsOptions(); - - void addPredefinedMacrosAndHeaderPathsOptionsForMsvc(); - - void addPredefinedMacrosAndHeaderPathsOptionsForNonMsvc(); - - void addWrappedQtHeadersIncludePath(); - + virtual void addWrappedQtHeadersIncludePath(); void addProjectConfigFileInclude(); - void addExtraOptions(); + void undefineClangVersionMacrosForMsvc(); private: QString clangIncludeDirectory() const; - -private: QString m_clangVersion; QString m_clangResourceDirectory; }; diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index 079f76fc6aa..88a85e17cda 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -125,7 +125,7 @@ void CompilerOptionsBuilder::addPrecompiledHeaderOptions(PchUsage pchUsage) m_options.append(result); } -void CompilerOptionsBuilder::addToolchainAndProjectDefines() +void CompilerOptionsBuilder::addToolchainAndProjectMacros() { addMacros(m_projectPart.toolChainMacros); addMacros(m_projectPart.projectMacros); @@ -258,21 +258,6 @@ void CompilerOptionsBuilder::addOptionsForLanguage(bool checkForBorlandExtension m_options.append(opts); } -void CompilerOptionsBuilder::addDefineToAvoidIncludingGccOrMinGwIntrinsics() -{ - // In gcc headers, lots of built-ins are referenced that clang does not understand. - // Therefore, prevent the inclusion of the header that references them. Of course, this - // will break if code actually requires stuff from there, but that should be the less common - // case. - - const Core::Id type = m_projectPart.toolchainType; - if (type == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID - || type == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID) { - addDefine({"_X86INTRIN_H_INCLUDED"}); - addDefine({"BOOST_UUID_NO_SIMD"}); - } -} - static QByteArray toMsCompatibilityVersionFormat(const QByteArray &mscFullVer) { return mscFullVer.left(2) diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 48c23b3e912..8ca985dc28c 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -54,13 +54,11 @@ public: virtual void enableExceptions(); void addHeaderPathOptions(); void addPrecompiledHeaderOptions(PchUsage pchUsage); - void addToolchainAndProjectDefines(); + void addToolchainAndProjectMacros(); void addMacros(const ProjectExplorer::Macros ¯os); virtual void addLanguageOption(ProjectFile::Kind fileKind); virtual void addOptionsForLanguage(bool checkForBorlandExtensions = true); - void addDefineToAvoidIncludingGccOrMinGwIntrinsics(); - void addMsvcCompatibilityVersion(); void undefineCppLanguageFeatureMacrosForMsvc2015(); diff --git a/src/plugins/cpptools/cppcanonicalsymbol.cpp b/src/plugins/cpptools/cppcanonicalsymbol.cpp index 0532ae8b2d2..3f1869de63b 100644 --- a/src/plugins/cpptools/cppcanonicalsymbol.cpp +++ b/src/plugins/cpptools/cppcanonicalsymbol.cpp @@ -26,10 +26,11 @@ #include "cppcanonicalsymbol.h" #include -#include #include +#include + #include #include @@ -58,7 +59,7 @@ Scope *CanonicalSymbol::getScopeAndExpression(const QTextCursor &cursor, QString QTextCursor tc = cursor; int line, column; - TextEditor::Convenience::convertPosition(cursor.document(), tc.position(), &line, &column); + Utils::Text::convertPosition(cursor.document(), tc.position(), &line, &column); ++column; // 1-based line and 1-based column int pos = tc.position(); diff --git a/src/plugins/cpptools/cppcompletion_test.cpp b/src/plugins/cpptools/cppcompletion_test.cpp index b4944763515..147ae4e4554 100644 --- a/src/plugins/cpptools/cppcompletion_test.cpp +++ b/src/plugins/cpptools/cppcompletion_test.cpp @@ -30,12 +30,12 @@ #include "cpptoolstestcase.h" #include -#include #include #include #include #include +#include #include #include @@ -127,8 +127,7 @@ public: const int pos = proposal.d->basePosition(); const int length = m_position - pos; - const QString prefix = Convenience::textAt(QTextCursor(m_textDocument), pos, - length); + const QString prefix = Utils::Text::textAt(QTextCursor(m_textDocument), pos, length); if (!prefix.isEmpty()) listmodel->filter(prefix); if (listmodel->isSortable(prefix)) diff --git a/src/plugins/cpptools/cppcompletionassist.cpp b/src/plugins/cpptools/cppcompletionassist.cpp index 3e1c19399e6..9b7cdc45127 100644 --- a/src/plugins/cpptools/cppcompletionassist.cpp +++ b/src/plugins/cpptools/cppcompletionassist.cpp @@ -38,11 +38,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -1091,7 +1091,7 @@ int InternalCppCompletionAssistProcessor::startCompletionHelper() } int line = 0, column = 0; - Convenience::convertPosition(m_interface->textDocument(), startOfExpression, &line, &column); + Utils::Text::convertPosition(m_interface->textDocument(), startOfExpression, &line, &column); const QString fileName = m_interface->fileName(); return startCompletionInternal(fileName, line, column, expression, endOfExpression); } @@ -1124,7 +1124,8 @@ bool InternalCppCompletionAssistProcessor::tryObjCCompletion() m_model->m_typeOfExpression->init(thisDocument, m_interface->snapshot()); int line = 0, column = 0; - Convenience::convertPosition(m_interface->textDocument(), m_interface->position(), &line, &column); + Utils::Text::convertPosition(m_interface->textDocument(), m_interface->position(), &line, + &column); Scope *scope = thisDocument->scopeAt(line, column); if (!scope) return false; @@ -2014,7 +2015,8 @@ bool InternalCppCompletionAssistProcessor::completeConstructorOrFunction(const Q // get current line and column int lineSigned = 0, columnSigned = 0; - Convenience::convertPosition(m_interface->textDocument(), m_interface->position(), &lineSigned, &columnSigned); + Utils::Text::convertPosition(m_interface->textDocument(), m_interface->position(), + &lineSigned, &columnSigned); unsigned line = lineSigned, column = columnSigned; // find a scope that encloses the current location, starting from the lastVisibileSymbol diff --git a/src/plugins/valgrind/memcheckengine.h b/src/plugins/cpptools/cppeditorwidgetinterface.h similarity index 54% rename from src/plugins/valgrind/memcheckengine.h rename to src/plugins/cpptools/cppeditorwidgetinterface.h index 6113390e91c..309fa581cdd 100644 --- a/src/plugins/valgrind/memcheckengine.h +++ b/src/plugins/cpptools/cppeditorwidgetinterface.h @@ -1,7 +1,6 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. -** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com) ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -26,44 +25,30 @@ #pragma once -#include "valgrindengine.h" +#include "cpptools_global.h" -#include "valgrindrunner.h" -#include "xmlprotocol/threadedparser.h" +#include -#include +#include -namespace Valgrind { -namespace Internal { +namespace TextEditor { class IAssistProvider; } -class MemcheckToolRunner : public ValgrindToolRunner +namespace CppTools { + +class CPPTOOLS_EXPORT CppEditorWidgetInterface { - Q_OBJECT - public: - explicit MemcheckToolRunner(ProjectExplorer::RunControl *runControl, - bool withGdb = false); + void renameUsages(const QString &replacement = QString()) + { + return renameUsagesInternal(replacement); + } - void start() override; - void stop() override; + virtual void showPreProcessorWidget() = 0; + virtual void updateSemanticInfo() = 0; + virtual void renameUsagesInternal(const QString &replacement) = 0; - QStringList suppressionFiles() const; - -signals: - void internalParserError(const QString &errorString); - void parserError(const Valgrind::XmlProtocol::Error &error); - void suppressionCount(const QString &name, qint64 count); - -private: - QString progressTitle() const override; - QStringList toolArguments() const override; - - void startDebugger(qint64 valgrindPid); - void appendLog(const QByteArray &data); - - const bool m_withGdb; - QHostAddress m_localServerAddress; + virtual void invokeTextEditorWidgetAssist(TextEditor::AssistKind assistKind, + TextEditor::IAssistProvider *provider) = 0; }; -} // namespace Internal -} // namespace Valgrind +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp similarity index 95% rename from src/plugins/cppeditor/cppfollowsymbolundercursor.cpp rename to src/plugins/cpptools/cppfollowsymbolundercursor.cpp index 6bc1cfa30e3..ed82a3f9a84 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp @@ -24,9 +24,11 @@ ****************************************************************************/ #include "cppfollowsymbolundercursor.h" -#include "cppeditorwidget.h" -#include "cppeditordocument.h" #include "cppvirtualfunctionassistprovider.h" +#include "cppmodelmanager.h" +#include "functionutils.h" +#include "cpptoolsreuse.h" +#include "symbolfinder.h" #include #include @@ -34,25 +36,20 @@ #include #include #include -#include -#include -#include -#include #include -#include +#include #include #include #include using namespace CPlusPlus; -using namespace CppTools; -using namespace CppEditor; -using namespace CppEditor::Internal; using namespace TextEditor; typedef TextEditorWidget::Link Link; +namespace CppTools { + namespace { class VirtualFunctionHelper { @@ -299,9 +296,9 @@ inline LookupItem skipForwardDeclarations(const QList &resolvedSymbo return result; } -CppEditorWidget::Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot, - const Document::Ptr &document, - SymbolFinder *symbolFinder) +Link attemptFuncDeclDef(const QTextCursor &cursor, Snapshot snapshot, + const Document::Ptr &document, + SymbolFinder *symbolFinder) { Link result; QTC_ASSERT(document, return result); @@ -496,8 +493,7 @@ Link FollowSymbolUnderCursor::findLink( int lineNumber = 0, positionInBlock = 0; QTextCursor cursor = data.cursor(); QTextDocument *document = cursor.document(); - TextEditor::Convenience::convertPosition(document, cursor.position(), &lineNumber, - &positionInBlock); + Utils::Text::convertPosition(document, cursor.position(), &lineNumber, &positionInBlock); const unsigned line = lineNumber; const unsigned column = positionInBlock + 1; @@ -610,11 +606,11 @@ Link FollowSymbolUnderCursor::findLink( } } - CppEditorWidget *editorWidget = static_cast(data.editorWidget()); + CppEditorWidgetInterface *editorWidget = data.editorWidget(); if (!editorWidget) return link; // Now we prefer the doc from the snapshot with macros expanded. - Document::Ptr doc = snapshot.document(editorWidget->textDocument()->filePath()); + Document::Ptr doc = snapshot.document(data.filePath()); if (!doc) { doc = documentFromSemanticInfo; if (!doc) @@ -697,7 +693,7 @@ Link FollowSymbolUnderCursor::findLink( if (Symbol *d = r.declaration()) { if (d->isDeclaration() || d->isFunction()) { const QString fileName = QString::fromUtf8(d->fileName(), d->fileNameLength()); - if (editorWidget->textDocument()->filePath().toString() == fileName) { + if (data.filePath().toString() == fileName) { if (unsigned(lineNumber) == d->line() && unsigned(positionInBlock) >= d->column()) { // TODO: check the end result = r; // take the symbol under cursor. @@ -706,8 +702,8 @@ Link FollowSymbolUnderCursor::findLink( } } else if (d->isUsingDeclaration()) { int tokenBeginLineNumber = 0, tokenBeginColumnNumber = 0; - editorWidget->convertPosition(beginOfToken, &tokenBeginLineNumber, - &tokenBeginColumnNumber); + Utils::Text::convertPosition(document, beginOfToken, &tokenBeginLineNumber, + &tokenBeginColumnNumber); if (unsigned(tokenBeginLineNumber) > d->line() || (unsigned(tokenBeginLineNumber) == d->line() && unsigned(tokenBeginColumnNumber) > d->column())) { @@ -736,7 +732,8 @@ Link FollowSymbolUnderCursor::findLink( params.openInNextSplit = inNextSplit; if (m_virtualFunctionAssistProvider->configure(params)) { - editorWidget->invokeAssist(FollowSymbol, m_virtualFunctionAssistProvider.data()); + editorWidget->invokeTextEditorWidgetAssist( + FollowSymbol,m_virtualFunctionAssistProvider.data()); m_virtualFunctionAssistProvider->clearParams(); } @@ -795,3 +792,5 @@ void FollowSymbolUnderCursor::setVirtualFunctionAssistProvider( { m_virtualFunctionAssistProvider = provider; } + +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppfollowsymbolundercursor.h b/src/plugins/cpptools/cppfollowsymbolundercursor.h similarity index 90% rename from src/plugins/cppeditor/cppfollowsymbolundercursor.h rename to src/plugins/cpptools/cppfollowsymbolundercursor.h index 54c500aaa5b..8e93a7097d6 100644 --- a/src/plugins/cppeditor/cppfollowsymbolundercursor.h +++ b/src/plugins/cpptools/cppfollowsymbolundercursor.h @@ -25,14 +25,13 @@ #pragma once -#include +#include "followsymbolinterface.h" -namespace CppEditor { -namespace Internal { +namespace CppTools { class VirtualFunctionAssistProvider; -class FollowSymbolUnderCursor : public CppTools::FollowSymbolInterface +class CPPTOOLS_EXPORT FollowSymbolUnderCursor : public CppTools::FollowSymbolInterface { public: FollowSymbolUnderCursor(); @@ -52,5 +51,4 @@ private: QSharedPointer m_virtualFunctionAssistProvider; }; -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 5a6db12be0b..da453017822 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -33,6 +33,7 @@ #include "cppindexingsupport.h" #include "cppmodelmanagersupportinternal.h" #include "cpprefactoringchanges.h" +#include "cpprefactoringengine.h" #include "cppsourceprocessor.h" #include "cpptoolsconstants.h" #include "cpptoolsplugin.h" @@ -165,7 +166,8 @@ public: QTimer m_delayedGcTimer; // Refactoring - RefactoringEngineInterface *m_refactoringEngine = nullptr; + CppRefactoringEngine m_builtInRefactoringEngine; + RefactoringEngineInterface *m_refactoringEngine { &m_builtInRefactoringEngine }; }; } // namespace Internal @@ -267,15 +269,18 @@ QString CppModelManager::editorConfigurationFileName() void CppModelManager::setRefactoringEngine(RefactoringEngineInterface *refactoringEngine) { - instance()->d->m_refactoringEngine = refactoringEngine; + if (refactoringEngine) + instance()->d->m_refactoringEngine = refactoringEngine; + else + instance()->d->m_refactoringEngine = &instance()->d->m_builtInRefactoringEngine; } -RefactoringEngineInterface *CppModelManager::refactoringEngine() +RefactoringEngineInterface &CppModelManager::refactoringEngine() { - return instance()->d->m_refactoringEngine; + return *instance()->d->m_refactoringEngine; } -FollowSymbolInterface *CppModelManager::followSymbolInterface() const +FollowSymbolInterface &CppModelManager::followSymbolInterface() const { return d->m_activeModelManagerSupport->followSymbolInterface(); } diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 229cfcef7de..df04beec3a1 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -153,7 +153,7 @@ public: CppCompletionAssistProvider *completionAssistProvider() const; BaseEditorDocumentProcessor *editorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const; - FollowSymbolInterface *followSymbolInterface() const; + FollowSymbolInterface &followSymbolInterface() const; void setIndexingSupport(CppIndexingSupport *indexingSupport); CppIndexingSupport *indexingSupport(); @@ -180,7 +180,7 @@ public: static QString editorConfigurationFileName(); static void setRefactoringEngine(RefactoringEngineInterface *refactoringEngine); - static RefactoringEngineInterface *refactoringEngine(); + static RefactoringEngineInterface &refactoringEngine(); void renameIncludes(const QString &oldFileName, const QString &newFileName); diff --git a/src/plugins/cpptools/cppmodelmanagersupport.h b/src/plugins/cpptools/cppmodelmanagersupport.h index 0a56de102c9..cb74f00efdd 100644 --- a/src/plugins/cpptools/cppmodelmanagersupport.h +++ b/src/plugins/cpptools/cppmodelmanagersupport.h @@ -49,7 +49,7 @@ public: virtual CppCompletionAssistProvider *completionAssistProvider() = 0; virtual BaseEditorDocumentProcessor *editorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) = 0; - virtual FollowSymbolInterface *followSymbolInterface() = 0; + virtual FollowSymbolInterface &followSymbolInterface() = 0; }; class CPPTOOLS_EXPORT ModelManagerSupportProvider diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp index a7c48674c9c..c03e2ed57e9 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.cpp @@ -25,6 +25,7 @@ #include "cppcompletionassist.h" #include "cppmodelmanagersupportinternal.h" +#include "cppfollowsymbolundercursor.h" #include "builtineditordocumentprocessor.h" #include @@ -51,7 +52,8 @@ ModelManagerSupport::Ptr ModelManagerSupportProviderInternal::createModelManager } ModelManagerSupportInternal::ModelManagerSupportInternal() - : m_completionAssistProvider(new InternalCompletionAssistProvider) + : m_completionAssistProvider(new InternalCompletionAssistProvider), + m_followSymbol(new FollowSymbolUnderCursor) { } @@ -70,7 +72,7 @@ CppCompletionAssistProvider *ModelManagerSupportInternal::completionAssistProvid return m_completionAssistProvider.data(); } -FollowSymbolInterface *ModelManagerSupportInternal::followSymbolInterface() +FollowSymbolInterface &ModelManagerSupportInternal::followSymbolInterface() { - return nullptr; + return *m_followSymbol; } diff --git a/src/plugins/cpptools/cppmodelmanagersupportinternal.h b/src/plugins/cpptools/cppmodelmanagersupportinternal.h index fba0cb23e3c..cd35ea5abce 100644 --- a/src/plugins/cpptools/cppmodelmanagersupportinternal.h +++ b/src/plugins/cpptools/cppmodelmanagersupportinternal.h @@ -40,13 +40,14 @@ public: ModelManagerSupportInternal(); virtual ~ModelManagerSupportInternal(); - virtual CppCompletionAssistProvider *completionAssistProvider(); - virtual BaseEditorDocumentProcessor *editorDocumentProcessor( - TextEditor::TextDocument *baseTextDocument); - FollowSymbolInterface *followSymbolInterface() override; + CppCompletionAssistProvider *completionAssistProvider() final; + BaseEditorDocumentProcessor *editorDocumentProcessor( + TextEditor::TextDocument *baseTextDocument) final; + FollowSymbolInterface &followSymbolInterface() final; private: QScopedPointer m_completionAssistProvider; + QScopedPointer m_followSymbol; }; class ModelManagerSupportProviderInternal : public ModelManagerSupportProvider diff --git a/src/plugins/cppeditor/cpprefactoringengine.cpp b/src/plugins/cpptools/cpprefactoringengine.cpp similarity index 82% rename from src/plugins/cppeditor/cpprefactoringengine.cpp rename to src/plugins/cpptools/cpprefactoringengine.cpp index 06ad6bd2c15..705a8ecc99e 100644 --- a/src/plugins/cppeditor/cpprefactoringengine.cpp +++ b/src/plugins/cpptools/cpprefactoringengine.cpp @@ -24,18 +24,17 @@ ****************************************************************************/ #include "cpprefactoringengine.h" -#include "cppeditorwidget.h" +#include "texteditor/texteditor.h" #include "utils/qtcassert.h" -namespace CppEditor { -namespace Internal { +namespace CppTools { void CppRefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &data, CppTools::ProjectPart *, RenameCallback &&renameSymbolsCallback) { - CppEditorWidget *editorWidget = static_cast(data.editorWidget()); + CppEditorWidgetInterface *editorWidget = data.editorWidget(); QTC_ASSERT(editorWidget, renameSymbolsCallback(QString(), ClangBackEnd::SourceLocationsContainer(), 0); return;); @@ -43,8 +42,14 @@ void CppRefactoringEngine::startLocalRenaming(const CppTools::CursorInEditor &da // Call empty callback renameSymbolsCallback(QString(), ClangBackEnd::SourceLocationsContainer(), - editorWidget->document()->revision()); + data.cursor().document()->revision()); +} + +void CppRefactoringEngine::startGlobalRenaming(const CppTools::CursorInEditor &data) +{ + CppEditorWidgetInterface *editorWidget = data.editorWidget(); + QTC_ASSERT(editorWidget, return;); + editorWidget->renameUsages(); } -} // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cppeditor/cpprefactoringengine.h b/src/plugins/cpptools/cpprefactoringengine.h similarity index 87% rename from src/plugins/cppeditor/cpprefactoringengine.h rename to src/plugins/cpptools/cpprefactoringengine.h index 380c537b3d8..acbf02e5e65 100644 --- a/src/plugins/cppeditor/cpprefactoringengine.h +++ b/src/plugins/cpptools/cpprefactoringengine.h @@ -25,22 +25,19 @@ #pragma once -#include +#include "refactoringengineinterface.h" -namespace CppEditor { -namespace Internal { +namespace CppTools { -class CppEditorWidget; - -class CppRefactoringEngine : public CppTools::RefactoringEngineInterface +class CPPTOOLS_EXPORT CppRefactoringEngine : public RefactoringEngineInterface { public: void startLocalRenaming(const CppTools::CursorInEditor &data, CppTools::ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback) override; + void startGlobalRenaming(const CppTools::CursorInEditor &data) override; bool isUsable() const override { return true; } }; -} // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cpptools/cppselectionchanger.cpp b/src/plugins/cpptools/cppselectionchanger.cpp index cee56aa21f5..5ac29f97cac 100644 --- a/src/plugins/cpptools/cppselectionchanger.cpp +++ b/src/plugins/cpptools/cppselectionchanger.cpp @@ -25,7 +25,7 @@ #include "cppselectionchanger.h" -#include +#include #include #include @@ -34,7 +34,7 @@ #include using namespace CPlusPlus; -using namespace TextEditor::Convenience; +using namespace Utils::Text; enum { debug = false diff --git a/src/plugins/cpptools/cppsymbolinfo.h b/src/plugins/cpptools/cppsymbolinfo.h index 17d2713bc37..dcd00dd3c21 100644 --- a/src/plugins/cpptools/cppsymbolinfo.h +++ b/src/plugins/cpptools/cppsymbolinfo.h @@ -39,7 +39,6 @@ public: int endLine = 0; int endColumn = 0; QString fileName; - bool failedToFollow = false; }; } // namespace CppTools diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 20ed13d4cff..c9ca4e4c18d 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -29,11 +29,13 @@ HEADERS += \ cppcompletionassistprovider.h \ cppcursorinfo.h \ cppcurrentdocumentfilter.h \ - cppeditoroutline.h \ cppdoxygen.h \ + cppeditoroutline.h \ + cppeditorwidgetinterface.h \ cppfileiterationorder.h \ cppfilesettingspage.h \ cppfindreferences.h \ + cppfollowsymbolundercursor.h \ cppfunctionsfilter.h \ cppincludesfilter.h \ cppindexingsupport.h \ @@ -49,6 +51,7 @@ HEADERS += \ cppqtstyleindenter.h \ cpprawprojectpart.h \ cpprefactoringchanges.h \ + cpprefactoringengine.h \ cppselectionchanger.h \ cppsemanticinfo.h \ cppsemanticinfoupdater.h \ @@ -60,6 +63,8 @@ HEADERS += \ cpptoolsplugin.h \ cpptoolsreuse.h \ cpptoolssettings.h \ + cppvirtualfunctionassistprovider.h \ + cppvirtualfunctionproposalitem.h \ cppworkingcopy.h \ doxygengenerator.h \ editordocumenthandle.h \ @@ -123,6 +128,7 @@ SOURCES += \ cppfileiterationorder.cpp \ cppfilesettingspage.cpp \ cppfindreferences.cpp \ + cppfollowsymbolundercursor.cpp \ cppfunctionsfilter.cpp \ cppincludesfilter.cpp \ cppindexingsupport.cpp \ @@ -138,6 +144,7 @@ SOURCES += \ cppqtstyleindenter.cpp \ cpprawprojectpart.cpp \ cpprefactoringchanges.cpp \ + cpprefactoringengine.cpp \ cppselectionchanger.cpp \ cppsemanticinfoupdater.cpp \ cppsourceprocessor.cpp \ @@ -145,6 +152,8 @@ SOURCES += \ cpptoolsplugin.cpp \ cpptoolsreuse.cpp \ cpptoolssettings.cpp \ + cppvirtualfunctionassistprovider.cpp \ + cppvirtualfunctionproposalitem.cpp \ cppworkingcopy.cpp \ doxygengenerator.cpp \ editordocumenthandle.cpp \ diff --git a/src/plugins/cpptools/cpptools.qbs b/src/plugins/cpptools/cpptools.qbs index 35cb74c2630..cad4da41a56 100644 --- a/src/plugins/cpptools/cpptools.qbs +++ b/src/plugins/cpptools/cpptools.qbs @@ -90,6 +90,7 @@ Project { "cppdoxygen.h", "cppeditoroutline.cpp", "cppeditoroutline.h", + "cppeditorwidgetinterface.h", "cppfileiterationorder.cpp", "cppfileiterationorder.h", "cppfilesettingspage.cpp", @@ -97,6 +98,8 @@ Project { "cppfilesettingspage.ui", "cppfindreferences.cpp", "cppfindreferences.h", + "cppfollowsymbolundercursor.cpp", + "cppfollowsymbolundercursor.h", "cppfunctionsfilter.cpp", "cppfunctionsfilter.h", "cppincludesfilter.cpp", @@ -133,6 +136,8 @@ Project { "cpprawprojectpart.h", "cpprefactoringchanges.cpp", "cpprefactoringchanges.h", + "cpprefactoringengine.cpp", + "cpprefactoringengine.h", "cppselectionchanger.cpp", "cppselectionchanger.h", "cppsemanticinfo.h", @@ -157,6 +162,10 @@ Project { "cpptoolsreuse.h", "cpptoolssettings.cpp", "cpptoolssettings.h", + "cppvirtualfunctionassistprovider.cpp", + "cppvirtualfunctionassistprovider.h", + "cppvirtualfunctionproposalitem.cpp", + "cppvirtualfunctionproposalitem.h", "cppworkingcopy.cpp", "cppworkingcopy.h", "cursorineditor.h", diff --git a/src/plugins/cpptools/cpptoolsreuse.cpp b/src/plugins/cpptools/cpptoolsreuse.cpp index fcb3c8b878e..bd011c0c05d 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -32,11 +32,11 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -216,7 +216,7 @@ const Macro *findCanonicalMacro(const QTextCursor &cursor, Document::Ptr documen QTC_ASSERT(document, return 0); int line, column; - TextEditor::Convenience::convertPosition(cursor.document(), cursor.position(), &line, &column); + Utils::Text::convertPosition(cursor.document(), cursor.position(), &line, &column); if (const Macro *macro = document->findMacroDefinitionAt(line)) { QTextCursor macroCursor = cursor; diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp b/src/plugins/cpptools/cppvirtualfunctionassistprovider.cpp similarity index 96% rename from src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp rename to src/plugins/cpptools/cppvirtualfunctionassistprovider.cpp index e2e3accffe3..5711eb912ca 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.cpp +++ b/src/plugins/cpptools/cppvirtualfunctionassistprovider.cpp @@ -24,21 +24,19 @@ ****************************************************************************/ #include "cppvirtualfunctionassistprovider.h" - -#include "cppeditorconstants.h" #include "cppvirtualfunctionproposalitem.h" +#include "cpptoolsreuse.h" +#include "functionutils.h" +#include "symbolfinder.h" +#include "typehierarchybuilder.h" + #include #include #include #include -#include -#include -#include -#include - #include #include #include @@ -50,10 +48,10 @@ #include using namespace CPlusPlus; -using namespace CppEditor::Internal; -using namespace CppTools; using namespace TextEditor; +namespace CppTools { + /// Activate current item with the same shortcut that is configured for Follow Symbol Under Cursor. /// This is limited to single-key shortcuts without modifiers. class VirtualFunctionProposalWidget : public GenericProposalWidget @@ -211,3 +209,5 @@ IAssistProcessor *VirtualFunctionAssistProvider::createProcessor() const { return new VirtualFunctionAssistProcessor(m_params); } + +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h b/src/plugins/cpptools/cppvirtualfunctionassistprovider.h similarity index 93% rename from src/plugins/cppeditor/cppvirtualfunctionassistprovider.h rename to src/plugins/cpptools/cppvirtualfunctionassistprovider.h index 363981b7ca6..08ff2018d49 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionassistprovider.h +++ b/src/plugins/cpptools/cppvirtualfunctionassistprovider.h @@ -25,6 +25,8 @@ #pragma once +#include "cpptools_global.h" + #include #include @@ -34,10 +36,9 @@ #include #include -namespace CppEditor { -namespace Internal { +namespace CppTools { -class VirtualFunctionAssistProvider : public TextEditor::IAssistProvider +class CPPTOOLS_EXPORT VirtualFunctionAssistProvider : public TextEditor::IAssistProvider { public: VirtualFunctionAssistProvider(); @@ -64,5 +65,4 @@ private: Parameters m_params; }; -} // namespace Internal -} // namespace CppEditor +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.cpp b/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp similarity index 96% rename from src/plugins/cppeditor/cppvirtualfunctionproposalitem.cpp rename to src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp index 44bd8d01cfe..474aecac467 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.cpp +++ b/src/plugins/cpptools/cppvirtualfunctionproposalitem.cpp @@ -25,11 +25,11 @@ #include "cppvirtualfunctionproposalitem.h" -#include "cppeditorconstants.h" +#include #include -using namespace CppEditor::Internal; +namespace CppTools { VirtualFunctionProposalItem::VirtualFunctionProposalItem( const TextEditor::TextEditorWidget::Link &link, bool openInSplit) @@ -52,3 +52,5 @@ void VirtualFunctionProposalItem::apply(TextEditor::TextDocumentManipulatorInter CppEditor::Constants::CPPEDITOR_ID, flags); } + +} // namespace CppTools diff --git a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h b/src/plugins/cpptools/cppvirtualfunctionproposalitem.h similarity index 92% rename from src/plugins/cppeditor/cppvirtualfunctionproposalitem.h rename to src/plugins/cpptools/cppvirtualfunctionproposalitem.h index 5d86d4b3906..19bb7715ea1 100644 --- a/src/plugins/cppeditor/cppvirtualfunctionproposalitem.h +++ b/src/plugins/cpptools/cppvirtualfunctionproposalitem.h @@ -25,13 +25,14 @@ #pragma once +#include "cpptools_global.h" + #include #include -namespace CppEditor { -namespace Internal { +namespace CppTools { -class VirtualFunctionProposalItem final : public TextEditor::AssistProposalItem +class CPPTOOLS_EXPORT VirtualFunctionProposalItem final : public TextEditor::AssistProposalItem { public: VirtualFunctionProposalItem(const TextEditor::TextEditorWidget::Link &link, @@ -46,5 +47,4 @@ private: bool m_openInSplit; }; -} // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cpptools/cursorineditor.h b/src/plugins/cpptools/cursorineditor.h index c93f9e83382..18097e5dbd3 100644 --- a/src/plugins/cpptools/cursorineditor.h +++ b/src/plugins/cpptools/cursorineditor.h @@ -25,12 +25,11 @@ #pragma once -#include +#include "cppeditorwidgetinterface.h" + #include -namespace TextEditor { -class TextEditorWidget; -} // namespace TextEditor +#include namespace CppTools { @@ -38,18 +37,18 @@ class CursorInEditor { public: CursorInEditor(const QTextCursor &cursor, const Utils::FileName &filePath, - TextEditor::TextEditorWidget *editorWidget = nullptr) + CppEditorWidgetInterface *editorWidget = nullptr) : m_cursor(cursor) , m_filePath(filePath) , m_editorWidget(editorWidget) {} - TextEditor::TextEditorWidget *editorWidget() const { return m_editorWidget; } + CppEditorWidgetInterface *editorWidget() const { return m_editorWidget; } const QTextCursor &cursor() const { return m_cursor; } const Utils::FileName &filePath() const { return m_filePath; } private: QTextCursor m_cursor; Utils::FileName m_filePath; - TextEditor::TextEditorWidget *m_editorWidget = nullptr; + CppEditorWidgetInterface *m_editorWidget = nullptr; }; } // namespace CppTools diff --git a/src/plugins/cpptools/doxygengenerator.cpp b/src/plugins/cpptools/doxygengenerator.cpp index e94ce3468e0..39e2e252757 100644 --- a/src/plugins/cpptools/doxygengenerator.cpp +++ b/src/plugins/cpptools/doxygengenerator.cpp @@ -25,11 +25,10 @@ #include "doxygengenerator.h" -#include - #include #include +#include #include #include @@ -73,10 +72,8 @@ void DoxygenGenerator::setAddLeadingAsterisks(bool add) static int lineBeforeCursor(const QTextCursor &cursor) { int line, column; - const bool converted = TextEditor::Convenience::convertPosition(cursor.document(), - cursor.position(), - &line, - &column); + const bool converted = Utils::Text::convertPosition(cursor.document(), cursor.position(), &line, + &column); QTC_ASSERT(converted, return std::numeric_limits::max()); return line - 1; diff --git a/src/plugins/cpptools/refactoringengineinterface.h b/src/plugins/cpptools/refactoringengineinterface.h index 1452c8e5768..afb6025c036 100644 --- a/src/plugins/cpptools/refactoringengineinterface.h +++ b/src/plugins/cpptools/refactoringengineinterface.h @@ -25,7 +25,9 @@ #pragma once +#include "cpptools_global.h" #include "cursorineditor.h" + #include #include @@ -46,7 +48,7 @@ enum class CallType }; // NOTE: This interface is not supposed to be owned as an interface pointer -class RefactoringEngineInterface +class CPPTOOLS_EXPORT RefactoringEngineInterface { public: using RenameCallback = ClangBackEnd::RefactoringClientInterface::RenameCallback; @@ -54,6 +56,7 @@ public: virtual void startLocalRenaming(const CursorInEditor &data, CppTools::ProjectPart *projectPart, RenameCallback &&renameSymbolsCallback) = 0; + virtual void startGlobalRenaming(const CursorInEditor &data) = 0; virtual bool isUsable() const = 0; }; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 9c52ad0b9ed..6d64a7e4409 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -840,17 +840,9 @@ void CdbEngine::shutdownEngine() } } -void CdbEngine::abortDebugger() +void CdbEngine::abortDebuggerProcess() { - if (isDying()) { - // We already tried. Try harder. - showMessage("ABORTING DEBUGGER. SECOND TIME."); - m_process.kill(); - } else { - // Be friendly the first time. This will change targetState(). - showMessage("ABORTING DEBUGGER. FIRST TIME."); - quitDebugger(); - } + m_process.kill(); } void CdbEngine::processFinished() diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 30bccb4a116..7a80e48dbac 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -70,7 +70,7 @@ public: void runEngine() override; void shutdownInferior() override; void shutdownEngine() override; - void abortDebugger() override; + void abortDebuggerProcess() override; void detachDebugger() override; bool hasCapability(unsigned cap) const override; void watchPoint(const QPoint &) override; diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index 7d46ca6cc08..ecf31ab8410 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -533,14 +533,11 @@ void DebuggerEngine::start() fp->setKeepOnFinish(FutureProgress::HideOnFinish); d->m_progress.reportStarted(); - DebuggerRunParameters &rp = runParameters(); + const DebuggerRunParameters &rp = runParameters(); d->m_inferiorPid = rp.attachPID.isValid() ? rp.attachPID : ProcessHandle(); if (d->m_inferiorPid.isValid()) runControl()->setApplicationProcessHandle(d->m_inferiorPid); - if (isNativeMixedActive()) - rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1"); - action(OperateByInstruction)->setEnabled(hasCapability(DisassemblerCapability)); QTC_ASSERT(state() == DebuggerNotReady || state() == DebuggerFinished, @@ -631,11 +628,6 @@ const DebuggerRunParameters &DebuggerEngine::runParameters() const return runTool()->runParameters(); } -DebuggerRunParameters &DebuggerEngine::runParameters() -{ - return runTool()->runParameters(); -} - DebuggerState DebuggerEngine::state() const { return d->m_state; @@ -728,7 +720,6 @@ void DebuggerEnginePrivate::doSetupEngine() { m_engine->showMessage("CALL: SETUP ENGINE"); QTC_ASSERT(state() == EngineSetupRequested, qDebug() << m_engine << state()); - m_engine->validateExecutable(); m_engine->setupEngine(); } @@ -1353,8 +1344,17 @@ void DebuggerEngine::quitDebugger() void DebuggerEngine::abortDebugger() { - // Overridden in e.g. GdbEngine. - quitDebugger(); + if (!isDying()) { + // Be friendly the first time. This will change targetState(). + showMessage("ABORTING DEBUGGER. FIRST TIME."); + quitDebugger(); + } else { + // We already tried. Try harder. + showMessage("ABORTING DEBUGGER. SECOND TIME."); + abortDebuggerProcess(); + if (runControl()) + runControl()->initiateFinish(); + } } void DebuggerEngine::requestInterruptInferior() @@ -1745,42 +1745,30 @@ void DebuggerEngine::setStateDebugging(bool on) d->m_isStateDebugging = on; } -void DebuggerEngine::validateExecutable() +void DebuggerRunParameters::validateExecutable() { - DebuggerRunParameters *sp = &runParameters(); - if (sp->skipExecutableValidation) - return; - if (sp->languages == QmlLanguage) - return; - - QString symbolFile = sp->symbolFile; - if (symbolFile.isEmpty()) - symbolFile = sp->inferior.executable; - if (symbolFile.isEmpty()) - return; - const bool warnOnRelease = boolSetting(WarnOnReleaseBuilds); bool warnOnInappropriateDebugger = false; QString detailedWarning; - switch (sp->toolChainAbi.binaryFormat()) { + switch (toolChainAbi.binaryFormat()) { case Abi::PEFormat: { QString preferredDebugger; - if (sp->toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { - if (sp->cppEngineType == CdbEngineType) + if (toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { + if (cppEngineType == CdbEngineType) preferredDebugger = "GDB"; - } else if (sp->cppEngineType != CdbEngineType) { + } else if (cppEngineType != CdbEngineType) { // osFlavor() is MSVC, so the recommended debugger is CDB preferredDebugger = "CDB"; } if (!preferredDebugger.isEmpty()) { warnOnInappropriateDebugger = true; - detailedWarning = tr( + detailedWarning = DebuggerEngine::tr( "The inferior is in the Portable Executable format.\n" "Selecting %1 as debugger would improve the debugging " "experience for this binary format.").arg(preferredDebugger); break; } - if (warnOnRelease && sp->cppEngineType == CdbEngineType) { + if (warnOnRelease && cppEngineType == CdbEngineType) { if (!symbolFile.endsWith(".exe", Qt::CaseInsensitive)) symbolFile.append(".exe"); QString errorMessage; @@ -1797,9 +1785,9 @@ void DebuggerEngine::validateExecutable() break; } case Abi::ElfFormat: { - if (sp->cppEngineType == CdbEngineType) { + if (cppEngineType == CdbEngineType) { warnOnInappropriateDebugger = true; - detailedWarning = tr( + detailedWarning = DebuggerEngine::tr( "The inferior is in the ELF format.\n" "Selecting GDB or LLDB as debugger would improve the debugging " "experience for this binary format."); @@ -1872,7 +1860,7 @@ void DebuggerEngine::validateExecutable() QRegExp exp = itExp->first; int index = exp.indexIn(string); if (index != -1) { - sp->sourcePathMap.insert(string.left(index) + exp.cap(1), itExp->second); + sourcePathMap.insert(string.left(index) + exp.cap(1), itExp->second); found = true; break; } @@ -1891,8 +1879,9 @@ void DebuggerEngine::validateExecutable() return; foreach (const QByteArray &name, interesting) { - const QString found = seen.contains(name) ? tr("Found.") : tr("Not found."); - detailedWarning.append('\n' + tr("Section %1: %2").arg(QString::fromUtf8(name)).arg(found)); + const QString found = seen.contains(name) ? DebuggerEngine::tr("Found.") + : DebuggerEngine::tr("Not found."); + detailedWarning.append('\n' + DebuggerEngine::tr("Section %1: %2").arg(QString::fromUtf8(name)).arg(found)); } break; } @@ -1900,14 +1889,14 @@ void DebuggerEngine::validateExecutable() return; } if (warnOnInappropriateDebugger) { - AsynchronousMessageBox::information(tr("Warning"), - tr("The selected debugger may be inappropriate for the inferior.\n" + AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), + DebuggerEngine::tr("The selected debugger may be inappropriate for the inferior.\n" "Examining symbols and setting breakpoints by file name and line number " "may fail.\n") + '\n' + detailedWarning); } else if (warnOnRelease) { - AsynchronousMessageBox::information(tr("Warning"), - tr("This does not seem to be a \"Debug\" build.\n" + AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), + DebuggerEngine::tr("This does not seem to be a \"Debug\" build.\n" "Setting breakpoints by file name and line number may fail.") + '\n' + detailedWarning); } @@ -2002,10 +1991,8 @@ void DebuggerEngine::checkState(DebuggerState state, const char *file, int line) bool DebuggerEngine::isNativeMixedEnabled() const { - if (DebuggerRunTool *rt = runTool()) { - const DebuggerRunParameters &runParams = rt->runParameters(); - return runParams.nativeMixedEnabled && (runParams.languages & QmlLanguage); - } + if (DebuggerRunTool *rt = runTool()) + return rt->runParameters().isNativeMixedDebugging(); return false; } @@ -2024,6 +2011,11 @@ bool DebuggerEngine::isNativeMixedActiveFrame() const return frame.language == QmlLanguage; } +bool DebuggerRunParameters::isNativeMixedDebugging() const +{ + return nativeMixedEnabled && isCppDebugging && isQmlDebugging; +} + } // namespace Internal } // namespace Debugger diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 74fafa81434..89723096d06 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -88,7 +88,6 @@ public: Utils::ProcessHandle attachPID; QStringList solibSearchPath; bool useTerminal = false; - bool needFixup = true; // FIXME: Make false the default... // Used by Qml debugging. QUrl qmlServer; @@ -132,7 +131,8 @@ public: DebuggerEngineType masterEngineType = NoEngineType; DebuggerEngineType cppEngineType = NoEngineType; - DebuggerLanguages languages = NoLanguage; + bool isCppDebugging = true; + bool isQmlDebugging = false; bool breakOnMain = false; bool multiProcess = false; // Whether to set detach-on-fork off. @@ -156,10 +156,15 @@ public: bool nativeMixedEnabled = false; + bool isNativeMixedDebugging() const; + void validateExecutable(); + Utils::MacroExpander *macroExpander = 0; // For Debugger testing. int testCase = 0; + + QStringList validationErrors; }; class UpdateParameters @@ -237,7 +242,7 @@ public: virtual ~DebuggerEngine(); const DebuggerRunParameters &runParameters() const; - DebuggerRunParameters &runParameters(); + virtual void setRunTool(DebuggerRunTool *runTool); DebuggerRunTool *runTool() const; @@ -358,7 +363,8 @@ public: virtual void resetLocation(); virtual void gotoLocation(const Internal::Location &location); virtual void quitDebugger(); // called when pressing the stop button - virtual void abortDebugger(); // called from the debug menu action + + void abortDebugger(); // called from the debug menu action void updateViews(); bool isSlaveEngine() const; @@ -448,6 +454,8 @@ protected: virtual void frameUp(); virtual void frameDown(); + virtual void abortDebuggerProcess() {} // second attempt + virtual void doUpdateLocals(const UpdateParameters ¶ms); void setMasterEngine(DebuggerEngine *masterEngine); @@ -466,8 +474,6 @@ protected: bool isStateDebugging() const; void setStateDebugging(bool on); - void validateExecutable(); - virtual void setupSlaveInferior(); virtual void setupSlaveEngine(); virtual void runSlaveEngine(); diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 45e70007f98..dcc07a6d87d 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -970,8 +970,6 @@ public: ActionContainer *m_menu = 0; - QHash m_contextsForLanguage; - Project *m_previousProject = 0; QPointer m_previousTarget; QPointer m_previousRunConfiguration; @@ -1073,11 +1071,6 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) dd = this; m_plugin = plugin; - -// m_toolBars.insert(CppLanguage, 0); -// m_toolBars.insert(QmlLanguage, 0); - m_contextsForLanguage.insert(CppLanguage, Context(C_CPPDEBUGGER)); - m_contextsForLanguage.insert(QmlLanguage, Context(C_QMLDEBUGGER)); } DebuggerPluginPrivate::~DebuggerPluginPrivate() @@ -2892,11 +2885,9 @@ static QString formatStartParameters(const DebuggerRunParameters &sp) str << "Start parameters: '" << sp.displayName << "' mode: " << sp.startMode << "\nABI: " << sp.toolChainAbi.toString() << '\n'; str << "Languages: "; - if (sp.languages == AnyLanguage) - str << "any "; - if (sp.languages & CppLanguage) + if (sp.isCppDebugging) str << "c++ "; - if (sp.languages & QmlLanguage) + if (sp.isQmlDebugging) str << "qml"; str << '\n'; if (!sp.inferior.executable.isEmpty()) { @@ -3368,17 +3359,19 @@ void DebuggerPluginPrivate::updateActiveLanguages() { if (!dd->m_currentRunTool) return; - const DebuggerLanguages languages = dd->m_currentRunTool->runParameters().languages; + const DebuggerRunParameters &rp = dd->m_currentRunTool->runParameters(); // Id perspective = (languages & QmlLanguage) && !(languages & CppLanguage) // ? QmlPerspectiveId : CppPerspectiveId; // m_mainWindow->restorePerspective(perspective); - for (DebuggerLanguage language: {QmlLanguage, CppLanguage}) { - const Context context = m_contextsForLanguage.value(language); - if (languages & language) - ICore::addAdditionalContext(context); - else - ICore::removeAdditionalContext(context); - } + if (rp.isCppDebugging) + ICore::addAdditionalContext(Context(C_CPPDEBUGGER)); + else + ICore::removeAdditionalContext(Context(C_CPPDEBUGGER)); + + if (rp.isQmlDebugging) + ICore::addAdditionalContext(Context(C_QMLDEBUGGER)); + else + ICore::removeAdditionalContext(Context(C_QMLDEBUGGER)); } void DebuggerPluginPrivate::onModeChanged(Id mode) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index 0cf35d9d7c1..eeff836bc2f 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -82,8 +82,6 @@ DebuggerEngine *createQmlEngine(bool useTerminal); DebuggerEngine *createQmlCppEngine(DebuggerEngine *cppEngine, bool useTerminal); DebuggerEngine *createLldbEngine(); -static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, QStringList &m_errors); - class LocalProcessRunner : public RunWorker { public: @@ -189,7 +187,8 @@ void DebuggerRunTool::setStartMode(DebuggerStartMode startMode) { if (startMode == AttachToQmlServer) { m_runParameters.startMode = AttachToRemoteProcess; - m_runParameters.languages = QmlLanguage; + m_runParameters.isCppDebugging = false; + m_runParameters.isQmlDebugging = true; m_runParameters.masterEngineType = QmlEngineType; m_runParameters.closeMode = KillAtClose; @@ -330,11 +329,6 @@ void DebuggerRunTool::setDeviceSymbolsRoot(const QString &deviceSymbolsRoot) m_runParameters.deviceSymbolsRoot = deviceSymbolsRoot; } -void DebuggerRunTool::setNeedFixup(bool on) -{ - m_runParameters.needFixup = on; -} - void DebuggerRunTool::setTestCase(int testCase) { m_runParameters.testCase = testCase; @@ -462,7 +456,7 @@ void DebuggerRunTool::start() } // QML and/or mixed are not prepared for it. - setSupportsReRunning(!(m_runParameters.languages & QmlLanguage)); + setSupportsReRunning(!m_runParameters.isQmlDebugging); // FIXME: Disabled due to Android. Make Android device report available ports instead. // int portsUsed = portsUsedByDebugger(); @@ -471,10 +465,8 @@ void DebuggerRunTool::start() // return; // } - if (!Internal::fixupParameters(m_runParameters, runControl(), m_errors)) { - reportFailure(m_errors.join('\n')); + if (!fixupParameters()) return; - } Utils::globalMacroExpander()->registerFileVariables( "DebuggedExecutable", tr("Debugged executable"), @@ -484,12 +476,19 @@ void DebuggerRunTool::start() runControl()->setDisplayName(m_runParameters.displayName); DebuggerEngine *cppEngine = nullptr; + switch (m_runParameters.cppEngineType) { case GdbEngineType: cppEngine = createGdbEngine(m_runParameters.useTerminal, m_runParameters.startMode); break; - case CdbEngineType: - cppEngine = createCdbEngine(&m_errors, m_runParameters.startMode); + case CdbEngineType: { + QStringList errors; + cppEngine = createCdbEngine(&errors, m_runParameters.startMode); + if (!errors.isEmpty()) { + reportFailure(errors.join('\n')); + return; + } + } break; case LldbEngineType: cppEngine = createLldbEngine(); @@ -516,9 +515,8 @@ void DebuggerRunTool::start() } if (!m_engine) { - m_errors.append(DebuggerPlugin::tr("Unable to create a debugging engine of the type \"%1\""). + reportFailure(DebuggerPlugin::tr("Unable to create a debugging engine of the type \"%1\""). arg(engineTypeName(m_runParameters.masterEngineType))); - reportFailure(m_errors.join('\n')); return; } @@ -584,6 +582,16 @@ const DebuggerRunParameters &DebuggerRunTool::runParameters() const return m_runParameters; } +bool DebuggerRunTool::isCppDebugging() const +{ + return m_runParameters.isCppDebugging; +} + +bool DebuggerRunTool::isQmlDebugging() const +{ + return m_runParameters.isQmlDebugging; +} + int DebuggerRunTool::portsUsedByDebugger() const { return isCppDebugging() + isQmlDebugging(); @@ -615,145 +623,34 @@ void DebuggerRunTool::abortDebugger() m_engine->abortDebugger(); } -/////////////////////////////////////////////////////////////////////// -// -// DebuggerRunControlCreator -// -/////////////////////////////////////////////////////////////////////// - -namespace Internal { - -static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, QStringList &m_errors) +bool DebuggerRunTool::fixupParameters() { - RunConfiguration *runConfig = runControl->runConfiguration(); - if (!runConfig) - return false; - - const Kit *kit = runConfig->target()->kit(); - QTC_ASSERT(kit, return false); - - // Extract as much as possible from available RunConfiguration. - const Runnable runnable = runConfig->runnable(); - if (rp.needFixup && runnable.is()) { - // FIXME: Needed for core dump which stores the executable in inferior, but not in runConfig - // executable. - const QString prevExecutable = rp.inferior.executable; - rp.inferior = runnable.as(); - if (rp.inferior.executable.isEmpty()) - rp.inferior.executable = prevExecutable; - rp.useTerminal = rp.inferior.runMode == ApplicationLauncher::Console; - // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) - rp.inferior.workingDirectory = FileUtils::normalizePathName(rp.inferior.workingDirectory); - } - - // We might get an executable from a local PID. - if (rp.needFixup && rp.inferior.executable.isEmpty() && rp.attachPID.isValid()) { - foreach (const DeviceProcessItem &p, DeviceProcessList::localProcesses()) { - if (p.pid == rp.attachPID.pid()) { - rp.inferior.executable = p.exe; - break; - } - } - } - - rp.macroExpander = kit->macroExpander(); + DebuggerRunParameters &rp = m_runParameters; if (rp.symbolFile.isEmpty()) rp.symbolFile = rp.inferior.executable; - rp.debugger = DebuggerKitInformation::runnable(kit); - const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH"); - if (!envBinary.isEmpty()) - rp.debugger.executable = QString::fromLocal8Bit(envBinary); + rp.stubEnvironment = rp.inferior.environment; // FIXME: Wrong, but contains DYLD_IMAGE_SUFFIX - if (rp.needFixup) { - if (auto envAspect = runConfig->extraAspect()) { - rp.inferior.environment = envAspect->environment(); // Correct. - rp.stubEnvironment = rp.inferior.environment; // FIXME: Wrong, but contains DYLD_IMAGE_SUFFIX - - // Copy over DYLD_IMAGE_SUFFIX etc - for (auto var : QStringList({"DYLD_IMAGE_SUFFIX", "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH"})) - if (rp.inferior.environment.hasKey(var)) - rp.debugger.environment.set(var, rp.inferior.environment.value(var)); - } - } - if (Project *project = runConfig->target()->project()) { - rp.projectSourceDirectory = project->projectDirectory().toString(); - rp.projectSourceFiles = project->files(Project::SourceFiles); - } - - rp.toolChainAbi = ToolChainKitInformation::targetAbi(kit); - - bool ok = false; - int nativeMixedOverride = qgetenv("QTC_DEBUGGER_NATIVE_MIXED").toInt(&ok); - if (ok) - rp.nativeMixedEnabled = bool(nativeMixedOverride); - - rp.cppEngineType = DebuggerKitInformation::engineType(kit); - if (rp.sysRoot.isEmpty()) - rp.sysRoot = SysRootKitInformation::sysRoot(kit).toString(); - - if (rp.displayName.isEmpty()) - rp.displayName = runConfig->displayName(); - - if (runConfig->property("supportsDebugger").toBool()) { - QString mainScript = runConfig->property("mainScript").toString(); - QString interpreter = runConfig->property("interpreter").toString(); - if (!interpreter.isEmpty() && mainScript.endsWith(".py")) { - rp.mainScript = mainScript; - rp.interpreter = interpreter; - QString args = runConfig->property("arguments").toString(); - if (!args.isEmpty()) { - if (!rp.inferior.commandLineArguments.isEmpty()) - rp.inferior.commandLineArguments.append(QLatin1Char(' ')); - rp.inferior.commandLineArguments.append(args); - } - rp.masterEngineType = PdbEngineType; - } - } - - if (auto debuggerAspect = runConfig->extraAspect()) { - rp.multiProcess = debuggerAspect->useMultiProcess(); - if (rp.languages == NoLanguage) { - if (debuggerAspect->useCppDebugger()) - rp.languages |= CppLanguage; - if (debuggerAspect->useQmlDebugger()) - rp.languages |= QmlLanguage; - } - } - - // This can happen e.g. when started from the command line. - if (rp.languages == NoLanguage) - rp.languages = CppLanguage; + // Copy over DYLD_IMAGE_SUFFIX etc + for (auto var : QStringList({"DYLD_IMAGE_SUFFIX", "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH"})) + if (rp.inferior.environment.hasKey(var)) + rp.debugger.environment.set(var, rp.inferior.environment.value(var)); // validate debugger if C++ debugging is enabled - if (rp.languages & CppLanguage) { - const QList tasks = DebuggerKitInformation::validateDebugger(kit); - if (!tasks.isEmpty()) { - foreach (const Task &t, tasks) { - if (t.type == Task::Warning) - continue; - m_errors.append(t.description); - } - if (!m_errors.isEmpty()) - return false; - } + if (rp.isCppDebugging && !rp.validationErrors.isEmpty()) { + reportFailure(rp.validationErrors.join('\n')); + return false; } - IDevice::ConstPtr device = runControl->device(); - if (rp.languages & QmlLanguage) { - if (device && device->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { - if (rp.qmlServer.host().isEmpty() || rp.qmlServer.port() <= 0) { - QTcpServer server; - const bool canListen = server.listen(QHostAddress::LocalHost) - || server.listen(QHostAddress::LocalHostIPv6); - if (!canListen) { - m_errors.append(DebuggerPlugin::tr("Not enough free ports for QML debugging.") + ' '); + if (rp.isQmlDebugging) { + if (device() && device()->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) { + if (rp.qmlServer.port() <= 0) { + rp.qmlServer = ProjectExplorer::urlFromLocalHostAndFreePort(); + if (rp.qmlServer.port() <= 0) { + reportFailure(DebuggerPlugin::tr("Not enough free ports for QML debugging.")); return false; } - rp.qmlServer.setHost(server.serverAddress().toString()); - rp.qmlServer.setPort(server.serverPort()); } - // Makes sure that all bindings go through the JavaScript engine, so that // breakpoints are actually hit! const QString optimizerKey = "QML_DISABLE_OPTIMIZER"; @@ -775,9 +672,9 @@ static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, Q } if (rp.masterEngineType == NoEngineType) { - if (rp.languages & QmlLanguage) { + if (rp.isQmlDebugging) { QmlDebug::QmlDebugServicesPreset service; - if (rp.languages & CppLanguage) { + if (rp.isCppDebugging) { if (rp.nativeMixedEnabled) { service = QmlDebug::QmlNativeDebuggerServices; } else { @@ -789,7 +686,7 @@ static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, Q service = QmlDebug::QmlDebuggerServices; } if (rp.startMode != AttachExternal && rp.startMode != AttachCrashedExternal) { - QString qmlarg = (rp.languages & CppLanguage) && rp.nativeMixedEnabled + QString qmlarg = rp.isCppDebugging && rp.nativeMixedEnabled ? QmlDebug::qmlDebugNativeArguments(service, false) : QmlDebug::qmlDebugTcpArguments(service, Port(rp.qmlServer.port())); QtcProcess::addArg(&rp.inferior.commandLineArguments, qmlarg); @@ -817,8 +714,8 @@ static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, Q if (perr != QtcProcess::SplitOk) { // perr == BadQuoting is never returned on Windows // FIXME? QTCREATORBUG-2809 - m_errors.append(DebuggerPlugin::tr("Debugging complex command lines " - "is currently not supported on Windows.")); + reportFailure(DebuggerPlugin::tr("Debugging complex command lines " + "is currently not supported on Windows.")); return false; } } @@ -826,40 +723,27 @@ static bool fixupParameters(DebuggerRunParameters &rp, RunControl *runControl, Q // FIXME: We can't handle terminals yet. if (rp.useTerminal && rp.cppEngineType == LldbEngineType) { qWarning("Run in Terminal is not supported yet with the LLDB backend"); - m_errors.append(DebuggerPlugin::tr("Run in Terminal is not supported with the LLDB backend.")); + appendMessage(DebuggerPlugin::tr("Run in Terminal is not supported with the LLDB backend."), + ErrorMessageFormat); rp.useTerminal = false; } + if (rp.isNativeMixedDebugging()) + rp.inferior.environment.set("QV4_FORCE_INTERPRETER", "1"); + + if (rp.isCppDebugging && !rp.skipExecutableValidation) + rp.validateExecutable(); + return true; } -} // Internal - -static DebuggerRunConfigurationAspect *debuggerAspect(const RunControl *runControl) -{ - return runControl->runConfiguration()->extraAspect(); -} - -static bool cppDebugging(const RunControl *runControl) -{ - auto aspect = debuggerAspect(runControl); - return aspect ? aspect->useCppDebugger() : true; // For cases like valgrind-with-gdb. -} - -static bool qmlDebugging(const RunControl *runControl) -{ - auto aspect = debuggerAspect(runControl); - return aspect ? aspect->useQmlDebugger() : false; // For cases like valgrind-with-gdb. -} - -/// DebuggerRunTool - DebuggerRunTool::DebuggerRunTool(RunControl *runControl) - : RunWorker(runControl), - m_isCppDebugging(cppDebugging(runControl)), - m_isQmlDebugging(qmlDebugging(runControl)) + : RunWorker(runControl) { setDisplayName("DebuggerRunTool"); + + RunConfiguration *runConfig = runControl->runConfiguration(); + runControl->setIcon(ProjectExplorer::Icons::DEBUG_START_SMALL_TOOLBAR); runControl->setPromptToStop([](bool *optionalPrompt) { return RunControl::showPromptToStopDialog( @@ -872,8 +756,72 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl) }); Runnable r = runnable(); - if (r.is()) + if (r.is()) { m_runParameters.inferior = r.as(); + m_runParameters.useTerminal = m_runParameters.inferior.runMode == ApplicationLauncher::Console; + // Normalize to work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch'...) + m_runParameters.inferior.workingDirectory = + FileUtils::normalizePathName(m_runParameters.inferior.workingDirectory); + } + + if (auto aspect = runConfig ? runConfig->extraAspect() : nullptr) { + m_runParameters.isCppDebugging = aspect->useCppDebugger(); + m_runParameters.isQmlDebugging = aspect->useQmlDebugger(); + m_runParameters.multiProcess = aspect->useMultiProcess(); + } + + if (runConfig) + m_runParameters.displayName = runConfig->displayName(); + + const Kit *kit = runConfig->target()->kit(); + QTC_ASSERT(kit, return); + + m_runParameters.macroExpander = kit->macroExpander(); + + m_runParameters.debugger = DebuggerKitInformation::runnable(kit); + const QByteArray envBinary = qgetenv("QTC_DEBUGGER_PATH"); + if (!envBinary.isEmpty()) + m_runParameters.debugger.executable = QString::fromLocal8Bit(envBinary); + + Project *project = runConfig ? runConfig->target()->project() : nullptr; + if (project) { + m_runParameters.projectSourceDirectory = project->projectDirectory().toString(); + m_runParameters.projectSourceFiles = project->files(Project::SourceFiles); + } + + m_runParameters.toolChainAbi = ToolChainKitInformation::targetAbi(kit); + + bool ok = false; + int nativeMixedOverride = qgetenv("QTC_DEBUGGER_NATIVE_MIXED").toInt(&ok); + if (ok) + m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride); + + m_runParameters.cppEngineType = DebuggerKitInformation::engineType(kit); + m_runParameters.sysRoot = SysRootKitInformation::sysRoot(kit).toString(); + + // This will only be shown in some cases, but we don't want to access + // the kit at that time anymore. + const QList tasks = DebuggerKitInformation::validateDebugger(kit); + for (const Task &t : tasks) { + if (t.type != Task::Warning) + m_runParameters.validationErrors.append(t.description); + } + + if (runConfig->property("supportsDebugger").toBool()) { + const QString mainScript = runConfig->property("mainScript").toString(); + const QString interpreter = runConfig->property("interpreter").toString(); + if (!interpreter.isEmpty() && mainScript.endsWith(".py")) { + m_runParameters.mainScript = mainScript; + m_runParameters.interpreter = interpreter; + const QString args = runConfig->property("arguments").toString(); + if (!args.isEmpty()) { + if (!m_runParameters.inferior.commandLineArguments.isEmpty()) + m_runParameters.inferior.commandLineArguments.append(' '); + m_runParameters.inferior.commandLineArguments.append(args); + } + m_runParameters.masterEngineType = PdbEngineType; + } + } } DebuggerEngine *DebuggerRunTool::activeEngine() const diff --git a/src/plugins/debugger/debuggerruncontrol.h b/src/plugins/debugger/debuggerruncontrol.h index 6bec12913da..ff46db5059f 100644 --- a/src/plugins/debugger/debuggerruncontrol.h +++ b/src/plugins/debugger/debuggerruncontrol.h @@ -70,8 +70,8 @@ public: void startDying() { m_isDying = true; } bool isDying() const { return m_isDying; } - bool isCppDebugging() const { return m_isCppDebugging; } - bool isQmlDebugging() const { return m_isQmlDebugging; } + bool isCppDebugging() const; + bool isQmlDebugging() const; int portsUsedByDebugger() const; void setSolibSearchPath(const QStringList &list); @@ -126,7 +126,7 @@ public: void setIosPlatform(const QString &platform); void setDeviceSymbolsRoot(const QString &deviceSymbolsRoot); - void setNeedFixup(bool on); + void setNeedFixup(bool) {} // FIXME: Remove after use in QtAppMan is gone. void setTestCase(int testCase); void setOverrideStartScript(const QString &script); void setToolChainAbi(const ProjectExplorer::Abi &abi); @@ -135,12 +135,11 @@ signals: void aboutToNotifyInferiorSetupOk(); private: + bool fixupParameters(); + QPointer m_engine; // Master engine Internal::DebuggerRunParameters m_runParameters; - QStringList m_errors; bool m_isDying = false; - const bool m_isCppDebugging; - const bool m_isQmlDebugging; }; class DEBUGGER_EXPORT GdbServerPortsGatherer : public ProjectExplorer::RunWorker diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index cdd689cd46a..ece1d1c87c4 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -4062,17 +4062,9 @@ void GdbEngine::handleGdbFinished(int exitCode, QProcess::ExitStatus exitStatus) notifyDebuggerProcessFinished(exitCode, exitStatus, "GDB"); } -void GdbEngine::abortDebugger() +void GdbEngine::abortDebuggerProcess() { - if (isDying()) { - // We already tried. Try harder. - showMessage("ABORTING DEBUGGER. SECOND TIME."); - m_gdbProc.kill(); - } else { - // Be friendly the first time. This will change targetState(). - showMessage("ABORTING DEBUGGER. FIRST TIME."); - quitDebugger(); - } + m_gdbProc.kill(); } void GdbEngine::resetInferior() diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index c7122340f06..a7537cfdebd 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -83,7 +83,7 @@ private: ////////// General Interface ////////// bool hasCapability(unsigned) const final; void detachDebugger() final; void shutdownInferior() final; - void abortDebugger() final; + void abortDebuggerProcess() final; void resetInferior() final; bool acceptsDebuggerCommands() const final; diff --git a/src/plugins/debugger/images/debugger_continue.png b/src/plugins/debugger/images/debugger_continue.png index 6ec4eddc1a1..e15d7e72624 100644 Binary files a/src/plugins/debugger/images/debugger_continue.png and b/src/plugins/debugger/images/debugger_continue.png differ diff --git a/src/plugins/debugger/images/debugger_continue@2x.png b/src/plugins/debugger/images/debugger_continue@2x.png index 69552eb9808..d28c87d835b 100644 Binary files a/src/plugins/debugger/images/debugger_continue@2x.png and b/src/plugins/debugger/images/debugger_continue@2x.png differ diff --git a/src/plugins/debugger/images/debugger_continue_1_mask.png b/src/plugins/debugger/images/debugger_continue_1_mask.png index 522e5f36cc3..1f5c0c56551 100644 Binary files a/src/plugins/debugger/images/debugger_continue_1_mask.png and b/src/plugins/debugger/images/debugger_continue_1_mask.png differ diff --git a/src/plugins/debugger/images/debugger_continue_1_mask@2x.png b/src/plugins/debugger/images/debugger_continue_1_mask@2x.png index 217ddc826f7..e3e06daa9d2 100644 Binary files a/src/plugins/debugger/images/debugger_continue_1_mask@2x.png and b/src/plugins/debugger/images/debugger_continue_1_mask@2x.png differ diff --git a/src/plugins/debugger/images/debugger_continue_2_mask.png b/src/plugins/debugger/images/debugger_continue_2_mask.png index 756ba959f03..8b83259ed13 100644 Binary files a/src/plugins/debugger/images/debugger_continue_2_mask.png and b/src/plugins/debugger/images/debugger_continue_2_mask.png differ diff --git a/src/plugins/debugger/images/debugger_continue_2_mask@2x.png b/src/plugins/debugger/images/debugger_continue_2_mask@2x.png index a4801fa6bac..860f76ca187 100644 Binary files a/src/plugins/debugger/images/debugger_continue_2_mask@2x.png and b/src/plugins/debugger/images/debugger_continue_2_mask@2x.png differ diff --git a/src/plugins/debugger/images/debugger_interrupt.png b/src/plugins/debugger/images/debugger_interrupt.png index f61bf0881b9..fccdf1149ef 100644 Binary files a/src/plugins/debugger/images/debugger_interrupt.png and b/src/plugins/debugger/images/debugger_interrupt.png differ diff --git a/src/plugins/debugger/images/debugger_interrupt@2x.png b/src/plugins/debugger/images/debugger_interrupt@2x.png index 6c99c073db4..8e493ca1f25 100644 Binary files a/src/plugins/debugger/images/debugger_interrupt@2x.png and b/src/plugins/debugger/images/debugger_interrupt@2x.png differ diff --git a/src/plugins/debugger/images/debugger_interrupt_mask.png b/src/plugins/debugger/images/debugger_interrupt_mask.png index 87f195f5c08..52f4f275b9f 100644 Binary files a/src/plugins/debugger/images/debugger_interrupt_mask.png and b/src/plugins/debugger/images/debugger_interrupt_mask.png differ diff --git a/src/plugins/debugger/images/debugger_interrupt_mask@2x.png b/src/plugins/debugger/images/debugger_interrupt_mask@2x.png index 6c477085d7b..c7794000177 100644 Binary files a/src/plugins/debugger/images/debugger_interrupt_mask@2x.png and b/src/plugins/debugger/images/debugger_interrupt_mask@2x.png differ diff --git a/src/plugins/debugger/images/mode_debug.png b/src/plugins/debugger/images/mode_debug.png index 55bdf6bc501..32a93258f1a 100644 Binary files a/src/plugins/debugger/images/mode_debug.png and b/src/plugins/debugger/images/mode_debug.png differ diff --git a/src/plugins/debugger/images/mode_debug@2x.png b/src/plugins/debugger/images/mode_debug@2x.png index 0dc56c6d93c..2bb24b99eef 100644 Binary files a/src/plugins/debugger/images/mode_debug@2x.png and b/src/plugins/debugger/images/mode_debug@2x.png differ diff --git a/src/plugins/debugger/images/mode_debug_mask.png b/src/plugins/debugger/images/mode_debug_mask.png index ed72f606c44..fe7b6819a5b 100644 Binary files a/src/plugins/debugger/images/mode_debug_mask.png and b/src/plugins/debugger/images/mode_debug_mask.png differ diff --git a/src/plugins/debugger/images/mode_debug_mask@2x.png b/src/plugins/debugger/images/mode_debug_mask@2x.png index 510c817c821..5340947ec75 100644 Binary files a/src/plugins/debugger/images/mode_debug_mask@2x.png and b/src/plugins/debugger/images/mode_debug_mask@2x.png differ diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index c1c1225bdd4..bf00138e9b4 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -160,17 +160,9 @@ void LldbEngine::shutdownEngine() notifyEngineShutdownOk(); } -void LldbEngine::abortDebugger() +void LldbEngine::abortDebuggerProcess() { - if (isDying()) { - // We already tried. Try harder. - showMessage("ABORTING DEBUGGER. SECOND TIME."); - m_lldbProc.kill(); - } else { - // Be friendly the first time. This will change targetState(). - showMessage("ABORTING DEBUGGER. FIRST TIME."); - quitDebugger(); - } + m_lldbProc.kill(); } void LldbEngine::setupEngine() @@ -899,6 +891,8 @@ void LldbEngine::handleStateNotification(const GdbMi &reportedState) } } else if (newState == "inferiorstopok") { notifyInferiorStopOk(); + if (!isDying()) + updateAll(); } else if (newState == "inferiorstopfailed") notifyInferiorStopFailed(); else if (newState == "inferiorill") diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 19932d56c76..dff437497b6 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -78,7 +78,7 @@ private: void runEngine() override; void shutdownInferior() override; void shutdownEngine() override; - void abortDebugger() override; + void abortDebuggerProcess() override; bool canHandleToolTip(const DebuggerToolTipContext &) const override; diff --git a/src/plugins/debugger/qml/qmlcppengine.cpp b/src/plugins/debugger/qml/qmlcppengine.cpp index 63ff26c1565..a5a9810b9ba 100644 --- a/src/plugins/debugger/qml/qmlcppengine.cpp +++ b/src/plugins/debugger/qml/qmlcppengine.cpp @@ -410,10 +410,10 @@ void QmlCppEngine::quitDebugger() m_cppEngine->quitDebugger(); } -void QmlCppEngine::abortDebugger() +void QmlCppEngine::abortDebuggerProcess() { EDEBUG("\nMASTER ABORT DEBUGGER"); - m_cppEngine->abortDebugger(); + m_cppEngine->abortDebuggerProcess(); } void QmlCppEngine::setState(DebuggerState newState, bool forced) diff --git a/src/plugins/debugger/qml/qmlcppengine.h b/src/plugins/debugger/qml/qmlcppengine.h index 38a3c00d566..9dcfb3284a4 100644 --- a/src/plugins/debugger/qml/qmlcppengine.h +++ b/src/plugins/debugger/qml/qmlcppengine.h @@ -112,7 +112,7 @@ protected: void shutdownInferior() override; void shutdownEngine() override; void quitDebugger() override; - void abortDebugger() override; + void abortDebuggerProcess() override; void loadAdditionalQmlStack() override; diff --git a/src/plugins/help/images/mode_help.png b/src/plugins/help/images/mode_help.png index 7247e639eb8..e2e3eb64d14 100644 Binary files a/src/plugins/help/images/mode_help.png and b/src/plugins/help/images/mode_help.png differ diff --git a/src/plugins/help/images/mode_help@2x.png b/src/plugins/help/images/mode_help@2x.png index ae8db24fd75..51e4ed8ff87 100644 Binary files a/src/plugins/help/images/mode_help@2x.png and b/src/plugins/help/images/mode_help@2x.png differ diff --git a/src/plugins/help/images/mode_help_mask.png b/src/plugins/help/images/mode_help_mask.png index 43eb4d120b2..144871e8542 100644 Binary files a/src/plugins/help/images/mode_help_mask.png and b/src/plugins/help/images/mode_help_mask.png differ diff --git a/src/plugins/help/images/mode_help_mask@2x.png b/src/plugins/help/images/mode_help_mask@2x.png index 611769bd968..50f12d8e117 100644 Binary files a/src/plugins/help/images/mode_help_mask@2x.png and b/src/plugins/help/images/mode_help_mask@2x.png differ diff --git a/src/plugins/ios/images/iosdevice.png b/src/plugins/ios/images/iosdevice.png index 9b3fabeaf35..892e09c7787 100644 Binary files a/src/plugins/ios/images/iosdevice.png and b/src/plugins/ios/images/iosdevice.png differ diff --git a/src/plugins/ios/images/iosdevice@2x.png b/src/plugins/ios/images/iosdevice@2x.png index 1e078270c64..89bbaf03477 100644 Binary files a/src/plugins/ios/images/iosdevice@2x.png and b/src/plugins/ios/images/iosdevice@2x.png differ diff --git a/src/plugins/projectexplorer/images/build.png b/src/plugins/projectexplorer/images/build.png index e4590537ed8..76bdf9a460c 100644 Binary files a/src/plugins/projectexplorer/images/build.png and b/src/plugins/projectexplorer/images/build.png differ diff --git a/src/plugins/projectexplorer/images/build@2x.png b/src/plugins/projectexplorer/images/build@2x.png index bb2b17ebc42..b3e3c581a34 100644 Binary files a/src/plugins/projectexplorer/images/build@2x.png and b/src/plugins/projectexplorer/images/build@2x.png differ diff --git a/src/plugins/projectexplorer/images/build_hammerhandle_mask.png b/src/plugins/projectexplorer/images/build_hammerhandle_mask.png index 8759e4204fc..15e318ac4ab 100644 Binary files a/src/plugins/projectexplorer/images/build_hammerhandle_mask.png and b/src/plugins/projectexplorer/images/build_hammerhandle_mask.png differ diff --git a/src/plugins/projectexplorer/images/build_hammerhandle_mask@2x.png b/src/plugins/projectexplorer/images/build_hammerhandle_mask@2x.png index 04304d35f82..8b2525dbf4e 100644 Binary files a/src/plugins/projectexplorer/images/build_hammerhandle_mask@2x.png and b/src/plugins/projectexplorer/images/build_hammerhandle_mask@2x.png differ diff --git a/src/plugins/projectexplorer/images/build_hammerhead_mask.png b/src/plugins/projectexplorer/images/build_hammerhead_mask.png index 31a174fd177..98f11810b3c 100644 Binary files a/src/plugins/projectexplorer/images/build_hammerhead_mask.png and b/src/plugins/projectexplorer/images/build_hammerhead_mask.png differ diff --git a/src/plugins/projectexplorer/images/build_hammerhead_mask@2x.png b/src/plugins/projectexplorer/images/build_hammerhead_mask@2x.png index 4bc0b4b7fc8..ec7ecd42b0f 100644 Binary files a/src/plugins/projectexplorer/images/build_hammerhead_mask@2x.png and b/src/plugins/projectexplorer/images/build_hammerhead_mask@2x.png differ diff --git a/src/plugins/projectexplorer/images/build_small.png b/src/plugins/projectexplorer/images/build_small.png deleted file mode 100644 index 991f2c0c306..00000000000 Binary files a/src/plugins/projectexplorer/images/build_small.png and /dev/null differ diff --git a/src/plugins/projectexplorer/images/buildhammerhandle.png b/src/plugins/projectexplorer/images/buildhammerhandle.png new file mode 100644 index 00000000000..6c7c8a00e05 Binary files /dev/null and b/src/plugins/projectexplorer/images/buildhammerhandle.png differ diff --git a/src/plugins/projectexplorer/images/buildhammerhandle@2x.png b/src/plugins/projectexplorer/images/buildhammerhandle@2x.png new file mode 100644 index 00000000000..5e67dc5ab9a Binary files /dev/null and b/src/plugins/projectexplorer/images/buildhammerhandle@2x.png differ diff --git a/src/plugins/projectexplorer/images/buildhammerhead.png b/src/plugins/projectexplorer/images/buildhammerhead.png new file mode 100644 index 00000000000..2f7fd76a1af Binary files /dev/null and b/src/plugins/projectexplorer/images/buildhammerhead.png differ diff --git a/src/plugins/projectexplorer/images/buildhammerhead@2x.png b/src/plugins/projectexplorer/images/buildhammerhead@2x.png new file mode 100644 index 00000000000..374166321cf Binary files /dev/null and b/src/plugins/projectexplorer/images/buildhammerhead@2x.png differ diff --git a/src/plugins/projectexplorer/images/debugger_beetle_mask.png b/src/plugins/projectexplorer/images/debugger_beetle_mask.png index b041005b3ae..816aacc3398 100644 Binary files a/src/plugins/projectexplorer/images/debugger_beetle_mask.png and b/src/plugins/projectexplorer/images/debugger_beetle_mask.png differ diff --git a/src/plugins/projectexplorer/images/debugger_beetle_mask@2x.png b/src/plugins/projectexplorer/images/debugger_beetle_mask@2x.png index f4f7098ee39..c240532d29e 100644 Binary files a/src/plugins/projectexplorer/images/debugger_beetle_mask@2x.png and b/src/plugins/projectexplorer/images/debugger_beetle_mask@2x.png differ diff --git a/src/plugins/projectexplorer/images/debugger_start.png b/src/plugins/projectexplorer/images/debugger_start.png index 973d1fad52b..0e7cd1a6723 100644 Binary files a/src/plugins/projectexplorer/images/debugger_start.png and b/src/plugins/projectexplorer/images/debugger_start.png differ diff --git a/src/plugins/projectexplorer/images/debugger_start@2x.png b/src/plugins/projectexplorer/images/debugger_start@2x.png index e29d9b603d4..ab7cc15f7ae 100644 Binary files a/src/plugins/projectexplorer/images/debugger_start@2x.png and b/src/plugins/projectexplorer/images/debugger_start@2x.png differ diff --git a/src/plugins/projectexplorer/images/desktopdevice.png b/src/plugins/projectexplorer/images/desktopdevice.png index 2323f95b6f1..10909fdd1d5 100644 Binary files a/src/plugins/projectexplorer/images/desktopdevice.png and b/src/plugins/projectexplorer/images/desktopdevice.png differ diff --git a/src/plugins/projectexplorer/images/desktopdevice@2x.png b/src/plugins/projectexplorer/images/desktopdevice@2x.png index 8abf5f330af..4fd9ca8a169 100644 Binary files a/src/plugins/projectexplorer/images/desktopdevice@2x.png and b/src/plugins/projectexplorer/images/desktopdevice@2x.png differ diff --git a/src/plugins/projectexplorer/images/devicestatusindicator.png b/src/plugins/projectexplorer/images/devicestatusindicator.png index 2b13d25aa26..44e045cfb4d 100644 Binary files a/src/plugins/projectexplorer/images/devicestatusindicator.png and b/src/plugins/projectexplorer/images/devicestatusindicator.png differ diff --git a/src/plugins/projectexplorer/images/devicestatusindicator@2x.png b/src/plugins/projectexplorer/images/devicestatusindicator@2x.png index 4cb3a5d42da..7f03474cd01 100644 Binary files a/src/plugins/projectexplorer/images/devicestatusindicator@2x.png and b/src/plugins/projectexplorer/images/devicestatusindicator@2x.png differ diff --git a/src/plugins/projectexplorer/images/mode_project.png b/src/plugins/projectexplorer/images/mode_project.png index 67fc3720463..cb4856b325a 100644 Binary files a/src/plugins/projectexplorer/images/mode_project.png and b/src/plugins/projectexplorer/images/mode_project.png differ diff --git a/src/plugins/projectexplorer/images/mode_project@2x.png b/src/plugins/projectexplorer/images/mode_project@2x.png index f0b7fdae0ef..264cece448f 100644 Binary files a/src/plugins/projectexplorer/images/mode_project@2x.png and b/src/plugins/projectexplorer/images/mode_project@2x.png differ diff --git a/src/plugins/projectexplorer/images/mode_project_mask.png b/src/plugins/projectexplorer/images/mode_project_mask.png index beffa6722b8..6e6092b7ad4 100644 Binary files a/src/plugins/projectexplorer/images/mode_project_mask.png and b/src/plugins/projectexplorer/images/mode_project_mask.png differ diff --git a/src/plugins/projectexplorer/images/mode_project_mask@2x.png b/src/plugins/projectexplorer/images/mode_project_mask@2x.png index bd195752ac7..3538453911b 100644 Binary files a/src/plugins/projectexplorer/images/mode_project_mask@2x.png and b/src/plugins/projectexplorer/images/mode_project_mask@2x.png differ diff --git a/src/plugins/projectexplorer/images/rebuildhammerhandles.png b/src/plugins/projectexplorer/images/rebuildhammerhandles.png index d0c117da138..181b4f38814 100644 Binary files a/src/plugins/projectexplorer/images/rebuildhammerhandles.png and b/src/plugins/projectexplorer/images/rebuildhammerhandles.png differ diff --git a/src/plugins/projectexplorer/images/rebuildhammerhandles@2x.png b/src/plugins/projectexplorer/images/rebuildhammerhandles@2x.png index 9ea2b3a8710..a9742c822e3 100644 Binary files a/src/plugins/projectexplorer/images/rebuildhammerhandles@2x.png and b/src/plugins/projectexplorer/images/rebuildhammerhandles@2x.png differ diff --git a/src/plugins/projectexplorer/images/rebuildhammerheads.png b/src/plugins/projectexplorer/images/rebuildhammerheads.png index 24de5314c9d..b683bd8bd47 100644 Binary files a/src/plugins/projectexplorer/images/rebuildhammerheads.png and b/src/plugins/projectexplorer/images/rebuildhammerheads.png differ diff --git a/src/plugins/projectexplorer/images/rebuildhammerheads@2x.png b/src/plugins/projectexplorer/images/rebuildhammerheads@2x.png index 50f8757d194..ac71ffc9cc8 100644 Binary files a/src/plugins/projectexplorer/images/rebuildhammerheads@2x.png and b/src/plugins/projectexplorer/images/rebuildhammerheads@2x.png differ diff --git a/src/plugins/projectexplorer/images/run.png b/src/plugins/projectexplorer/images/run.png index 2df52b8e7f8..7650f122067 100644 Binary files a/src/plugins/projectexplorer/images/run.png and b/src/plugins/projectexplorer/images/run.png differ diff --git a/src/plugins/projectexplorer/images/run@2x.png b/src/plugins/projectexplorer/images/run@2x.png index 9e6e984d7ca..f55a9bd37c4 100644 Binary files a/src/plugins/projectexplorer/images/run@2x.png and b/src/plugins/projectexplorer/images/run@2x.png differ diff --git a/src/plugins/projectexplorer/images/run_mask.png b/src/plugins/projectexplorer/images/run_mask.png index aaaf05ce22d..d08de1ad5f0 100644 Binary files a/src/plugins/projectexplorer/images/run_mask.png and b/src/plugins/projectexplorer/images/run_mask.png differ diff --git a/src/plugins/projectexplorer/images/run_mask@2x.png b/src/plugins/projectexplorer/images/run_mask@2x.png index 38f6445c252..72af48223ed 100644 Binary files a/src/plugins/projectexplorer/images/run_mask@2x.png and b/src/plugins/projectexplorer/images/run_mask@2x.png differ diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 03e10fe2583..46b63e23934 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -65,21 +65,21 @@ static QIcon createCenteredIcon(const QIcon &icon, const QIcon &overlay) { QPixmap targetPixmap; const qreal appDevicePixelRatio = qApp->devicePixelRatio(); - int deviceSpaceIconSize = Core::Constants::TARGET_ICON_SIZE * appDevicePixelRatio; - targetPixmap = QPixmap(deviceSpaceIconSize, deviceSpaceIconSize); + targetPixmap = QPixmap(Core::Constants::MODEBAR_ICON_SIZE * appDevicePixelRatio, + Core::Constants::MODEBAR_ICON_SIZE * appDevicePixelRatio); targetPixmap.setDevicePixelRatio(appDevicePixelRatio); targetPixmap.fill(Qt::transparent); QPainter painter(&targetPixmap); // painter in user space - QPixmap pixmap = icon.pixmap(Core::Constants::TARGET_ICON_SIZE); // already takes app devicePixelRatio into account + QPixmap pixmap = icon.pixmap(Core::Constants::MODEBAR_ICON_SIZE); // already takes app devicePixelRatio into account qreal pixmapDevicePixelRatio = pixmap.devicePixelRatio(); - painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, - (Core::Constants::TARGET_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); + painter.drawPixmap((Core::Constants::MODEBAR_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, + (Core::Constants::MODEBAR_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); if (!overlay.isNull()) { - pixmap = overlay.pixmap(Core::Constants::TARGET_ICON_SIZE); // already takes app devicePixelRatio into account + pixmap = overlay.pixmap(Core::Constants::MODEBAR_ICON_SIZE); // already takes app devicePixelRatio into account pixmapDevicePixelRatio = pixmap.devicePixelRatio(); - painter.drawPixmap((Core::Constants::TARGET_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, - (Core::Constants::TARGET_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); + painter.drawPixmap((Core::Constants::MODEBAR_ICON_SIZE - pixmap.width() / pixmapDevicePixelRatio) / 2, + (Core::Constants::MODEBAR_ICON_SIZE - pixmap.height() / pixmapDevicePixelRatio) / 2, pixmap); } return QIcon(targetPixmap); diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 85e1a5a4add..649c3e658f5 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -1,6 +1,5 @@ - images/build_small.png images/category_buildrun.png images/closetab.png images/debugger_start.png @@ -12,6 +11,10 @@ images/mode_project_mask.png images/mode_project_mask@2x.png images/projectexplorer.png + images/buildhammerhandle.png + images/buildhammerhandle@2x.png + images/buildhammerhead.png + images/buildhammerhead@2x.png images/rebuildhammerhandles.png images/rebuildhammerhandles@2x.png images/rebuildhammerheads.png diff --git a/src/plugins/projectexplorer/projectexplorericons.cpp b/src/plugins/projectexplorer/projectexplorericons.cpp index e86fe915bc3..cd1913838da 100644 --- a/src/plugins/projectexplorer/projectexplorericons.cpp +++ b/src/plugins/projectexplorer/projectexplorericons.cpp @@ -34,10 +34,14 @@ const Icon BUILD(":/projectexplorer/images/build.png"); const Icon BUILD_FLAT({ {":/projectexplorer/images/build_hammerhandle_mask.png", Theme::IconsBuildHammerHandleColor}, {":/projectexplorer/images/build_hammerhead_mask.png", Theme::IconsBuildHammerHeadColor}}); -const Icon BUILD_SMALL(":/projectexplorer/images/build_small.png"); +const Icon BUILD_SMALL({ + {":/projectexplorer/images/buildhammerhandle.png", Theme::IconsBuildHammerHandleColor}, + {":/projectexplorer/images/buildhammerhead.png", Theme::IconsBuildHammerHeadColor}}, Icon::Tint); const Icon REBUILD({ {":/projectexplorer/images/rebuildhammerhandles.png", Theme::IconsBuildHammerHandleColor}, - {":/projectexplorer/images/rebuildhammerheads.png", Theme::IconsBuildHammerHeadColor}}, Icon::Tint); + {":/projectexplorer/images/buildhammerhandle.png", Theme::IconsBuildHammerHandleColor}, + {":/projectexplorer/images/rebuildhammerheads.png", Theme::IconsBuildHammerHeadColor}, + {":/projectexplorer/images/buildhammerhead.png", Theme::IconsBuildHammerHeadColor}}, Icon::Tint); const Icon RUN(":/projectexplorer/images/run.png"); const Icon RUN_FLAT({ {":/projectexplorer/images/run_mask.png", Theme::IconsRunToolBarColor}}); diff --git a/src/plugins/projectexplorer/projectmacro.cpp b/src/plugins/projectexplorer/projectmacro.cpp index cdbd48772e7..5d2824f01db 100644 --- a/src/plugins/projectexplorer/projectmacro.cpp +++ b/src/plugins/projectexplorer/projectmacro.cpp @@ -38,7 +38,11 @@ bool Macro::isValid() const QByteArray Macro::toByteArray() const { switch (type) { - case MacroType::Define: return QByteArray("#define ") + key + ' ' + value; + case MacroType::Define: { + if (value.isEmpty()) + return QByteArray("#define ") + key; + return QByteArray("#define ") + key + ' ' + value; + } case MacroType::Undefine: return QByteArray("#undef ") + key; case MacroType::Invalid: break; } @@ -109,6 +113,8 @@ QByteArray Macro::toKeyValue(const QByteArray &prefix) const keyValue = prefix; if (value.isEmpty()) + keyValue += key + '='; + else if (value == "1") keyValue += key; else keyValue += key + '=' + value; diff --git a/src/plugins/projectexplorer/runnables.cpp b/src/plugins/projectexplorer/runnables.cpp index 3ac15f53ef7..33d612f0adc 100644 --- a/src/plugins/projectexplorer/runnables.cpp +++ b/src/plugins/projectexplorer/runnables.cpp @@ -46,6 +46,7 @@ QUrl urlFromLocalHostAndFreePort() { QUrl serverUrl; QTcpServer server; + serverUrl.setScheme(urlTcpScheme()); if (server.listen(QHostAddress::LocalHost) || server.listen(QHostAddress::LocalHostIPv6)) { serverUrl.setHost(server.serverAddress().toString()); serverUrl.setPort(server.serverPort()); @@ -68,4 +69,9 @@ QString urlSocketScheme() return QString("socket"); } +QString urlTcpScheme() +{ + return QString("tcp"); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/runnables.h b/src/plugins/projectexplorer/runnables.h index f28aefeda4b..a893545d23a 100644 --- a/src/plugins/projectexplorer/runnables.h +++ b/src/plugins/projectexplorer/runnables.h @@ -56,5 +56,6 @@ PROJECTEXPLORER_EXPORT bool operator==(const StandardRunnable &r1, const Standar PROJECTEXPLORER_EXPORT QUrl urlFromLocalHostAndFreePort(); PROJECTEXPLORER_EXPORT QUrl urlFromLocalSocket(); PROJECTEXPLORER_EXPORT QString urlSocketScheme(); +PROJECTEXPLORER_EXPORT QString urlTcpScheme(); } // namespace ProjectExplorer diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp index ad968d38202..deb380e49ce 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.cpp @@ -49,19 +49,19 @@ namespace Internal { static const char ANDROID_RC_ID_PREFIX[] = "Qt4ProjectManager.AndroidRunConfiguration:"; -static QString pathFromId(const Core::Id id) +static Utils::FileName pathFromId(const Core::Id id) { - return id.suffixAfter(ANDROID_RC_ID_PREFIX); + return Utils::FileName::fromString(id.suffixAfter(ANDROID_RC_ID_PREFIX)); } QmakeAndroidRunConfiguration::QmakeAndroidRunConfiguration(Target *target) : AndroidRunConfiguration(target) {} -void QmakeAndroidRunConfiguration::initialize(Core::Id id, const Utils::FileName &path) +void QmakeAndroidRunConfiguration::initialize(Core::Id id) { AndroidRunConfiguration::initialize(id); - m_proFilePath = path; + m_proFilePath = pathFromId(id); ctor(); } @@ -110,7 +110,7 @@ QString QmakeAndroidRunConfiguration::defaultDisplayName() return node->displayName(); } - return QFileInfo(pathFromId(id())).completeBaseName(); + return displayNameForId(id()); } QString QmakeAndroidRunConfiguration::disabledReason() const @@ -129,6 +129,11 @@ QString QmakeAndroidRunConfiguration::buildSystemTarget() const return qmakeProject()->mapProFilePathToTarget(m_proFilePath); } +QString QmakeAndroidRunConfiguration::displayNameForId(Core::Id id) +{ + return pathFromId(id).toFileInfo().completeBaseName(); +} + QmakeProject *QmakeAndroidRunConfiguration::qmakeProject() const { Target *t = target(); diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.h b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.h index 817a78e2bac..c0265b9abbc 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.h +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunconfiguration.h @@ -50,9 +50,11 @@ public: QString buildSystemTarget() const final; + static QString displayNameForId(Core::Id id); + private: friend class ProjectExplorer::IRunConfigurationFactory; - void initialize(Core::Id id, const Utils::FileName &path = Utils::FileName()); + void initialize(Core::Id id); void copyFrom(const QmakeAndroidRunConfiguration *source); bool fromMap(const QVariantMap &map) override; diff --git a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp index e048479a420..4fd903972ce 100644 --- a/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp +++ b/src/plugins/qmakeandroidsupport/qmakeandroidrunfactories.cpp @@ -46,11 +46,6 @@ namespace Internal { static const char ANDROID_RC_ID_PREFIX[] = "Qt4ProjectManager.AndroidRunConfiguration:"; -static Utils::FileName pathFromId(const Core::Id id) -{ - return Utils::FileName::fromString(id.suffixAfter(ANDROID_RC_ID_PREFIX)); -} - QmakeAndroidRunConfigurationFactory::QmakeAndroidRunConfigurationFactory(QObject *parent) : IRunConfigurationFactory(parent) { @@ -58,7 +53,7 @@ QmakeAndroidRunConfigurationFactory::QmakeAndroidRunConfigurationFactory(QObject QString QmakeAndroidRunConfigurationFactory::displayNameForId(Core::Id id) const { - return pathFromId(id).toFileInfo().completeBaseName(); + return QmakeAndroidRunConfiguration::displayNameForId(id); } bool QmakeAndroidRunConfigurationFactory::canCreate(Target *parent, Core::Id id) const @@ -92,8 +87,6 @@ QList QmakeAndroidRunConfigurationFactory::availableCreationIds(Target RunConfiguration *QmakeAndroidRunConfigurationFactory::doCreate(Target *parent, Core::Id id) { - if (parent->project()->rootProjectNode()) - return createHelper(parent, id, pathFromId(id)); return createHelper(parent, id); } diff --git a/src/plugins/qmakeprojectmanager/profileeditor.cpp b/src/plugins/qmakeprojectmanager/profileeditor.cpp index 97c119c456e..637cb1b239c 100644 --- a/src/plugins/qmakeprojectmanager/profileeditor.cpp +++ b/src/plugins/qmakeprojectmanager/profileeditor.cpp @@ -46,6 +46,8 @@ #include #include +#include + using namespace TextEditor; using namespace Utils; @@ -89,7 +91,40 @@ ProFileEditorWidget::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cur // find the beginning of a filename QString buffer; int beginPos = positionInBlock - 1; - while (beginPos >= 0) { + int endPos = positionInBlock; + + // Check is cursor is somewhere on $${PWD}: + const int chunkStart = std::max(0, positionInBlock - 7); + const int chunkLength = 14 + std::min(0, positionInBlock - 7); + QString chunk = block.mid(chunkStart, chunkLength); + + const QString curlyPwd = "$${PWD}"; + const QString pwd = "$$PWD"; + const int posCurlyPwd = chunk.indexOf(curlyPwd); + const int posPwd = chunk.indexOf(pwd); + bool doBackwardScan = true; + + if (posCurlyPwd >= 0) { + const int end = chunkStart + posCurlyPwd + curlyPwd.count(); + const int start = chunkStart + posCurlyPwd; + if (start <= positionInBlock && end >= positionInBlock) { + buffer = pwd; + beginPos = chunkStart + posCurlyPwd - 1; + endPos = end; + doBackwardScan = false; + } + } else if (posPwd >= 0) { + const int end = chunkStart + posPwd + pwd.count(); + const int start = chunkStart + posPwd; + if (start <= positionInBlock && end >= positionInBlock) { + buffer = pwd; + beginPos = start - 1; + endPos = end; + doBackwardScan = false; + } + } + + while (doBackwardScan && beginPos >= 0) { QChar c = block.at(beginPos); if (isValidFileNameChar(c)) { buffer.prepend(c); @@ -99,8 +134,20 @@ ProFileEditorWidget::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cur } } + if (doBackwardScan + && beginPos > 0 + && block.mid(beginPos - 1, pwd.count()) == pwd + && (block.at(beginPos + pwd.count() - 1) == '/' || block.at(beginPos + pwd.count() - 1) == '\\')) { + buffer.prepend("$$"); + beginPos -= 2; + } else if (doBackwardScan + && beginPos >= curlyPwd.count() - 1 + && block.mid(beginPos - curlyPwd.count() + 1, curlyPwd.count()) == curlyPwd) { + buffer.prepend(pwd); + beginPos -= curlyPwd.count(); + } + // find the end of a filename - int endPos = positionInBlock; while (endPos < block.count()) { QChar c = block.at(endPos); if (isValidFileNameChar(c)) { @@ -121,13 +168,8 @@ ProFileEditorWidget::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cur } // if the buffer starts with $$PWD accept it - if (buffer.startsWith(QLatin1String("PWD/")) || - buffer.startsWith(QLatin1String("PWD\\"))) { - if (beginPos > 0 && block.mid(beginPos - 1, 2) == QLatin1String("$$")) { - beginPos -=2; - buffer = buffer.mid(4); - } - } + if (buffer.startsWith("$$PWD/") || buffer.startsWith("$$PWD\\")) + buffer = buffer.mid(6); QDir dir(textDocument()->filePath().toFileInfo().absolutePath()); QString fileName = dir.filePath(buffer); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index e8fbe3a71cf..eebf3c0f8d1 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -107,15 +107,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV : NodeInstanceServerInterface(nodeInstanceView), m_localServer(new QLocalServer(this)), m_nodeInstanceView(nodeInstanceView), - m_firstBlockSize(0), - m_secondBlockSize(0), - m_thirdBlockSize(0), - m_writeCommandCounter(0), - m_firstLastReadCommandCounter(0), - m_secondLastReadCommandCounter(0), - m_thirdLastReadCommandCounter(0), - m_runModus(runModus), - m_synchronizeId(-1) + m_runModus(runModus) { if (instanceViewBenchmark().isInfoEnabled()) m_benchmarkTimer.start(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h index 9ab15b15c7c..4cf8f1241e3 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h @@ -118,15 +118,15 @@ private: QPointer m_qmlPuppetEditorProcess; QPointer m_qmlPuppetPreviewProcess; QPointer m_qmlPuppetRenderProcess; - quint32 m_firstBlockSize; - quint32 m_secondBlockSize; - quint32 m_thirdBlockSize; - quint32 m_writeCommandCounter; - quint32 m_firstLastReadCommandCounter; - quint32 m_secondLastReadCommandCounter; - quint32 m_thirdLastReadCommandCounter; + quint32 m_firstBlockSize = 0; + quint32 m_secondBlockSize = 0; + quint32 m_thirdBlockSize = 0; + quint32 m_writeCommandCounter = 0; + quint32 m_firstLastReadCommandCounter = 0; + quint32 m_secondLastReadCommandCounter = 0; + quint32 m_thirdLastReadCommandCounter = 0; RunModus m_runModus; - int m_synchronizeId; + int m_synchronizeId = -1; QTime m_benchmarkTimer; }; diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index ce532708143..d73f96df940 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -749,10 +749,6 @@ bool operator <(const ModelNode &firstNode, const ModelNode &secondNode) Internal::InternalNodePointer ModelNode::internalNode() const { - if (!isValid()) { - Q_ASSERT_X(isValid(), Q_FUNC_INFO, "model node is invalid"); - throw InvalidModelNodeException(__LINE__, __FUNCTION__, __FILE__); - } return m_internalNode; } diff --git a/src/plugins/qmldesigner/designercore/model/textmodifier.cpp b/src/plugins/qmldesigner/designercore/model/textmodifier.cpp index 8b5ea35ff1c..9016619f6db 100644 --- a/src/plugins/qmldesigner/designercore/model/textmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/textmodifier.cpp @@ -26,7 +26,8 @@ #include "textmodifier.h" #include -#include + +#include using namespace QmlDesigner; @@ -38,7 +39,7 @@ int TextModifier::getLineInDocument(QTextDocument *document, int offset) { int line = -1; int column = -1; - TextEditor::Convenience::convertPosition(document, offset, &line, &column); + Utils::Text::convertPosition(document, offset, &line, &column); return line; } diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp index 2b919e7f429..0152d994e4a 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.cpp @@ -29,6 +29,7 @@ #include "qmlprofilerstatemanager.h" #include +#include namespace QmlProfiler { namespace Internal { @@ -65,13 +66,19 @@ void QmlProfilerClientManager::setRetryParams(int interval, int maxAttempts) m_maximumRetries = maxAttempts; } -void QmlProfilerClientManager::setServerUrl(const QUrl &server) +void QmlProfilerClientManager::connectToServer(const QUrl &server) { if (m_server != server) { m_server = server; disconnectClient(); stopConnectionTimer(); } + if (server.scheme() == ProjectExplorer::urlTcpScheme()) + connectToTcpServer(); + else if (server.scheme() == ProjectExplorer::urlSocketScheme()) + startLocalServer(); + else + QTC_ASSERT(false, emit connectionFailed()); } void QmlProfilerClientManager::clearConnection() @@ -166,9 +173,9 @@ void QmlProfilerClientManager::stopRecording() void QmlProfilerClientManager::retryConnect() { - if (m_server.scheme() == "socket") { + if (m_server.scheme() == ProjectExplorer::urlSocketScheme()) { startLocalServer(); - } else if (!m_server.host().isEmpty() && m_server.port() > 0) { + } else if (m_server.scheme() == ProjectExplorer::urlTcpScheme()) { disconnectClient(); connectToTcpServer(); } else { diff --git a/src/plugins/qmlprofiler/qmlprofilerclientmanager.h b/src/plugins/qmlprofiler/qmlprofilerclientmanager.h index 61a9d178004..c64429abc70 100644 --- a/src/plugins/qmlprofiler/qmlprofilerclientmanager.h +++ b/src/plugins/qmlprofiler/qmlprofilerclientmanager.h @@ -47,7 +47,7 @@ public: ~QmlProfilerClientManager(); void setProfilerStateManager(QmlProfilerStateManager *profilerState); - void setServerUrl(const QUrl &server); + void connectToServer(const QUrl &server); void clearConnection(); void clearBufferedData(); @@ -58,8 +58,6 @@ public: void setRetryParams(int interval, int maxAttempts); void retryConnect(); - void connectToTcpServer(); - void startLocalServer(); void stopRecording(); @@ -69,6 +67,9 @@ signals: void connectionClosed(); private: + void connectToTcpServer(); + void startLocalServer(); + QPointer m_profilerState; QPointer m_modelManager; QScopedPointer m_connection; diff --git a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp index 143e317cd75..7a24026e93e 100644 --- a/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerruncontrol.cpp @@ -127,17 +127,10 @@ void QmlProfilerRunner::start() }); infoBox->show(); - }); - - clientManager->setServerUrl(serverUrl); - if (serverUrl.port() != -1) { - clientManager->connectToTcpServer(); - } else { - clientManager->startLocalServer(); - } + }, Qt::QueuedConnection); // Queue any connection failures after reportStarted() + clientManager->connectToServer(serverUrl); d->m_profilerState->setCurrentState(QmlProfilerStateManager::AppRunning); - reportStarted(); } @@ -284,9 +277,13 @@ LocalQmlProfilerSupport::LocalQmlProfilerSupport(RunControl *runControl, const Q StandardRunnable debuggee = runnable().as(); - QString code = serverUrl.scheme() == "socket" - ? QString("file:%1").arg(serverUrl.path()) - : QString("port:%1").arg(serverUrl.port()); + QString code; + if (serverUrl.scheme() == urlSocketScheme()) + code = QString("file:%1").arg(serverUrl.path()); + else if (serverUrl.scheme() == urlTcpScheme()) + code = QString("port:%1").arg(serverUrl.port()); + else + QTC_CHECK(false); QString arguments = QmlDebug::qmlDebugCommandLineArguments(QmlDebug::QmlProfilerServices, code, true); diff --git a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp index 53489eaee8b..754455c86b4 100644 --- a/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp +++ b/src/plugins/qmlprofiler/tests/localqmlprofilerrunner_test.cpp @@ -56,6 +56,7 @@ void LocalQmlProfilerRunnerTest::testRunner() debuggee.environment = Utils::Environment::systemEnvironment(); // should not be used anywhere but cannot be empty + serverUrl.setScheme(ProjectExplorer::urlSocketScheme()); serverUrl.setPath("invalid"); runControl = new ProjectExplorer::RunControl(nullptr, diff --git a/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp b/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp index d2347d42640..0318a6b6185 100644 --- a/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp +++ b/src/plugins/qmlprofiler/tests/qmlprofilerclientmanager_test.cpp @@ -73,38 +73,32 @@ void QmlProfilerClientManagerTest::testConnectionFailure_data() QUrl localUrl = urlFromLocalHostAndFreePort(); QTest::addColumn("serverUrl"); - QVarLengthArray hosts({"", "/-/|\\-\\|/-", localUrl.host()}); - QVarLengthArray ports({-1, 5, localUrl.port()}); - QVarLengthArray sockets({"", "/-/|\\-\\|/-", urlFromLocalSocket().path()}); + const QVarLengthArray hosts({"", "/-/|\\-\\|/-", localUrl.host()}); + const QVarLengthArray ports({-1, 5, localUrl.port()}); + const QVarLengthArray sockets({"", "/-/|\\-\\|/-", urlFromLocalSocket().path()}); + const QVarLengthArray schemes({"", urlSocketScheme(), urlTcpScheme()}); - foreach (QmlProfilerModelManager *modelManager, modelManagers) { - foreach (QmlProfilerStateManager *stateManager, stateManagers) { - foreach (QString host, hosts) { - foreach (int port, ports) { - QString tag = QString::fromLatin1("%1, %2, %3, %4, %5") - .arg(QLatin1String(modelManager ? "modelManager" : "")) - .arg(QLatin1String(stateManager ? "stateManager" : "")) - .arg(host.isEmpty() ? "" : host) - .arg(Utils::Port(port).isValid() ? port : 0) - .arg(""); - QUrl url; - url.setHost(host); - url.setPort(port); - QTest::newRow(tag.toLatin1().constData()) << modelManager << stateManager << url; + for (QmlProfilerModelManager *modelManager : modelManagers) { + for (QmlProfilerStateManager *stateManager : stateManagers) { + for (const QString &host : hosts) { + for (int port : ports) { + for (const QString &socket : sockets) { + for (const QString &scheme : schemes ) { + QUrl url; + url.setScheme(scheme); + url.setHost(host); + url.setPort(port); + url.setPath(socket); + QString tag = QString::fromLatin1("%1, %2, %3") + .arg(QLatin1String(modelManager ? "modelManager" : "")) + .arg(QLatin1String(stateManager ? "stateManager" : "")) + .arg(url.toString()); + QTest::newRow(tag.toLatin1().constData()) << modelManager + << stateManager << url; + } + } } } - foreach (QString socket, sockets) { - QString tag = QString::fromLatin1("%1, %2, %3, %4, %5") - .arg(QLatin1String(modelManager ? "modelManager" : "")) - .arg(QLatin1String(stateManager ? "stateManager" : "")) - .arg("") - .arg(0) - .arg(socket); - QUrl url; - url.setScheme(urlSocketScheme()); - url.setPath(socket); - QTest::newRow(tag.toLatin1().constData()) << modelManager << stateManager << url; - } } } } @@ -137,24 +131,17 @@ void QmlProfilerClientManagerTest::testConnectionFailure() clientManager.setModelManager(modelManager); clientManager.setProfilerStateManager(stateManager); - clientManager.setServerUrl(serverUrl); QVERIFY(!clientManager.isConnected()); - clientManager.connectToTcpServer(); + clientManager.connectToServer(serverUrl); QTRY_COMPARE(failedSpy.count(), 1); QCOMPARE(closedSpy.count(), 0); QCOMPARE(openedSpy.count(), 0); QVERIFY(!clientManager.isConnected()); - clientManager.startLocalServer(); - QTRY_COMPARE(failedSpy.count(), 2); - QCOMPARE(closedSpy.count(), 0); - QCOMPARE(openedSpy.count(), 0); - QVERIFY(!clientManager.isConnected()); - clientManager.retryConnect(); - QTRY_COMPARE(failedSpy.count(), 3); + QTRY_COMPARE(failedSpy.count(), 2); QCOMPARE(closedSpy.count(), 0); QCOMPARE(openedSpy.count(), 0); QVERIFY(!clientManager.isConnected()); @@ -181,8 +168,7 @@ void QmlProfilerClientManagerTest::testUnresponsiveTcp() server.listen(QHostAddress(serverUrl.host()), serverUrl.port()); QSignalSpy connectionSpy(&server, SIGNAL(newConnection())); - clientManager.setServerUrl(serverUrl); - clientManager.connectToTcpServer(); + clientManager.connectToServer(serverUrl); QTRY_VERIFY(connectionSpy.count() > 0); QTRY_COMPARE(failedSpy.count(), 1); @@ -208,8 +194,7 @@ void QmlProfilerClientManagerTest::testUnresponsiveLocal() QLocalSocket socket; QSignalSpy connectionSpy(&socket, SIGNAL(connected())); - clientManager.setServerUrl(socketUrl); - clientManager.startLocalServer(); + clientManager.connectToServer(socketUrl); socket.connectToServer(socketUrl.path()); QTRY_COMPARE(connectionSpy.count(), 1); @@ -280,8 +265,7 @@ void QmlProfilerClientManagerTest::testResponsiveTcp() connect(&clientManager, &QmlProfilerClientManager::connectionFailed, &clientManager, &QmlProfilerClientManager::retryConnect); - clientManager.setServerUrl(serverUrl); - clientManager.connectToTcpServer(); + clientManager.connectToServer(serverUrl); QTRY_COMPARE(openedSpy.count(), 1); QCOMPARE(closedSpy.count(), 0); @@ -329,8 +313,7 @@ void QmlProfilerClientManagerTest::testResponsiveLocal() connect(&clientManager, &QmlProfilerClientManager::connectionFailed, &clientManager, &QmlProfilerClientManager::retryConnect); - clientManager.setServerUrl(socketUrl); - clientManager.startLocalServer(); + clientManager.connectToServer(socketUrl); { QScopedPointer socket(new QLocalSocket(this)); @@ -397,8 +380,7 @@ void QmlProfilerClientManagerTest::testInvalidData() server.listen(QHostAddress(serverUrl.host()), serverUrl.port()); - clientManager.setServerUrl(serverUrl); - clientManager.connectToTcpServer(); + clientManager.connectToServer(serverUrl); QTRY_VERIFY(dataSent); QTRY_COMPARE(failedSpy.count(), 1); @@ -427,8 +409,7 @@ void QmlProfilerClientManagerTest::testStopRecording() connect(&clientManager, &QmlProfilerClientManager::connectionFailed, &clientManager, &QmlProfilerClientManager::retryConnect); - clientManager.setServerUrl(socketUrl); - clientManager.startLocalServer(); + clientManager.connectToServer(socketUrl); QScopedPointer socket(new QLocalSocket(this)); socket->connectToServer(socketUrl.path()); diff --git a/src/plugins/resourceeditor/resourceeditorplugin.cpp b/src/plugins/resourceeditor/resourceeditorplugin.cpp index 07c532f4eff..bc28f947475 100644 --- a/src/plugins/resourceeditor/resourceeditorplugin.cpp +++ b/src/plugins/resourceeditor/resourceeditorplugin.cpp @@ -283,7 +283,7 @@ void ResourceEditorPlugin::renameFileContextMenu() void ResourceEditorPlugin::removeFileContextMenu() { - auto rfn = dynamic_cast(ProjectTree::findCurrentNode()); + auto rfn = dynamic_cast(ProjectTree::findCurrentNode()); QTC_ASSERT(rfn, return); QString path = rfn->filePath().toString(); FolderNode *parent = rfn->parentFolderNode(); diff --git a/src/plugins/texteditor/codeassist/assistinterface.cpp b/src/plugins/texteditor/codeassist/assistinterface.cpp index 42670678895..3577718dfb4 100644 --- a/src/plugins/texteditor/codeassist/assistinterface.cpp +++ b/src/plugins/texteditor/codeassist/assistinterface.cpp @@ -91,7 +91,7 @@ using namespace TextEditor; #include "assistinterface.h" -#include +#include #include #include @@ -125,7 +125,7 @@ QChar AssistInterface::characterAt(int position) const QString AssistInterface::textAt(int pos, int length) const { - return Convenience::textAt(QTextCursor(m_textDocument), pos, length); + return Utils::Text::textAt(QTextCursor(m_textDocument), pos, length); } void AssistInterface::prepareForAsyncUse() diff --git a/src/plugins/texteditor/textdocument.cpp b/src/plugins/texteditor/textdocument.cpp index 7c53c812962..1bb79b9e83a 100644 --- a/src/plugins/texteditor/textdocument.cpp +++ b/src/plugins/texteditor/textdocument.cpp @@ -25,7 +25,6 @@ #include "textdocument.h" -#include "convenience.h" #include "extraencodingsettings.h" #include "fontsettings.h" #include "indenter.h" @@ -39,6 +38,7 @@ #include #include #include +#include #include #include @@ -303,7 +303,7 @@ QString TextDocument::plainText() const QString TextDocument::textAt(int pos, int length) const { - return Convenience::textAt(QTextCursor(document()), pos, length); + return Utils::Text::textAt(QTextCursor(document()), pos, length); } QChar TextDocument::characterAt(int pos) const diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 34594795670..80365d7449c 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -37,7 +37,6 @@ #include "circularclipboardassist.h" #include "codecselector.h" #include "completionsettings.h" -#include "convenience.h" #include "highlighterutils.h" #include "icodestylepreferences.h" #include "indenter.h" @@ -77,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -267,7 +267,7 @@ public: // Does the last handler still applies? const int documentRevision = textCursor.document()->revision(); - const int position = Convenience::wordStartCursor(textCursor).position(); + const int position = Text::wordStartCursor(textCursor).position(); if (m_lastHandlerInfo.applies(documentRevision, position)) { m_lastHandlerInfo.handler->showToolTip(m_widget, point, /*decorate=*/ false); return; @@ -1448,7 +1448,7 @@ bool TextEditorWidget::selectBlockUp() if (!TextBlockUserData::findNextClosingParenthesis(&cursor, true)) return false; - setTextCursor(Convenience::flippedCursor(cursor)); + setTextCursor(Text::flippedCursor(cursor)); d->_q_matchParentheses(); return true; } @@ -1473,7 +1473,7 @@ bool TextEditorWidget::selectBlockDown() if ( cursor != d->m_selectBlockAnchor) TextBlockUserData::findNextClosingParenthesis(&cursor, true); - setTextCursor(Convenience::flippedCursor(cursor)); + setTextCursor(Text::flippedCursor(cursor)); d->_q_matchParentheses(); return true; } @@ -2802,7 +2802,7 @@ QRect TextEditorWidget::cursorRect(int pos) const void TextEditorWidget::convertPosition(int pos, int *line, int *column) const { - Convenience::convertPosition(document(), pos, line, column); + Text::convertPosition(document(), pos, line, column); } bool TextEditorWidget::event(QEvent *e) @@ -4324,7 +4324,6 @@ void TextEditorWidget::paintEvent(QPaintEvent *e) for (int i = line.lineNumber() + 1; i < eline.lineNumber(); ++i) { rr = layout->lineAt(i).naturalTextRect(); rr.moveTop(rr.top() + r.top()); - rr.setLeft(r.left() + x); painter.fillRect(rr, palette().highlight()); } diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 1ef00e05174..d83d1654432 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -77,7 +77,6 @@ SOURCES += texteditorplugin.cpp \ snippets/snippetassistcollector.cpp \ codeassist/assistinterface.cpp \ codeassist/assistproposalitem.cpp \ - convenience.cpp \ codeassist/runner.cpp \ codeassist/completionassistprovider.cpp \ codeassist/genericproposalmodel.cpp \ @@ -187,7 +186,6 @@ HEADERS += texteditorplugin.h \ snippets/snippetassistcollector.h \ codeassist/assistinterface.h \ codeassist/assistproposalitem.h \ - convenience.h \ codeassist/assistenums.h \ codeassist/runner.h \ codeassist/assistproposaliteminterface.h \ diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 2b5f43e2478..1dfbde68a85 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -58,8 +58,6 @@ Project { "completionsettingspage.cpp", "completionsettingspage.h", "completionsettingspage.ui", - "convenience.cpp", - "convenience.h", "displaysettings.cpp", "displaysettings.h", "displaysettingspage.cpp", diff --git a/src/plugins/valgrind/memcheckengine.cpp b/src/plugins/valgrind/memcheckengine.cpp deleted file mode 100644 index 8e6202e4d88..00000000000 --- a/src/plugins/valgrind/memcheckengine.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Author: Nicolas Arnaud-Cormos, KDAB (nicolas.arnaud-cormos@kdab.com) -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "memcheckengine.h" -#include "memchecktool.h" -#include "valgrindsettings.h" -#include "xmlprotocol/error.h" -#include "xmlprotocol/status.h" - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -using namespace Debugger; -using namespace ProjectExplorer; -using namespace Valgrind::XmlProtocol; - -namespace Valgrind { -namespace Internal { - -class LocalAddressFinder : public RunWorker -{ -public: - LocalAddressFinder(RunControl *runControl, QHostAddress *localServerAddress) - : RunWorker(runControl), connection(device()->sshParameters()) - { - connect(&connection, &QSsh::SshConnection::connected, this, [this, localServerAddress] { - *localServerAddress = connection.connectionInfo().localAddress; - reportStarted(); - }); - connect(&connection, &QSsh::SshConnection::error, this, [this] { - reportFailure(); - }); - } - - void start() override - { - connection.connectToHost(); - } - - QSsh::SshConnection connection; -}; - -MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb) - : ValgrindToolRunner(runControl), - m_withGdb(withGdb), - m_localServerAddress(QHostAddress::LocalHost) -{ - setDisplayName("MemcheckToolRunner"); - connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error, - this, &MemcheckToolRunner::parserError); - connect(m_runner.parser(), &XmlProtocol::ThreadedParser::suppressionCount, - this, &MemcheckToolRunner::suppressionCount); - - if (withGdb) { - connect(&m_runner, &ValgrindRunner::valgrindStarted, - this, &MemcheckToolRunner::startDebugger); - connect(&m_runner, &ValgrindRunner::logMessageReceived, - this, &MemcheckToolRunner::appendLog); -// m_runner.disableXml(); - } else { - connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError, - this, &MemcheckToolRunner::internalParserError); - } - - // We need a real address to connect to from the outside. - if (device()->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) - addStartDependency(new LocalAddressFinder(runControl, &m_localServerAddress)); -} - -QString MemcheckToolRunner::progressTitle() const -{ - return tr("Analyzing Memory"); -} - -void MemcheckToolRunner::start() -{ - m_runner.setLocalServerAddress(m_localServerAddress); - ValgrindToolRunner::start(); -} - -void MemcheckToolRunner::stop() -{ - disconnect(m_runner.parser(), &ThreadedParser::internalError, - this, &MemcheckToolRunner::internalParserError); - ValgrindToolRunner::stop(); -} - -QStringList MemcheckToolRunner::toolArguments() const -{ - QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"}; - - QTC_ASSERT(m_settings, return arguments); - - if (m_settings->trackOrigins()) - arguments << "--track-origins=yes"; - - if (m_settings->showReachable()) - arguments << "--show-reachable=yes"; - - QString leakCheckValue; - switch (m_settings->leakCheckOnFinish()) { - case ValgrindBaseSettings::LeakCheckOnFinishNo: - leakCheckValue = "no"; - break; - case ValgrindBaseSettings::LeakCheckOnFinishYes: - leakCheckValue = "full"; - break; - case ValgrindBaseSettings::LeakCheckOnFinishSummaryOnly: - default: - leakCheckValue = "summary"; - break; - } - arguments << "--leak-check=" + leakCheckValue; - - foreach (const QString &file, m_settings->suppressionFiles()) - arguments << QString("--suppressions=%1").arg(file); - - arguments << QString("--num-callers=%1").arg(m_settings->numCallers()); - - if (m_withGdb) - arguments << "--vgdb=yes" << "--vgdb-error=0"; - - return arguments; -} - -QStringList MemcheckToolRunner::suppressionFiles() const -{ - return m_settings->suppressionFiles(); -} - -void MemcheckToolRunner::startDebugger(qint64 valgrindPid) -{ - auto debugger = new Debugger::DebuggerRunTool(runControl()); - debugger->setStartMode(Debugger::AttachToRemoteServer); - debugger->setRunControlName(QString("VGdb %1").arg(valgrindPid)); - debugger->setRemoteChannel(QString("| vgdb --pid=%1").arg(valgrindPid)); - debugger->setUseContinueInsteadOfRun(true); - debugger->addExpectedSignal("SIGTRAP"); - - connect(runControl(), &RunControl::stopped, debugger, &RunControl::deleteLater); - - debugger->initiateStart(); -} - -void MemcheckToolRunner::appendLog(const QByteArray &data) -{ - appendMessage(QString::fromUtf8(data), Utils::StdOutFormat); -} - -} // namespace Internal -} // namespace Valgrind diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index 917bafa888e..f668ee3a5fb 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -25,36 +25,44 @@ ****************************************************************************/ #include "memchecktool.h" -#include "memcheckengine.h" + #include "memcheckerrorview.h" #include "valgrindsettings.h" #include "valgrindplugin.h" +#include "valgrindengine.h" +#include "valgrindsettings.h" +#include "valgrindrunner.h" +#include "xmlprotocol/error.h" +#include "xmlprotocol/error.h" +#include "xmlprotocol/errorlistmodel.h" +#include "xmlprotocol/frame.h" +#include "xmlprotocol/stack.h" +#include "xmlprotocol/stackmodel.h" +#include "xmlprotocol/status.h" +#include "xmlprotocol/suppression.h" +#include "xmlprotocol/threadedparser.h" + +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include #include @@ -67,20 +75,20 @@ #include #include -#include #include #include #include #include #include -#include #include +#include using namespace Core; using namespace Debugger; using namespace ProjectExplorer; using namespace Utils; using namespace Valgrind::XmlProtocol; + using namespace std::placeholders; namespace Valgrind { @@ -92,6 +100,167 @@ const char MEMCHECK_WITH_GDB_RUN_MODE[] = "MemcheckTool.MemcheckWithGdbRunMode"; const char MemcheckPerspectiveId[] = "Memcheck.Perspective"; const char MemcheckErrorDockId[] = "Memcheck.Dock.Error"; + +class MemcheckToolRunner : public ValgrindToolRunner +{ + Q_OBJECT + +public: + explicit MemcheckToolRunner(ProjectExplorer::RunControl *runControl, + bool withGdb = false); + + void start() override; + void stop() override; + + QStringList suppressionFiles() const; + +signals: + void internalParserError(const QString &errorString); + void parserError(const Valgrind::XmlProtocol::Error &error); + void suppressionCount(const QString &name, qint64 count); + +private: + QString progressTitle() const override; + QStringList toolArguments() const override; + + void startDebugger(qint64 valgrindPid); + void appendLog(const QByteArray &data); + + const bool m_withGdb; + QHostAddress m_localServerAddress; +}; + +class LocalAddressFinder : public RunWorker +{ +public: + LocalAddressFinder(RunControl *runControl, QHostAddress *localServerAddress) + : RunWorker(runControl), connection(device()->sshParameters()) + { + connect(&connection, &QSsh::SshConnection::connected, this, [this, localServerAddress] { + *localServerAddress = connection.connectionInfo().localAddress; + reportStarted(); + }); + connect(&connection, &QSsh::SshConnection::error, this, [this] { + reportFailure(); + }); + } + + void start() override + { + connection.connectToHost(); + } + + QSsh::SshConnection connection; +}; + +MemcheckToolRunner::MemcheckToolRunner(RunControl *runControl, bool withGdb) + : ValgrindToolRunner(runControl), + m_withGdb(withGdb), + m_localServerAddress(QHostAddress::LocalHost) +{ + setDisplayName("MemcheckToolRunner"); + connect(m_runner.parser(), &XmlProtocol::ThreadedParser::error, + this, &MemcheckToolRunner::parserError); + connect(m_runner.parser(), &XmlProtocol::ThreadedParser::suppressionCount, + this, &MemcheckToolRunner::suppressionCount); + + if (withGdb) { + connect(&m_runner, &ValgrindRunner::valgrindStarted, + this, &MemcheckToolRunner::startDebugger); + connect(&m_runner, &ValgrindRunner::logMessageReceived, + this, &MemcheckToolRunner::appendLog); +// m_runner.disableXml(); + } else { + connect(m_runner.parser(), &XmlProtocol::ThreadedParser::internalError, + this, &MemcheckToolRunner::internalParserError); + } + + // We need a real address to connect to from the outside. + if (device()->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) + addStartDependency(new LocalAddressFinder(runControl, &m_localServerAddress)); +} + +QString MemcheckToolRunner::progressTitle() const +{ + return tr("Analyzing Memory"); +} + +void MemcheckToolRunner::start() +{ + m_runner.setLocalServerAddress(m_localServerAddress); + ValgrindToolRunner::start(); +} + +void MemcheckToolRunner::stop() +{ + disconnect(m_runner.parser(), &ThreadedParser::internalError, + this, &MemcheckToolRunner::internalParserError); + ValgrindToolRunner::stop(); +} + +QStringList MemcheckToolRunner::toolArguments() const +{ + QStringList arguments = {"--tool=memcheck", "--gen-suppressions=all"}; + + QTC_ASSERT(m_settings, return arguments); + + if (m_settings->trackOrigins()) + arguments << "--track-origins=yes"; + + if (m_settings->showReachable()) + arguments << "--show-reachable=yes"; + + QString leakCheckValue; + switch (m_settings->leakCheckOnFinish()) { + case ValgrindBaseSettings::LeakCheckOnFinishNo: + leakCheckValue = "no"; + break; + case ValgrindBaseSettings::LeakCheckOnFinishYes: + leakCheckValue = "full"; + break; + case ValgrindBaseSettings::LeakCheckOnFinishSummaryOnly: + default: + leakCheckValue = "summary"; + break; + } + arguments << "--leak-check=" + leakCheckValue; + + foreach (const QString &file, m_settings->suppressionFiles()) + arguments << QString("--suppressions=%1").arg(file); + + arguments << QString("--num-callers=%1").arg(m_settings->numCallers()); + + if (m_withGdb) + arguments << "--vgdb=yes" << "--vgdb-error=0"; + + return arguments; +} + +QStringList MemcheckToolRunner::suppressionFiles() const +{ + return m_settings->suppressionFiles(); +} + +void MemcheckToolRunner::startDebugger(qint64 valgrindPid) +{ + auto debugger = new Debugger::DebuggerRunTool(runControl()); + debugger->setStartMode(Debugger::AttachToRemoteServer); + debugger->setRunControlName(QString("VGdb %1").arg(valgrindPid)); + debugger->setRemoteChannel(QString("| vgdb --pid=%1").arg(valgrindPid)); + debugger->setUseContinueInsteadOfRun(true); + debugger->addExpectedSignal("SIGTRAP"); + + connect(runControl(), &RunControl::stopped, debugger, &RunControl::deleteLater); + + debugger->initiateStart(); +} + +void MemcheckToolRunner::appendLog(const QByteArray &data) +{ + appendMessage(QString::fromUtf8(data), Utils::StdOutFormat); +} + + static ErrorListModel::RelevantFrameFinder makeFrameFinder(const QStringList &projectFiles) { return [projectFiles](const Error &error) { @@ -711,3 +880,5 @@ void destroyMemcheckTool() } // namespace Internal } // namespace Valgrind + +#include "memchecktool.moc" diff --git a/src/plugins/valgrind/valgrind.pro b/src/plugins/valgrind/valgrind.pro index 4bbd41fc5c7..216e3568173 100644 --- a/src/plugins/valgrind/valgrind.pro +++ b/src/plugins/valgrind/valgrind.pro @@ -21,7 +21,6 @@ HEADERS += \ workarounds.h \ callgrindtextmark.h \ memchecktool.h \ - memcheckengine.h \ memcheckerrorview.h \ suppressiondialog.h @@ -41,7 +40,6 @@ SOURCES += \ workarounds.cpp \ callgrindtextmark.cpp \ memchecktool.cpp \ - memcheckengine.cpp \ memcheckerrorview.cpp \ suppressiondialog.cpp diff --git a/src/plugins/valgrind/valgrind.qbs b/src/plugins/valgrind/valgrind.qbs index 44814d0ce6f..5b7fb8f040c 100644 --- a/src/plugins/valgrind/valgrind.qbs +++ b/src/plugins/valgrind/valgrind.qbs @@ -27,7 +27,6 @@ QtcPlugin { "callgrindtextmark.cpp", "callgrindtextmark.h", "callgrindtool.cpp", "callgrindtool.h", "callgrindvisualisation.cpp", "callgrindvisualisation.h", - "memcheckengine.cpp", "memcheckengine.h", "memcheckerrorview.cpp", "memcheckerrorview.h", "memchecktool.cpp", "memchecktool.h", "suppressiondialog.cpp", "suppressiondialog.h", diff --git a/src/plugins/welcome/images/mode_edit_mask.png b/src/plugins/welcome/images/mode_edit_mask.png deleted file mode 100644 index 221f4915193..00000000000 Binary files a/src/plugins/welcome/images/mode_edit_mask.png and /dev/null differ diff --git a/src/plugins/welcome/images/mode_welcome.png b/src/plugins/welcome/images/mode_welcome.png index 24cfcd8cc8e..186b85f1918 100644 Binary files a/src/plugins/welcome/images/mode_welcome.png and b/src/plugins/welcome/images/mode_welcome.png differ diff --git a/src/plugins/welcome/images/mode_welcome@2x.png b/src/plugins/welcome/images/mode_welcome@2x.png index f1e91895231..f911a462542 100644 Binary files a/src/plugins/welcome/images/mode_welcome@2x.png and b/src/plugins/welcome/images/mode_welcome@2x.png differ diff --git a/src/plugins/welcome/images/mode_welcome_mask.png b/src/plugins/welcome/images/mode_welcome_mask.png index 86912bb0695..696af0c5499 100644 Binary files a/src/plugins/welcome/images/mode_welcome_mask.png and b/src/plugins/welcome/images/mode_welcome_mask.png differ diff --git a/src/plugins/welcome/images/mode_welcome_mask@2x.png b/src/plugins/welcome/images/mode_welcome_mask@2x.png index daee953529c..060ada0cf54 100644 Binary files a/src/plugins/welcome/images/mode_welcome_mask@2x.png and b/src/plugins/welcome/images/mode_welcome_mask@2x.png differ diff --git a/src/plugins/welcome/welcome.qrc b/src/plugins/welcome/welcome.qrc index 5321c6ebd46..28e8d22d1c8 100644 --- a/src/plugins/welcome/welcome.qrc +++ b/src/plugins/welcome/welcome.qrc @@ -8,7 +8,6 @@ images/blogs@2x.png images/community.png images/community@2x.png - images/mode_edit_mask.png images/open.png images/open@2x.png images/project.png diff --git a/src/plugins/winrt/images/winrtdevice.png b/src/plugins/winrt/images/winrtdevice.png index d8f5bb71211..2b45adb69a1 100644 Binary files a/src/plugins/winrt/images/winrtdevice.png and b/src/plugins/winrt/images/winrtdevice.png differ diff --git a/src/plugins/winrt/images/winrtdevice@2x.png b/src/plugins/winrt/images/winrtdevice@2x.png index 305c2e9376d..a57f2b49783 100644 Binary files a/src/plugins/winrt/images/winrtdevice@2x.png and b/src/plugins/winrt/images/winrtdevice@2x.png differ diff --git a/src/shared/clang/clang_installation.pri b/src/shared/clang/clang_installation.pri index 517ded4e4b4..f7428c0be3c 100644 --- a/src/shared/clang/clang_installation.pri +++ b/src/shared/clang/clang_installation.pri @@ -3,10 +3,10 @@ LLVM_INSTALL_DIR = $$clean_path($$LLVM_INSTALL_DIR) isEmpty(LLVM_INSTALL_DIR): error("No LLVM_INSTALL_DIR provided") !exists($$LLVM_INSTALL_DIR): error("LLVM_INSTALL_DIR does not exist: $$LLVM_INSTALL_DIR") -defineReplace(extractVersion) { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)$, \\1)) } -defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+$, \\1)) } -defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+$, \\1)) } -defineReplace(extractPatchVersion) { return($$replace(1, ^\\d+\\.\\d+\\.(\\d+)$, \\1)) } +defineReplace(extractVersion) { return($$replace(1, ^(\\d+\\.\\d+\\.\\d+)\\w*$, \\1)) } +defineReplace(extractMajorVersion) { return($$replace(1, ^(\\d+)\\.\\d+\\.\\d+\\w*$, \\1)) } +defineReplace(extractMinorVersion) { return($$replace(1, ^\\d+\\.(\\d+)\\.\\d+\\w*$, \\1)) } +defineReplace(extractPatchVersion) { return($$replace(1, ^\\d+\\.\\d+\\.(\\d+)\\w*$, \\1)) } defineTest(versionIsAtLeast) { actual_major_version = $$extractMajorVersion($$1) diff --git a/src/tools/clangbackend/ipcsource/clangasyncjob.h b/src/tools/clangbackend/ipcsource/clangasyncjob.h index c8a7b799473..58b6a1f8455 100644 --- a/src/tools/clangbackend/ipcsource/clangasyncjob.h +++ b/src/tools/clangbackend/ipcsource/clangasyncjob.h @@ -47,7 +47,7 @@ public: Result asyncResult() const { return m_futureWatcher.future().result(); } - QFuture runAsync() override + QFuture runAsync() final { const auto onFinished = [this]() { finalizeAsyncRun(); @@ -64,7 +64,7 @@ public: return future; } - void preventFinalization() override + void preventFinalization() final { m_futureWatcher.disconnect(); } diff --git a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri index c12ba232543..6919db68399 100644 --- a/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri +++ b/src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri @@ -9,6 +9,7 @@ HEADERS += \ $$PWD/clangcompletecodejob.h \ $$PWD/clangcreateinitialdocumentpreamblejob.h \ $$PWD/clangdocument.h \ + $$PWD/clangdocumentjob.h \ $$PWD/clangdocumentprocessor.h \ $$PWD/clangdocumentprocessors.h \ $$PWD/clangdocuments.h \ diff --git a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp index d3f0726aff2..9def46b2dba 100644 --- a/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp +++ b/src/tools/clangbackend/ipcsource/clangcodemodelserver.cpp @@ -281,7 +281,6 @@ void ClangCodeModelServer::requestFollowSymbol(const RequestFollowSymbolMessage JobRequest jobRequest = processor.createJobRequest(JobRequest::Type::FollowSymbol); fillJobRequest(jobRequest, message); jobRequest.dependentFiles = message.dependentFiles(); - jobRequest.resolveTarget = message.resolveTarget(); processor.addJob(jobRequest); processor.process(); } catch (const std::exception &exception) { diff --git a/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp b/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp index 2b767604121..9970d59269b 100644 --- a/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp +++ b/src/tools/clangbackend/ipcsource/clangcompletecodejob.cpp @@ -33,52 +33,35 @@ namespace ClangBackEnd { -static CompleteCodeJob::AsyncResult runAsyncHelper(const TranslationUnit &translationUnit, - UnsavedFiles unsavedFiles, - quint32 line, - quint32 column, - qint32 funcNameStartLine, - qint32 funcNameStartColumn) -{ - TIME_SCOPE_DURATION("CompleteCodeJobRunner"); - - const TranslationUnit::CodeCompletionResult results - = translationUnit.complete(unsavedFiles, line, column, - funcNameStartLine, funcNameStartColumn); - - CompleteCodeJob::AsyncResult asyncResult; - asyncResult.completions = results.completions; - asyncResult.correction = results.correction; - - return asyncResult; -} - IAsyncJob::AsyncPrepareResult CompleteCodeJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::CompleteCode, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); + const TranslationUnit translationUnit = *m_translationUnit; + const UnsavedFiles unsavedFiles = *context().unsavedFiles; + const quint32 line = jobRequest.line; + const quint32 column = jobRequest.column; + const qint32 funcNameStartLine = jobRequest.funcNameStartLine; + const qint32 funcNameStartColumn = jobRequest.funcNameStartColumn; + setRunner([translationUnit, unsavedFiles, line, column, + funcNameStartLine, funcNameStartColumn]() { + TIME_SCOPE_DURATION("CompleteCodeJobRunner"); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const UnsavedFiles unsavedFiles = *context().unsavedFiles; - const quint32 line = jobRequest.line; - const quint32 column = jobRequest.column; - const qint32 funcNameStartLine = jobRequest.funcNameStartLine; - const qint32 funcNameStartColumn = jobRequest.funcNameStartColumn; - setRunner([translationUnit, unsavedFiles, line, column, - funcNameStartLine, funcNameStartColumn]() { - return runAsyncHelper(translationUnit, unsavedFiles, line, column, - funcNameStartLine, funcNameStartColumn); - }); - return AsyncPrepareResult{translationUnit.id()}; + UnsavedFiles theUnsavedFiles = unsavedFiles; + const TranslationUnit::CodeCompletionResult results + = translationUnit.complete(theUnsavedFiles, line, column, + funcNameStartLine, funcNameStartColumn); - } catch (const std::exception &exception) { - qWarning() << "Error in CompleteCodeJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + CompleteCodeJob::AsyncResult asyncResult; + asyncResult.completions = results.completions; + asyncResult.correction = results.correction; + + return asyncResult; + }); + + return AsyncPrepareResult{translationUnit.id()}; } void CompleteCodeJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangcompletecodejob.h b/src/tools/clangbackend/ipcsource/clangcompletecodejob.h index 54b0ae5ec34..4e9c274faf9 100644 --- a/src/tools/clangbackend/ipcsource/clangcompletecodejob.h +++ b/src/tools/clangbackend/ipcsource/clangcompletecodejob.h @@ -25,8 +25,7 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" #include @@ -38,16 +37,13 @@ struct CompleteCodeJobResult CompletionCorrection correction = CompletionCorrection::NoCorrection; }; -class CompleteCodeJob : public AsyncJob +class CompleteCodeJob : public DocumentJob { public: using AsyncResult = CompleteCodeJobResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp index 62ae318f61d..b60a5ca613f 100644 --- a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp +++ b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.cpp @@ -31,36 +31,20 @@ namespace ClangBackEnd { -static void runAsyncHelper(const TranslationUnit &translationUnit, - const TranslationUnitUpdateInput &translationUnitUpdateInput) -{ - TIME_SCOPE_DURATION("CreateInitialDocumentPreambleJobRunner"); - - translationUnit.reparse(translationUnitUpdateInput); -} - IAsyncJob::AsyncPrepareResult CreateInitialDocumentPreambleJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::CreateInitialDocumentPreamble, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); + setRunner([translationUnit, updateInput]() { + TIME_SCOPE_DURATION("CreateInitialDocumentPreambleJobRunner"); + return translationUnit.reparse(updateInput); + }); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); - setRunner([translationUnit, updateInput]() { - return runAsyncHelper(translationUnit, updateInput); - }); - return AsyncPrepareResult{translationUnit.id()}; - - } catch (const std::exception &exception) { - qWarning() << "Error in CreateInitialDocumentPreambleJob::prepareAsyncRun:" - << exception.what(); - return AsyncPrepareResult(); - } + return AsyncPrepareResult{translationUnit.id()}; } void CreateInitialDocumentPreambleJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h index 570b746460e..f8b790ea36d 100644 --- a/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h +++ b/src/tools/clangbackend/ipcsource/clangcreateinitialdocumentpreamblejob.h @@ -25,20 +25,15 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" namespace ClangBackEnd { -class CreateInitialDocumentPreambleJob : public AsyncJob +class CreateInitialDocumentPreambleJob : public DocumentJob { public: AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangdocumentjob.h b/src/tools/clangbackend/ipcsource/clangdocumentjob.h new file mode 100644 index 00000000000..7808286ce0b --- /dev/null +++ b/src/tools/clangbackend/ipcsource/clangdocumentjob.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "clangasyncjob.h" +#include "clangdocument.h" + +#include + +#include + +namespace ClangBackEnd { + +template +class DocumentJob : public AsyncJob +{ +protected: + bool acquireDocument() + { + try { + m_pinnedDocument = IAsyncJob::context().documentForJobRequest(); + m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + + const PreferredTranslationUnit preferredTranslationUnit + = IAsyncJob::context().jobRequest.preferredTranslationUnit; + m_translationUnit.reset( + new TranslationUnit(m_pinnedDocument.translationUnit(preferredTranslationUnit))); + return true; + } catch (const std::exception &) { + return false; + } + } + +protected: + Document m_pinnedDocument; + FileContainer m_pinnedFileContainer; + + std::unique_ptr m_translationUnit; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangfollowsymbol.cpp b/src/tools/clangbackend/ipcsource/clangfollowsymbol.cpp index ab6bd824bb6..bc151bc93c4 100644 --- a/src/tools/clangbackend/ipcsource/clangfollowsymbol.cpp +++ b/src/tools/clangbackend/ipcsource/clangfollowsymbol.cpp @@ -41,10 +41,16 @@ namespace { struct Tokens { + Tokens(const Tokens &) = delete; Tokens(const Cursor &cursor) { tu = cursor.cxTranslationUnit(); clang_tokenize(tu, cursor.cxSourceRange(), &data, &tokenCount); } + Tokens(const CXTranslationUnit &tu) { + const CXSourceRange range + = clang_getCursorExtent(clang_getTranslationUnitCursor(tu)); + clang_tokenize(tu, range, &data, &tokenCount); + } ~Tokens() { clang_disposeTokens(tu, data, tokenCount); } @@ -198,11 +204,11 @@ static IndexerCallbacks createIndexerCallbacks() }; } -static FollowSymbolResult followSymbolInDependentFiles(CXIndex index, - const Cursor &cursor, - const Utf8String &tokenSpelling, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs) +static SourceRangeContainer followSymbolInDependentFiles(CXIndex index, + const Cursor &cursor, + const Utf8String &tokenSpelling, + const QVector &dependentFiles, + const CommandLineArguments ¤tArgs) { int argsCount = 0; if (currentArgs.data()) @@ -250,63 +256,61 @@ static FollowSymbolResult followSymbolInDependentFiles(CXIndex index, for (const std::future &future: indexFutures) future.wait(); - FollowSymbolResult result; for (const FollowSymbolData &data: dataVector) { if (!data.result().start().filePath().isEmpty()) { - result.range = data.result(); - break; + return data.result(); } } - return result; + return SourceRangeContainer(); } -FollowSymbolResult FollowSymbol::followSymbol(CXIndex index, - const Cursor &fullCursor, - uint line, - uint column, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs) +SourceRangeContainer FollowSymbol::followSymbol(CXTranslationUnit tu, + CXIndex index, + const Cursor &fullCursor, + uint line, + uint column, + const QVector &dependentFiles, + const CommandLineArguments ¤tArgs) { - FollowSymbolResult result; - Tokens tokens(fullCursor); - if (!tokens.tokenCount) { - result.failedToFollow = true; - return result; - } + std::unique_ptr tokens(new Tokens(fullCursor)); - const CXTranslationUnit tu = fullCursor.cxTranslationUnit(); + if (!tokens->tokenCount) + tokens.reset(new Tokens(tu)); - QVector cursors(static_cast(tokens.tokenCount)); - clang_annotateTokens(tu, tokens.data, tokens.tokenCount, cursors.data()); - int tokenIndex = getTokenIndex(tu, tokens, line, column); - QTC_ASSERT(tokenIndex >= 0, return result); + if (!tokens->tokenCount) + return SourceRangeContainer(); - const Utf8String tokenSpelling = ClangString(clang_getTokenSpelling(tu, tokens.data[tokenIndex])); + QVector cursors(static_cast(tokens->tokenCount)); + clang_annotateTokens(tu, tokens->data, tokens->tokenCount, cursors.data()); + int tokenIndex = getTokenIndex(tu, *tokens, line, column); + QTC_ASSERT(tokenIndex >= 0, return SourceRangeContainer()); + + const Utf8String tokenSpelling = ClangString( + clang_getTokenSpelling(tu, tokens->data[tokenIndex])); if (tokenSpelling.isEmpty()) - return result; + return SourceRangeContainer(); Cursor cursor{cursors[tokenIndex]}; + if (cursor.kind() == CXCursor_InclusionDirective) { CXFile file = clang_getIncludedFile(cursors[tokenIndex]); const ClangString filename(clang_getFileName(file)); const SourceLocation loc(tu, filename, 1, 1); - result.range = SourceRange(loc, loc); - return result; + return SourceRange(loc, loc); } - if (cursor.isDefinition()) { - // For definitions we can always find a declaration in current TU - result.range = extractMatchingTokenRange(cursor.canonical(), tokenSpelling); - return result; - } + // For definitions we can always find a declaration in current TU + if (cursor.isDefinition()) + return extractMatchingTokenRange(cursor.canonical(), tokenSpelling); + SourceRangeContainer result; if (!cursor.isDeclaration()) { // This is the symbol usage // We want to return definition or at least declaration of this symbol const Cursor referencedCursor = cursor.referenced(); if (referencedCursor.isNull() || referencedCursor == cursor) - return result; - result.range = extractMatchingTokenRange(referencedCursor, tokenSpelling); + return SourceRangeContainer(); + result = extractMatchingTokenRange(referencedCursor, tokenSpelling); // We've already found what we need if (referencedCursor.isDefinition()) @@ -317,17 +321,16 @@ FollowSymbolResult FollowSymbol::followSymbol(CXIndex index, const Cursor definitionCursor = cursor.definition(); if (!definitionCursor.isNull() && definitionCursor != cursor) { // If we are able to find a definition in current TU - result.range = extractMatchingTokenRange(definitionCursor, tokenSpelling); - return result; + return extractMatchingTokenRange(definitionCursor, tokenSpelling); } // Search for the definition in the dependent files - FollowSymbolResult dependentFilesResult = followSymbolInDependentFiles(index, - cursor, - tokenSpelling, - dependentFiles, - currentArgs); - return dependentFilesResult.range.start().filePath().isEmpty() ? + SourceRangeContainer dependentFilesResult = followSymbolInDependentFiles(index, + cursor, + tokenSpelling, + dependentFiles, + currentArgs); + return dependentFilesResult.start().filePath().isEmpty() ? result : dependentFilesResult; } diff --git a/src/tools/clangbackend/ipcsource/clangfollowsymbol.h b/src/tools/clangbackend/ipcsource/clangfollowsymbol.h index c3c0c5c2092..a881bd9631d 100644 --- a/src/tools/clangbackend/ipcsource/clangfollowsymbol.h +++ b/src/tools/clangbackend/ipcsource/clangfollowsymbol.h @@ -34,18 +34,19 @@ class Utf8String; namespace ClangBackEnd { class Cursor; -class FollowSymbolResult; +class SourceRangeContainer; class CommandLineArguments; class FollowSymbol { public: - static FollowSymbolResult followSymbol(CXIndex index, - const Cursor &fullCursor, - uint line, - uint column, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs); + static SourceRangeContainer followSymbol(CXTranslationUnit tu, + CXIndex index, + const Cursor &fullCursor, + uint line, + uint column, + const QVector &dependentFiles, + const CommandLineArguments ¤tArgs); }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.cpp b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.cpp index 2a04be1b0e7..7136db34326 100644 --- a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.cpp +++ b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.cpp @@ -33,50 +33,29 @@ namespace ClangBackEnd { -static FollowSymbolJob::AsyncResult runAsyncHelperFollow(const TranslationUnit &translationUnit, - quint32 line, - quint32 column, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs) -{ - TIME_SCOPE_DURATION("FollowSymbolJobRunner"); - - return translationUnit.followSymbol(line, column, dependentFiles, currentArgs); -} - IAsyncJob::AsyncPrepareResult FollowSymbolJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::FollowSymbol, return AsyncPrepareResult()); - // Is too slow because of IPC timings, no implementation for now - QTC_ASSERT(jobRequest.resolveTarget, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); + const CommandLineArguments currentArgs(updateInput.filePath.constData(), + updateInput.projectArguments, + updateInput.fileArguments, + false); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); + const quint32 line = jobRequest.line; + const quint32 column = jobRequest.column; + const QVector &dependentFiles = jobRequest.dependentFiles; + setRunner([translationUnit, line, column, dependentFiles, currentArgs]() { + TIME_SCOPE_DURATION("FollowSymbolJobRunner"); + return translationUnit.followSymbol(line, column, dependentFiles, currentArgs); + }); - const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); - const CommandLineArguments currentArgs(updateInput.filePath.constData(), - updateInput.projectArguments, - updateInput.fileArguments, - false); - - const quint32 line = jobRequest.line; - const quint32 column = jobRequest.column; - const QVector &dependentFiles = jobRequest.dependentFiles; - setRunner([translationUnit, line, column, dependentFiles, currentArgs]() { - return runAsyncHelperFollow(translationUnit, line, column, dependentFiles, currentArgs); - }); - return AsyncPrepareResult{translationUnit.id()}; - - } catch (const std::exception &exception) { - qWarning() << "Error in FollowSymbolJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + return AsyncPrepareResult{translationUnit.id()}; } void FollowSymbolJob::finalizeAsyncRun() @@ -85,8 +64,7 @@ void FollowSymbolJob::finalizeAsyncRun() const AsyncResult result = asyncResult(); const FollowSymbolMessage message(m_pinnedFileContainer, - result.range, - result.failedToFollow, + result, context().jobRequest.ticketNumber); context().client->followSymbol(message); } diff --git a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h index ce2ca4e06c0..3a8741db1c6 100644 --- a/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h +++ b/src/tools/clangbackend/ipcsource/clangfollowsymboljob.h @@ -25,42 +25,18 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" #include namespace ClangBackEnd { -class FollowSymbolResult +class FollowSymbolJob : public DocumentJob { public: - FollowSymbolResult() = default; - FollowSymbolResult(const SourceRangeContainer &range, bool failedToFollow = false) - : range(range) - , failedToFollow(failedToFollow) - {} - - friend bool operator==(const FollowSymbolResult &first, const FollowSymbolResult &second) - { - return first.range == second.range - && first.failedToFollow == second.failedToFollow; - } - - SourceRangeContainer range; - bool failedToFollow = false; -}; - -class FollowSymbolJob : public AsyncJob -{ -public: - using AsyncResult = FollowSymbolResult; + using AsyncResult = SourceRangeContainer; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp index 45fe842dda3..c325c494c9b 100644 --- a/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.cpp @@ -25,49 +25,10 @@ #include "clangiasyncjob.h" -#include "clangcompletecodejob.h" -#include "clangcreateinitialdocumentpreamblejob.h" -#include "clangfollowsymboljob.h" -#include "clangparsesupportivetranslationunitjob.h" -#include "clangreparsesupportivetranslationunitjob.h" -#include "clangrequestdocumentannotationsjob.h" -#include "clangrequestreferencesjob.h" -#include "clangresumedocumentjob.h" -#include "clangsuspenddocumentjob.h" -#include "clangupdatedocumentannotationsjob.h" - Q_LOGGING_CATEGORY(jobsLog, "qtc.clangbackend.jobs"); namespace ClangBackEnd { -IAsyncJob *IAsyncJob::create(JobRequest::Type type) -{ - switch (type) { - case JobRequest::Type::UpdateDocumentAnnotations: - return new UpdateDocumentAnnotationsJob(); - case JobRequest::Type::ParseSupportiveTranslationUnit: - return new ParseSupportiveTranslationUnitJob(); - case JobRequest::Type::ReparseSupportiveTranslationUnit: - return new ReparseSupportiveTranslationUnitJob(); - case JobRequest::Type::CreateInitialDocumentPreamble: - return new CreateInitialDocumentPreambleJob(); - case JobRequest::Type::CompleteCode: - return new CompleteCodeJob(); - case JobRequest::Type::RequestDocumentAnnotations: - return new RequestDocumentAnnotationsJob(); - case JobRequest::Type::RequestReferences: - return new RequestReferencesJob(); - case JobRequest::Type::FollowSymbol: - return new FollowSymbolJob(); - case JobRequest::Type::SuspendDocument: - return new SuspendDocumentJob(); - case JobRequest::Type::ResumeDocument: - return new ResumeDocumentJob(); - } - - return nullptr; -} - IAsyncJob::IAsyncJob() : m_context(JobContext()) { diff --git a/src/tools/clangbackend/ipcsource/clangiasyncjob.h b/src/tools/clangbackend/ipcsource/clangiasyncjob.h index 98f61e857ab..e4481fcbf5d 100644 --- a/src/tools/clangbackend/ipcsource/clangiasyncjob.h +++ b/src/tools/clangbackend/ipcsource/clangiasyncjob.h @@ -39,8 +39,6 @@ namespace ClangBackEnd { class IAsyncJob { public: - static IAsyncJob *create(JobRequest::Type type); - struct AsyncPrepareResult { operator bool() const { return !translationUnitId.isEmpty(); } Utf8String translationUnitId; diff --git a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp index 383c2ecaa45..4ea098db3ac 100644 --- a/src/tools/clangbackend/ipcsource/clangjobqueue.cpp +++ b/src/tools/clangbackend/ipcsource/clangjobqueue.cpp @@ -105,11 +105,11 @@ void JobQueue::removeExpiredRequests() bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest) { - const JobRequest::ExpirationReasons expirationReasons = jobRequest.expirationReasons; + const JobRequest::ExpirationConditions conditions = jobRequest.expirationConditions; const UnsavedFiles unsavedFiles = m_documents.unsavedFiles(); - using ExpirationReason = JobRequest::ExpirationReason; + using Condition = JobRequest::ExpirationCondition; - if (expirationReasons.testFlag(ExpirationReason::UnsavedFilesChanged)) { + if (conditions.testFlag(Condition::UnsavedFilesChanged)) { if (jobRequest.unsavedFilesChangeTimePoint != unsavedFiles.lastChangeTimePoint()) { qCDebug(jobsLog) << "Removing due to outdated unsaved files:" << jobRequest; return true; @@ -118,7 +118,7 @@ bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest) bool projectCheckedAndItExists = false; - if (expirationReasons.testFlag(ExpirationReason::DocumentClosed)) { + if (conditions.testFlag(Condition::DocumentClosed)) { if (!m_documents.hasDocument(jobRequest.filePath, jobRequest.projectPartId)) { qCDebug(jobsLog) << "Removing due to already closed document:" << jobRequest; return true; @@ -138,7 +138,7 @@ bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest) return true; } - if (expirationReasons.testFlag(ExpirationReason::DocumentRevisionChanged)) { + if (conditions.testFlag(Condition::DocumentRevisionChanged)) { if (document.documentRevision() > jobRequest.documentRevision) { qCDebug(jobsLog) << "Removing due to changed document revision:" << jobRequest; return true; @@ -146,7 +146,7 @@ bool JobQueue::isJobRequestExpired(const JobRequest &jobRequest) } } - if (expirationReasons.testFlag(ExpirationReason::ProjectChanged)) { + if (conditions.testFlag(Condition::ProjectChanged)) { if (!projectCheckedAndItExists && !m_projectParts.hasProjectPart(jobRequest.projectPartId)) { qCDebug(jobsLog) << "Removing due to already closed project:" << jobRequest; return true; @@ -194,10 +194,10 @@ void JobQueue::cancelJobRequest(const JobRequest &jobRequest) m_cancelJobRequest(jobRequest); } -static bool passesPreconditions(const JobRequest &request, const Document &document) +static bool areRunConditionsMet(const JobRequest &request, const Document &document) { - using Condition = JobRequest::Condition; - const JobRequest::Conditions conditions = request.conditions; + using Condition = JobRequest::RunCondition; + const JobRequest::RunConditions conditions = request.runConditions; if (conditions.testFlag(Condition::DocumentSuspended) && !document.isSuspended()) { qCDebug(jobsLog) << "Not choosing due to unsuspended document:" << request; @@ -250,7 +250,7 @@ JobRequests JobQueue::takeJobRequestsToRunNow() const Document &document = m_documents.document(request.filePath, request.projectPartId); - if (!passesPreconditions(request, document)) + if (!areRunConditionsMet(request, document)) continue; const Utf8String id = document.translationUnit(request.preferredTranslationUnit).id(); diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp index 5ce175f1a5a..9f8eb55f77f 100644 --- a/src/tools/clangbackend/ipcsource/clangjobrequest.cpp +++ b/src/tools/clangbackend/ipcsource/clangjobrequest.cpp @@ -25,6 +25,24 @@ #include "clangjobrequest.h" +#include "clangcompletecodejob.h" +#include "clangcreateinitialdocumentpreamblejob.h" +#include "clangfollowsymboljob.h" +#include "clangparsesupportivetranslationunitjob.h" +#include "clangreparsesupportivetranslationunitjob.h" +#include "clangrequestdocumentannotationsjob.h" +#include "clangrequestreferencesjob.h" +#include "clangresumedocumentjob.h" +#include "clangsuspenddocumentjob.h" +#include "clangupdatedocumentannotationsjob.h" + +#include +#include +#include +#include + +#include + #include #include @@ -35,6 +53,7 @@ namespace ClangBackEnd { static const char *JobRequestTypeToText(JobRequest::Type type) { switch (type) { + RETURN_TEXT_FOR_CASE(Invalid); RETURN_TEXT_FOR_CASE(UpdateDocumentAnnotations); RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit); RETURN_TEXT_FOR_CASE(ReparseSupportiveTranslationUnit); @@ -96,47 +115,31 @@ QDebug operator<<(QDebug debug, const JobRequest &jobRequest) return debug.space(); } -JobRequest::JobRequest() +static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::Type type) { - static quint64 idCounter = 0; - id = ++idCounter; -} + using Type = JobRequest::Type; + using Condition = JobRequest::ExpirationCondition; + using Conditions = JobRequest::ExpirationConditions; -bool JobRequest::operator==(const JobRequest &other) const -{ - return type == other.type - && expirationReasons == other.expirationReasons - && conditions == other.conditions - - && filePath == other.filePath - && projectPartId == other.projectPartId - && unsavedFilesChangeTimePoint == other.unsavedFilesChangeTimePoint - && projectChangeTimePoint == other.projectChangeTimePoint - && documentRevision == other.documentRevision - && preferredTranslationUnit == other.preferredTranslationUnit - - && line == other.line - && column == other.column - && ticketNumber == other.ticketNumber; -} - -JobRequest::ExpirationReasons JobRequest::expirationReasonsForType(Type type) -{ switch (type) { case Type::UpdateDocumentAnnotations: - return ExpirationReasons(ExpirationReason::AnythingChanged); + return Conditions(Condition::AnythingChanged); case Type::RequestReferences: case Type::RequestDocumentAnnotations: case Type::FollowSymbol: - return ExpirationReasons(ExpirationReason::DocumentClosed) - | ExpirationReasons(ExpirationReason::DocumentRevisionChanged); + return Conditions(Condition::DocumentClosed) + | Conditions(Condition::DocumentRevisionChanged); default: - return ExpirationReason::DocumentClosed; + return Condition::DocumentClosed; } } -JobRequest::Conditions JobRequest::conditionsForType(JobRequest::Type type) +static JobRequest::RunConditions conditionsForType(JobRequest::Type type) { + using Type = JobRequest::Type; + using Condition = JobRequest::RunCondition; + using Conditions = JobRequest::RunConditions; + if (type == Type::SuspendDocument) { return Conditions(Condition::DocumentUnsuspended) | Conditions(Condition::DocumentNotVisible); @@ -156,4 +159,100 @@ JobRequest::Conditions JobRequest::conditionsForType(JobRequest::Type type) return conditions; } +JobRequest::JobRequest(Type type) +{ + static quint64 idCounter = 0; + + id = ++idCounter; + this->type = type; + runConditions = conditionsForType(type); + expirationConditions = expirationConditionsForType(type); +} + +IAsyncJob *JobRequest::createJob() const +{ + switch (type) { + case JobRequest::Type::Invalid: + QTC_CHECK(false && "Cannot create job for invalid job request."); + break; + case JobRequest::Type::UpdateDocumentAnnotations: + return new UpdateDocumentAnnotationsJob(); + case JobRequest::Type::ParseSupportiveTranslationUnit: + return new ParseSupportiveTranslationUnitJob(); + case JobRequest::Type::ReparseSupportiveTranslationUnit: + return new ReparseSupportiveTranslationUnitJob(); + case JobRequest::Type::CreateInitialDocumentPreamble: + return new CreateInitialDocumentPreambleJob(); + case JobRequest::Type::CompleteCode: + return new CompleteCodeJob(); + case JobRequest::Type::RequestDocumentAnnotations: + return new RequestDocumentAnnotationsJob(); + case JobRequest::Type::RequestReferences: + return new RequestReferencesJob(); + case JobRequest::Type::FollowSymbol: + return new FollowSymbolJob(); + case JobRequest::Type::SuspendDocument: + return new SuspendDocumentJob(); + case JobRequest::Type::ResumeDocument: + return new ResumeDocumentJob(); + } + + return nullptr; +} + +void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const +{ + // If a job request with a ticket number is cancelled, the plugin side + // must get back some results in order to clean up the state there. + + switch (type) { + case JobRequest::Type::Invalid: + case JobRequest::Type::UpdateDocumentAnnotations: + case JobRequest::Type::ParseSupportiveTranslationUnit: + case JobRequest::Type::ReparseSupportiveTranslationUnit: + case JobRequest::Type::CreateInitialDocumentPreamble: + case JobRequest::Type::RequestDocumentAnnotations: + case JobRequest::Type::SuspendDocument: + case JobRequest::Type::ResumeDocument: + break; + case JobRequest::Type::RequestReferences: + client.references(ReferencesMessage(FileContainer(), + QVector(), + false, + ticketNumber)); + break; + case JobRequest::Type::CompleteCode: + client.codeCompleted(CodeCompletedMessage(CodeCompletions(), + CompletionCorrection::NoCorrection, + ticketNumber)); + break; + case JobRequest::Type::FollowSymbol: + client.followSymbol(FollowSymbolMessage(FileContainer(), + SourceRangeContainer(), + ticketNumber)); + break; + } +} + +bool JobRequest::operator==(const JobRequest &other) const +{ + return type == other.type + && expirationConditions == other.expirationConditions + && runConditions == other.runConditions + + && filePath == other.filePath + && projectPartId == other.projectPartId + && unsavedFilesChangeTimePoint == other.unsavedFilesChangeTimePoint + && projectChangeTimePoint == other.projectChangeTimePoint + && documentRevision == other.documentRevision + && preferredTranslationUnit == other.preferredTranslationUnit + + && line == other.line + && column == other.column + && ticketNumber == other.ticketNumber; + + // Additional members that are not compared here explicitly are + // supposed to depend on the already compared ones. +} + } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangjobrequest.h b/src/tools/clangbackend/ipcsource/clangjobrequest.h index 954ac6122e0..78aaed6618a 100644 --- a/src/tools/clangbackend/ipcsource/clangjobrequest.h +++ b/src/tools/clangbackend/ipcsource/clangjobrequest.h @@ -39,12 +39,16 @@ namespace ClangBackEnd { +class ClangCodeModelClientInterface; class Document; +class IAsyncJob; class JobRequest { public: enum class Type { + Invalid, + UpdateDocumentAnnotations, CreateInitialDocumentPreamble, @@ -60,7 +64,7 @@ public: ResumeDocument, }; - enum class Condition { + enum class RunCondition { NoCondition = 1 << 0, DocumentVisible = 1 << 1, DocumentNotVisible = 1 << 2, @@ -68,9 +72,9 @@ public: DocumentUnsuspended = 1 << 4, CurrentDocumentRevision = 1 << 5, }; - Q_DECLARE_FLAGS(Conditions, Condition) + Q_DECLARE_FLAGS(RunConditions, RunCondition) - enum class ExpirationReason { + enum class ExpirationCondition { Never = 1 << 0, DocumentClosed = 1 << 1, @@ -83,21 +87,21 @@ public: | UnsavedFilesChanged | ProjectChanged, }; - Q_DECLARE_FLAGS(ExpirationReasons, ExpirationReason) + Q_DECLARE_FLAGS(ExpirationConditions, ExpirationCondition) public: - static ExpirationReasons expirationReasonsForType(Type type); - static Conditions conditionsForType(Type type); + JobRequest(Type type = Type::Invalid); - JobRequest(); + IAsyncJob *createJob() const; + void cancelJob(ClangCodeModelClientInterface &client) const; bool operator==(const JobRequest &other) const; public: quint64 id = 0; Type type; - ExpirationReasons expirationReasons; - Conditions conditions; + ExpirationConditions expirationConditions; + RunConditions runConditions; // General Utf8String filePath; @@ -114,7 +118,6 @@ public: qint32 funcNameStartColumn = -1; quint64 ticketNumber = 0; Utf8StringVector dependentFiles; - bool resolveTarget = true; }; using JobRequests = QVector; diff --git a/src/tools/clangbackend/ipcsource/clangjobs.cpp b/src/tools/clangbackend/ipcsource/clangjobs.cpp index f241593ec62..033dc4ef1a4 100644 --- a/src/tools/clangbackend/ipcsource/clangjobs.cpp +++ b/src/tools/clangbackend/ipcsource/clangjobs.cpp @@ -29,9 +29,6 @@ #include "clangiasyncjob.h" #include "projects.h" -#include -#include - #include #include #include @@ -58,7 +55,7 @@ Jobs::Jobs(Documents &documents, return isJobRunningForJobRequest(jobRequest); }); m_queue.setCancelJobRequest([this](const JobRequest &jobRequest) { - return cancelJobRequest(jobRequest); + jobRequest.cancelJob(m_client); }); } @@ -79,10 +76,7 @@ JobRequest Jobs::createJobRequest(const Document &document, JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit) const { - JobRequest jobRequest; - jobRequest.type = type; - jobRequest.expirationReasons = JobRequest::expirationReasonsForType(type); - jobRequest.conditions = JobRequest::conditionsForType(type); + JobRequest jobRequest(type); jobRequest.filePath = document.filePath(); jobRequest.projectPartId = document.projectPart().id(); jobRequest.unsavedFilesChangeTimePoint = m_unsavedFiles.lastChangeTimePoint(); @@ -131,7 +125,7 @@ JobRequests Jobs::runJobs(const JobRequests &jobsRequests) bool Jobs::runJob(const JobRequest &jobRequest) { - IAsyncJob *asyncJob = IAsyncJob::create(jobRequest.type); + IAsyncJob *asyncJob = jobRequest.createJob(); QTC_ASSERT(asyncJob, return false); JobContext context(jobRequest, &m_documents, &m_unsavedFiles, &m_client); @@ -203,29 +197,4 @@ bool Jobs::isJobRunningForJobRequest(const JobRequest &jobRequest) const return Utils::anyOf(m_running.values(), hasJobRequest); } -void Jobs::cancelJobRequest(const JobRequest &jobRequest) -{ - // TODO: Consider to refactor this. Jobs should not know anything about - // concrete messages. On the other hand, having this here avoids - // duplication in multiple job classes. - - // If a job request with a ticket number is cancelled, the plugin side - // must get back some results in order to clean up the state there. - switch (jobRequest.type) { - case JobRequest::Type::RequestReferences: - m_client.references(ReferencesMessage(FileContainer(), - QVector(), - false, - jobRequest.ticketNumber)); - break; - case JobRequest::Type::CompleteCode: - m_client.codeCompleted(CodeCompletedMessage(CodeCompletions(), - CompletionCorrection::NoCorrection, - jobRequest.ticketNumber)); - break; - default: - break; - } -} - } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangjobs.h b/src/tools/clangbackend/ipcsource/clangjobs.h index c91758566b8..d154d401e88 100644 --- a/src/tools/clangbackend/ipcsource/clangjobs.h +++ b/src/tools/clangbackend/ipcsource/clangjobs.h @@ -80,7 +80,6 @@ public /*for tests*/: bool isJobRunningForJobRequest(const JobRequest &jobRequest) const; private: - void cancelJobRequest(const JobRequest &jobRequest); JobRequests runJobs(const JobRequests &jobRequest); bool runJob(const JobRequest &jobRequest); void onJobFinished(IAsyncJob *asyncJob); diff --git a/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.cpp b/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.cpp index c7646f5834b..017426ab021 100644 --- a/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.cpp @@ -31,43 +31,24 @@ namespace ClangBackEnd { -static ParseSupportiveTranslationUnitJob::AsyncResult runAsyncHelper( - const TranslationUnit &translationUnit, - const TranslationUnitUpdateInput &translationUnitUpdateInput) -{ - TIME_SCOPE_DURATION("ParseSupportiveTranslationUnitJob"); - - TranslationUnitUpdateInput updateInput = translationUnitUpdateInput; - updateInput.parseNeeded = true; - - ParseSupportiveTranslationUnitJob::AsyncResult asyncResult; - asyncResult.updateResult = translationUnit.update(updateInput); - - return asyncResult; -} - IAsyncJob::AsyncPrepareResult ParseSupportiveTranslationUnitJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::ParseSupportiveTranslationUnit, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); + setRunner([translationUnit, updateInput]() { + TIME_SCOPE_DURATION("ParseSupportiveTranslationUnitJob"); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); - setRunner([translationUnit, updateInput]() { - return runAsyncHelper(translationUnit, updateInput); - }); - return AsyncPrepareResult{translationUnit.id()}; + TranslationUnitUpdateInput theUpdateInput = updateInput; + theUpdateInput.parseNeeded = true; - } catch (const std::exception &exception) { - qWarning() << "Error in ParseForSupportiveTranslationUnitJob::prepareAsyncRun:" - << exception.what(); - return AsyncPrepareResult(); - } + return translationUnit.update(updateInput); + }); + + return AsyncPrepareResult{translationUnit.id()}; } void ParseSupportiveTranslationUnitJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.h b/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.h index 6d4d01131e2..5a0cfec1837 100644 --- a/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.h +++ b/src/tools/clangbackend/ipcsource/clangparsesupportivetranslationunitjob.h @@ -25,27 +25,18 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" +#include "clangtranslationunitupdater.h" namespace ClangBackEnd { -struct ParseSupportiveTranslationUnitJobResult -{ - TranslationUnitUpdateResult updateResult; -}; - -class ParseSupportiveTranslationUnitJob : public AsyncJob +class ParseSupportiveTranslationUnitJob : public DocumentJob { public: - using AsyncResult = ParseSupportiveTranslationUnitJobResult; + using AsyncResult = TranslationUnitUpdateResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.cpp b/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.cpp index 833b8fe2b9d..a02821fff48 100644 --- a/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.cpp @@ -31,43 +31,27 @@ namespace ClangBackEnd { -static ReparseSupportiveTranslationUnitJob::AsyncResult runAsyncHelper( - const TranslationUnit &translationUnit, - const TranslationUnitUpdateInput &translationUnitUpdateInput) -{ - TIME_SCOPE_DURATION("ReparseSupportiveTranslationUnitJob"); - - TranslationUnitUpdateInput updateInput = translationUnitUpdateInput; - updateInput.reparseNeeded = true; - - ReparseSupportiveTranslationUnitJob::AsyncResult asyncResult; - asyncResult.updateResult = translationUnit.reparse(updateInput); - - return asyncResult; -} - IAsyncJob::AsyncPrepareResult ReparseSupportiveTranslationUnitJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::ReparseSupportiveTranslationUnit, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); + setRunner([translationUnit, updateInput]() { + TIME_SCOPE_DURATION("ReparseSupportiveTranslationUnitJob"); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const TranslationUnitUpdateInput updateInput = m_pinnedDocument.createUpdateInput(); - setRunner([translationUnit, updateInput]() { - return runAsyncHelper(translationUnit, updateInput); - }); - return AsyncPrepareResult{translationUnit.id()}; + TranslationUnitUpdateInput theUpdateInput = updateInput; + theUpdateInput.reparseNeeded = true; - } catch (const std::exception &exception) { - qWarning() << "Error in ReparseSupportiveTranslationUnitJob::prepareAsyncRun:" - << exception.what(); - return AsyncPrepareResult(); - } + ReparseSupportiveTranslationUnitJob::AsyncResult asyncResult; + asyncResult.updateResult = translationUnit.reparse(theUpdateInput); + + return asyncResult; + }); + + return AsyncPrepareResult{translationUnit.id()}; } void ReparseSupportiveTranslationUnitJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.h b/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.h index 1b352c2c361..cb146299c72 100644 --- a/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.h +++ b/src/tools/clangbackend/ipcsource/clangreparsesupportivetranslationunitjob.h @@ -25,8 +25,7 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" namespace ClangBackEnd { @@ -35,17 +34,13 @@ struct ReparseSupportiveTranslationUnitJobResult TranslationUnitUpdateResult updateResult; }; -class ReparseSupportiveTranslationUnitJob : public AsyncJob +class ReparseSupportiveTranslationUnitJob : public DocumentJob { public: using AsyncResult = ReparseSupportiveTranslationUnitJobResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp index f0f7f78210c..99ac98eec2a 100644 --- a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.cpp @@ -33,62 +33,39 @@ namespace ClangBackEnd { -static RequestDocumentAnnotationsJob::AsyncResult runAsyncHelper( - const TranslationUnit &translationUnit) -{ - TIME_SCOPE_DURATION("RequestDocumentAnnotationsJobRunner"); - - RequestDocumentAnnotationsJob::AsyncResult asyncResult; - - translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic, - asyncResult.diagnostics, - asyncResult.highlightingMarks, - asyncResult.skippedSourceRanges); - - return asyncResult; -} - IAsyncJob::AsyncPrepareResult RequestDocumentAnnotationsJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestDocumentAnnotations, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + setRunner([translationUnit]() { + TIME_SCOPE_DURATION("RequestDocumentAnnotationsJobRunner"); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - setRunner([translationUnit]() { - return runAsyncHelper(translationUnit); - }); - return AsyncPrepareResult{translationUnit.id()}; + RequestDocumentAnnotationsJob::AsyncResult asyncResult; + translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic, + asyncResult.diagnostics, + asyncResult.highlightingMarks, + asyncResult.skippedSourceRanges); + return asyncResult; + }); - } catch (const std::exception &exception) { - qWarning() << "Error in RequestDocumentAnnotationsJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + return AsyncPrepareResult{translationUnit.id()}; } void RequestDocumentAnnotationsJob::finalizeAsyncRun() { if (context().isDocumentOpen()) { const AsyncResult result = asyncResult(); - sendAnnotations(result); + context().client->documentAnnotationsChanged( + DocumentAnnotationsChangedMessage(m_pinnedFileContainer, + result.diagnostics, + result.firstHeaderErrorDiagnostic, + result.highlightingMarks, + result.skippedSourceRanges)); } } -void RequestDocumentAnnotationsJob::sendAnnotations( - const RequestDocumentAnnotationsJob::AsyncResult &result) -{ - const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer, - result.diagnostics, - result.firstHeaderErrorDiagnostic, - result.highlightingMarks, - result.skippedSourceRanges); - - context().client->documentAnnotationsChanged(message); -} - } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h index dcbe42b6e45..1c78621119e 100644 --- a/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h +++ b/src/tools/clangbackend/ipcsource/clangrequestdocumentannotationsjob.h @@ -25,8 +25,7 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" #include #include @@ -42,20 +41,13 @@ struct RequestDocumentAnnotationsJobResult QVector skippedSourceRanges; }; -class RequestDocumentAnnotationsJob : public AsyncJob +class RequestDocumentAnnotationsJob : public DocumentJob { public: using AsyncResult = RequestDocumentAnnotationsJobResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - void sendAnnotations(const AsyncResult &result); - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp index 1ebc22c9713..39b3319488e 100644 --- a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.cpp @@ -33,38 +33,22 @@ namespace ClangBackEnd { -static RequestReferencesJob::AsyncResult runAsyncHelper(const TranslationUnit &translationUnit, - quint32 line, - quint32 column) -{ - TIME_SCOPE_DURATION("RequestReferencesJobRunner"); - - return translationUnit.references(line, column); -} - IAsyncJob::AsyncPrepareResult RequestReferencesJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::RequestReferences, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const quint32 line = jobRequest.line; + const quint32 column = jobRequest.column; + setRunner([translationUnit, line, column]() { + TIME_SCOPE_DURATION("RequestReferencesJobRunner"); + return translationUnit.references(line, column); + }); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const quint32 line = jobRequest.line; - const quint32 column = jobRequest.column; - setRunner([translationUnit, line, column]() { - return runAsyncHelper(translationUnit, line, column); - }); - return AsyncPrepareResult{translationUnit.id()}; - - } catch (const std::exception &exception) { - qWarning() << "Error in RequestReferencesJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + return AsyncPrepareResult{translationUnit.id()}; } void RequestReferencesJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h index 13a904bddc1..d92d869a9bb 100644 --- a/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h +++ b/src/tools/clangbackend/ipcsource/clangrequestreferencesjob.h @@ -25,25 +25,18 @@ #pragma once -#include "clangasyncjob.h" +#include "clangdocumentjob.h" #include "clangreferencescollector.h" -#include "clangdocument.h" - -#include namespace ClangBackEnd { -class RequestReferencesJob : public AsyncJob +class RequestReferencesJob : public DocumentJob { public: using AsyncResult = ReferencesResult; AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp index 0e71813ba20..87fe54bfae9 100644 --- a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.cpp @@ -31,33 +31,19 @@ namespace ClangBackEnd { -static bool runAsyncHelper(const TranslationUnit &translationUnit) -{ - TIME_SCOPE_DURATION("SuspendDocumentJobRunner"); - - return translationUnit.suspend(); -} - IAsyncJob::AsyncPrepareResult SuspendDocumentJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(jobRequest.type == JobRequest::Type::SuspendDocument, return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + TranslationUnit translationUnit = *m_translationUnit; + setRunner([translationUnit]() { + TIME_SCOPE_DURATION("SuspendDocumentJobRunner"); + return translationUnit.suspend(); + }); - TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - setRunner([translationUnit]() { - return runAsyncHelper(translationUnit); - }); - return AsyncPrepareResult{translationUnit.id()}; - - } catch (const std::exception &exception) { - qWarning() << "Error in SuspendDocumentJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + return AsyncPrepareResult{translationUnit.id()}; } void SuspendDocumentJob::finalizeAsyncRun() diff --git a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h index 16d5b52a1ea..5948f8226f1 100644 --- a/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h +++ b/src/tools/clangbackend/ipcsource/clangsuspenddocumentjob.h @@ -25,20 +25,15 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" +#include "clangdocumentjob.h" namespace ClangBackEnd { -class SuspendDocumentJob : public AsyncJob +class SuspendDocumentJob : public DocumentJob { public: AsyncPrepareResult prepareAsyncRun() override; void finalizeAsyncRun() override; - -private: - Document m_pinnedDocument; - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp index adc732118eb..720bfb92555 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.cpp @@ -243,13 +243,13 @@ void TranslationUnit::extractDiagnostics(DiagnosticContainer &firstHeaderErrorDi } } -FollowSymbolResult TranslationUnit::followSymbol(uint line, - uint column, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs) const +SourceRangeContainer TranslationUnit::followSymbol(uint line, + uint column, + const QVector &dependentFiles, + const CommandLineArguments ¤tArgs) const { - return FollowSymbol::followSymbol(m_cxIndex, cursorAt(line, column), line, column, - dependentFiles, currentArgs); + return FollowSymbol::followSymbol(m_cxTranslationUnit, m_cxIndex, cursorAt(line, column), line, + column, dependentFiles, currentArgs); } } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangtranslationunit.h b/src/tools/clangbackend/ipcsource/clangtranslationunit.h index 3ae020478ee..9634c8cb510 100644 --- a/src/tools/clangbackend/ipcsource/clangtranslationunit.h +++ b/src/tools/clangbackend/ipcsource/clangtranslationunit.h @@ -37,7 +37,6 @@ class DiagnosticSet; class HighlightingMarkContainer; class HighlightingMarks; class ReferencesResult; -class FollowSymbolResult; class SkippedSourceRanges; class SourceLocation; class SourceRange; @@ -101,10 +100,10 @@ public: HighlightingMarks highlightingMarksInRange(const SourceRange &range) const; SkippedSourceRanges skippedSourceRanges() const; - FollowSymbolResult followSymbol(uint line, - uint column, - const QVector &dependentFiles, - const CommandLineArguments ¤tArgs) const; + SourceRangeContainer followSymbol(uint line, + uint column, + const QVector &dependentFiles, + const CommandLineArguments ¤tArgs) const; private: const Utf8String m_id; diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp index 3698d1c40c8..7333ca68787 100644 --- a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp +++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.cpp @@ -33,47 +33,31 @@ namespace ClangBackEnd { -static UpdateDocumentAnnotationsJob::AsyncResult runAsyncHelper( - const TranslationUnit &translationUnit, - const TranslationUnitUpdateInput &translationUnitUpdatInput) -{ - TIME_SCOPE_DURATION("UpdateDocumentAnnotationsJobRunner"); - - UpdateDocumentAnnotationsJob::AsyncResult asyncResult; - - // Update - asyncResult.updateResult = translationUnit.update(translationUnitUpdatInput); - - // Collect - translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic, - asyncResult.diagnostics, - asyncResult.highlightingMarks, - asyncResult.skippedSourceRanges); - - return asyncResult; -} - IAsyncJob::AsyncPrepareResult UpdateDocumentAnnotationsJob::prepareAsyncRun() { const JobRequest jobRequest = context().jobRequest; QTC_ASSERT(isExpectedJobRequestType(jobRequest), return AsyncPrepareResult()); + QTC_ASSERT(acquireDocument(), return AsyncPrepareResult()); - try { - m_pinnedDocument = context().documentForJobRequest(); - m_pinnedFileContainer = m_pinnedDocument.fileContainer(); + const TranslationUnit translationUnit = *m_translationUnit; + const TranslationUnitUpdateInput updateInput = createUpdateInput(m_pinnedDocument); + setRunner([translationUnit, updateInput]() { + TIME_SCOPE_DURATION("UpdateDocumentAnnotationsJobRunner"); - const TranslationUnit translationUnit - = m_pinnedDocument.translationUnit(jobRequest.preferredTranslationUnit); - const TranslationUnitUpdateInput updateInput = createUpdateInput(m_pinnedDocument); - setRunner([translationUnit, updateInput]() { - return runAsyncHelper(translationUnit, updateInput); - }); - return AsyncPrepareResult{translationUnit.id()}; + // Update + UpdateDocumentAnnotationsJob::AsyncResult asyncResult; + asyncResult.updateResult = translationUnit.update(updateInput); - } catch (const std::exception &exception) { - qWarning() << "Error in UpdateDocumentAnnotationsJob::prepareAsyncRun:" << exception.what(); - return AsyncPrepareResult(); - } + // Collect + translationUnit.extractDocumentAnnotations(asyncResult.firstHeaderErrorDiagnostic, + asyncResult.diagnostics, + asyncResult.highlightingMarks, + asyncResult.skippedSourceRanges); + + return asyncResult; + }); + + return AsyncPrepareResult{translationUnit.id()}; } void UpdateDocumentAnnotationsJob::finalizeAsyncRun() @@ -81,8 +65,13 @@ void UpdateDocumentAnnotationsJob::finalizeAsyncRun() if (!context().isOutdated()) { const AsyncResult result = asyncResult(); - incorporateUpdaterResult(result); - sendAnnotations(result); + m_pinnedDocument.incorporateUpdaterResult(result.updateResult); + context().client->documentAnnotationsChanged( + DocumentAnnotationsChangedMessage(m_pinnedFileContainer, + result.diagnostics, + result.firstHeaderErrorDiagnostic, + result.highlightingMarks, + result.skippedSourceRanges)); } } @@ -97,21 +86,5 @@ UpdateDocumentAnnotationsJob::createUpdateInput(const Document &document) const return document.createUpdateInput(); } -void UpdateDocumentAnnotationsJob::incorporateUpdaterResult(const AsyncResult &result) -{ - m_pinnedDocument.incorporateUpdaterResult(result.updateResult); -} - -void UpdateDocumentAnnotationsJob::sendAnnotations(const AsyncResult &result) -{ - const DocumentAnnotationsChangedMessage message(m_pinnedFileContainer, - result.diagnostics, - result.firstHeaderErrorDiagnostic, - result.highlightingMarks, - result.skippedSourceRanges); - - context().client->documentAnnotationsChanged(message); -} - } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h index a49e9b45b51..141b3535a09 100644 --- a/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h +++ b/src/tools/clangbackend/ipcsource/clangupdatedocumentannotationsjob.h @@ -25,9 +25,7 @@ #pragma once -#include "clangasyncjob.h" -#include "clangdocument.h" -#include "clangtranslationunitupdater.h" +#include "clangdocumentjob.h" #include #include @@ -45,7 +43,7 @@ struct UpdateDocumentAnnotationsJobResult QVector skippedSourceRanges; }; -class UpdateDocumentAnnotationsJob : public AsyncJob +class UpdateDocumentAnnotationsJob : public DocumentJob { public: using AsyncResult = UpdateDocumentAnnotationsJobResult; @@ -56,16 +54,6 @@ public: protected: virtual bool isExpectedJobRequestType(const JobRequest &jobRequest) const; virtual TranslationUnitUpdateInput createUpdateInput(const Document &document) const; - -private: - void incorporateUpdaterResult(const AsyncResult &result); - void sendAnnotations(const AsyncResult &result); - -protected: - Document m_pinnedDocument; - -private: - FileContainer m_pinnedFileContainer; }; } // namespace ClangBackEnd diff --git a/src/tools/clangbackend/ipcsource/highlightingmark.cpp b/src/tools/clangbackend/ipcsource/highlightingmark.cpp index 510192b6e70..9339d4ba9e7 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmark.cpp +++ b/src/tools/clangbackend/ipcsource/highlightingmark.cpp @@ -105,7 +105,8 @@ bool HighlightingMark::hasFunctionArguments() const HighlightingMark::operator HighlightingMarkContainer() const { - return HighlightingMarkContainer(m_line, m_column, m_length, m_types); + return HighlightingMarkContainer(m_line, m_column, m_length, m_types, m_isIdentifier, + m_isInclusion); } namespace { @@ -288,6 +289,8 @@ void HighlightingMark::functionKind(const Cursor &cursor, Recursion recursion) void HighlightingMark::identifierKind(const Cursor &cursor, Recursion recursion) { + m_isIdentifier = (cursor.kind() != CXCursor_PreprocessingDirective); + switch (cursor.kind()) { case CXCursor_Destructor: case CXCursor_Constructor: @@ -352,6 +355,7 @@ HighlightingType literalKind(const Cursor &cursor) switch (cursor.kind()) { case CXCursor_CharacterLiteral: case CXCursor_StringLiteral: + case CXCursor_InclusionDirective: case CXCursor_ObjCStringLiteral: return HighlightingType::StringLiteral; case CXCursor_IntegerLiteral: case CXCursor_ImaginaryLiteral: @@ -438,6 +442,8 @@ void HighlightingMark::collectKinds(CXTranslationUnit cxTranslationUnit, case CXToken_Comment: m_types.mainHighlightingType = HighlightingType::Comment; break; case CXToken_Literal: m_types.mainHighlightingType = literalKind(cursor); break; } + + m_isInclusion = (cursor.kind() == CXCursor_InclusionDirective); } std::ostream &operator<<(std::ostream &os, const HighlightingMark& highlightingMark) diff --git a/src/tools/clangbackend/ipcsource/highlightingmark.h b/src/tools/clangbackend/ipcsource/highlightingmark.h index 151bd263d25..b322391c49d 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmark.h +++ b/src/tools/clangbackend/ipcsource/highlightingmark.h @@ -87,6 +87,8 @@ private: uint m_length; uint m_offset = 0; HighlightingTypes m_types; + bool m_isIdentifier = false; + bool m_isInclusion = false; }; diff --git a/src/tools/clangbackend/ipcsource/highlightingmarks.cpp b/src/tools/clangbackend/ipcsource/highlightingmarks.cpp index 2e157ff835e..ed8ddfdd656 100644 --- a/src/tools/clangbackend/ipcsource/highlightingmarks.cpp +++ b/src/tools/clangbackend/ipcsource/highlightingmarks.cpp @@ -68,15 +68,12 @@ QVector HighlightingMarks::toHighlightingMarksContain const auto isValidHighlightMark = [] (const HighlightingMark &highlightMark) { return !highlightMark.hasInvalidMainType() - && !highlightMark.hasMainType(HighlightingType::StringLiteral) - && !highlightMark.hasMainType(HighlightingType::NumberLiteral) - && !highlightMark.hasMainType(HighlightingType::Comment); + && !highlightMark.hasMainType(HighlightingType::NumberLiteral) + && !highlightMark.hasMainType(HighlightingType::Comment); }; - - for (const HighlightingMark &highlightMark : *this) { + for (const HighlightingMark &highlightMark : *this) if (isValidHighlightMark(highlightMark)) containers.push_back(highlightMark); - } return containers; } diff --git a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h index 118fb8182a5..c144c7a9c51 100644 --- a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h +++ b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h @@ -47,56 +47,6 @@ public: { } - Sqlite::Table createSymbolsTable() - { - Sqlite::Table table; - table.setUseIfNotExists(true); - table.setName("symbols"); - table.addColumn("symbolId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); - const Sqlite::Column &usrColumn = table.addColumn("usr", Sqlite::ColumnType::Text); - table.addColumn("symbolName", Sqlite::ColumnType::Text); - table.addIndex({usrColumn}); - - Sqlite::ImmediateTransaction transaction(database); - table.initialize(database); - transaction.commit(); - - return table; - } - - Sqlite::Table createLocationsTable() - { - Sqlite::Table table; - table.setUseIfNotExists(true); - table.setName("locations"); - table.addColumn("symbolId", Sqlite::ColumnType::Integer); - table.addColumn("line", Sqlite::ColumnType::Integer); - table.addColumn("column", Sqlite::ColumnType::Integer); - const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); - table.addIndex({sourceIdColumn}); - - Sqlite::ImmediateTransaction transaction(database); - table.initialize(database); - transaction.commit(); - - return table; - } - - Sqlite::Table createSourcesTable() - { - Sqlite::Table table; - table.setUseIfNotExists(true); - table.setName("sources"); - table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); - table.addColumn("sourcePath", Sqlite::ColumnType::Text); - - Sqlite::ImmediateTransaction transaction(database); - table.initialize(database); - transaction.commit(); - - return table; - } - Sqlite::Table createNewSymbolsTable() const { Sqlite::Table table; @@ -137,9 +87,6 @@ public: public: Database &database; - Sqlite::Table symbolsTable{createSymbolsTable()}; - Sqlite::Table locationsTable{createLocationsTable()}; - Sqlite::Table sourcesTable{createSourcesTable()}; Sqlite::Table newSymbolsTablet{createNewSymbolsTable()}; Sqlite::Table newLocationsTable{createNewLocationsTable()}; WriteStatement insertSymbolsToNewSymbolsStatement{ diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 7a8da5aafb7..4dd173e1bfb 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -32,6 +32,7 @@ #include "symbolscollector.h" #include "symbolstorage.h" +#include #include #include @@ -47,12 +48,13 @@ public: Sqlite::ReadStatement, Sqlite::WriteStatement>; using Storage = ClangBackEnd::SymbolStorage; + using DatabaseInitializer = RefactoringDatabaseInitializer; SymbolIndexing(FilePathCache &filePathCache, Utils::PathString &&databaseFilePath) : m_filePathCache(filePathCache), - m_database(std::move(databaseFilePath)) - + m_database(std::move(databaseFilePath)), + m_databaseInitializer(m_database) { } @@ -75,6 +77,7 @@ public: private: FilePathCache &m_filePathCache; Sqlite::Database m_database; + DatabaseInitializer m_databaseInitializer; SymbolsCollector m_collector{m_filePathCache}; StatementFactory m_statementFactory{m_database}; Storage m_symbolStorage{m_statementFactory, m_filePathCache}; diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index 800361a9df1..d82f71ae752 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -18,6 +18,18 @@ sodipodi:docname="qtcreatoricons.svg"> + + + + - - - - + x1="510.75" + y1="73.5" + x2="510.75" + y2="75.5" /> + + transform="translate(388,513)" /> - - - - - - - - - - - - @@ -6288,6 +6232,77 @@ cy="564" r="3.5" /> + + + + + + + + + + + + + + + - + - + - + - + + d="m 212,52 c -1.275,0 -3.30877,1.17695 -3.88477,2.75195 L 212,56.9375 215.88477,54.75195 C 215.30877,53.17595 213.275,52 212,52 Z m -4.67578,3.68359 -1.98633,1.76563 -1.39648,-1.39453 c -0.194,-0.194 -0.51304,-0.194 -0.70703,0 -0.194,0.194 -0.194,0.51303 0,0.70703 l 1.6875,1.6875 L 204.03516,62 H 202.5 c -0.275,0 -0.5,0.225 -0.5,0.5 0,0.275 0.225,0.5 0.5,0.5 h 1.48828 l 1.19141,3.8125 -1.62696,1.62695 c -0.194,0.194 -0.194,0.51303 0,0.70703 0.194,0.194 0.51304,0.194 0.70704,0 l 1.375,-1.375 3.55273,2.36719 2.3125,0.58594 V 58 Z m 9.35156,0 L 212.5,58 v 12.72461 l 2.3125,-0.58594 3.55078,-2.36719 1.375,1.375 c 0.194,0.194 0.51303,0.194 0.70703,0 0.194,-0.194 0.194,-0.51303 0,-0.70703 l -1.625,-1.625 L 220.01172,63 H 221.5 c 0.275,0 0.5,-0.225 0.5,-0.5 0,-0.275 -0.225,-0.5 -0.5,-0.5 h -1.53516 l -0.88672,-3.55078 1.6875,-1.6875 c 0.19401,-0.194 0.194,-0.51303 0,-0.70703 -0.19399,-0.194 -0.51303,-0.194 -0.70703,0 l -1.39648,1.39453 z" + id="path5403-3" + inkscape:connector-curvature="0" /> - + - + - + + points="603,50 621,61 603,72 " + id="polygon5749-6" + transform="translate(0,-4)" /> - + + transform="translate(-5,-1.000238)"> - + + y="48" /> + y="48" /> - + + x="752" + y="48" /> - + - + + id="build-5" + transform="translate(-1,-3)"> - + + id="build-5-2" + transform="translate(-1,-3)"> + points="873.684,57.071 870.148,60.606 859.542,50 866.613,50 " + id="polygon5757-3-4" + transform="translate(0,-1)" /> - - - - + + + + + + - + transform="translate(-190,-45)"> + + + - + id="src/plugins/ios/images/iosdevice" + transform="translate(-266,-42)"> + + id="phone_body_big" + transform="translate(1,-3)"> - + transform="translate(-282,-26)"> + @@ -7791,20 +7862,22 @@ style="fill:#b3b3b3" /> - + + x="569" + y="370" /> + style="fill:#000000;fill-opacity:1"> - + transform="translate(-246,-26)"> + - + @@ -8084,34 +8160,36 @@ style="fill:#0dbf0d;fill-opacity:1" /> - + + transform="translate(0.5,-4)"> @@ -8120,7 +8198,7 @@ y="0" xlink:href="#g5189" id="use5200" - transform="matrix(1,0,0,-1,0,726)" + transform="matrix(1,0,0,-1,0,720)" width="100%" height="100%" /> - + transform="translate(-210,-26)"> + - + + x="501.75" + y="50.5" /> + bottoqtscreen="" + transform="translate(1,-3)"> - + transform="translate(-318,27)"> + + height="100%" + style="stroke-width:0.89442718" /> @@ -8330,11 +8414,11 @@ sodipodi:nodetypes="ccccccc" inkscape:connector-curvature="0" id="path5089-53" - d="m 581,371.5 -1.5,1.5 -6.5,0 0,-4.5 1.5,-1.5 6.5,0 z" + d="m 581,371.5 -1.5,1.5 H 573 v -4.5 l 1.5,-1.5 h 6.5 z" style="fill:#000000;fill-opacity:1" /> @@ -8350,7 +8434,7 @@ y="0" xlink:href="#rect5349" id="use5495" - transform="translate(12.5,0)" + transform="translate(12.5)" width="100%" height="100%" /> - + + x="501.75" + y="53.5" /> + transform="translate(2,-3)"> @@ -8422,19 +8508,20 @@ inkscape:connector-curvature="0" id="rect7899-2-7-1-7" style="fill:#333333" - d="m 524.75,71.5 4,0 0,1 -4,0 z m -5,0 4,0 0,1 -4,0 z m 5,-2 4,0 0,1 -4,0 z m -3,0 2,0 0,1 -2,0 z m 3,-5 4,0 0,1 -4,0 z m -3,0 2,0 0,1 -2,0 z m 3,-2 4,0 0,1 -4,0 z m -5,0 4,0 0,1 -4,0 z m 5,-4 4,0 0,1 -4,0 z m -4,0 3,0 0,1 -3,0 z" + d="m 525.75,68.5 h 4 v 1 h -4 z m -5,0 h 4 v 1 h -4 z m 5,-2 h 4 v 1 h -4 z m -3,0 h 2 v 1 h -2 z m 3,-5 h 4 v 1 h -4 z m -3,0 h 2 v 1 h -2 z m 3,-2 h 4 v 1 h -4 z m -5,0 h 4 v 1 h -4 z m 5,-4 h 4 v 1 h -4 z m -4,0 h 3 v 1 h -3 z" sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccccccccccc" /> - + transform="translate(-282,27)"> + - + + x="508.25" + y="55" + rx="2" + ry="2" /> + x="508.25" + y="55" + rx="2" + ry="2" /> - + - + transform="translate(-210,27)"> + - + id="src/plugins/winrt/images/winrtdevice" + transform="translate(-206,-74)"> + - + id="src/plugins/winrt/images/winrtdevicesmall" + transform="translate(-238,-58)"> + setUtf8Source(src); + doc->check(); +} + QTEST_MAIN(tst_Misc) #include "tst_misc.moc" diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index 80cca223b42..76bd2fe2215 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1049,7 +1049,7 @@ void tst_Dumpers::initTestCase() ok = debugger.waitForFinished(); QVERIFY(ok); QByteArray output = debugger.readAllStandardOutput(); - //qDebug() << "stdout: " << output; + //qDebug().noquote() << "stdout: " << output; bool usePython = !output.contains("Python scripting is not supported in this copy of GDB"); qDebug() << "Python : " << (usePython ? "ok" : "*** not ok ***"); qDebug() << "Dumper dir : " << DUMPERDIR; @@ -1418,11 +1418,11 @@ void tst_Dumpers::dumper() error = make.readAllStandardError(); //qDebug() << "stdout: " << output; if (make.exitCode()) { - qDebug() << error; + qDebug().noquote() << error; qDebug() << "\n------------------ CODE --------------------"; - qDebug() << fullCode; + qDebug().noquote() << fullCode; qDebug() << "\n------------------ CODE --------------------"; - qDebug() << "Project file: " << proFile.fileName(); + qDebug().noquote() << "Project file: " << proFile.fileName(); } if (data.neededDwarfVersion.isRestricted) { @@ -1588,7 +1588,7 @@ void tst_Dumpers::dumper() if (m_debuggerEngine == GdbEngine) { int posDataStart = output.indexOf("data="); if (posDataStart == -1) { - qDebug() << "NO \"data=\" IN OUTPUT: " << output; + qDebug().noquote() << "NO \"data=\" IN OUTPUT: " << output; QVERIFY(posDataStart != -1); } contents = output.mid(posDataStart); @@ -1600,7 +1600,7 @@ void tst_Dumpers::dumper() //qDebug() << "FOUND NS: " << context.nameSpace; } else if (m_debuggerEngine == LldbEngine) { - //qDebug() << "GOT OUTPUT: " << output; + //qDebug().noquote() << "GOT OUTPUT: " << output; int pos = output.indexOf("data=[{"); QVERIFY(pos != -1); output = output.mid(pos); @@ -1608,7 +1608,7 @@ void tst_Dumpers::dumper() int posNameSpaceStart = output.indexOf("@NS@"); if (posNameSpaceStart == -1) - qDebug() << "OUTPUT: " << output; + qDebug().noquote() << "OUTPUT: " << output; QVERIFY(posNameSpaceStart != -1); posNameSpaceStart += sizeof("@NS@") - 1; int posNameSpaceEnd = output.indexOf("@", posNameSpaceStart); @@ -1624,7 +1624,7 @@ void tst_Dumpers::dumper() QByteArray locals("|script|"); int localsBeginPos = output.indexOf(locals, output.indexOf(localsAnswerStart)); if (localsBeginPos == -1) - qDebug() << "OUTPUT: " << output; + qDebug().noquote() << "OUTPUT: " << output; QVERIFY(localsBeginPos != -1); do { const int msgStart = localsBeginPos + locals.length(); @@ -1755,8 +1755,8 @@ void tst_Dumpers::dumper() break; qDebug() << "MSG: " << fullOutput.mid(pos1, pos2 - pos1 - 1); } - qDebug() << "CONTENTS : " << contents; - qDebug() << "FULL OUTPUT : " << fullOutput.data(); + qDebug().noquote() << "CONTENTS : " << contents; + qDebug().noquote() << "FULL OUTPUT : " << fullOutput.data(); qDebug() << "Qt VERSION : " << QString::number(context.qtVersion, 16); if (m_debuggerEngine != CdbEngine) qDebug() << "GCC VERSION : " << context.gccVersion; diff --git a/tests/auto/utils/camelhumpmatcher/tst_camelhumpmatcher.cpp b/tests/auto/utils/camelhumpmatcher/tst_camelhumpmatcher.cpp index dea71dbf235..3777c7b755f 100644 --- a/tests/auto/utils/camelhumpmatcher/tst_camelhumpmatcher.cpp +++ b/tests/auto/utils/camelhumpmatcher/tst_camelhumpmatcher.cpp @@ -57,6 +57,7 @@ void tst_CamelHumpMatcher::camelHumpMatcher_data() QTest::addColumn("expectedIndex"); QTest::newRow("underscore") << "vl" << "very_long_camel_hump" << 0; + QTest::newRow("underscore-uppercase") << "vl" << "VERY_LONG_CAMEL_HUMP" << 0; QTest::newRow("exact") << "VeryLongCamelHump" << "VeryLongCamelHump" << 0; QTest::newRow("prefix-segments") << "velo" << "very_long_Camel_hump" << 0; QTest::newRow("humps") << "vlc" << "VeryLongCamelHump" << 0; @@ -74,6 +75,7 @@ void tst_CamelHumpMatcher::camelHumpMatcher_data() QTest::newRow("no-partial") << "NCH" << "LongCamelHump" << -1; QTest::newRow("middle-after-number") << "CH" << "Long1CamelHump" << 5; QTest::newRow("middle-after-underscore") << "CH" << "long_camel_hump" << 5; + QTest::newRow("middle-after-underscore-uppercase") << "CH" << "LONG_CAMEL_HUMP" << 5; QTest::newRow("middle-continued") << "cahu" << "LongCamelHump" << 4; } diff --git a/tests/system/objects.map b/tests/system/objects.map index e8aa510c03c..02020a785f4 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -178,7 +178,7 @@ :QtVersionLabel_KitPage {container=':qt_tabwidget_stackedwidget_QWidget' text='Qt version:' type='QLabel' unnamed='1' visible='1'} :Remove_QPushButton {container=':qt_tabwidget_stackedwidget_QScrollArea' text='Remove' type='QPushButton' unnamed='1' visible='1'} :Restart required.OK_QPushButton {text='OK' type='QPushButton' unnamed='1' visible='1' window=':Restart required_QMessageBox'} -:Restart required_QMessageBox {text='The language change will take effect after a restart of Qt Creator.' type='QMessageBox' unnamed='1' visible='1'} +:Restart required_QMessageBox {text='The language change will take effect after restart.' type='QMessageBox' unnamed='1' visible='1'} :Revert to Saved.Proceed_QPushButton {text='Proceed' type='QPushButton' unnamed='1' visible='1' window=':Revert to Saved_QMessageBox'} :Revert to Saved_QMessageBox {text?='You will lose your current changes if you proceed reverting*' type='QMessageBox' unnamed='1' visible='1'} :RunSettingsEnvironmentDetails_Utils::DetailsButton {leftWidget=':RunSettingsUseBuildEnvironment_QLabel' text='Details' type='Utils::DetailsButton' unnamed='1' visible='1' window=':Qt Creator_Core::Internal::MainWindow'} diff --git a/tests/system/suite_editors/tst_delete_externally/test.py b/tests/system/suite_editors/tst_delete_externally/test.py index fa85df88ae5..89d72c6a88b 100644 --- a/tests/system/suite_editors/tst_delete_externally/test.py +++ b/tests/system/suite_editors/tst_delete_externally/test.py @@ -45,7 +45,8 @@ def main(): contentBefore = readFile(currentFile) os.remove(currentFile) if not currentFile.endswith(".bin"): - popupText = "The file %s was removed. Do you want to save it under a different name, or close the editor?" + popupText = ("The file %s has been removed from disk. Do you want to " + "save it under a different name, or close the editor?") test.compare(waitForObject(":File has been removed_QMessageBox").text, popupText % currentFile) clickButton(waitForObject(":File has been removed.Save_QPushButton")) @@ -56,11 +57,10 @@ def main(): test.compare(readFile(currentFile), contentBefore, "Verifying that file '%s' was restored correctly" % currentFile) - # Different warning because of QTCREATORBUG-8130 - popupText2 = "The file %s has been removed outside Qt Creator. Do you want to save it under a different name, or close the editor?" + # Test for QTCREATORBUG-8130 os.remove(currentFile) test.compare(waitForObject(":File has been removed_QMessageBox").text, - popupText2 % currentFile) + popupText % currentFile) clickButton(waitForObject(":File has been removed.Close_QPushButton")) test.verify(checkIfObjectExists(objectMap.realName(editor), False), "Was the editor closed after deleting the file?") diff --git a/tests/system/suite_editors/tst_edit_externally/test.py b/tests/system/suite_editors/tst_edit_externally/test.py index e48232e9a4d..c545b64dea3 100644 --- a/tests/system/suite_editors/tst_edit_externally/test.py +++ b/tests/system/suite_editors/tst_edit_externally/test.py @@ -45,9 +45,9 @@ def main(): if not startedWithoutPluginError(): return - mBox = ("{text?='The file * has changed outside Qt Creator. Do you want to reload it?' " + mBox = ("{text?='The file * has been changed on disk. Do you want to reload it?' " "type='QMessageBox' unnamed='1' visible='1'}") - popupText = "The file %s has changed outside Qt Creator. Do you want to reload it?" + popupText = "The file %s has been changed on disk. Do you want to reload it?" formerContent = None for i, currentFile in enumerate(files): diff --git a/tests/unit/unittest/clangasyncjob-base.cpp b/tests/unit/unittest/clangasyncjob-base.cpp index 81593c9ac3a..6535a15ef7c 100644 --- a/tests/unit/unittest/clangasyncjob-base.cpp +++ b/tests/unit/unittest/clangasyncjob-base.cpp @@ -49,10 +49,7 @@ void ClangAsyncJobTest::BaseSetUp(ClangBackEnd::JobRequest::Type jobRequestType, JobRequest ClangAsyncJobTest::createJobRequest(const Utf8String &filePath, JobRequest::Type type) const { - JobRequest jobRequest; - jobRequest.type = type; - jobRequest.expirationReasons = JobRequest::expirationReasonsForType(type); - jobRequest.conditions = JobRequest::conditionsForType(type); + JobRequest jobRequest(type); jobRequest.filePath = filePath; jobRequest.projectPartId = projectPartId; jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint(); diff --git a/tests/unit/unittest/clangfollowsymbol-test.cpp b/tests/unit/unittest/clangfollowsymbol-test.cpp index 046932034f0..566c02b0e5d 100644 --- a/tests/unit/unittest/clangfollowsymbol-test.cpp +++ b/tests/unit/unittest/clangfollowsymbol-test.cpp @@ -56,20 +56,11 @@ using ::ClangBackEnd::UnsavedFiles; using ::ClangBackEnd::ReferencesResult; using ::ClangBackEnd::SourceRangeContainer; -using ClangBackEnd::FollowSymbolResult; - namespace { const Utf8String sourceFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_main.cpp"); const Utf8String headerFilePath = Utf8StringLiteral(TESTDATA_DIR"/followsymbol_header.h"); const Utf8String cursorPath = Utf8StringLiteral(TESTDATA_DIR"/cursor.cpp"); -std::ostream &operator<<(std::ostream &os, const FollowSymbolResult &result) -{ - os << result.range; - - return os; -} - MATCHER_P3(MatchesHeaderSourceRange, line, column, length, std::string(negation ? "isn't " : "is ") + PrintToString(SourceRangeContainer { @@ -83,7 +74,7 @@ MATCHER_P3(MatchesHeaderSourceRange, line, column, length, SourceLocationContainer(headerFilePath, line, column + length) }; - return arg == FollowSymbolResult {expected, false}; + return arg == expected; } MATCHER_P3(MatchesSourceRange, line, column, length, @@ -99,7 +90,7 @@ MATCHER_P3(MatchesSourceRange, line, column, length, SourceLocationContainer(sourceFilePath, line, column + length) }; - return arg == FollowSymbolResult {expected, false}; + return arg == expected; } MATCHER_P4(MatchesFileSourceRange, filename, line, column, length, @@ -115,7 +106,7 @@ MATCHER_P4(MatchesFileSourceRange, filename, line, column, length, SourceLocationContainer(filename, line, column + length) }; - return arg == FollowSymbolResult {expected, false}; + return arg == expected; } class Data { @@ -150,7 +141,7 @@ private: class FollowSymbol : public ::testing::Test { protected: - FollowSymbolResult followSymbol(uint line, uint column) + SourceRangeContainer followSymbol(uint line, uint column) { ClangBackEnd::TranslationUnitUpdateInput updateInput = d->document().createUpdateInput(); const ClangBackEnd::CommandLineArguments currentArgs(updateInput.filePath.constData(), @@ -162,7 +153,7 @@ protected: currentArgs); } - FollowSymbolResult followHeaderSymbol(uint line, uint column) + SourceRangeContainer followHeaderSymbol(uint line, uint column) { ClangBackEnd::TranslationUnitUpdateInput updateInput = d->headerDocument().createUpdateInput(); diff --git a/tests/unit/unittest/clangjobqueue-test.cpp b/tests/unit/unittest/clangjobqueue-test.cpp index c3236a4d6da..dd3f4fc0364 100644 --- a/tests/unit/unittest/clangjobqueue-test.cpp +++ b/tests/unit/unittest/clangjobqueue-test.cpp @@ -538,10 +538,7 @@ JobRequest JobQueue::createJobRequest( JobRequest::Type type, PreferredTranslationUnit preferredTranslationUnit) const { - JobRequest jobRequest; - jobRequest.type = type; - jobRequest.expirationReasons = JobRequest::expirationReasonsForType(type); - jobRequest.conditions = JobRequest::conditionsForType(type); + JobRequest jobRequest(type); jobRequest.filePath = filePath; jobRequest.projectPartId = projectPartId; jobRequest.unsavedFilesChangeTimePoint = unsavedFiles.lastChangeTimePoint(); diff --git a/tests/unit/unittest/highlightingmarks-test.cpp b/tests/unit/unittest/highlightingmarks-test.cpp index 16c7bc59e60..1aeeb734feb 100644 --- a/tests/unit/unittest/highlightingmarks-test.cpp +++ b/tests/unit/unittest/highlightingmarks-test.cpp @@ -1184,6 +1184,42 @@ TEST_F(HighlightingMarks, UsingTemplateFunction) ASSERT_THAT(infos[3], HasOnlyType(HighlightingType::Function)); } +TEST_F(HighlightingMarks, HeaderNameIsInclusion) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(239, 31)); + ClangBackEnd::HighlightingMarkContainer container(infos[2]); + ASSERT_THAT(container.isIncludeDirectivePath(), true); +} + +TEST_F(HighlightingMarks, HeaderNameIsInclusionWithAngleBrackets) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(289, 31)); + ClangBackEnd::HighlightingMarkContainer container(infos[2]); + ASSERT_THAT(container.isIncludeDirectivePath(), true); +} + + +TEST_F(HighlightingMarks, NotInclusion) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(241, 13)); + ClangBackEnd::HighlightingMarkContainer container(infos[1]); + ASSERT_THAT(container.isIncludeDirectivePath(), false); +} + +TEST_F(HighlightingMarks, MacroIsIdentifier) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(232, 30)); + ClangBackEnd::HighlightingMarkContainer container(infos[2]); + ASSERT_THAT(container.isIdentifier(), true); +} + +TEST_F(HighlightingMarks, DefineIsNotIdentifier) +{ + const auto infos = translationUnit.highlightingMarksInRange(sourceRange(232, 30)); + ClangBackEnd::HighlightingMarkContainer container(infos[1]); + ASSERT_THAT(container.isIncludeDirectivePath(), false); +} + Data *HighlightingMarks::d; void HighlightingMarks::SetUpTestCase() diff --git a/tests/unit/unittest/mockmutex.h b/tests/unit/unittest/mockmutex.h new file mode 100644 index 00000000000..cccb34e2ff2 --- /dev/null +++ b/tests/unit/unittest/mockmutex.h @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +class MockMutex +{ +public: + using MutexType = MockMutex; + + MOCK_METHOD0(lock, void ()); + MOCK_METHOD0(unlock, void ()); +}; diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index 55c06cb81e4..bad4eefda2e 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -27,6 +27,8 @@ #include "googletest.h" +#include "mockmutex.h" + #include #include @@ -34,8 +36,19 @@ class MockSqliteDatabase { public: + using MutexType = MockMutex; + + MockSqliteDatabase() = default; + MockSqliteDatabase(const MockMutex &mockMutex) + { + ON_CALL(*this, databaseMutex()) + .WillByDefault(ReturnRef(const_cast(mockMutex))); + } + MOCK_METHOD1(execute, void (Utils::SmallStringView sqlStatement)); + MOCK_METHOD0(databaseMutex, + MockMutex &()); }; diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index 862742aedd9..386424386f9 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -25,31 +25,6 @@ #include "mocksqlitereadstatement.h" -template -std::vector values(std::size_t, QueryType...) -{ - FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload."; -} - -template -std::vector> values(std::size_t, - Utils::SmallStringView, - uint, - uint) -{ - FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload."; -} - -template class ContainerType, - typename ElementType> -std::vector> tupleValues(std::size_t, - const ContainerType &) -{ - FAIL() << "MockSqliteReadStatement::value was instanciated implicitly. Please add an explicit overload."; -} - template <> std::vector MockSqliteReadStatement::values(std::size_t reserveSize) { @@ -58,20 +33,24 @@ std::vector MockSqliteReadStatement::values(std::s template <> std::vector -MockSqliteReadStatement::structValues( - std::size_t reserveSize, - const Utils::PathString &sourcePath, - const uint &line, - const uint &column) +MockSqliteReadStatement::values(std::size_t reserveSize, + const Utils::PathString &sourcePath, + const uint &line, + const uint &column) { - return structValuesReturnStdVectorLocation(reserveSize, sourcePath, line, column); + return valuesReturnStdVectorLocation(reserveSize, sourcePath, line, column); } template <> std::vector -MockSqliteReadStatement::structValues( - std::size_t reserveSize, - const std::vector &sourceIds) +MockSqliteReadStatement::values(std::size_t reserveSize, const std::vector &sourceIds) { - return structValuesReturnStdVectorSource(reserveSize, sourceIds); + return valuesReturnStdVectorSource(reserveSize, sourceIds); +} + +template <> +Utils::optional +MockSqliteReadStatement::value(const Utils::SmallStringView &text) +{ + return valueReturnUInt32(text); } diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index f5b88c84673..b97ab1dc7d2 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -31,6 +31,7 @@ #include "mocksqlitedatabase.h" +#include #include #include @@ -53,28 +54,31 @@ public: MOCK_CONST_METHOD1(valuesReturnStdVectorInt, std::vector(std::size_t)); - MOCK_CONST_METHOD4(structValuesReturnStdVectorLocation, + MOCK_CONST_METHOD4(valuesReturnStdVectorLocation, std::vector(std::size_t, Utils::SmallStringView, qint64, qint64)); - MOCK_CONST_METHOD2(structValuesReturnStdVectorSource, + MOCK_CONST_METHOD2(valuesReturnStdVectorSource, std::vector(std::size_t, const std::vector &)); - template - std::vector values(std::size_t, QueryType...); + MOCK_CONST_METHOD1(valueReturnUInt32, + Utils::optional(Utils::SmallStringView)); + template - std::vector structValues(std::size_t reserveSize, const QueryType&... queryValues); + std::vector values(std::size_t reserveSize, const QueryType&... queryValues); template class QueryContainerType, typename QueryElementType> - std::vector structValues(std::size_t reserveSize, - const QueryContainerType &queryValues); + std::vector values(std::size_t reserveSize, + const QueryContainerType &queryValues); + template + Utils::optional value(const QueryTypes&... queryValues); public: Utils::SmallString sqlStatement; @@ -85,7 +89,7 @@ std::vector MockSqliteReadStatement::values(std::size_t reserveSize); template <> std::vector -MockSqliteReadStatement::structValues( +MockSqliteReadStatement::values( std::size_t reserveSize, const Utils::PathString &sourcePath, const uint &line, @@ -93,8 +97,11 @@ MockSqliteReadStatement::structValues( template <> std::vector -MockSqliteReadStatement::structValues( +MockSqliteReadStatement::values( std::size_t reserveSize, const std::vector &); +template <> +Utils::optional +MockSqliteReadStatement::value(const Utils::SmallStringView&); diff --git a/tests/unit/unittest/readandwritemessageblock-test.cpp b/tests/unit/unittest/readandwritemessageblock-test.cpp index ac57f833986..445743543a7 100644 --- a/tests/unit/unittest/readandwritemessageblock-test.cpp +++ b/tests/unit/unittest/readandwritemessageblock-test.cpp @@ -208,8 +208,7 @@ TEST_F(ReadAndWriteMessageBlock, CompareRequestFollowSymbol) QVector dependentFiles; dependentFiles.push_back(QString("somefile.cpp")); dependentFiles.push_back(QString("otherfile.cpp")); - CompareMessage(ClangBackEnd::RequestFollowSymbolMessage{fileContainer, dependentFiles, 13, 37, - false}); + CompareMessage(ClangBackEnd::RequestFollowSymbolMessage{fileContainer, dependentFiles, 13, 37}); } TEST_F(ReadAndWriteMessageBlock, CompareReferences) diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp new file mode 100644 index 00000000000..3f1c52a0212 --- /dev/null +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include + +#include + +namespace { + +using Initializer = ClangBackEnd::RefactoringDatabaseInitializer>; + +using Sqlite::Table; + +class RefactoringDatabaseInitializer : public testing::Test +{ +protected: + NiceMock mockMutex; + NiceMock mockDatabase{mockMutex}; + Initializer initializer{mockDatabase}; +}; + +TEST_F(RefactoringDatabaseInitializer, AddSymbolsTable) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); + + initializer.createSymbolsTable(); +} + +TEST_F(RefactoringDatabaseInitializer, AddLocationsTable) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId ON locations(sourceId)"))); + + initializer.createLocationsTable(); +} + +TEST_F(RefactoringDatabaseInitializer, AddSourcesTable) +{ + InSequence s; + + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)"))); + + initializer.createSourcesTable(); +} + + +TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) +{ + InSequence s; + + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId ON locations(sourceId)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); + + Initializer initializer{mockDatabase}; +} +} diff --git a/tests/unit/unittest/refactoringengine-test.cpp b/tests/unit/unittest/refactoringengine-test.cpp index 7367a33cdf2..a4f7d32d04a 100644 --- a/tests/unit/unittest/refactoringengine-test.cpp +++ b/tests/unit/unittest/refactoringengine-test.cpp @@ -129,12 +129,12 @@ void RefactoringEngine::SetUp() projectPart = CppTools::ProjectPart::Ptr(new CppTools::ProjectPart); projectPart->files.push_back(projectFile); - commandLine = Utils::SmallStringVector(ClangCompilerOptionsBuilder::build( - projectPart.data(), - projectFile.kind, - CppTools::CompilerOptionsBuilder::PchUsage::None, + ClangCompilerOptionsBuilder clangCOBuilder(*projectPart, CLANG_VERSION, - CLANG_RESOURCE_DIR)); + CLANG_RESOURCE_DIR); + commandLine = Utils::SmallStringVector(clangCOBuilder.build( + projectFile.kind, + CppTools::CompilerOptionsBuilder::PchUsage::None)); commandLine.push_back(qStringFilePath); } diff --git a/tests/unit/unittest/smallstring-test.cpp b/tests/unit/unittest/smallstring-test.cpp index ea18fcacc2d..345480182bc 100644 --- a/tests/unit/unittest/smallstring-test.cpp +++ b/tests/unit/unittest/smallstring-test.cpp @@ -286,21 +286,21 @@ TEST(SmallString, LongSmallStringHasShortSmallStringSizeZero) ASSERT_THAT(longText.shortStringSize(), 0); } -TEST(SmallString, BeginIsEqualEndForEmptySmallString) +TEST(SmallString, SmallStringBeginIsEqualEndForEmptySmallString) { SmallString text; ASSERT_THAT(text.begin(), Eq(text.end())); } -TEST(SmallString, BeginIsNotEqualEndForNonEmptySmallString) +TEST(SmallString, SmallStringBeginIsNotEqualEndForNonEmptySmallString) { SmallString text("x"); ASSERT_THAT(text.begin(), Ne(text.end())); } -TEST(SmallString, BeginPlusOneIsEqualEndForSmallStringWidthSizeOne) +TEST(SmallString, SmallStringBeginPlusOneIsEqualEndForSmallStringWidthSizeOne) { SmallString text("x"); @@ -309,21 +309,21 @@ TEST(SmallString, BeginPlusOneIsEqualEndForSmallStringWidthSizeOne) ASSERT_THAT(beginPlusOne, Eq(text.end())); } -TEST(SmallString, RBeginIsEqualREndForEmptySmallString) +TEST(SmallString, SmallStringRBeginIsEqualREndForEmptySmallString) { SmallString text; ASSERT_THAT(text.rbegin(), Eq(text.rend())); } -TEST(SmallString, RBeginIsNotEqualREndForNonEmptySmallString) +TEST(SmallString, SmallStringRBeginIsNotEqualREndForNonEmptySmallString) { SmallString text("x"); ASSERT_THAT(text.rbegin(), Ne(text.rend())); } -TEST(SmallString, RBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) +TEST(SmallString, SmallStringRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) { SmallString text("x"); @@ -332,21 +332,21 @@ TEST(SmallString, RBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) ASSERT_THAT(beginPlusOne, Eq(text.rend())); } -TEST(SmallString, ConstRBeginIsEqualREndForEmptySmallString) +TEST(SmallString, SmallStringConstRBeginIsEqualREndForEmptySmallString) { const SmallString text; ASSERT_THAT(text.rbegin(), Eq(text.rend())); } -TEST(SmallString, ConstRBeginIsNotEqualREndForNonEmptySmallString) +TEST(SmallString, SmallStringConstRBeginIsNotEqualREndForNonEmptySmallString) { const SmallString text("x"); ASSERT_THAT(text.rbegin(), Ne(text.rend())); } -TEST(SmallString, ConstRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) +TEST(SmallString, SmallStringSmallStringConstRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) { const SmallString text("x"); @@ -355,6 +355,273 @@ TEST(SmallString, ConstRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) ASSERT_THAT(beginPlusOne, Eq(text.rend())); } +TEST(SmallString, SmallStringDistanceBetweenBeginAndEndIsZeroForEmptyText) +{ + SmallString text(""); + + auto distance = std::distance(text.begin(), text.end()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, SmallStringDistanceBetweenBeginAndEndIsOneForOneSign) +{ + SmallString text("x"); + + auto distance = std::distance(text.begin(), text.end()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, SmallStringDistanceBetweenRBeginAndREndIsZeroForEmptyText) +{ + SmallString text(""); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, SmallStringDistanceBetweenRBeginAndREndIsOneForOneSign) +{ + SmallString text("x"); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, SmallStringBeginPointsToX) +{ + SmallString text("x"); + + auto sign = *text.begin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, SmallStringRBeginPointsToX) +{ + SmallString text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, ConstSmallStringBeginPointsToX) +{ + const SmallString text("x"); + + auto sign = *text.begin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, ConstSmallStringRBeginPointsToX) +{ + const SmallString text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, SmallStringViewBeginIsEqualEndForEmptySmallString) +{ + SmallStringView text{""}; + + ASSERT_THAT(text.begin(), Eq(text.end())); +} + +TEST(SmallString, SmallStringViewBeginIsNotEqualEndForNonEmptySmallString) +{ + SmallStringView text("x"); + + ASSERT_THAT(text.begin(), Ne(text.end())); +} + +TEST(SmallString, SmallStringViewBeginPlusOneIsEqualEndForSmallStringWidthSizeOne) +{ + SmallStringView text("x"); + + auto beginPlusOne = text.begin() + std::size_t(1); + + ASSERT_THAT(beginPlusOne, Eq(text.end())); +} + +TEST(SmallString, SmallStringViewRBeginIsEqualREndForEmptySmallString) +{ + SmallStringView text{""}; + + ASSERT_THAT(text.rbegin(), Eq(text.rend())); +} + +TEST(SmallString, SmallStringViewRBeginIsNotEqualREndForNonEmptySmallString) +{ + SmallStringView text("x"); + + ASSERT_THAT(text.rbegin(), Ne(text.rend())); +} + +TEST(SmallString, SmallStringViewRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) +{ + SmallStringView text("x"); + + auto beginPlusOne = text.rbegin() + 1l; + + ASSERT_THAT(beginPlusOne, Eq(text.rend())); +} + +TEST(SmallString, SmallStringViewConstRBeginIsEqualREndForEmptySmallString) +{ + const SmallStringView text{""}; + + ASSERT_THAT(text.rbegin(), Eq(text.rend())); +} + +TEST(SmallString, SmallStringViewConstRBeginIsNotEqualREndForNonEmptySmallString) +{ + const SmallStringView text("x"); + + ASSERT_THAT(text.rbegin(), Ne(text.rend())); +} + +TEST(SmallString, SmallStringViewConstRBeginPlusOneIsEqualREndForSmallStringWidthSizeOne) +{ + const SmallStringView text("x"); + + auto beginPlusOne = text.rbegin() + 1l; + + ASSERT_THAT(beginPlusOne, Eq(text.rend())); +} + +TEST(SmallString, SmallStringViewDistanceBetweenBeginAndEndIsZeroForEmptyText) +{ + SmallStringView text(""); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, SmallStringViewDistanceBetweenBeginAndEndIsOneForOneSign) +{ + SmallStringView text("x"); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, SmallStringViewDistanceBetweenRBeginAndREndIsZeroForEmptyText) +{ + SmallStringView text(""); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, SmallStringViewDistanceBetweenRBeginAndREndIsOneForOneSign) +{ + SmallStringView text("x"); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, ConstSmallStringViewDistanceBetweenBeginAndEndIsZeroForEmptyText) +{ + const SmallStringView text(""); + + auto distance = std::distance(text.begin(), text.end()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, ConstSmallStringViewDistanceBetweenBeginAndEndIsOneForOneSign) +{ + const SmallStringView text("x"); + + auto distance = std::distance(text.begin(), text.end()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, ConstSmallStringViewDistanceBetweenRBeginAndREndIsZeroForEmptyText) +{ + const SmallStringView text(""); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 0); +} + +TEST(SmallString, ConstSmallStringViewDistanceBetweenRBeginAndREndIsOneForOneSign) +{ + const SmallStringView text("x"); + + auto distance = std::distance(text.rbegin(), text.rend()); + + ASSERT_THAT(distance, 1); +} + +TEST(SmallString, SmallStringViewBeginPointsToX) +{ + SmallStringView text("x"); + + auto sign = *text.begin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, SmallStringViewRBeginPointsToX) +{ + SmallStringView text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, ConstSmallStringViewBeginPointsToX) +{ + const SmallStringView text("x"); + + auto sign = *text.begin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, ConstSmallStringViewRBeginPointsToX) +{ + const SmallStringView text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, SmallStringLiteralViewRBeginPointsToX) +{ + SmallStringLiteral text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + +TEST(SmallString, ConstSmallStringLiteralViewRBeginPointsToX) +{ + const SmallStringLiteral text("x"); + + auto sign = *text.rbegin(); + + ASSERT_THAT(sign, 'x'); +} + TEST(SmallString, ConstructorStandardString) { std::string stdStringText = "short string"; @@ -737,6 +1004,12 @@ TEST(SmallString, StringViewIsEmpty) ASSERT_TRUE(SmallStringView("").isEmpty()); } +TEST(SmallString, StringViewEmpty) +{ + ASSERT_FALSE(SmallStringView("text").empty()); + ASSERT_TRUE(SmallStringView("").empty()); +} + TEST(SmallString, HasContent) { ASSERT_TRUE(SmallString("text").hasContent()); diff --git a/tests/unit/unittest/sqlitedatabase-test.cpp b/tests/unit/unittest/sqlitedatabase-test.cpp index 83dd405122c..98b14359458 100644 --- a/tests/unit/unittest/sqlitedatabase-test.cpp +++ b/tests/unit/unittest/sqlitedatabase-test.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -96,6 +97,30 @@ TEST_F(SqliteDatabase, AddTable) ASSERT_THAT(database.tables(), Contains(sqliteTable)); } +TEST_F(SqliteDatabase, GetChangesCount) +{ + Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + statement.write(42); + + ASSERT_THAT(database.changesCount(), 1); +} + +TEST_F(SqliteDatabase, GetTotalChangesCount) +{ + Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + statement.write(42); + + ASSERT_THAT(database.lastInsertedRowId(), 1); +} + +TEST_F(SqliteDatabase, GetLastInsertedRowId) +{ + Sqlite::WriteStatement statement("INSERT INTO test(name) VALUES (?)", database); + statement.write(42); + + ASSERT_THAT(database.lastInsertedRowId(), 1); +} + TEST_F(SqliteDatabase, TableIsReadyAfterOpenDatabase) { database.close(); @@ -112,6 +137,10 @@ void SqliteDatabase::SetUp() { database.setJournalMode(JournalMode::Memory); database.setDatabaseFilePath(databaseFilePath); + auto &table = database.addTable(); + table.setName("test"); + table.addColumn("name"); + database.open(); } diff --git a/tests/unit/unittest/sqlitedatabasebackend-test.cpp b/tests/unit/unittest/sqlitedatabasebackend-test.cpp index fb7fb032d9f..7663139f013 100644 --- a/tests/unit/unittest/sqlitedatabasebackend-test.cpp +++ b/tests/unit/unittest/sqlitedatabasebackend-test.cpp @@ -61,19 +61,21 @@ using SqliteDatabaseBackendSlowTest = SqliteDatabaseBackend; TEST_F(SqliteDatabaseBackend, OpenAlreadyOpenDatabase) { - ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite), Exception); + ASSERT_THROW(databaseBackend.open(databaseFilePath, OpenMode::ReadWrite), + Sqlite::DatabaseIsAlreadyOpen); } TEST_F(SqliteDatabaseBackend, CloseAlreadyClosedDatabase) { databaseBackend.close(); - ASSERT_THROW(databaseBackend.close(), Exception); + ASSERT_THROW(databaseBackend.close(), Sqlite::DatabaseIsAlreadyClosed); } TEST_F(SqliteDatabaseBackend, OpenWithWrongPath) { - ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db", OpenMode::ReadWrite), Exception); + ASSERT_THROW(databaseBackend.open("/xxx/SqliteDatabaseBackendTest.db", OpenMode::ReadWrite), + Sqlite::WrongFilePath); } TEST_F(SqliteDatabaseBackend, DefaultJournalMode) @@ -148,7 +150,8 @@ TEST_F(SqliteDatabaseBackend, TextEncodingCannotBeChangedAfterTouchingDatabase) databaseBackend.execute("CREATE TABLE text(name, number)"); - ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16), Exception); + ASSERT_THROW(databaseBackend.setTextEncoding(TextEncoding::Utf16), + Sqlite::PragmaValueNotSet); } TEST_F(SqliteDatabaseBackend, OpenModeReadOnly) diff --git a/tests/unit/unittest/sqlitestatement-test.cpp b/tests/unit/unittest/sqlitestatement-test.cpp index 21eabdfadd2..30ea9cbca84 100644 --- a/tests/unit/unittest/sqlitestatement-test.cpp +++ b/tests/unit/unittest/sqlitestatement-test.cpp @@ -24,6 +24,7 @@ ****************************************************************************/ #include "googletest.h" +#include "sqliteteststatement.h" #include #include @@ -54,7 +55,7 @@ MATCHER_P3(HasValues, value1, value2, rowid, { Database &database = arg.database(); - ReadStatement statement("SELECT name, number FROM test WHERE rowid=?", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE rowid=?", database); statement.bind(1, rowid); statement.next(); @@ -74,6 +75,10 @@ protected: struct Output { + Output(Utils::SmallString name, Utils::SmallString number, long long value) + : name(name), number(number), value(value) + {} + Utils::SmallString name; Utils::SmallString number; long long value; @@ -87,17 +92,26 @@ struct Output } }; -TEST_F(SqliteStatement, PrepareFailure) +TEST_F(SqliteStatement, ThrowsStatementHasErrorForWrongSqlStatement) { - ASSERT_THROW(ReadStatement("blah blah blah", database), Exception); - ASSERT_THROW(WriteStatement("blah blah blah", database), Exception); - ASSERT_THROW(ReadStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception); - ASSERT_THROW(WriteStatement("SELECT name, number FROM test '", database), Exception); + ASSERT_THROW(ReadStatement("blah blah blah", database), Sqlite::StatementHasError); +} + +TEST_F(SqliteStatement, ThrowsNotReadOnlySqlStatementForWritableSqlStatementInReadStatement) +{ + ASSERT_THROW(ReadStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), + Sqlite::NotReadOnlySqlStatement); +} + +TEST_F(SqliteStatement, ThrowsNotReadonlySqlStatementForWritableSqlStatementInReadStatement) +{ + ASSERT_THROW(WriteStatement("SELECT name, number FROM test", database), + Sqlite::NotWriteSqlStatement); } TEST_F(SqliteStatement, CountRows) { - ReadStatement statement("SELECT * FROM test", database); + SqliteTestStatement statement("SELECT * FROM test", database); int nextCount = 0; while (statement.next()) ++nextCount; @@ -109,36 +123,50 @@ TEST_F(SqliteStatement, CountRows) TEST_F(SqliteStatement, Value) { - ReadStatement statement("SELECT name, number FROM test ORDER BY name", database); + SqliteTestStatement statement("SELECT name, number FROM test ORDER BY name", database); statement.next(); statement.next(); - ASSERT_THAT(statement.value(0), 0); - ASSERT_THAT(statement.value(0), 0); - ASSERT_THAT(statement.value(0), 0.0); + ASSERT_THAT(statement.fetchValue(0), 0); + ASSERT_THAT(statement.fetchValue(0), 0); + ASSERT_THAT(statement.fetchValue(0), 0.0); ASSERT_THAT(statement.text(0), "foo"); - ASSERT_THAT(statement.value(1), 23); - ASSERT_THAT(statement.value(1), 23); - ASSERT_THAT(statement.value(1), 23.3); + ASSERT_THAT(statement.fetchValue(1), 23); + ASSERT_THAT(statement.fetchValue(1), 23); + ASSERT_THAT(statement.fetchValue(1), 23.3); ASSERT_THAT(statement.text(1), "23.3"); } -TEST_F(SqliteStatement, ValueFailure) +TEST_F(SqliteStatement, ThrowNoValuesToFetchForNotSteppedStatement) { - ReadStatement statement("SELECT name, number FROM test", database); - ASSERT_THROW(statement.value(0), Exception); + SqliteTestStatement statement("SELECT name, number FROM test", database); - statement.reset(); + ASSERT_THROW(statement.fetchValue(0), Sqlite::NoValuesToFetch); +} +TEST_F(SqliteStatement, ThrowNoValuesToFetchForDoneStatement) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); while (statement.next()) {} - ASSERT_THROW(statement.value(0), Exception); - statement.reset(); + ASSERT_THROW(statement.fetchValue(0), Sqlite::NoValuesToFetch); +} +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNegativeColumn) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); statement.next(); - ASSERT_THROW(statement.value(-1), Exception); - ASSERT_THROW(statement.value(2), Exception); + + ASSERT_THROW(statement.fetchValue(-1), Sqlite::InvalidColumnFetched); +} + +TEST_F(SqliteStatement, ThrowInvalidColumnFetchedForNotExistingColumn) +{ + SqliteTestStatement statement("SELECT name, number FROM test", database); + statement.next(); + + ASSERT_THROW(statement.fetchValue(2), Sqlite::InvalidColumnFetched); } TEST_F(SqliteStatement, ToIntergerValue) @@ -165,7 +193,7 @@ TEST_F(SqliteStatement, ToStringValue) TEST_F(SqliteStatement, ColumnNames) { - ReadStatement statement("SELECT name, number FROM test", database); + SqliteTestStatement statement("SELECT name, number FROM test", database); auto columnNames = statement.columnNames(); @@ -175,19 +203,19 @@ TEST_F(SqliteStatement, ColumnNames) TEST_F(SqliteStatement, BindString) { - ReadStatement statement("SELECT name, number FROM test WHERE name=?", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE name=?", database); statement.bind(1, "foo"); statement.next(); ASSERT_THAT(statement.text(0), "foo"); - ASSERT_THAT(statement.value(1), 23.3); + ASSERT_THAT(statement.fetchValue(1), 23.3); } TEST_F(SqliteStatement, BindInteger) { - ReadStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, 40); statement.next(); @@ -197,7 +225,7 @@ TEST_F(SqliteStatement, BindInteger) TEST_F(SqliteStatement, BindLongInteger) { - ReadStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, int64_t(40)); statement.next(); @@ -207,7 +235,7 @@ TEST_F(SqliteStatement, BindLongInteger) TEST_F(SqliteStatement, BindDouble) { - ReadStatement statement("SELECT name, number FROM test WHERE number=?", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=?", database); statement.bind(1, 23.3); statement.next(); @@ -217,7 +245,7 @@ TEST_F(SqliteStatement, BindDouble) TEST_F(SqliteStatement, BindIntegerByParameter) { - ReadStatement statement("SELECT name, number FROM test WHERE number=@number", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); statement.bind("@number", 40); statement.next(); @@ -227,7 +255,7 @@ TEST_F(SqliteStatement, BindIntegerByParameter) TEST_F(SqliteStatement, BindLongIntegerByParameter) { - ReadStatement statement("SELECT name, number FROM test WHERE number=@number", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); statement.bind("@number", int64_t(40)); statement.next(); @@ -237,7 +265,7 @@ TEST_F(SqliteStatement, BindLongIntegerByParameter) TEST_F(SqliteStatement, BindDoubleByIndex) { - ReadStatement statement("SELECT name, number FROM test WHERE number=@number", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@number", database); statement.bind(statement.bindingIndexForName("@number"), 23.3); statement.next(); @@ -245,25 +273,37 @@ TEST_F(SqliteStatement, BindDoubleByIndex) ASSERT_THAT(statement.text(0), "foo"); } -TEST_F(SqliteStatement, BindFailure) +TEST_F(SqliteStatement, BindIndexIsZeroIsThrowingBindingIndexIsOutOfBound) { - ReadStatement statement("SELECT name, number FROM test WHERE number=@number", database); + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); - ASSERT_THROW(statement.bind(0, 40), Exception); - ASSERT_THROW(statement.bind(2, 40), Exception); - ASSERT_THROW(statement.bind("@name", 40), Exception); + ASSERT_THROW(statement.bind(0, 40), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, BindIndexIsTpLargeIsThrowingBindingIndexIsOutOfBound) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=$1", database); + + ASSERT_THROW(statement.bind(2, 40), Sqlite::BindingIndexIsOutOfRange); +} + +TEST_F(SqliteStatement, WrongBindingNameThrowingBindingIndexIsOutOfBound) +{ + SqliteTestStatement statement("SELECT name, number FROM test WHERE number=@name", database); + + ASSERT_THROW(statement.bind("@name2", 40), Sqlite::WrongBingingName); } TEST_F(SqliteStatement, RequestBindingNamesFromStatement) { - WriteStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); + SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); ASSERT_THAT(statement.bindingColumnNames(), ElementsAre("name", "number", "id")); } TEST_F(SqliteStatement, BindValues) { - WriteStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); + SqliteTestStatement statement("UPDATE test SET name=?, number=? WHERE rowid=?", database); statement.bindValues("see", 7.23, 1); statement.execute(); @@ -282,7 +322,7 @@ TEST_F(SqliteStatement, WriteValues) TEST_F(SqliteStatement, BindNamedValues) { - WriteStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); + SqliteTestStatement statement("UPDATE test SET name=@name, number=@number WHERE rowid=@id", database); statement.bindNameValues("@name", "see", "@number", 7.23, "@id", 1); statement.execute(); @@ -299,13 +339,20 @@ TEST_F(SqliteStatement, WriteNamedValues) ASSERT_THAT(statement, HasValues("see", "7.23", 1)); } -TEST_F(SqliteStatement, ClosedDatabase) +TEST_F(SqliteStatement, CannotWriteToClosedDatabase) { database.close(); - ASSERT_THROW(WriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception); - ASSERT_THROW(ReadStatement("SELECT * FROM test", database), Exception); - ASSERT_THROW(ReadWriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), Exception); - database.open(QDir::tempPath() + QStringLiteral("/SqliteStatementTest.db")); + + ASSERT_THROW(WriteStatement("INSERT INTO test(name, number) VALUES (?, ?)", database), + Sqlite::DatabaseIsNotOpen); +} + +TEST_F(SqliteStatement, CannotReadFromClosedDatabase) +{ + database.close(); + + ASSERT_THROW(ReadStatement("SELECT * FROM test", database), + Sqlite::DatabaseIsNotOpen); } TEST_F(SqliteStatement, GetTupleValuesWithoutArguments) @@ -313,7 +360,7 @@ TEST_F(SqliteStatement, GetTupleValuesWithoutArguments) using Tuple = std::tuple; ReadStatement statement("SELECT name, number, value FROM test", database); - auto values = statement.tupleValues(3); + auto values = statement.values(3); ASSERT_THAT(values, ElementsAre(Tuple{"bar", 0, 1}, Tuple{"foo", 23.3, 2}, @@ -333,7 +380,7 @@ TEST_F(SqliteStatement, GetStructValuesWithoutArguments) { ReadStatement statement("SELECT name, number, value FROM test", database); - auto values = statement.structValues(3); + auto values = statement.values(3); ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1}, Output{"foo", "23.3", 2}, @@ -356,7 +403,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryValues) std::vector queryValues = {40, 23.3}; ReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database); - auto values = statement.tupleValues(3, queryValues); + auto values = statement.values(3, queryValues); ASSERT_THAT(values, ElementsAre(Tuple{"poo", 40, 3.}, Tuple{"foo", 23.3, 2.})); @@ -375,14 +422,14 @@ TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryValues) TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndContainerQueryTupleValues) { using Tuple = std::tuple; - using Tuple2 = std::tuple; + using ResultTuple = std::tuple; std::vector queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}}; ReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database); - auto values = statement.tupleValues(3, queryValues); + auto values = statement.values(3, queryValues); - ASSERT_THAT(values, ElementsAre(Tuple2{"poo", 40, 3}, - Tuple2{"bar", 0, 1})); + ASSERT_THAT(values, ElementsAre(ResultTuple{"poo", 40, 3}, + ResultTuple{"bar", 0, 1})); } TEST_F(SqliteStatement, GetValuesForSingleOutputValuesAndContainerQueryTupleValues) @@ -401,7 +448,7 @@ TEST_F(SqliteStatement, GetValuesForMultipleOutputValuesAndMultipleQueryValue) using Tuple = std::tuple; ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto values = statement.tupleValues(3, "bar", "blah", 1); + auto values = statement.values(3, "bar", "blah", 1); ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1})); } @@ -410,9 +457,9 @@ TEST_F(SqliteStatement, CallGetValuesForMultipleOutputValuesAndMultipleQueryValu { using Tuple = std::tuple; ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=?", database); - statement.tupleValues(3, "bar", "blah"); + statement.values(3, "bar", "blah"); - auto values = statement.tupleValues(3, "bar", "blah"); + auto values = statement.values(3, "bar", "blah"); ASSERT_THAT(values, ElementsAre(Tuple{"bar", "blah", 1})); } @@ -421,7 +468,7 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndMultipleQueryValue) { ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); - auto values = statement.structValues(3, "bar", "blah", 1); + auto values = statement.values(3, "bar", "blah", 1); ASSERT_THAT(values, ElementsAre(Output{"bar", "blah", 1})); } @@ -431,7 +478,7 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryValues) std::vector queryValues = {40, 23.3}; ReadStatement statement("SELECT name, number, value FROM test WHERE number=?", database); - auto values = statement.structValues(3, queryValues); + auto values = statement.values(3, queryValues); ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3}, Output{"foo", "23.3", 2})); @@ -443,12 +490,41 @@ TEST_F(SqliteStatement, GetStructOutputValuesAndContainerQueryTupleValues) std::vector queryValues = {{"poo", "40", 3}, {"bar", "blah", 1}}; ReadStatement statement("SELECT name, number, value FROM test WHERE name= ? AND number=? AND value=?", database); - auto values = statement.structValues(3, queryValues); + auto values = statement.values(3, queryValues); ASSERT_THAT(values, ElementsAre(Output{"poo", "40", 3}, Output{"bar", "blah", 1})); } +TEST_F(SqliteStatement, GetOptionalSingleValueAndMultipleQueryValue) +{ + ReadStatement statement("SELECT name FROM test WHERE name=? AND number=? AND value=?", database); + + auto value = statement.value("bar", "blah", 1); + + ASSERT_THAT(value.value(), Eq("bar")); +} + +TEST_F(SqliteStatement, GetOptionalOutputValueAndMultipleQueryValue) +{ + ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + + auto value = statement.value("bar", "blah", 1); + + ASSERT_THAT(value.value(), Eq(Output{"bar", "blah", 1})); +} + +TEST_F(SqliteStatement, GetOptionalTupleValueAndMultipleQueryValue) +{ + using Tuple = std::tuple; + ReadStatement statement("SELECT name, number, value FROM test WHERE name=? AND number=? AND value=?", database); + + auto value = statement.value("bar", "blah", 1); + + ASSERT_THAT(value.value(), Eq(Tuple{"bar", "blah", 1})); +} + + void SqliteStatement::SetUp() { database.setJournalMode(JournalMode::Memory); @@ -461,7 +537,8 @@ void SqliteStatement::SetUp() void SqliteStatement::TearDown() { - database.close(); + if (database.isOpen()) + database.close(); } } diff --git a/tests/unit/unittest/sqliteteststatement.h b/tests/unit/unittest/sqliteteststatement.h new file mode 100644 index 00000000000..870180b5d05 --- /dev/null +++ b/tests/unit/unittest/sqliteteststatement.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#pragma once + +#include + +class SQLITE_EXPORT SqliteTestStatement : public Sqlite::Statement +{ +public: + explicit SqliteTestStatement(Utils::SmallStringView sqlStatement, Sqlite::Database &database) + : Sqlite::Statement(sqlStatement, database) + {} + + using Statement::bind; + using Statement::bindingColumnNames; + using Statement::bindingIndexForName; + using Statement::bindNameValues; + using Statement::bindValues; + using Statement::columnNames; + using Statement::database; + using Statement::execute; + using Statement::next; + using Statement::text; + using Statement::fetchValue; + +protected: + void checkIsWritableStatement(); +}; + diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp new file mode 100644 index 00000000000..69f90a71221 --- /dev/null +++ b/tests/unit/unittest/sqlitetransaction-test.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include +#include + +namespace { + +using DeferredTransaction = Sqlite::DeferredTransaction; +using ImmediateTransaction = Sqlite::ImmediateTransaction; +using ExclusiveTransaction = Sqlite::ExclusiveTransaction; + +class SqliteTransaction : public testing::Test +{ +protected: + MockMutex mockMutex; + MockSqliteDatabase mockDatabase{mockMutex}; +}; + +TEST_F(SqliteTransaction, DeferredTransactionCommit) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN"))); + EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); + + DeferredTransaction transaction{mockDatabase}; + transaction.commit(); +} + +TEST_F(SqliteTransaction, DeferredTransactionRollBack) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN"))); + EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK"))); + EXPECT_CALL(mockMutex, unlock()); + + DeferredTransaction transaction{mockDatabase}; +} + +TEST_F(SqliteTransaction, ImmediateTransactionCommit) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); + EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); + + ImmediateTransaction transaction{mockDatabase}; + transaction.commit(); +} + +TEST_F(SqliteTransaction, ImmediateTransactionRollBack) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); + EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK"))); + EXPECT_CALL(mockMutex, unlock()); + + ImmediateTransaction transaction{mockDatabase}; +} + +TEST_F(SqliteTransaction, ExclusiveTransactionCommit) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN EXCLUSIVE"))); + EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); + + ExclusiveTransaction transaction{mockDatabase}; + transaction.commit(); +} + +TEST_F(SqliteTransaction, ExclusiveTransactionRollBack) +{ + EXPECT_CALL(mockDatabase, databaseMutex()); + EXPECT_CALL(mockMutex, lock()); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN EXCLUSIVE"))); + EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK"))); + EXPECT_CALL(mockMutex, unlock()); + + ExclusiveTransaction transaction{mockDatabase}; +} + +} + + diff --git a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp index cdf48b5817c..0995663ad44 100644 --- a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp @@ -42,54 +42,22 @@ using Sqlite::Table; class StorageSqliteStatementFactory : public testing::Test { protected: - NiceMock mockDatabase; + NiceMock mockMutex; + NiceMock mockDatabase{mockMutex}; StatementFactory factory{mockDatabase}; }; -TEST_F(StorageSqliteStatementFactory, AddSymbolsTable) -{ - InSequence s; - - EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); - EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); - - factory.createSymbolsTable(); -} - -TEST_F(StorageSqliteStatementFactory, AddLocationsTable) -{ - InSequence s; - - EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId ON locations(sourceId)"))); - EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); - - factory.createLocationsTable(); -} - -TEST_F(StorageSqliteStatementFactory, AddSourcesTable) -{ - InSequence s; - - EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); - - factory.createSourcesTable(); -} - TEST_F(StorageSqliteStatementFactory, AddNewSymbolsTable) { InSequence s; + EXPECT_CALL(mockMutex, lock()); EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); factory.createNewSymbolsTable(); } @@ -99,24 +67,23 @@ TEST_F(StorageSqliteStatementFactory, AddNewLocationsTable) { InSequence s; + EXPECT_CALL(mockMutex, lock()); EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newLocations_sourceId ON newLocations(sourceId)"))); EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); factory.createNewLocationsTable(); } TEST_F(StorageSqliteStatementFactory, AddTablesInConstructor) { - EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))).Times(5); - EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))).Times(5); + EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))).Times(2); + EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))).Times(2); + EXPECT_CALL(mockMutex, lock()).Times(2); + EXPECT_CALL(mockMutex, unlock()).Times(2); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId ON locations(sourceId)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, sourcePath TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)"))); diff --git a/tests/unit/unittest/symbolquery-test.cpp b/tests/unit/unittest/symbolquery-test.cpp index 2de8cc251b4..50925bd7f3c 100644 --- a/tests/unit/unittest/symbolquery-test.cpp +++ b/tests/unit/unittest/symbolquery-test.cpp @@ -63,9 +63,9 @@ protected: TEST_F(SymbolQuery, LocationsAt) { - EXPECT_CALL(selectLocationsForSymbolLocation, structValuesReturnStdVectorLocation(_, Eq("/path/to/file.cpp"), 14, 7)) + EXPECT_CALL(selectLocationsForSymbolLocation, valuesReturnStdVectorLocation(_, Eq("/path/to/file.cpp"), 14, 7)) .WillRepeatedly(Return(locations)); - EXPECT_CALL(selectSourcePathForId, structValuesReturnStdVectorSource(_, ElementsAre(1, 2, 4))); + EXPECT_CALL(selectSourcePathForId, valuesReturnStdVectorSource(_, ElementsAre(1, 2, 4))); query.locationsAt("/path/to/file.cpp", 14, 7); } diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index fd8715b71b6..2628157a330 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -59,9 +59,9 @@ protected: protected: FilePathCache filePathCache; - NiceMock mockDatabase; + NiceMock mockMutex; + NiceMock mockDatabase{mockMutex}; StatementFactory statementFactory{mockDatabase}; - MockSqliteWriteStatement &insertSymbolsToNewSymbolsStatement = statementFactory.insertSymbolsToNewSymbolsStatement; MockSqliteWriteStatement &insertLocationsToNewLocationsStatement = statementFactory.insertLocationsToNewLocationsStatement; MockSqliteWriteStatement &insertSourcesStatement = statementFactory.insertSourcesStatement; @@ -172,6 +172,7 @@ TEST_F(SymbolStorage, AddSymbolsAndSourceLocationsCallsWrite) { InSequence sequence; + EXPECT_CALL(mockMutex, lock()); EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))); EXPECT_CALL(insertSymbolsToNewSymbolsStatement, write(_, _, _)).Times(2); EXPECT_CALL(insertLocationsToNewLocationsStatement, write(1, 42, 23, 3)); @@ -188,6 +189,7 @@ TEST_F(SymbolStorage, AddSymbolsAndSourceLocationsCallsWrite) EXPECT_CALL(deleteNewSymbolsTableStatement, execute()); EXPECT_CALL(deleteNewLocationsTableStatement, execute()); EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))); + EXPECT_CALL(mockMutex, unlock()); storage.addSymbolsAndSourceLocations(symbolEntries, sourceLocations); } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 4b579ac7792..25ba21f42f8 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -74,7 +74,9 @@ SOURCES += \ symbolquery-test.cpp \ storagesqlitestatementfactory-test.cpp \ querysqlitestatementfactory-test.cpp \ - sqliteindex-test.cpp + sqliteindex-test.cpp \ + sqlitetransaction-test.cpp \ + refactoringdatabaseinitializer-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -200,7 +202,9 @@ HEADERS += \ mocksqlitedatabase.h \ mocksqlitereadstatement.h \ google-using-declarations.h \ - mocksymbolindexing.h + mocksymbolindexing.h \ + sqliteteststatement.h \ + mockmutex.h !isEmpty(LIBCLANG_LIBS) { HEADERS += \